---
title: MCP 터널 문제 해결
url: https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/troubleshooting
description: 터널 스택에서 연결, TLS, IP 검증 및 OAuth 라우팅 문제를 진단합니다.
---

<Note>
  MCP tunnels(MCP 터널)는 연구 프리뷰 단계입니다. 사용해 보려면 [액세스를 요청](https://claude.com/form/mcp-tunnels)하세요.
</Note>

터널을 통한 요청은 세 계층 중 하나에서 실패할 수 있으며, 순서대로 진단하세요: [터널 엣지](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components)로의 아웃바운드 연결, Anthropic에서 [프록시](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components)로의 [내부 TLS](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components), 그다음 [업스트림 MCP 서버](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components)를 향한 라우팅 및 IP 검증입니다.

## 빠른 참조

| 증상                                                                                                                                                                | 원인                                                                    | 해결 방법                                                                                                                                                 |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| 에이전트 **+ MCP Server** 선택기에 터널이 나타나지 않음                                                                                                                            | 선택기는 세션의 워크스페이스에 있으면서 활성 인증서가 하나 이상 있는 터널만 나열합니다.                     | CA 인증서를 등록하거나, 터널이 생성된 워크스페이스에서 세션을 여세요.                                                                                                              |
| 호출자에게 HTTP 500이 표시되고 [cloudflared](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components) 로그에 `No ingress rules were defined`가 기록됨 | cloudflared에 로컬 대상이 없습니다.                                             | cloudflared 서비스에 `--url http://localhost:8080` 및 `network_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 검증](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/troubleshooting#upstream-ip-validation)을 참조하세요.                         |
| 프록시가 `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>:8080`이 `wrong version number`로 실패함                                                                                                          | 예상된 동작입니다. 리스너는 평문 WebSocket입니다. TLS는 WS 스트림 내부에서 이루어집니다.             | 대신 [Managed Agent 또는 Messages API](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/overview#use-the-tunneled-mcp-servers)를 통해 확인하세요. |

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

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

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

<Steps>
  <Step title="인증 서버용 프록시 라우트 추가">
    ```yaml
    routes:
      mcp: http://your-mcp-server:8080
      auth: http://your-auth-server:8080
    ```

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

  <Step title="분할 엔드포인트 디스커버리 메타데이터 제공">
    인증 서버의 `/.well-known/oauth-authorization-server` 응답은 `authorization_endpoint`를 기존의 허용 목록에 등록된 호스트명으로 지정하고, 나머지는 모두 터널로 지정해야 합니다:

    ```json
    {
      "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"]
    }
    ```
  </Step>

  <Step title="MCP 서버가 터널 발급자를 가리키도록 설정">
    MCP 서버의 `/.well-known/oauth-protected-resource` 응답은 인증 서버로 터널 호스트명을 참조해야 합니다:

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

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

## 설정 컴포넌트 인증 실패

[설정 컴포넌트](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/concepts#components)(Helm Job 또는 Compose `setup` 서비스)는 페더레이션 규칙을 통해 OIDC JWT를 교환하여 Tunnels API에 인증합니다. 교환이 실패하면 Workload Identity Federation 참조 문서의 [실패한 교환 문제 해결](https://platform.claude.com/docs/ko/manage-claude/wif-reference#troubleshoot-a-failed-exchange)을 참조하세요. 실패 유형(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은 훅 리소스를 관리하지 않으므로 재시도하기 전에 삭제하세요:

```bash
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에 등록되어 있습니다.

전체 검증 규칙은 [인증서 요구 사항](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/reference#certificate-requirements)을 참조하세요.

## 업스트림 IP 검증

SSRF 보호를 위해 프록시는 기본적으로 RFC1918 사설 범위(`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`)의 주소로만 연결합니다. 프록시-업스트림 연결에는 IPv4만 지원됩니다. ([네트워크 요구 사항](https://platform.claude.com/docs/ko/agents-and-tools/mcp-tunnels/overview#network-requirements)의 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 서버가 사용하는 사설 범위를 포함하세요:

```yaml 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
```

<Warning>
  로컬 테스트 외에는 `0.0.0.0/0`을 피하세요. SSRF 보호가 완전히 비활성화됩니다.
</Warning>
