조코딩님의 영상을 보면서 context7 remote MCP server를 로컬claude desktop과 연동하려고 했는데 문제가 생겨버림..
우선 smithery라고 MCP tool들을 모아둔 웹사이트에서 claude desktop과 연동하고 싶은 tool로 들어간다. 우리의 경우, 사용자 요청에 따라 관련된 개발 문서나 코딩 예제를 claude한테 갖다주는 context7이라는 tool을 사용할 것임.
영상에서는 해당 tool의 download섹션에 있는 json파일 내용을 claude_desktop_config.json 에 그대로 복붙하면 곧바로 tool을 사용할 수 있다고 나왔는데, smithery가 방식을 바꾼 건지 복붙할 수 있는 json파일이 아무리 찾아봐도 없었다.

대신 사이트에 나와있는npx -y @smithery/cli@latest install @upstash/context7-mcp --client claude 라는 코맨드를 통해 해결할 수 있었다.
*주의: 해당 코맨드는 MCP 서버를 로컬에 설치하는 명령이 아니고 Claude Desktop용 MCP 연결 설정을 자동 생성하는 명령임
즉, 무슨 말이냐 하면 이 context7은 애초에 remote server이므로 코드를 로컬로 가져와서 MCP 서버가 로컬에서 돌아가는 방식이 아님.
->이미 어딘가에서 돌아가고 있는 원격 MCP 서버임.
(대략 설명하자면 MCP 클라이언트에 해당되는 Claude가 필요할 때마다 로컬에서 프록시 subprocess를 실행해서 이 프록시를 통해 원격 MCP 서버와 소통하게 됨->추후에 더 설명할 것)
해당 명령 실행 후, 로컬에 있는 claude_desktop_config.json 파일을 까봤더니, 다음과 같은 항목이 자동 생성되어있는 걸 확인했다. 이렇게 하면 MCP 서버 자동 연결 설정이 끝인줄 알았으나..
{
"mcpServers": {
"context7-mcp": {
"command": "cmd",
"args": [
"/c",
"npx",
"-y",
"mcp-remote",
"https://server.smithery.ai/@upstash/context7-mcp/mcp"
]
}
}
}
여전히 Claude Desktop에 개발자 메뉴에 MCP 서버 아무것도 잡히지 않아서 GPT한테 물어보니까 config에 "type"항목을 추가해서 명시하라고 한다.
실제로 Claude Code 문서를 읽어봤더니 다음과 같이 type 항목을 넣어줘야하는 것을 알 수 있다.

여기서 MCP transport(전송) 방식 중 stdio 에 대해 좀 더 공부하고 가자.
stdio 방식의 MCP는 stdin / stdout (입출력 파이프) 를 통해 JSON-RPC 메시지를 주고받음으로써 MCP 클라이언트와 서버가 소통하는 방식이다.
참고로 stdin/stdout은 사람이 터미널에 타이핑하는 입력이 아니라 프로그램 ↔ 프로그램 사이에 OS가 연결해준 파이프라고 한다.
앞서도 잠깐 언급했지만 이 실습에서는 로컬 MCP 서버를 띄운 게 아니고 (원격)remote MCP 서버를 사용했고, 이를 위해 mcp-remote라는 프록시(중계기) 가 끼어 있었다.
구조는 다음과 같다.
Claude Desktop
⇅ (stdio, JSON-RPC)
mcp-remote (로컬 프록시)
⇅ (HTTP / streamable HTTP)
원격 MCP 서버 (Upstash context7 등)
왜 mcp-remote 로컬 프록시가 필요한가?
stdin/stdout에 쓰인 내용이
→ 곧바로 외부 MCP 서버로 전달되는 건 불가능하고
대신 mcp-remote라고 하는 로컬 프록시가 stdin/stdout을 읽고 그 내용을 HTTP 요청으로 변환(번역) 해서 외부 MCP 서버에 전달하는 방식으로 동작.
개념만 보면 어려우니까 구체적인 예시를 살펴보면 MCP 클라이언트인 Claude Desktop은 다음의 방식으로 원격 MCP 서버와 소통하게 된다.

먼저 사용자가 프롬프트로 "3 더하기 5의 결과를 MCP tool을 사용해서 알려줘"라고 한다면,
Claude Desktop(MCP 클라이언트)는 앞서 설정한 config파일을 참고해서 mcp-remote subprocess를 띄움.
(하지만 Claude 입장에서는 그냥:
“stdio로 통신 가능한 MCP 서버 하나가 실행됐다”
라고 인식됨.)
Claude Desktop은 mcp-remote의 stdin(입력 파이프) 에 메시지를 쓴다.
“MCP 서버야, 너가 제공하는 tool 목록 알려줘”

하지만 stdin은 로컬 파이프이기 때문에
외부 MCP 서버로 직접 전달될 수는 없으므로 mcp-remote 프록시가 stdin을 읽어서 해당 JSON-RPC를 HTTP 형식 요청으로 변환해서 MCP 서버에 전달하게 된다.
그럼 해당 메시지를 요청받은 MCP 서버가 들려주는 응답:
“나는 add, search_docs 같은 tool을 제공하고,
각각 이런 역할을 해.”
이 응답은 마찬가지로 HTTP 응답으로 돌아오고 다시 mcp-remote가 받아서 JSON-RPC 응답 형태로 변환한 뒤 stdout에 써서 Claude Desktop으로 전달된다.
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"name": "add",
"description": "Add two numbers",
"inputSchema": {
"type": "object",
"properties": {
"a": { "type": "integer" },
"b": { "type": "integer" }
},
"required": ["a", "b"]
}
},
{
"name": "search_docs",
"description": "Search documents",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
}
}
}
]
}
그럼 Claude 입장에서는 왜 이 remote MCP 서버가 “stdio MCP 서버처럼” 보일까?
이유는 단순히 Claude가 항상 “로컬 subprocess와 stdio로만” 통신하기 때문이다.
Claude는:

그래서 원격 MCP 서버라도 type은 그냥 stdio로 설정해주면 끝!
나의 경우 처음에 claude_desktop_config.json에서 type: "stdio"를 명시하지 않아서 개발자 section의 MCP서버가 아무것도 잡히지 않는 불상사가 생겨버린 것이라고 추측할 수 있다^^
즉 Claude입장에서는 “이 서버와 어떻게 통신해야 하는지”를 알 수 없었기 때문에 서버를 아예 실행(launch)되지 않았던 것이라고 한다.(이건 비슷한 사례를 못 찾아서 GPT 피셜을 그대로 쓴것..)