Claude Platform Docs
MessagesMCP 터널

MCP 터널 문제 해결

터널 스택에서 연결, TLS, IP 검증 및 OAuth 라우팅 문제를 진단합니다.

터널을 통한 요청은 세 계층 중 하나에서 실패할 수 있으며, 순서대로 진단하세요: 터널 엣지로의 아웃바운드 연결, Anthropic에서 프록시로의 내부 TLS, 그다음 업스트림 MCP 서버를 향한 라우팅 및 IP 검증입니다.

빠른 참조

증상원인해결 방법
에이전트 + MCP Server 선택기에 터널이 나타나지 않음선택기는 세션의 워크스페이스에 있으면서 활성 인증서가 하나 이상 있는 터널만 나열합니다.CA 인증서를 등록하거나, 터널이 생성된 워크스페이스에서 세션을 여세요.
호출자에게 HTTP 500이 표시되고 cloudflared 로그에 No ingress rules were defined가 기록됨cloudflared에 로컬 대상이 없습니다.cloudflared 서비스에 --url http://localhost:8080network_mode: "service:mcp-proxy"를 추가하세요.
프록시 로그에 no route for host가 기록됨tunnel_domain이 할당된 도메인과 일치하지 않거나, config.yaml을 편집한 후 재시작하지 않았습니다.tunnel_domain을 터널 상세 페이지에 표시된 정확한 도메인으로 설정한 다음 프록시를 재시작하세요(docker compose restart mcp-proxy).
프록시 로그에 IP validation failed: <ip> is not a private address가 기록됨업스트림 MCP 서버가 RFC1918 범위 밖으로 확인됩니다.업스트림 IP 검증을 참조하세요.
프록시가 cannot unmarshal !!seq into map[string]string과 함께 종료됨routes가 YAML 리스트입니다.routes: { name: http://host:port }를 사용하세요.
프록시가 open /data/tls.key: permission denied와 함께 종료됨키가 0600이며, 프록시 컨테이너는 비루트(non-root)로 실행됩니다.chmod 644 data/tls.key.
curl https://<proxy>:8080wrong version number로 실패함예상된 동작입니다. 리스너는 평문 WebSocket입니다. TLS는 WS 스트림 내부에서 이루어집니다.대신 Managed Agent 또는 Messages API를 통해 확인하세요.

다음 섹션에서는 한 줄짜리 해결 방법 이상이 필요한 실패 사례를 다룹니다.

소스 IP 허용 목록 뒤에서 OAuth가 실패함

인증 서버의 소스 IP 허용 목록(allowlist)이 Anthropic의 백엔드가 /token, /register 및 디스커버리 엔드포인트에 도달하는 것을 차단하면 OAuth 흐름이 실패합니다. Anthropic의 이그레스(egress) 범위를 허용 목록에 추가하고 싶지 않다면, 브라우저 대상 /authorize 엔드포인트는 기존 공개 호스트명에 유지하면서 백엔드 간 OAuth 호출을 터널을 통해 라우팅할 수 있습니다.

  1. 인증 서버용 프록시 라우트 추가

    routes:
      mcp: http://your-mcp-server:8080
      auth: http://your-auth-server:8080

    routes를 편집한 후 프록시를 재시작하세요(docker compose restart mcp-proxy 또는 helm upgrade).

  2. 분할 엔드포인트 디스커버리 메타데이터 제공

    인증 서버의 /.well-known/oauth-authorization-server 응답은 authorization_endpoint를 기존의 허용 목록에 등록된 호스트명으로 지정하고, 나머지는 모두 터널로 지정해야 합니다:

    {
      "issuer": "https://auth.<tunnel-domain>",
      "authorization_endpoint": "https://<your-allowlisted-host>/authorize",
      "token_endpoint": "https://auth.<tunnel-domain>/token",
      "registration_endpoint": "https://auth.<tunnel-domain>/register",
      "code_challenge_methods_supported": ["S256"]
    }
  3. MCP 서버가 터널 발급자를 가리키도록 설정

    MCP 서버의 /.well-known/oauth-protected-resource 응답은 인증 서버로 터널 호스트명을 참조해야 합니다:

    {
      "resource": "https://mcp.<tunnel-domain>",
      "authorization_servers": ["https://auth.<tunnel-domain>"]
    }

이 구성을 사용하면 사용자의 브라우저는 기존 호스트명의 /authorize에 접속하고(허용 목록이 이미 허용함), Anthropic의 백엔드는 터널을 통해 /token, /register 및 디스커버리 문서에 도달합니다.

설정 컴포넌트 인증 실패

설정 컴포넌트(Helm Job 또는 Compose setup 서비스)는 페더레이션 규칙을 통해 OIDC JWT를 교환하여 Tunnels API에 인증합니다. 교환이 실패하면 Workload Identity Federation 참조 문서의 실패한 교환 문제 해결을 참조하세요. 실패 유형(subject, audience, issuer, JWKS, 수명)은 동일합니다.

터널 관련 원인:

  • 차트의 기본 audience는 api.anthropic.com(스킴 없음)입니다. 규칙의 audience가 https://api.anthropic.com이라면 api.wif.audience를 일치하도록 설정하세요.
  • 교환 성공 후 Tunnels API에서 403이 반환되면 규칙의 범위(scope)에 workspace:manage_tunnels가 포함되어 있지 않거나, 규칙의 서비스 계정이 터널의 워크스페이스 멤버가 아닌 것입니다. 범위를 설정하고 서비스 계정을 워크스페이스에 추가하세요.

Helm에서 설정 컴포넌트는 pre-install 훅 Job으로 실행됩니다. 실패 시 Job은 검사를 위해 남겨집니다(kubectl logs job/mcp-tunnel-setup -n mcp-tunnel). Helm은 훅 리소스를 관리하지 않으므로 재시도하기 전에 삭제하세요:

helm uninstall mcp-tunnel -n mcp-tunnel
kubectl -n mcp-tunnel delete job mcp-tunnel-setup

터널이 연결되지 않음

먼저 cloudflared 로그를 확인하세요. 일반적인 원인:

  • TUNNEL_TOKEN이 누락되었거나, 만료되었거나, 잘못 복사되었습니다.
  • 방화벽이 터널 엣지로 향하는 포트 7844의 아웃바운드 TCP/UDP를 차단하고 있습니다.

cloudflared는 UDP 수신 버퍼 크기에 대한 경고를 기록할 수도 있습니다. 이는 QUIC 튜닝 힌트이며 오류가 아닙니다.

인증서 오류

내부 TLS 중에 Anthropic이 프록시의 인증서를 거부하면 프록시는 tls handshake failed를 기록합니다. 다음을 확인하세요:

  • 서버 인증서가 만료되지 않았습니다.
  • 인증서의 Subject Alternative Name이 *.<tunnel-domain>과 일치합니다.
  • 서명 CA가 이 터널에 대해 Anthropic에 등록되어 있습니다.

전체 검증 규칙은 인증서 요구 사항을 참조하세요.

업스트림 IP 검증

SSRF 보호를 위해 프록시는 기본적으로 RFC1918 사설 범위(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)의 주소로만 연결합니다. 프록시-업스트림 연결에는 IPv4만 지원됩니다. (네트워크 요구 사항의 cloudflared-엣지 이그레스 범위는 다른 홉입니다.)

프록시가 IP validation failed: <ip> is not a private address를 기록하면 업스트림 호스트명이 해당 범위 밖으로 확인된 것입니다. Kubernetes에서 일부 관리형 배포판은 Service CIDR을 RFC1918 밖에 할당합니다. kubectl get svc kubernetes -n default -o jsonpath='{.spec.clusterIP}'가 사설 범위 밖의 주소를 반환하면 클러스터의 Service CIDR을 조회하여 추가하세요.

주소가 정당한 경우, 이를 포함하는 가장 좁은 CIDR을 upstream.allowed_ips에 추가하세요. allowed_ips를 설정하면 RFC1918 기본값을 확장하는 것이 아니라 대체하므로, 다른 업스트림 MCP 서버가 사용하는 사설 범위를 포함하세요:

config/mcp-proxy.yaml
upstream:
  allowed_ips:
    - 10.0.0.0/8
    - 172.16.0.0/12
    - 192.168.0.0/16
    - 127.0.0.0/8       # loopback, for local testing only

Was this page helpful?