Dépanner les tunnels MCP
Diagnostiquez les problèmes de connectivité, de TLS, de validation d'IP et de routage OAuth dans une pile de tunnel.
Une requête transitant par le tunnel peut échouer à l'une de trois couches ; diagnostiquez-les dans l'ordre : la connexion sortante vers le tunnel edge (périphérie du tunnel), le inner TLS (TLS interne) d'Anthropic vers votre proxy, puis le routage et la validation d'IP vers le upstream MCP server (serveur MCP en amont).
Référence rapide
| Symptôme | Cause | Correctif |
|---|---|---|
| Le tunnel n'apparaît pas dans le sélecteur + MCP Server de l'agent | Le sélecteur ne liste que les tunnels de l'espace de travail de la session qui possèdent au moins un certificat actif. | Enregistrez un certificat d'autorité de certification (CA), ou ouvrez la session dans l'espace de travail dans lequel le tunnel a été créé. |
L'appelant reçoit un HTTP 500 ; cloudflared journalise No ingress rules were defined | cloudflared n'a pas de cible locale. | Ajoutez --url http://localhost:8080 et network_mode: "service:mcp-proxy" au service cloudflared. |
Le proxy journalise no route for host | tunnel_domain ne correspond pas au domaine attribué, ou config.yaml a été modifié sans redémarrage. | Définissez tunnel_domain sur le domaine exact affiché sur la page de détail du tunnel, puis redémarrez le proxy (docker compose restart mcp-proxy). |
Le proxy journalise IP validation failed: <ip> is not a private address | Le serveur MCP en amont se résout en dehors de RFC1918. | Consultez Validation d'IP en amont. |
Le proxy se termine avec cannot unmarshal !!seq into map[string]string | routes est une liste YAML. | Utilisez routes: { name: http://host:port }. |
Le proxy se termine avec open /data/tls.key: permission denied | La clé est en 0600 ; le conteneur du proxy s'exécute sans privilèges root. | chmod 644 data/tls.key. |
curl https://<proxy>:8080 échoue avec wrong version number | Comportement attendu ; l'écouteur est un WebSocket en clair. Le TLS s'effectue à l'intérieur du flux WS. | Vérifiez plutôt via un Managed Agent ou l'API Messages. |
Les sections suivantes couvrent les échecs qui nécessitent plus qu'un correctif d'une ligne.
OAuth échoue derrière une liste d'autorisation d'IP source
Les flux OAuth échouent lorsque la liste d'autorisation d'IP source de votre serveur d'autorisation empêche le backend d'Anthropic d'atteindre /token, /register et les points de terminaison de découverte. Si vous préférez ne pas autoriser les plages de sortie d'Anthropic, vous pouvez acheminer les appels OAuth de backend à backend via le tunnel tout en conservant le point de terminaison /authorize, destiné au navigateur, sur votre nom d'hôte public existant.
Ajouter une route de proxy pour le serveur d'autorisation
routes: mcp: http://your-mcp-server:8080 auth: http://your-auth-server:8080Redémarrez le proxy après avoir modifié
routes(docker compose restart mcp-proxy, ouhelm upgrade).Servir des métadonnées de découverte à points de terminaison séparés
La réponse
/.well-known/oauth-authorization-serverde votre serveur d'autorisation doit faire pointerauthorization_endpointvers votre nom d'hôte existant déjà autorisé, et tout le reste vers le tunnel :{ "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"] }Faire pointer le serveur MCP vers l'émetteur du tunnel
La réponse
/.well-known/oauth-protected-resourcede votre serveur MCP doit référencer le nom d'hôte du tunnel comme serveur d'autorisation :{ "resource": "https://mcp.<tunnel-domain>", "authorization_servers": ["https://auth.<tunnel-domain>"] }
Avec cette configuration, le navigateur de l'utilisateur atteint /authorize sur votre nom d'hôte existant (que votre liste d'autorisation permet déjà), tandis que le backend d'Anthropic atteint /token, /register et les documents de découverte via le tunnel.
Échecs d'authentification du composant de configuration
Le setup component (composant de configuration) (Job Helm ou service setup Compose) s'authentifie auprès de l'API Tunnels en échangeant un JWT OIDC via votre règle de fédération. Lorsque l'échange échoue, consultez Dépanner un échange en échec dans la référence Workload Identity Federation ; les modes d'échec (sujet, audience, émetteur, JWKS, durée de vie) sont les mêmes.
Causes spécifiques aux tunnels :
- L'audience par défaut du chart est
api.anthropic.com(sans schéma). Si l'audience de votre règle esthttps://api.anthropic.com, définissezapi.wif.audiencepour qu'elle corresponde. - Un
403de l'API Tunnels après un échange réussi signifie que la portée de la règle n'inclut pasworkspace:manage_tunnels, ou que le compte de service de la règle n'est pas membre de l'espace de travail du tunnel. Définissez la portée et ajoutez le compte de service à l'espace de travail.
Sur Helm, le composant de configuration s'exécute en tant que Job de hook de pré-installation. En cas d'échec, le Job est conservé pour inspection (kubectl logs job/mcp-tunnel-setup -n mcp-tunnel). Helm ne gère pas les ressources de hook, supprimez-le donc avant de réessayer :
helm uninstall mcp-tunnel -n mcp-tunnel
kubectl -n mcp-tunnel delete job mcp-tunnel-setupLe tunnel ne se connecte pas
Vérifiez d'abord les journaux de cloudflared. Causes courantes :
- Le
TUNNEL_TOKENest manquant, expiré ou mal copié. - Un pare-feu bloque le trafic TCP/UDP sortant sur le port 7844 vers la périphérie du tunnel.
cloudflared peut également journaliser des avertissements concernant la taille des tampons de réception UDP ; il s'agit d'une indication de réglage QUIC, et non d'une erreur.
Erreurs de certificat
Lorsqu'Anthropic rejette le certificat du proxy pendant le TLS interne, le proxy journalise tls handshake failed. Vérifiez que :
- Le certificat serveur n'a pas expiré.
- Le Subject Alternative Name du certificat correspond à
*.<tunnel-domain>. - L'autorité de certification signataire est enregistrée auprès d'Anthropic pour ce tunnel.
Consultez les exigences relatives aux certificats pour l'ensemble des règles de validation.
Validation d'IP en amont
Pour la protection contre le SSRF, le proxy ne se connecte par défaut qu'aux adresses des plages privées RFC1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). Seul IPv4 est pris en charge pour la connexion du proxy vers l'amont. (La plage de sortie de cloudflared vers la périphérie, décrite dans Exigences réseau, correspond à un saut différent.)
Si le proxy journalise IP validation failed: <ip> is not a private address, le nom d'hôte en amont s'est résolu en dehors de cet ensemble. Sur Kubernetes, certaines distributions gérées allouent le CIDR de Service en dehors de RFC1918 ; si kubectl get svc kubernetes -n default -o jsonpath='{.spec.clusterIP}' renvoie une adresse en dehors des plages privées, recherchez le CIDR de Service de votre cluster et ajoutez-le.
Si l'adresse est légitime, ajoutez le CIDR couvrant le plus étroit à upstream.allowed_ips. Définir allowed_ips remplace la valeur par défaut RFC1918 au lieu de l'étendre ; incluez donc les plages privées utilisées par vos autres serveurs MCP en amont :
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 onlyWas this page helpful?