Summary#
MCP Runtime Session Auth Failure Modes는 “MCP 서버에 연결된다/도구가 보인다” 수준을 넘어, 장시간 세션·재연결·도구 호출 경계·transport 전환에서 인증 상태가 어떻게 유지되거나 깨지는지를 다루는 구현 위험이다.
핵심 실패 모드는 세 가지다.
-
Reconnect token renewal / expiry / re-authentication 실패
HTTP/SSE/Streamable HTTP 기반 MCP 세션에서 access token이 만료되었는데 reconnect 또는 stream 재수립 시 갱신된 token을 쓰지 않거나, 만료된 bearer token으로 자동 재시도하면 서버는 401/403 또는 도구 목록 공백처럼 보이는 실패를 낼 수 있다. -
Permission-scope drift across tool-call boundaries
tools/list시점의 권한, 실제tools/call시점의 권한, 내부 downstream API 호출 시점의 권한이 서로 달라지면 “보이는 도구는 있으나 호출 실패”, “권한이 축소되었는데 stale cache가 계속 허용”, “tool metadata와 실제 authorization policy 불일치”가 발생할 수 있다. -
Cross-transport auth leak: SSE / Streamable HTTP vs stdio
HTTP 계층에서는 bearer token, Authorization header, OAuth-style session이 쓰일 수 있지만, stdio transport는 로컬 subprocess 입출력 경계다. HTTP용 bearer token을 stdio process argv, environment, log, proxy bridge, adapter message body에 그대로 넘기면 transport 경계를 넘는 credential leak가 된다.
이 capsule은 broad MCP auth가 아니라 runtime session continuation, tool-call authorization boundary, transport-specific credential handling에 초점을 둔다.
Key Points#
- MCP 인증은 transport별로 다르게 모델링해야 한다.
- HTTP 기반 transport에서는 HTTP Authorization header, bearer token, OAuth-style authorization이 자연스럽다.
- stdio transport는 로컬 프로세스와 stdin/stdout으로 통신하므로, 원격 HTTP bearer token을 그대로 전달하는 방식은 별도 위협 모델 검토가 필요하다.
-
같은 MCP server wrapper라도 “remote SSE/HTTP server”와 “local stdio server”는 credential 저장·전달·로그 노출 위험이 다르다.
-
Reconnect는 단순 TCP/HTTP 재시도가 아니라 auth state 재검증 지점이다.
- SSE 또는 Streamable HTTP 연결이 끊긴 뒤 재연결할 때, client는 현재 access token의 만료 여부를 확인해야 한다.
- 만료 직전 token으로 장기 stream을 열고, 이후
tools/call만 새 token이 필요한 구조라면 stream state와 call state가 분리될 수 있다. -
권장 계약:
- reconnect 전 token freshness 확인
- 401/403 수신 시 무한 재시도 금지
- refresh 성공 후 새 session 또는 새 initialize flow 수행 여부 명시
- refresh 실패 시 사용자 재인증 또는 agent 작업 중단
-
initialize성공은 이후 tool call 권한을 보장하지 않는다. - MCP lifecycle상 client는 initialize 후 일반 요청을 수행하지만, authorization policy는 별도 런타임 상태일 수 있다.
- 예: 초기 연결 시에는
repo:readscope가 있었지만 사용자가 권한을 철회했거나, refresh token으로 갱신된 access token에서 일부 scope가 빠졌거나, org policy가 변경된 경우. -
client가
tools/list결과를 장시간 cache하면, 실제tools/call시점의 권한과 drift가 생긴다. -
Tool visibility와 call authorization은 분리해서 검증해야 한다.
tools/list는 “현재 user/session/token에서 노출 가능한 도구 목록”이어야 한다.tools/call은 “해당 호출 시점에 해당 input과 대상 resource에 대해 허용되는가”를 다시 확인해야 한다.- 도구가 보였다는 사실만으로 호출을 허용하면 stale authorization 또는 confused deputy 문제가 생길 수 있다.
-
반대로 호출 시점 검증만 있고 list filtering이 없으면 agent가 사용할 수 없는 도구를 계획에 포함해 UX와 안정성이 나빠진다.
-
Scope drift는 downgrade와 upgrade 양쪽 모두 위험하다.
- Downgrade drift: token refresh 후 scope가 줄었는데 client cache는 기존 도구를 계속 표시한다.
- Upgrade drift: 사용자가 새 권한을 받았는데 client가 stale list를 유지해 도구를 못 쓴다.
- Mixed drift: tool metadata는 “read-only”로 표시되지만 downstream API credential은 write 권한을 가진다.
-
완화:
- reconnect 또는 token refresh 후
tools/list재조회 - server의
listChangedcapability 또는 equivalent invalidation 활용 - tool call마다 server-side authorization enforcement
- tool metadata에 필요한 scope/resource를 명시하되, metadata를 권한의 유일한 source of truth로 쓰지 않기
- reconnect 또는 token refresh 후
-
SSE / Streamable HTTP에서는 Authorization header 전달이 모든 요청에 일관되어야 한다.
- HTTP POST 요청, SSE GET/stream 요청, redirect 이후 요청, reverse proxy upstream 요청에서 Authorization header가 다르게 처리될 수 있다.
- 브라우저
EventSource는 임의 header 설정에 제약이 있으므로, SSE client 구현이 bearer token을 어떻게 전달하는지 확인해야 한다. -
query parameter로 access token을 넘기는 방식은 로그, browser history, proxy, analytics에 남을 수 있어 신중해야 한다.
-
stdio bridge는 token을 “데이터”로 취급하지 말고 “credential”로 취급해야 한다.
- 위험한 패턴:
mcp-server --token <bearer>형태로 process argv에 token 전달- environment variable에 장기 token 저장 후 subprocess 전체에 노출
- HTTP Authorization header를 JSON-RPC message body나 debug log에 복사
- SSE gateway가 받은 user token을 local stdio server에 그대로 위임
-
더 안전한 패턴:
- stdio server에는 최소 권한의 별도 credential 사용
- user token 대신 short-lived, audience-restricted, tool-specific token 또는 server-side session handle 사용
- argv/log/stdout/stderr에 secret redaction 적용
- bridge boundary에서 explicit allowlist 기반 credential forwarding
-
Cross-transport proxy는 audience와 trust boundary를 명확히 해야 한다.
- SSE/HTTP endpoint가 받은 bearer token은 원래 특정 resource server 또는 MCP endpoint를 대상으로 발급되었을 수 있다.
- 그 token을 stdio subprocess, 다른 upstream API, 다른 MCP server에 재사용하면 token audience confusion이 생긴다.
-
token이 bearer credential인 이상 “가진 자가 사용 가능”하므로, transport adapter는 token 재사용을 기본값으로 허용하지 않아야 한다.
-
Failure symptoms는 보안 문제와 운영 문제로 동시에 나타난다.
- 도구 목록이 비어 있음
- initialize는 성공하지만
tools/call만 401/403 - reconnect 후 일부 도구만 실패
- 장기 실행 agent가 처음에는 성공하다가 token expiry 이후 반복 실패
- proxy 뒤에서는 실패하지만 local stdio에서는 성공
-
debug log에 Authorization header 또는 access token이 남음
-
권장 구현 체크리스트
- token expiry, refresh, reconnect, reinitialize 정책을 명시한다.
- 401/403 발생 시 refresh 가능 오류와 permanent authorization failure를 구분한다.
- refresh 후
tools/list를 재조회하거나 권한 cache를 무효화한다. tools/call마다 server-side authorization을 수행한다.- tool metadata의 required scope와 실제 enforcement policy를 contract test로 검증한다.
- HTTP/SSE/Streamable HTTP 요청 전체에서 Authorization header 보존 여부를 테스트한다.
- redirect, reverse proxy, CDN, auth gateway가 Authorization header를 제거하거나 잘못 전달하지 않는지 확인한다.
- stdio transport에는 HTTP bearer token을 자동 forwarding하지 않는다.
- process argv, environment, logs, traces, crash dump에서 token redaction을 적용한다.
- transport adapter별 threat model을 문서화한다.
Cautions#
-
MCP 명세와 SDK는 버전별로 transport, lifecycle, authorization 세부가 바뀔 수 있다. 구현 시점의 MCP specification version과 SDK version을 고정해 검증해야 한다.
-
공개 자료는 MCP authorization, transport, lifecycle, tool listing/calling의 원칙을 제공하지만, “reconnect token renewal failure”나 “permission-scope drift”라는 이름의 표준 실패 taxonomy를 직접 정의하지는 않는다. 본 초안은 공개 명세와 일반 OAuth/bearer-token 보안 원칙을 조합한 implementation-level capsule이다.
-
특정 MCP SDK, host, client, gateway에서 위 실패가 실제로 재현된다고 단정하지 않는다. 브라우저, Node.js, Python, desktop host, reverse proxy 환경마다 header 처리와 reconnect 동작이 다르다.
-
stdio transport가 항상 안전하거나 항상 위험하다는 의미가 아니다. 위험은 HTTP credential을 로컬 process boundary로 부주의하게 넘기거나, local subprocess의 log/process/env 노출을 고려하지 않을 때 커진다.
-
bearer token을 query parameter로 전달하는 방식은 일부 SSE 제약을 우회하기 위해 쓰일 수 있으나, URL log 노출 위험이 크다. 가능하면 header-capable client, short-lived token, one-time session handle, server-side session binding을 검토해야 한다.
-
tools/list를 권한별로 filtering해도tools/callauthorization을 생략하면 안 된다. list 결과는 UX와 planning hint일 뿐, 최종 access-control decision은 호출 시점에 서버가 수행해야 한다.
Sources#
- https://modelcontextprotocol.io/specification/2025-06-18/basic/transports
- https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization
- https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle
- https://modelcontextprotocol.io/specification/2025-06-18/server/tools
- https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices
- https://www.rfc-editor.org/rfc/rfc6750
- https://developer.mozilla.org/en-US/docs/Web/API/EventSource
Related#
- Write Boundary Leakage, Projection Lag UX, Command Idempotency, and Authorization Drift
- Claude Code PTY Session Recovery Failure Modes: Detached Subprocesses, Approval Boundaries, Output Truncation, and Tool-State Resumption
- List-Tools Ordering, and Stale Tool Registration Recovery
Sagwan Revalidation 2026-08-02T19:43:12Z#
- verdict:
refresh - note: 핵심은 유효하나 최신 MCP OAuth·Streamable HTTP 권고 반영 필요