Model Context Protocol 서버의 발견, 연결, 프록시, 인증 — stdio 서브프로세스부터 인프로세스 Chrome 브릿지까지.
Claude Code가 MCP 서버를 발견, 연결, 프록시, 인증하는 방법을 살펴봅니다. MCP 통합은 여러 아키텍처 레이어로 구성되며, 각 레이어가 명확한 책임을 가집니다.
services/mcp/ (연결 생명주기, 설정 로드, OAuth) →
tools/MCPTool/ (원격 MCP 호출을 래핑하는 프록시 도구) →
commands/mcp/ (슬래시 커맨드) →
components/mcp/ (React UI 패널)
/mcp 슬래시 커맨드 인터페이스. 서버 추가/제거/상태 확인MCP는 8가지 전송 유형을 지원하며, 공개(Public), 내부(Internal), 인프로세스(In-process)로 분류됩니다.
stdio — 서브프로세스 spawn 방식. 자식 프로세스의 stdin/stdout으로 JSON-RPC 통신. stderr는 'pipe'로 캡처하며 64MB 하드 캡 적용sse — HTTP Server-Sent Events. OAuth 인증 지원. 장기 연결 유지http — Streamable HTTP 전송. 요청/응답 기반 통신ws — WebSocket 전송. 양방향 실시간 통신sse-ide — IDE 확장 전용 SSE. VS Code, JetBrains 등 IDE에서 MCP 서버와 통신ws-ide — IDE 전용 WebSocket 전송sdk — SDK 프로세스 브릿지. 외부 SDK 프로세스와 통신in-process — Chrome MCP 및 Computer Use 전용. 별도 프로세스 없이 같은 Node.js 이벤트 루프에서 실행. queueMicrotask()로 재귀 호출 시 스택 오버플로를 방지// in-process 전송 — 스택 오버플로 방지
// 동일 이벤트 루프에서 MCP 서버를 실행할 때
// 재귀적 호출 체인이 스택을 초과할 수 있음
queueMicrotask(() => {
// 다음 마이크로태스크에서 처리하여 스택 깊이 초기화
handleMessage(message)
})
MCP 서버 설정은 7단계 우선순위 계층으로 조립됩니다. 상위 범위가 하위 범위보다 우선합니다.
managed-mcp.json. MDM(모바일 디바이스 관리)으로 배포. 엔터프라이즈 IT 관리자가 제어--mcp-server 등)로 전달된 서버 설정.mcp.json 파일. CWD 및 상위 디렉토리를 순회하며 탐색~/.claude/projects/<hash>/. 프로젝트별 로컬 오버라이드~/.claude/settings.json. 사용자 전역 설정managed-mcp.json이 존재하면 addMcpConfig()가 수동 서버 추가/제거를 차단합니다. claude mcp add my-tool 실행 시 "엔터프라이즈 MCP 구성이 활성화되어 독점 제어" 오류가 발생합니다. 이를 통해 엔터프라이즈 환경에서 승인된 MCP 서버만 사용하도록 보장합니다.
MCP 서버 연결은 8단계를 거칩니다.
client.connect() 타임아웃 — 기본 30초 타임아웃. 응답 없으면 연결 실패로 처리needs-auth로 전환. McpAuthTool 의사 도구를 모델의 도구 목록에 주입하여 모델이 OAuth 흐름을 시작할 수 있게 함ToolListChanged 등 서버 알림을 구독. 연결 끊김 시 지수적 백오프로 재연결 (1초 ~ 30초)// 배치 연결 — 전송 유형별 동시성 제한
const STDIO_CONCURRENCY = 3 // 서브프로세스 폭주 방지
const REMOTE_CONCURRENCY = 20 // 네트워크 연결은 더 관대
// 재연결 지수적 백오프
const RECONNECT_BASE = 1000 // 1초
const RECONNECT_MAX = 30000 // 30초 상한
원격 MCP 서버가 401을 반환하면, 해당 서버 상태가 needs-auth로 전환됩니다. 이 시점에서 McpAuthTool이라는 의사 도구가 모델의 도구 목록에 주입됩니다. 모델이 이 도구를 호출하면 OAuth PKCE 흐름이 시작되고, 사용자에게 브라우저 인증을 안내합니다. 인증 완료 후 해당 서버의 모든 도구가 정상적으로 도구 목록에 등장합니다.
MCPTool은 모든 MCP 서버 도구의 공통 템플릿입니다. 실제 도구 인스턴스는 fetchToolsForClient()가 서버에서 메타데이터를 가져온 후 딥 클론으로 생성합니다.
MCP 도구 이름은 mcp__<server>__<tool> 형식으로 정규화됩니다. 이를 통해 여러 MCP 서버에서 동일한 이름의 도구가 존재하더라도 충돌을 방지합니다.
// 도구 이름 정규화 예시
// 서버 "github"의 "create_issue" 도구 →
"mcp__github__create_issue"
// 서버 "slack"의 "send_message" 도구 →
"mcp__slack__send_message"
MCPTool은 직접 사용되지 않고 템플릿 역할을 합니다. fetchToolsForClient()가 서버에서 도구 목록을 받으면, 각 도구에 대해 MCPTool을 딥 클론하고 실제 메타데이터(이름, 설명, 입력 스키마)를 주입합니다. 이 패턴을 통해 모든 MCP 도구가 동일한 실행 로직(원격 호출, 에러 처리, 결과 변환)을 공유하면서도 개별적인 도구 정의를 가질 수 있습니다.
MCP는 전체 PKCE(Proof Key for Code Exchange) 흐름과 XAA(교차 앱 액세스) 확장을 지원합니다.
needs-auth로 전환McpAuthTool 의사 도구가 모델 도구 목록에 주입McpAuthTool을 호출하여 OAuth PKCE 흐름 시작Slack API는 HTTP 200 상태 코드에 에러를 포함하여 반환하는 비표준 동작을 합니다. 예를 들어 invalid_refresh_token 에러가 200 OK 응답 본문에 포함됩니다. MCP 클라이언트는 이를 invalid_grant로 정규화하고, 합성 400 응답으로 재작성하여 표준 OAuth 에러 처리 경로를 태웁니다.
XAA는 엔터프라이즈 SSO(Single Sign-On) 확장입니다. 기업 환경에서 중앙 인증 서버를 통해 여러 MCP 서버에 대한 액세스를 일괄 관리할 수 있게 합니다.
Elicitation은 MCP 서버가 작업 도중 사용자에게 구조화된 입력을 요청하는 메커니즘입니다.
form 모드 — JSON Schema 기반. 서버가 JSON Schema를 제공하면 클라이언트가 이에 맞는 입력 폼을 렌더링하여 사용자에게 표시url 모드 — 2단계 프로세스. 서버가 URL을 제공하고, 사용자가 해당 URL에서 작업을 완료한 후 결과를 반환Elicitation 요청은 훅(hook)이 프로그래밍 방식으로 충족할 수 있습니다. 예를 들어, CI/CD 파이프라인에서 MCP 서버가 배포 승인을 요청할 때 훅이 자동으로 승인 응답을 제공할 수 있습니다. 이를 통해 비대화형 환경에서도 elicitation 기반 워크플로를 자동화할 수 있습니다.
여러 설정 범위에 동일한 MCP 서버가 중복 등록될 수 있습니다. MCP 통합은 콘텐츠 기반(이름 기반이 아님) 중복 제거를 수행합니다.
stdio:["cmd","arg1","arg2"] — 명령어와 인수 배열로 서명 생성url:https://example.com/mcp — URL로 서명 생성// 중복 제거 서명 예시
// stdio 서버: 명령어 + 인수가 동일하면 같은 서버
'stdio:["npx","@modelcontextprotocol/server-github"]'
// 원격 서버: URL이 동일하면 같은 서버
'url:https://slack.mcp.example.com/sse'
services/mcp/(연결), tools/MCPTool/(프록시), commands/mcp/(CLI), components/mcp/(UI)in-process는 Chrome MCP 전용으로 queueMicrotask()로 스택 오버플로를 방지합니다managed-mcp.json 존재 시 수동 추가/제거가 차단됩니다mcp__<server>__<tool> 형식으로 정규화되며, 설명 2048자 캡과 결과 100KB 캡이 적용됩니다McpAuthTool 의사 도구 주입으로 모델이 인증을 트리거합니다invalid_grant 정규화로 처리됩니다Q1. 같은 MCP 서버가 .mcp.json(프로젝트)과 ~/.claude/settings.json(사용자)에 모두 정의되어 있으면 어느 것이 적용되나요?
.mcp.json의 설정이 ~/.claude/settings.json보다 우선 적용됩니다.Q2. stdio MCP 서버의 stderr 노이즈는 어떻게 처리되나요?
StdioClientTransport는 자식 프로세스를 stderr: 'pipe' 옵션으로 spawn합니다. stderr 출력은 축적된 후 logMCPError를 통해 로그됩니다. 64MB 하드 캡이 적용되어 과도한 stderr 노이즈가 메모리를 소진하는 것을 방지합니다.Q3. wrapFetchWithTimeout()의 목적과 GET 요청을 건너뛰는 이유는?
wrapFetchWithTimeout()은 POST 요청에 60초 타임아웃을 적용합니다. GET 요청은 SSE(Server-Sent Events) 연결에 사용되며, 이는 의도적으로 장기간 유지되는 연결이므로 타임아웃을 적용하면 정상 동작이 중단됩니다.Q4. Slack이 HTTP 200 응답에 invalid_refresh_token 에러를 반환하면 MCP 클라이언트는 어떻게 처리하나요?
invalid_refresh_token을 표준 OAuth 에러인 invalid_grant로 정규화하고, 200 응답을 합성 400으로 재작성합니다. 이를 통해 표준 OAuth 에러 처리 로직이 정상 동작합니다.Q5. 엔터프라이즈 managed-mcp.json이 존재할 때 claude mcp add my-tool을 실행하면 어떻게 되나요?
managed-mcp.json이 존재하면 엔터프라이즈 잠금이 활성화됩니다. addMcpConfig()는 수동 서버 추가를 차단하고 "엔터프라이즈 MCP 구성이 활성화되어 독점 제어" 오류를 발생시킵니다. 이는 기업 환경에서 승인된 도구만 사용하도록 보장하는 보안 메커니즘입니다.