Créer un connecteur MCP distant
Construit un serveur MCP Streamable-HTTP sans état (TypeScript, @modelcontextprotocol/sdk) qui fonctionne comme un connecteur personnalisé claude.ai, avec éventuellement des cartes visuelles en ligne (MCP Apps), et l'expédie sur Vercel. Testé sur un projet réel avec plus de 30 outils.
Les modèles se trouvent dans templates/ à côté de ce fichier. Des notes plus détaillées sont dans references/ ; ne les lisez que lorsque l'étape les nécessite :
references/mcp-apps-cards.md— cartes en ligne : ressourceui://, protocole postMessage, CSP, listes cliquablesreferences/deploy-vercel.md— configuration Vercel, déploiement, ré-ajout du connecteur dans claude.aireferences/gotchas.md— pièges qui ont coûté du temps réel (à lire avant de déboguer)
Flux de travail
- Clarifier (ne demandez que ce que vous ne pouvez pas déduire) : quelles données/API, lecture seule ou écritures, nécessite une authentification ou non, souhaite des cartes ou uniquement du texte. Par défaut : données publiques, lecture seule, pas d'authentification, texte + cartes.
- Sonder chaque API en amont avant d'écrire du code.
curlchaque point de terminaison : statut, forme de la réponse, formats de date, limites de débit, timeouts, redirections (un301signifie que l'URL a changé, par ex.api.frankfurter.dev, pas.app). Les points de terminaison SPARQL/recherche publics peuvent être lents : mesurez le temps, gardez les requêtes simples, filtrez dans le code. - Générer la structure à partir de
templates/(copierpackage.json,tsconfig.json,vercel.json,api/,src/,scripts/), renommermy-connector,npm install. - Écrire les outils dans
src/server.ts(unregisterToolchacun). Règles ci-dessous. - Ajouter chaque outil à
scripts/test-client.ts. Le testeur échoue en cas d'outils non testés, de sortie vide et deisError. - Vérifier en local :
npm run typecheck, lancerPORT=<port libre> npm run dev, confirmer que le log indique « listening » (pasEADDRINUSE), puisnpm test -- http://localhost:<port>/mcp. Objectif : « Untested tools: none. Problems: 0 ». - Documenter : README avec un tableau des outils (une ligne par outil), CONTRIBUTING, LICENSE.
- Commiter, pousser, déployer uniquement avec l'accord de l'utilisateur (voir
references/deploy-vercel.md), puis exécuter le test contre l'URL en direct. - Demander à l'utilisateur de supprimer et ré-ajouter le connecteur dans claude.ai (il met en cache la liste des outils) et fournir 3 à 5 invites de test courtes.
Règles de conception des outils
- Peu d'outils, qui fonctionnent réellement. Les noms sont des verbes en
snake_case:search_x,get_x,list_x. - Schéma Zod avec des limites sur chaque entrée (
min/max,default) ; décrivez chaque champ avec un exemple. - La description indique ce qu'il retourne et quand l'utiliser, en une ou deux phrases. Le modèle la lit pour choisir l'outil.
- Annotations :
readOnlyHint: true, idempotentHint: true, destructiveHint: false, plusopenWorldHint: truepour les API externes. - Envelopper chaque gestionnaire dans
safe(...): les échecs en amont deviennent des résultatsisErroravec un message lisible, jamais un plantage. - Nommer la source de données dans chaque résultat. Indiquez quand les données sont modifiées par la communauté ou provisoires.
- Ne jamais planter sur des champs manquants ; utiliser « inconnu » comme fallback.
- Tolérance aux fautes de frappe : en cas d'absence de correspondance, retourner des suggestions « vouliez-vous dire » au lieu d'un résultat vide.
- Mettre en cache les appels en amont (le modèle
getJson/getTexta un TTL, une déduplication des requêtes en vol, un cache court en cas d'échec, un timeout). Utilisez des TTL courts (minutes) pour les données en direct, des heures pour les données statiques. Soyez gentil avec les API gratuites. - Retourner à la fois du texte (pour le modèle) et
structuredContent(pour la carte) via une fonction d'aide commecard(text, data). - Pas de secrets dans le dépôt. Si une clé est requise, la lire depuis
process.envet la documenter. - Filtrer le travail lourd dans le code, pas dans la requête en amont, lorsque l'amont est lent.
Serveur sans état (adapté à Vercel)
Un nouveau McpServer et transport sont créés par requête (src/handler.ts) ; pas de sessions, pas de mémoire entre les requêtes. Le seul état est le cache en mémoire, qui est au mieux. CORS et une limite de taille de corps sont dans le handler. api/mcp.ts exporte { fetch } et maxDuration: 30 ; vercel.json réécrit /mcp vers /api/mcp.
Cartes (MCP Apps), version courte
Enregistrer une ressource HTML ui://… (mimeType: text/html;profile=mcp-app), puis donner à chaque outil `_meta: { ui: { resourceUri },