Das ist eine für den Ausdruck optimierte Ansicht des gesamten Kapitels inkl. Unterseiten.
Druckvorgang starten.
Zur Standardansicht zurückkehren.
MCP-Server
Die DataBridge unterstützt das Model Context Protocol: ein eingebauter, read-only Server für Jobs, Mappings, Service-Bus-Queues und echte Connector-Schemas für KI-Assistenten wie Claude Code, GitHub Copilot oder Microsoft 365 Copilot.
Die dsyr.DataBridge unterstützt das Model Context Protocol (MCP)
— den offenen Standard, über den KI-Assistenten strukturiert auf externe Systeme zugreifen. Ein
eingebauter, read-only MCP-Server macht dieselben Daten, die auch über die HTTP-APIs
(GetJobByRowKey, GetMappingByRowKey) verfügbar sind, sowie die Service-Bus-Queue-Diagnose
zusätzlich als MCP-Tools ansprechbar — sodass ein KI-Assistent (Claude Code, GitHub Copilot,
Microsoft 365 Copilot, …) direkt gegen eine laufende DataBridge-Instanz Fragen stellen kann, statt
Tabellen manuell in Azure Storage Explorer oder per REST-Aufruf durchzusehen.
Read-only
Kein Tool verändert, löscht oder sendet irgendetwas. Der Server eignet sich zum Nachschlagen,
Validieren und Debuggen — nicht zum Auslösen von Jobs oder Schreiben in Zielsysteme. Was genau
jedes einzelne Tool lesen darf (und was bewusst nicht zurückgegeben wird, z. B. Nachrichten-
inhalte oder Connection-Credentials), steht auf der Unterseite Operationen.
Auf dieser Seite
- Funktionsweise — Endpunkt, Transport, Authentifizierung und wie die Function
intern aufgebaut ist.
- Operationen — die zehn verfügbaren Tools im Detail: was jedes einzelne liest,
und was es nicht liest.
- Nutzung — Einrichtung mit Claude Code, GitHub Copilot (VS Code) und Microsoft 365
Copilot.
Kurzüberblick
| |
|---|
| Function | Mcp (DataBridge/Functions/McpApi.cs) |
| Route | POST /api/mcp (JSON-RPC-Austausch über Streamable HTTP) |
| Auth-Level | Function (Function Key als ?code=-Query-Parameter) |
| Tools | 10 — Jobs & Mappings, Service-Bus-Diagnose, Connector-Schema (siehe Operationen) |
| Schreibzugriff | Keiner — alle Tools sind read-only, siehe Operationen |
Der Server ist damit direkt an einer laufenden Function App (lokal oder in Azure) ansprechbar,
ohne eigenen Prozess oder zusätzliche Infrastruktur.
1 - Funktionsweise
Wie der MCP-Server technisch aufgebaut ist: Endpunkt, Transport, Authentifizierung, interner Aufbau und eine bekannte Einschränkung.
Endpunkt
| |
|---|
| Function | Mcp (DataBridge/Functions/McpApi.cs) |
| Route | POST /api/mcp (JSON-RPC-Austausch); GET /api/mcp liefert bewusst 405 — siehe Bekannte Einschränkung |
| Auth-Level | Function (Function Key als ?code=-Query-Parameter) |
| Protokoll | MCP über Streamable HTTP, stateless — jede POST-Anfrage ist ein eigenständiger JSON-RPC-Austausch, es gibt keine langlebige Server-Session |
Der Server ist damit direkt an einer laufenden Function App (lokal oder in Azure) ansprechbar,
ohne eigenen Prozess oder zusätzliche Infrastruktur. Da die Authentifizierung über den normalen
Azure-Functions-Mechanismus läuft (Function Key), lässt sich der Server ohne zusätzliche
Identity-Provider-Konfiguration einrichten — der Key kann als Query-Parameter oder als Header
übergeben werden, je nachdem, was der jeweilige Client unterstützt (siehe Nutzung).
Interner Aufbau
Der Mcp-Function-Trigger baut pro HTTP-Anfrage einen eigenen
StreamableHttpServerTransport auf und
delegiert die eigentliche Tool-Logik an den IMcpToolService (DataBridge.Core/Services/Mcp/),
der wiederum dieselben Service-Interfaces (IJobService, IMappingService,
IServiceBusService, IConnectionService) aufruft wie die klassischen HTTP-Funktionen — es gibt
keine internen Selbstaufrufe zwischen den Functions. McpApi.cs bleibt dadurch auf die reine
Protokoll-Anbindung beschränkt (Tool-Registrierung, Transport), analog zum dünnen Zuschnitt von
JobApi/MappingApi. Die eigentliche Tool-Logik (Init-Guard, Job-/Mapping-Lesezugriff,
Service-Bus-Delegation, Connector-Auflösung) liegt in IMcpToolService, testbar unabhängig vom
Protokoll-Layer. Details zur Service-Schicht: Architektur.
Die [Description]-Attribute und Standardwerte für die Tool-Parameter liegen bewusst auf den
Methoden von IMcpToolService selbst (reines System.ComponentModel) — McpApi.cs bindet die
Tools direkt auf diese Service-Methoden, ohne zusätzliche Wrapper-Methoden. Der Transport-Teil
(ModelContextProtocol.AspNetCore) bleibt im Host; DataBridge.Core referenziert nur
ModelContextProtocol.Core, und das ausschließlich für die McpException (siehe unten).
Fehlerweitergabe an den Client
Der MCP-C#-SDK ersetzt jede unbehandelte Exception eines Tools durch den generischen Text
„An error occurred invoking ‘…’.“ und hängt nur bei einer McpException deren Message an.
Alle anderen Exceptions landen zwar im Log, der Client sieht aber nicht, warum der Aufruf
fehlgeschlagen ist. Ein CallToolFilter hilft hier nicht, weil der Catch im SDK innerhalb des
Tool-Aufrufs sitzt. McpToolService wirft deshalb bei den beiden Connector-Tools
(list_connector_tables, get_connector_table_schema) Connector-Fehler und unbekannte
Connection-Namen als McpException weiter (SurfaceConnectorErrors), sodass z. B. die
angefragte $metadata-URL und der HTTP-Status beim Client ankommen. Der Test
McpApiTests.ToolsCall_ListConnectorTables_ConnectorFails_ErrorResultCarriesTheCause sichert
dieses Verhalten durch die echte SDK-Pipeline ab.
Bekannte Einschränkung: GET auf /api/mcp
Manche MCP-Clients (typischerweise Remote-Clients, die den Endpunkt über eine echte
Azure-Deployment-URL statt lokal ansprechen) versuchen nach dem initialize-POST zusätzlich
einen GET auf denselben Endpunkt, um einen optionalen Server-zu-Client-SSE-Stream zu öffnen
(Teil der Streamable-HTTP-Spezifikation).
Da dieser Server stateless ist (keine Session, kein Server-Push), unterstützt er diesen
Stream bewusst nicht. Die Route ist deshalb zusätzlich zum POST-Handler mit einem eigenen
GET-Handler registriert, der spezifikationskonform mit 405 Method Not Allowed (statt einem
nicht aussagekräftigen, von Azure Functions automatisch erzeugten 404) antwortet:
[Function("McpGet")]
public IActionResult HandleMcpGetRequest(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "mcp")] HttpRequest req)
{
req.HttpContext.Response.Headers.Append("Allow", "POST");
return new StatusCodeResult(StatusCodes.Status405MethodNotAllowed);
}
Manche Clients interpretieren 405 als „kein SSE-Support, aber Server ist erreichbar" und
fallen automatisch auf reines POST zurück; ein 404 liest sich dagegen wie „Endpunkt existiert
nicht" und lässt die Verbindung fehlschlagen. Ohne diesen Handler tritt das Problem nur bei
Remote-/Azure-Deployments zuverlässig auf — lokal (Claude Code über .mcp.json) sendet der
Client i. d. R. keinen GET-Probe-Request, daher blieb es dort unbemerkt.
2 - Operationen
Die zehn MCP-Tools im Detail: was jedes einzelne liest — und was bewusst nicht zurückgegeben wird.
Alle zehn Tools sind als ReadOnly = true, Idempotent = true und Destructive = false markiert
(MCP-Tool-Annotationen, die dem aufrufenden Client mitgeben, dass wiederholte Aufrufe risikolos
sind). Kein Tool schreibt, löscht oder sendet — weder in der jobs-/mappings-Tabelle, noch in
den Service-Bus-Queues, noch in einem Quell-/Zielsystem.
Grenze ist Metadaten vs. Nutzdaten, nicht nur lesend vs. schreibend
Auch innerhalb der reinen Lesezugriffe gibt es eine bewusste zweite Grenze: Betriebs-/
Konfigurationsdaten (Job-Namen, Schemata, Fehlermeldungen, Zeitstempel) sind unkritisch und werden
vollständig zurückgegeben. Fachliche Nutz-/Kundendaten — z. B. der Inhalt einer
Service-Bus-Nachricht — werden dagegen nie zurückgegeben, selbst wenn das zugrunde liegende
Tool ansonsten “nur liest”. Details dazu unten bei den Peek-Tools.
Jobs & Mappings (Table Storage)
Lesen ausschließlich aus den beiden Tabellen jobs/mappings, über dieselben In-Memory-Caches
wie JobApi/MappingApi (IJobService.Jobs/IMappingService.Mappings — reine Query<T>()-Reads,
kein Upsert/Delete im Codepfad).
| Tool | Liest | Liest nicht |
|---|
list_jobs | Alle konfigurierten Jobs: Quelle/Ziel-Connection, Richtung, Priorität, Zeitplan, Mapping-Name, aus der jobs-Tabelle | Keine Connection-Credentials (nur der Name der Connection, nicht ihre Zugangsdaten) |
get_job | Ein einzelner Job anhand seines RowKey (Job-Name) — dieselben Felder wie list_jobs | dito |
list_mappings | Alle Feld-Mappings zwischen Quell- und Zielsystemen aus der mappings-Tabelle | Keine tatsächlichen Datensatz-Inhalte — nur die Mapping-Konfiguration (welches Feld auf welches Feld abgebildet wird), nicht produzierte/synchronisierte Daten |
get_mapping | Ein einzelnes Mapping anhand seines Namens (der Mapping-Name, auf den ein Job verweist und unter dem list_mappings es auflistet) | dito |
Warum keine Credentials möglich sind: IConnectionService.GetConnector(name) liefert nur die
IConnector-Instanz zurück, nicht das zugrunde liegende ConnectionSetting-Objekt. Felder wie
ClientSecret, Password oder ApiKeyValue sind private Felder in den konkreten Connectoren und
nicht Teil des IConnector-Interfaces — es gibt schlicht keinen Rückgabewert, über den sie
herauskommen könnten.
Service Bus (Diagnose)
Reine Peek-/Status-Operationen über IServiceBusService. Die beiden Peek-Tools erzeugen den
Empfänger ohne PeekLock und rufen ausschließlich receiver.PeekMessagesAsync(...) auf — es gibt
im Codepfad kein ReceiveMessagesAsync, CompleteMessageAsync, DeadLetterMessageAsync oder
AbandonMessageAsync. Auch SendMessageAsync (existiert auf IServiceBusService für
GetChanges) ist von keinem MCP-Tool aus erreichbar.
| Tool | Liest | Liest nicht |
|---|
list_queue_statuses | Laufzeit-Status (aktive/dead-letter/geplante Nachrichtenanzahl) aller Export-Queues | Keine einzelnen Nachrichten — nur Zähler |
get_queue_status | Laufzeit-Status einer einzelnen Queue für eine Job-Priorität | dito |
peek_queue_messages | Sequenznummer, JobName, SourceKey, Enqueue-Zeitpunkt, Zustellversuche und BodySize (Größe des Nachrichteninhalts in Bytes) je Nachricht | Den Nachrichteninhalt selbst (Body) nicht — siehe Kasten unten |
peek_dead_letter_queue_messages | Zusätzlich zu den obigen Feldern: DeadLetterReason, DeadLetterErrorDescription, ErrorMessage, ErrorTimeStamp, ErrorStackTrace, OperationId | dito — auch hier nur BodySize, nie Body |
Warum kein Nachrichteninhalt
Der Body einer Queue-Nachricht enthält die fachlichen Nutzdaten des jeweiligen Jobs — z. B.
bei einem BC-Artikelstamm-Job Produktcode, Bezeichnung und Dimensionswerte, bei anderen Jobs unter
Umständen Kundennamen, Adressen oder Preise. Das ist etwas grundlegend anderes als Betriebsmetadaten
wie ein Fehlertext oder ein Zeitstempel. Beide Peek-Tools geben deshalb bewusst nie den
Nachrichteninhalt zurück — nur dessen Größe in Bytes (BodySize), berechnet über
message.Body.ToMemory().Length, ohne den Inhalt jemals zu deserialisieren oder als String zu
lesen. Für die Fehleranalyse reichen die übrigen Felder (insbesondere bei
peek_dead_letter_queue_messages die Fehlerdetails) in aller Regel aus.
| Tool | Liest | Liest nicht |
|---|
list_connector_tables | Tabellen-/Entitätsnamen einer Connection direkt aus den Metadaten des Zielsystems — zum Abgleich mit den in Jobs/Mappings konfigurierten Namen | Keine tatsächlichen Datensätze aus der Tabelle — nur ihren Namen |
get_connector_table_schema | Spalten-Metadaten (Typ, Nullable, maximale Länge, bei SQL-Dezimalspalten Precision/Scale, Primary Key) einer Tabelle/Entität — zum Validieren eines Mappings gegen das tatsächliche Schema, statt sich auf die Mapping-Konfiguration allein zu verlassen | Keine tatsächlichen Datensätze/Zeilenwerte — nur die Spalten-Struktur |
Beide Tools nehmen einen connectionName entgegen (den RowKey aus der connections-Tabelle —
siehe Verbindungen, z. B. BC_Test oder CRM_Test) sowie
einen tableName/Ressourcennamen. Für BC/NAV gibt es zusätzlich den apiPath (derselbe Wert wie
TableMapping.SourcePath/TargetPath im Mapping), da beide Connectoren ihr Schema über einen
versionierten OData-$metadata-Endpunkt beziehen. Bei BC ist er optional: leer bedeutet v2.0
(die Standard-API); Custom-APIs (z. B. publisher/gruppe/v1.0) brauchen ihren Pfad weiterhin.
Bei den SQL-Connectoren hat apiPath eine andere Bedeutung, siehe unten.
Diese beiden Tools sind die einzigen mit OpenWorld = true — sie greifen tatsächlich auf das
externe Quell-/Zielsystem der jeweiligen Connection zu, nicht nur auf die eigene
DataBridge-Infrastruktur. Ungültige Connection-Namen liefern eine klare Meldung
(„Connection ‘…’ is not configured or not initialized") statt einer rohen
KeyNotFoundException — es lässt sich also nicht durch Ausprobieren beliebiger Namen etwas über
das System herausfinden, das über list_jobs/get_job nicht sowieso schon sichtbar wäre.
Schlägt der Zugriff auf das Zielsystem fehl (falscher apiPath, unbekannte Tabelle, Host nicht
erreichbar), enthält das Fehlerergebnis die Ursache, z. B. GET …/api/nope/v1.0/$metadata returned 404 Not Found — technisch als McpException, weil der MCP-SDK nur deren Message an den Client
durchreicht (siehe Funktionsweise).
Connector-Unterstützung
list_connector_tables/get_connector_table_schema funktionieren für alle Connectoren:
D365BC, D365NAV, D365CE (Dataverse), OpenAPI sowie die SQL-Connectoren MSSQL, MySQL,
Oracle und PostgreSQL. Der Rückgabewert ist je Connector unterschiedlich vollständig, da
nicht jedes System dieselbe Metadaten-Tiefe bietet:
| Connector | Typ | Nullable | Max. Länge | Precision/Scale | Primary Key |
|---|
| D365BC / D365NAV | ✅ | ✅ | ✅ (nur Strings) | ❌ | ✅ |
| D365CE (Dataverse) | ✅ | ✅ | ✅ (nur Strings) | ❌ | ✅ |
| OpenAPI | ✅ | ✅ | ✅ (falls maxLength im Schema) | ❌ | ❌ (kein natives Konzept — immer null) |
| MSSQL / MySQL / PostgreSQL | ✅ | ✅ | ✅ (nur Strings) | ✅ (nur Dezimalspalten) | ✅ |
| Oracle | ✅ | ✅ | ✅ (in Zeichen, CHAR_LENGTH) | ✅ (nur Dezimalspalten) | ✅ |
SQL-Connectoren: Schema über apiPath
Bei den SQL-Connectoren gibt apiPath das Schema an, in dem die Tabelle liegt — bei
MySQL die Datenbank. Ohne apiPath wird das Standard-Schema der Verbindung verwendet
(MSSQL SCHEMA_NAME(), MySQL DATABASE(), PostgreSQL current_schema(), Oracle der
angemeldete Benutzer). Damit werden gleichnamige Tabellen in unterschiedlichen Schemas
(z. B. dbo.Customers und archive.Customers) nicht vermischt.
| Connector | Metadatenquelle | apiPath |
|---|
| MSSQL | INFORMATION_SCHEMA | Schema, z. B. dbo |
| PostgreSQL | INFORMATION_SCHEMA | Schema, z. B. public |
| MySQL | INFORMATION_SCHEMA | Datenbank |
| Oracle | USER_TAB_COLUMNS/USER_CONSTRAINTS, mit apiPath ALL_*-Views | Owner/Schema, z. B. HR |
Tabellen- und Schemaname werden groß-/kleinschreibungsunabhängig verglichen und als
Parameter an die Datenbank übergeben. Die Metadaten werden je Connector-Instanz
zwischengespeichert — Schemaänderungen an der Datenbank werden erst nach einem Neustart der
Function App sichtbar.
SQL-Connectoren: Datentypen
Die Datentypen aus dem Datenbank-Katalog werden auf .NET-Typen abgebildet. Dabei werden
Precision und Scale sowie bei MySQL der vollständige Spaltentyp (COLUMN_TYPE) berücksichtigt.
Unbekannte Typen (z. B. json, xml, Array-Typen) erscheinen als String.
| .NET-Typ | MSSQL | PostgreSQL | MySQL | Oracle |
|---|
Guid | uniqueidentifier | uuid | — | — |
Boolean | bit | boolean | tinyint(1)/boolean, bit(1) | boolean (23ai) |
Byte | tinyint | — | tinyint unsigned | — |
Int16 | smallint | smallint | tinyint, smallint, year | number(1–4,0) |
Int32 | int | integer | int, mediumint, smallint unsigned | number(5–9,0) |
Int64 | bigint | bigint | bigint, int unsigned, bit(n>1) | number(10–18,0) |
Decimal | decimal, numeric, money | numeric | decimal, bigint unsigned | number mit Nachkommastellen, ab 19 Stellen oder ohne Angabe |
Single | real, float(1–24) | real | float | binary_float |
Double | float | double precision | double | binary_double, float |
DateOnly | date | date | date | — |
DateTime | datetime, datetime2, smalldatetime | timestamp | datetime, timestamp | date, timestamp, timestamp with local time zone |
DateTimeOffset | datetimeoffset | timestamp with time zone | — | timestamp with time zone |
TimeSpan | time | time, interval | time | interval |
Byte[] | binary, varbinary, image, timestamp/rowversion | bytea | binary, varbinary, blob-Typen | blob, raw |
String | Zeichentypen, xml | Zeichentypen, json/jsonb | Zeichentypen, json | Zeichentypen, clob, json |
Besonderheiten:
- MSSQL
timestamp ist der alte Name von rowversion, eine binäre Zeilenversion und kein
Datum — daher Byte[]. - MySQL speichert
BOOLEAN als tinyint(1); erst der vollständige Spaltentyp macht daraus
Boolean. Vorzeichenlose Ganzzahlen erhalten den nächstgrößeren Typ, damit der Wertebereich
passt. timestamp hat keinen Offset und wird daher DateTime. - Oracle kennt keine eigenen Ganzzahltypen;
NUMBER(p,0) wird nach der Anzahl der Stellen
auf Int16/Int32/Int64 abgebildet. DATE enthält immer eine Uhrzeit und wird daher
DateTime, nicht DateOnly. - GUIDs, die als Text gespeichert sind (MySQL
char(36), Oracle varchar2(36)), erscheinen als
String.
Zusammenfassung: was über MCP grundsätzlich nicht möglich ist
- Keine Schreib-, Lösch- oder Sende-Operation auf
jobs/mappings/Service-Bus-Queues oder einem
Ziel-/Quellsystem — es gibt für keines der zehn Tools einen Codepfad zu Upsert, Delete,
SendMessageAsync, CompleteMessageAsync o. Ä. - Keine Connection-Credentials (Passwörter, Client-Secrets, API-Keys) — die sind strukturell nie
Teil eines Rückgabewerts.
- Kein tatsächlicher Nachrichteninhalt aus einer Service-Bus-Queue — nur dessen Byte-Größe.
- Keine tatsächlichen Datensatz-Werte aus einem Ziel-/Quellsystem über die Connector-Tools — nur
Tabellennamen und Spalten-Struktur, keine Zeilen.
3 - Nutzung
Den MCP-Server mit Claude Code, GitHub Copilot (VS Code) oder Microsoft 365 Copilot verbinden.
Der Server spricht Standard-MCP über Streamable HTTP — grundsätzlich verbindet sich jeder
MCP-fähige Client über dieselbe URL (.../api/mcp?code=<Function-Key>). Die folgenden Abschnitte
zeigen die konkrete Einrichtung für die gängigsten Clients.
Claude Code
Dieses Repository bringt bereits eine passende .mcp.json
mit:
{
"mcpServers": {
"databridge": {
"type": "http",
"url": "${DATABRIDGE_MCP_URL:-http://localhost:7062}/api/mcp?code=${DATABRIDGE_FUNCTION_KEY:-local}"
}
}
}
Lokal (Core Tools / Debugger): Der lokale Function-Host prüft den Auth-Level Function nicht
— der Platzhalterwert local in der URL reicht aus. Voraussetzung ist nur, dass die Function App
tatsächlich auf Port 7062 läuft (nicht der func-Standard 7071!):
- Visual Studio /
dotnet run: Startprofil DataBridge aus src/DataBridge/Properties/launchSettings.json
(setzt bereits --port 7062). - VS Code: Task
func: host start aus .vscode/tasks.json (ebenfalls fest auf --port 7062). - Rider: die in der IDE angezeigte „Azure Functions Project"-Run-Configuration
DataBridge —
im Feld „Function host arguments" muss host start --pause-on-error --port 7062 stehen.
Danach lädt Claude Code den databridge-Server automatisch; die Tools erscheinen mit dem Präfix
mcp__databridge__....
Gegen eine Azure-Deployment-Instanz: Die URL enthält zwei Umgebungsvariablen, die ohne
eigene Werte auf den lokalen Host zeigen. Für ein Deployment setzt man sie in der nicht
eingecheckten .claude/settings.local.json des Repositorys:
{
"env": {
"DATABRIDGE_MCP_URL": "https://<function-app-name>.azurewebsites.net",
"DATABRIDGE_FUNCTION_KEY": "<Function Key>"
}
}
Den Function Key gibt es im Azure Portal → Function App → Funktionen → Mcp →
Funktionsschlüssel. Niemals einen echten Key in .mcp.json committen. Geänderte Werte greifen
erst beim Start einer neuen Claude-Code-Session.
Eine eigene Datei wie .mcp.local.json wertet Claude Code nicht aus. Wer zusätzlich einen
persönlichen Server-Eintrag braucht (etwa für eine zweite Instanz), legt ihn über
claude mcp add --scope local --transport http <name> "<url>" an.
Beispiel-Interaktion
Ein typischer Anwendungsfall: prüfen, ob ein Mapping-Feld wirklich im Zielsystem existiert.
Prompt: „Prüfe, ob das Mapping BCAccounts gültige Zielfelder hat — vergleiche mit den
echten Metadaten der Connection."
Claude ruft dafür typischerweise nacheinander auf:
get_mapping mit rowKey: "BCAccounts" → liefert die konfigurierten Feld-Mappings inkl.
TargetTable/TargetPath.get_connector_table_schema mit der targetConnection aus dem zugehörigen Job sowie
tableName/apiPath aus dem Mapping → liefert das tatsächliche Schema.- Vergleicht beide Ergebnisse und meldet fehlende Felder oder Typ-Abweichungen.
Damit lassen sich Mapping-Fehler bereits vor dem ersten produktiven Lauf eines Jobs erkennen,
statt sie erst über eine fehlgeschlagene Dead-Letter-Nachricht zu bemerken (siehe
peek_dead_letter_queue_messages, Operationen).
GitHub Copilot (VS Code)
VS Code (ab Version 1.99, Agent-/Chat-Modus) unterstützt MCP-Server nativ über eine mcp.json —
entweder projektweit unter .vscode/mcp.json oder als Nutzer-Konfiguration über die
Command Palette (MCP: Open User Configuration). Anders als Claude Codes .mcp.json liegt der
Server hier unter dem Schlüssel servers, nicht mcpServers:
{
"servers": {
"databridge": {
"type": "http",
"url": "https://<function-app-name>.azurewebsites.net/api/mcp?code=${input:databridgeFunctionKey}"
}
},
"inputs": [
{
"id": "databridgeFunctionKey",
"type": "promptString",
"description": "DataBridge MCP Function Key",
"password": true
}
]
}
Der inputs-Block sorgt dafür, dass VS Code beim ersten Verbindungsversuch einmalig nach dem
Function Key fragt (maskierte Eingabe) statt ihn im Klartext in der Datei zu speichern — dieselbe
Absicht wie die ${DATABRIDGE_FUNCTION_KEY:-local}-Umgebungsvariable im Claude-Code-Beispiel oben,
nur über den VS-Code-eigenen Mechanismus. Lokal (Function-Host ohne Auth-Prüfung) reicht auch hier
ein beliebiger Platzhalterwert. Details zu Input-Variablen:
VS Code MCP-Konfigurationsreferenz.
Nach dem Speichern zeigt VS Code den Server im Chat-/Agent-Modus an; die Tools lassen sich dort
wie jedes andere MCP-Tool auswählen und aufrufen.
Microsoft 365 Copilot
Microsoft 365 Copilot bindet externe MCP-Server nicht direkt per URL im Chat ein, sondern über
Copilot Studio — dort lässt sich ein bestehender MCP-Server einem Agenten als Tool hinzufügen,
und dieser Agent dann in Microsoft 365 Copilot veröffentlichen. Die Einrichtung erfolgt über den
MCP-Onboarding-Wizard in Copilot Studio:
- Im Agenten zur Seite Tools wechseln → Add a tool → New tool → Model Context Protocol.
- Server-URL eintragen:
https://<function-app-name>.azurewebsites.net/api/mcp. - Als Authentifizierungsart API key wählen (nicht OAuth 2.0 — unser Server nutzt den
Azure-Functions-eigenen Function-Key-Mechanismus, kein OAuth).
- Als Type Query wählen und als Parametername
code eintragen — das entspricht genau
dem ?code=-Query-Parameter, den auch Claude Code und VS Code verwenden. - Create, dann den Function Key als API-Key-Wert für die Verbindung hinterlegen.
Copilot Studio unterstützt für MCP ausschließlich den Streamable-HTTP-Transport (SSE ist
seit August 2025 deprecatet) — genau das Protokoll, das McpApi.cs implementiert, es sind also
keine serverseitigen Anpassungen nötig.
Stand der Unterstützung
Die Microsoft-365-Copilot-Integration für MCP-Server entwickelt sich weiter (Copilot Studio hat
die GA für MCP-Tools im Sommer 2026 erreicht); ob und wie ein Tool in einer konkreten
Microsoft-365-Oberfläche (Copilot Chat, Excel, Teams, …) angezeigt wird, hängt vom jeweiligen
Copilot-Erlebnis und der Agenten-Konfiguration ab. Vor einem produktiven Rollout die Verbindung
mit einem Testagenten in Copilot Studio verifizieren.
Alternativ lässt sich der Server auch als benutzerdefinierter Connector über eine
OpenAPI-Beschreibung in Power Apps einbinden (x-ms-agentic-protocol: mcp-streamable-1.0) — das
ist der Weg, wenn mehr Kontrolle über die Connector-Konfiguration nötig ist als der Wizard bietet.
Details dazu: Microsoft-Dokumentation zu MCP in Copilot Studio.