- Startseite
- Documentation
- MCP
- MCP-Server- und Tool-Erstellung
MCP-Server- und Tool-Erstellung
Dieses Dokument erläutert, wie MCP-Server-Definitionen zu aufrufbaren mcp_*-Tools im Coding-Agent werden, und was Operatoren erwarten sollten, wenn Konfigurationen ungültig, dupliziert, deaktiviert oder durch Authentifizierung geschützt sind.
Architektur im Überblick
Abschnitt betitelt „Architektur im Überblick“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) Server-Konfigurationsmodell und Validierung
Abschnitt betitelt „1) Server-Konfigurationsmodell und Validierung“src/mcp/types.ts definiert die Erstellungsstruktur, die von MCP-Konfigurationsautoren und zur Laufzeit verwendet wird:
stdio(Standard, wenntypefehlt): erfordertcommand, optionalargs,env,cwdhttp: erforderturl, optionalheaderssse: erforderturl, optionalheaders(aus Kompatibilitätsgründen beibehalten)- Gemeinsame Felder:
enabled,timeout,auth
validateServerConfig() (src/mcp/config.ts) erzwingt grundlegende Transport-Regeln:
- Lehnt Konfigurationen ab, die sowohl
commandals auchurlsetzen - Erfordert
commandfür stdio - Erfordert
urlfür http/sse - Lehnt unbekannte
type-Werte ab
config-writer.ts wendet diese Validierung für Hinzufüge-/Aktualisierungsoperationen an und validiert auch Servernamen:
- Nicht leer
- Maximal 100 Zeichen
- Nur
[a-zA-Z0-9_.-]
Transport-Fallstricke
Abschnitt betitelt „Transport-Fallstricke“- Fehlendes
typebedeutet stdio. Wenn Sie HTTP/SSE beabsichtigt, abertypeweggelassen haben, wirdcommandobligatorisch. ssewird weiterhin akzeptiert, aber intern als HTTP-Transport behandelt (createHttpTransport).- Die Validierung ist strukturell, nicht erreichbarkeitsbezogen: Eine syntaktisch gültige URL kann trotzdem beim Verbindungsaufbau fehlschlagen.
2) Erkennung, Normalisierung und Prioritäten
Abschnitt betitelt „2) Erkennung, Normalisierung und Prioritäten“Capability-basierte Erkennung
Abschnitt betitelt „Capability-basierte Erkennung“loadAllMCPConfigs() (src/mcp/config.ts) lädt kanonische MCPServer-Einträge über loadCapability(mcpCapability.id).
Die Capability-Schicht (src/capability/index.ts) führt dann folgendes aus:
- Lädt Provider in Prioritätsreihenfolge
- Dedupliziert nach
server.name(erster Treffer = höchste Priorität) - Validiert die deduplizierten Einträge
Ergebnis: Doppelte Servernamen über verschiedene Quellen hinweg werden nicht zusammengeführt. Eine Definition gewinnt; Duplikate mit niedrigerer Priorität werden überdeckt.
.mcp.json und verwandte Dateien
Abschnitt betitelt „.mcp.json und verwandte Dateien“Der dedizierte Fallback-Provider in src/discovery/mcp-json.ts liest mcp.json und .mcp.json aus dem Projektstammverzeichnis (niedrige Priorität).
In der Praxis kommen MCP-Server auch von Providern mit höherer Priorität (zum Beispiel native .xcsh/...- und toolspezifische Konfigurationsverzeichnisse). Hinweise zur Erstellung:
- Bevorzugen Sie
.xcsh/mcp.json(Projekt) oder~/.xcsh/mcp.json(Benutzer) für explizite Kontrolle. - Verwenden Sie
mcp.json/.mcp.jsonim Stammverzeichnis, wenn Sie Fallback-Kompatibilität benötigen. - Die Wiederverwendung desselben Servernamens in mehreren Quellen verursacht Prioritäts-Überdeckung, keine Zusammenführung.
Normalisierungsverhalten
Abschnitt betitelt „Normalisierungsverhalten“convertToLegacyConfig() (src/mcp/config.ts) bildet kanonische MCPServer auf die Laufzeit-MCPServerConfig ab.
Wichtiges Verhalten:
- Transport wird abgeleitet als
server.transport ?? (command ? "stdio" : url ? "http" : "stdio") - Deaktivierte Server (
enabled === false) werden vor dem Verbindungsaufbau entfernt - Optionale Felder werden beibehalten, wenn vorhanden
Umgebungsvariablen-Expansion während der Erkennung
Abschnitt betitelt „Umgebungsvariablen-Expansion während der Erkennung“mcp-json.ts expandiert Umgebungsvariablen-Platzhalter in String-Feldern mit expandEnvVarsDeep():
- Unterstützt
${VAR}und${VAR:-default} - Nicht aufgelöste Werte bleiben als literale
${VAR}-Strings erhalten
mcp-json.ts führt auch Laufzeit-Typprüfungen für Benutzer-JSON durch und protokolliert Warnungen für ungültige enabled/timeout-Werte, anstatt die gesamte Datei fehlschlagen zu lassen.
3) Authentifizierung und Laufzeitwert-Auflösung
Abschnitt betitelt „3) Authentifizierung und Laufzeitwert-Auflösung“MCPManager.prepareConfig()/#resolveAuthConfig() (src/mcp/manager.ts) ist der letzte Durchlauf vor dem Verbindungsaufbau.
OAuth-Anmeldedaten-Injektion
Abschnitt betitelt „OAuth-Anmeldedaten-Injektion“Wenn die Konfiguration folgendes enthält:
auth: { type: "oauth", credentialId: "..." }und die Anmeldedaten im Auth-Speicher existieren:
http/sse: InjiziertAuthorization: Bearer <access_token>-Headerstdio: InjiziertOAUTH_ACCESS_TOKEN-Umgebungsvariable
Wenn die Anmeldedaten-Suche fehlschlägt, protokolliert der Manager eine Warnung und fährt mit nicht aufgelöster Authentifizierung fort.
Header-/Umgebungsvariablen-Wertauflösung
Abschnitt betitelt „Header-/Umgebungsvariablen-Wertauflösung“Vor dem Verbindungsaufbau löst der Manager jeden Header-/Umgebungsvariablen-Wert über resolveConfigValue() (src/config/resolve-config-value.ts) auf:
- Wert beginnt mit
!=> Shell-Befehl ausführen, getrimmte Stdout-Ausgabe verwenden (gecacht) - Andernfalls wird der Wert zuerst als Umgebungsvariablenname behandelt (
process.env[name]), Fallback auf den literalen Wert - Nicht aufgelöste Befehls-/Umgebungsvariablen-Werte werden aus der finalen Header-/Umgebungsvariablen-Map weggelassen
Betrieblicher Hinweis: Dies bedeutet, dass ein falsch geschriebener Secret-Befehl/Umgebungsvariablen-Schlüssel stillschweigend diesen Header-/Umgebungsvariablen-Eintrag entfernen kann, was nachgelagert 401/403-Fehler oder Server-Startfehler verursacht.
4) Tool-Bridge: MCP -> Agent-aufrufbare Tools
Abschnitt betitelt „4) Tool-Bridge: MCP -> Agent-aufrufbare Tools“src/mcp/tool-bridge.ts konvertiert MCP-Tool-Definitionen in CustomTools.
Benennung und Kollisionsdomäne
Abschnitt betitelt „Benennung und Kollisionsdomäne“Tool-Namen werden generiert als:
mcp_<sanitized_server_name>_<sanitized_tool_name>Regeln:
- Kleinbuchstaben
- Nicht-
[a-z_]-Zeichen werden zu_ - Wiederholte Unterstriche werden zusammengefasst
- Redundantes
<server>_-Präfix im Tool-Namen wird einmal entfernt
Dies vermeidet viele Kollisionen, aber nicht alle. Verschiedene Rohnamen können dennoch zum selben Bezeichner sanitisiert werden (zum Beispiel werden my-server und my.server ähnlich sanitisiert), und die Registry-Einfügung erfolgt nach dem Last-Write-Wins-Prinzip.
Schema-Abbildung
Abschnitt betitelt „Schema-Abbildung“convertSchema() behält das MCP-JSON-Schema weitgehend unverändert bei, ergänzt aber Objekt-Schemas ohne properties mit {} für Provider-Kompatibilität.
Ausführungs-Abbildung
Abschnitt betitelt „Ausführungs-Abbildung“MCPTool.execute() / DeferredMCPTool.execute():
- Ruft MCP
tools/callauf - Flacht MCP-Inhalte in darstellbaren Text ab
- Gibt strukturierte Details zurück (
serverName,mcpToolName, Provider-Metadaten) - Bildet vom Server gemeldete
isError-Werte aufError: ...-Textergebnisse ab - Bildet geworfene Transport-/Laufzeitfehler auf
MCP error: ...ab - Bewahrt Abbruch-Semantik durch Übersetzung von AbortError in
ToolAbortError
5) Operator-Lebenszyklus: Hinzufügen/Bearbeiten/Entfernen und Live-Updates
Abschnitt betitelt „5) Operator-Lebenszyklus: Hinzufügen/Bearbeiten/Entfernen und Live-Updates“Der interaktive Modus stellt /mcp in src/modes/controllers/mcp-command-controller.ts bereit.
Unterstützte Operationen:
add(Assistent oder Schnellhinzufügung)remove/rmenable/disabletestreauth/unauthreload
Konfigurationsschreibvorgänge sind atomar (writeMCPConfigFile: temporäre Datei + Umbenennung).
Nach Änderungen ruft der Controller #reloadMCP() auf:
mcpManager.disconnectAll()mcpManager.discoverAndConnect()session.refreshMCPTools(mcpManager.getTools())
refreshMCPTools() ersetzt alle mcp_-Registry-Einträge und reaktiviert sofort den neuesten MCP-Tool-Satz, sodass Änderungen ohne Neustart der Sitzung wirksam werden.
Modusunterschiede
Abschnitt betitelt „Modusunterschiede“- Interaktiver/TUI-Modus:
/mcpbietet eine In-App-Benutzeroberfläche (Assistent, OAuth-Flow, Verbindungsstatus-Text, sofortige Laufzeit-Neubindung). - SDK/Headless-Integration:
discoverAndLoadMCPTools()(src/mcp/loader.ts) gibt geladene Tools + Fehler pro Server zurück; keine/mcp-Befehls-UX.
6) Benutzer-sichtbare Fehlermeldungen
Abschnitt betitelt „6) Benutzer-sichtbare Fehlermeldungen“Häufige Fehlermeldungen, die Benutzer/Operatoren sehen:
- Validierungsfehler beim Hinzufügen/Aktualisieren:
Invalid server config: ...Server "<name>" already exists in <path>
- Probleme mit Schnellhinzufügungs-Argumenten:
Use either --url or -- <command...>, not both.--token requires --url (HTTP/SSE transport).
- Verbindungs-/Testfehler:
Failed to connect to "<name>": <message>- Timeout-Hilfetext schlägt vor, das Timeout zu erhöhen
- Auth-Hilfetext für
401/403
- Auth/OAuth-Flows:
Authentication required ... OAuth endpoints could not be discoveredOAuth flow timed out. Please try again.OAuth authentication failed: ...
- Verwendung deaktivierter Server:
Server "<name>" is disabled. Run /mcp enable <name> first.
Fehlerhaftes Quell-JSON bei der Erkennung wird generell als Warnungen/Logs behandelt; Config-Writer-Pfade werfen explizite Fehler.
7) Praktische Hinweise zur Erstellung
Abschnitt betitelt „7) Praktische Hinweise zur Erstellung“Für robuste MCP-Erstellung in dieser Codebasis:
- Halten Sie Servernamen global eindeutig über alle MCP-fähigen Konfigurationsquellen hinweg.
- Bevorzugen Sie alphanumerische/Unterstrich-Namen, um Kollisionen durch sanitisierte Namen in generierten
mcp_*-Tool-Namen zu vermeiden. - Verwenden Sie explizite
type-Angaben, um versehentliche stdio-Standards zu vermeiden. - Behandeln Sie
enabled: falseals vollständige Deaktivierung: Der Server wird aus dem Laufzeit-Verbindungsset ausgelassen. - Speichern Sie für OAuth-Konfigurationen eine gültige
credentialId; andernfalls wird die Auth-Injektion übersprungen. - Wenn Sie befehlsbasierte Secret-Auflösung (
!cmd) verwenden, überprüfen Sie, dass die Befehlsausgabe stabil und nicht leer ist.