- Home
- Documentation
- MCP
- Creazione di server e strumenti MCP
Creazione di server e strumenti MCP
Questo documento spiega come le definizioni di server MCP diventano strumenti mcp_* richiamabili nell’agente di codifica, e cosa devono aspettarsi gli operatori quando le configurazioni sono non valide, duplicate, disabilitate o protette da autenticazione.
Architettura in sintesi
Sezione intitolata “Architettura in sintesi”Config sources (.xcsh/.claude/.cursor/.vscode/mcp.json, mcp.json, etc.) -> discovery providers normalize to canonical MCPServer -> capability loader dedupes by server name (higher provider priority wins) -> loadAllMCPConfigs converts to MCPServerConfig + skips enabled:false -> MCPManager connects/listTools (with auth/header/env resolution) -> MCPTool/DeferredMCPTool bridge exposes tools as mcp_<server>_<tool> -> AgentSession.refreshMCPTools replaces live MCP tools immediately1) Modello di configurazione del server e validazione
Sezione intitolata “1) Modello di configurazione del server e validazione”src/mcp/types.ts definisce la struttura di creazione utilizzata dagli autori di configurazioni MCP e dal runtime:
stdio(predefinito quando mancatype): richiedecommand, opzionalmenteargs,env,cwdhttp: richiedeurl, opzionalmenteheaderssse: richiedeurl, opzionalmenteheaders(mantenuto per compatibilità)- campi condivisi:
enabled,timeout,auth
validateServerConfig() (src/mcp/config.ts) applica le regole fondamentali di trasporto:
- rifiuta le configurazioni che impostano sia
commandcheurl - richiede
commandper stdio - richiede
urlper http/sse - rifiuta valori
typesconosciuti
config-writer.ts applica questa validazione per le operazioni di aggiunta/aggiornamento e verifica anche i nomi dei server:
- non vuoti
- massimo 100 caratteri
- solo
[a-zA-Z0-9_.-]
Problematiche di trasporto
Sezione intitolata “Problematiche di trasporto”- L’omissione di
typeimplica stdio. Se si intende HTTP/SSE ma si omettetype,commanddiventa obbligatorio. sseè ancora accettato ma trattato internamente come trasporto HTTP (createHttpTransport).- La validazione è strutturale, non verifica la raggiungibilità: un URL sintatticamente valido può comunque fallire al momento della connessione.
2) Scoperta, normalizzazione e precedenza
Sezione intitolata “2) Scoperta, normalizzazione e precedenza”Scoperta basata sulle capacità
Sezione intitolata “Scoperta basata sulle capacità”loadAllMCPConfigs() (src/mcp/config.ts) carica gli elementi canonici MCPServer tramite loadCapability(mcpCapability.id).
Il livello di capacità (src/capability/index.ts) quindi:
- carica i provider in ordine di priorità
- deduplica per
server.name(il primo vince = priorità più alta) - valida gli elementi deduplicati
Risultato: i nomi di server duplicati tra le sorgenti non vengono uniti. Una sola definizione vince; i duplicati con priorità inferiore vengono oscurati.
.mcp.json e file correlati
Sezione intitolata “.mcp.json e file correlati”Il provider di fallback dedicato in src/discovery/mcp-json.ts legge mcp.json e .mcp.json nella root del progetto (bassa priorità).
In pratica, i server MCP provengono anche da provider con priorità più alta (ad esempio i file nativi .xcsh/... e le directory di configurazione specifiche degli strumenti). Linee guida per la creazione:
- Preferire
.xcsh/mcp.json(progetto) o~/.xcsh/mcp.json(utente) per un controllo esplicito. - Usare
mcp.json/.mcp.jsonnella root quando si necessita di compatibilità di fallback. - Il riutilizzo dello stesso nome di server in più sorgenti causa un oscuramento per precedenza, non una fusione.
Comportamento di normalizzazione
Sezione intitolata “Comportamento di normalizzazione”convertToLegacyConfig() (src/mcp/config.ts) mappa il MCPServer canonico nel MCPServerConfig di runtime.
Comportamento chiave:
- il trasporto viene dedotto come
server.transport ?? (command ? "stdio" : url ? "http" : "stdio") - i server disabilitati (
enabled === false) vengono esclusi prima della connessione - i campi opzionali vengono preservati quando presenti
Espansione delle variabili d’ambiente durante la scoperta
Sezione intitolata “Espansione delle variabili d’ambiente durante la scoperta”mcp-json.ts espande i segnaposto di ambiente nei campi stringa con expandEnvVarsDeep():
- supporta
${VAR}e${VAR:-default} - i valori non risolti rimangono come stringhe letterali
${VAR}
mcp-json.ts esegue inoltre verifiche del tipo a runtime per il JSON dell’utente e registra avvisi per valori enabled/timeout non validi invece di far fallire l’intero file.
3) Risoluzione dei valori di autenticazione e runtime
Sezione intitolata “3) Risoluzione dei valori di autenticazione e runtime”MCPManager.prepareConfig()/#resolveAuthConfig() (src/mcp/manager.ts) è il passaggio finale prima della connessione.
Iniezione delle credenziali OAuth
Sezione intitolata “Iniezione delle credenziali OAuth”Se la configurazione contiene:
auth: { type: "oauth", credentialId: "..." }e la credenziale esiste nell’archivio di autenticazione:
http/sse: inietta l’intestazioneAuthorization: Bearer <access_token>stdio: inietta la variabile d’ambienteOAUTH_ACCESS_TOKEN
Se la ricerca delle credenziali fallisce, il manager registra un avviso e continua con l’autenticazione non risolta.
Risoluzione dei valori di intestazione/ambiente
Sezione intitolata “Risoluzione dei valori di intestazione/ambiente”Prima della connessione, il manager risolve ogni valore di intestazione/ambiente tramite resolveConfigValue() (src/config/resolve-config-value.ts):
- valore che inizia con
!=> esegue il comando shell, usa lo stdout pulito (memorizzato nella cache) - altrimenti, tratta il valore prima come nome di variabile d’ambiente (
process.env[name]), con fallback al valore letterale - i valori di comando/ambiente non risolti vengono omessi dalla mappa finale di intestazioni/ambiente
Avvertenza operativa: ciò significa che una chiave di comando/ambiente per il segreto scritta in modo errato può rimuovere silenziosamente quella voce di intestazione/ambiente, producendo errori 401/403 a valle o errori di avvio del server.
4) Bridge degli strumenti: MCP -> strumenti richiamabili dall’agente
Sezione intitolata “4) Bridge degli strumenti: MCP -> strumenti richiamabili dall’agente”src/mcp/tool-bridge.ts converte le definizioni degli strumenti MCP in CustomTool.
Denominazione e dominio delle collisioni
Sezione intitolata “Denominazione e dominio delle collisioni”I nomi degli strumenti vengono generati come:
mcp_<sanitized_server_name>_<sanitized_tool_name>Regole:
- conversione in minuscolo
- i caratteri non conformi a
[a-z_]diventano_ - i trattini bassi ripetuti vengono compressi
- il prefisso ridondante
<server>_nel nome dello strumento viene rimosso una volta
Questo evita molte collisioni, ma non tutte. Nomi raw diversi possono comunque produrre lo stesso identificatore dopo la sanitizzazione (ad esempio my-server e my.server producono risultati simili), e l’inserimento nel registro è last-write-wins.
Mappatura dello schema
Sezione intitolata “Mappatura dello schema”convertSchema() mantiene lo schema JSON MCP per lo più invariato, ma corregge gli schemi oggetto privi di properties aggiungendo {} per la compatibilità con i provider.
Mappatura dell’esecuzione
Sezione intitolata “Mappatura dell’esecuzione”MCPTool.execute() / DeferredMCPTool.execute():
- chiama MCP
tools/call - appiattisce il contenuto MCP in testo visualizzabile
- restituisce dettagli strutturati (
serverName,mcpToolName, metadati del provider) - mappa
isErrorsegnalato dal server in un risultato testualeError: ... - mappa i fallimenti di trasporto/runtime lanciati in
MCP error: ... - preserva la semantica di interruzione traducendo AbortError in
ToolAbortError
5) Ciclo di vita dell’operatore: aggiunta/modifica/rimozione e aggiornamenti in tempo reale
Sezione intitolata “5) Ciclo di vita dell’operatore: aggiunta/modifica/rimozione e aggiornamenti in tempo reale”La modalità interattiva espone /mcp in src/modes/controllers/mcp-command-controller.ts.
Operazioni supportate:
add(procedura guidata o aggiunta rapida)remove/rmenable/disabletestreauth/unauthreload
Le scritture di configurazione sono atomiche (writeMCPConfigFile: file temporaneo + rinomina).
Dopo le modifiche, il controller chiama #reloadMCP():
mcpManager.disconnectAll()mcpManager.discoverAndConnect()session.refreshMCPTools(mcpManager.getTools())
refreshMCPTools() sostituisce tutte le voci mcp_ nel registro e riattiva immediatamente il set più recente di strumenti MCP, quindi le modifiche hanno effetto senza riavviare la sessione.
Differenze tra modalità
Sezione intitolata “Differenze tra modalità”- Modalità interattiva/TUI:
/mcpfornisce un’interfaccia utente in-app (procedura guidata, flusso OAuth, testo dello stato della connessione, ricollegamento immediato al runtime). - Integrazione SDK/headless:
discoverAndLoadMCPTools()(src/mcp/loader.ts) restituisce gli strumenti caricati e gli errori per server; nessuna interfaccia utente per il comando/mcp.
6) Superfici di errore visibili all’utente
Sezione intitolata “6) Superfici di errore visibili all’utente”Stringhe di errore comuni che utenti/operatori vedono:
- errori di validazione in aggiunta/aggiornamento:
Invalid server config: ...Server "<name>" already exists in <path>
- problemi con gli argomenti di aggiunta rapida:
Use either --url or -- <command...>, not both.--token requires --url (HTTP/SSE transport).
- errori di connessione/test:
Failed to connect to "<name>": <message>- il testo di aiuto per il timeout suggerisce di aumentare il valore
- il testo di aiuto per l’autenticazione per
401/403
- flussi di autenticazione/OAuth:
Authentication required ... OAuth endpoints could not be discoveredOAuth flow timed out. Please try again.OAuth authentication failed: ...
- utilizzo di un server disabilitato:
Server "<name>" is disabled. Run /mcp enable <name> first.
Il JSON sorgente non valido durante la scoperta viene generalmente gestito come avvisi/log; i percorsi di config-writer generano errori espliciti.
7) Linee guida pratiche per la creazione
Sezione intitolata “7) Linee guida pratiche per la creazione”Per una creazione robusta di MCP in questa codebase:
- Mantenere i nomi dei server globalmente univoci in tutte le sorgenti di configurazione compatibili con MCP.
- Preferire nomi alfanumerici/con trattino basso per evitare collisioni di nomi sanitizzati nei nomi degli strumenti
mcp_*generati. - Usare
typeesplicito per evitare impostazioni predefinite stdio accidentali. - Trattare
enabled: falsecome disattivazione completa: il server viene omesso dal set di connessione al runtime. - Per le configurazioni OAuth, memorizzare un
credentialIdvalido; altrimenti l’iniezione dell’autenticazione viene saltata. - Se si utilizza la risoluzione dei segreti basata su comandi (
!cmd), verificare che l’output del comando sia stabile e non vuoto.