---
title: "Model Context Protocol trifft auf OpenAPI"
description: "Lerne erste Details zum MCP und wie es mit OpenAPI Schnittstellen funktioniert."
canonical_url: "https://www.blueshoe.de/blog/model-context-protocol-mit-openapi/"
---

Künstliche Intelligenz (KI) - insbesondere Large-Language Models (LLMs) - sind in aller Munde. Nun sollen diese nicht nur generativ
Text, Bilder, Video und Audio erzeugen, sondern auch die Software bedienen, mit der wir als Menschen arbeiten. Um
Effizienzen zu heben und Mensch-Maschine Schnittstellen natürlicher zu gestalten. In diesem Blogpost bieten wir einen
simplen Einstieg in das Model Context Protocol (MCP) und zeigen unsere ersten Erfahrungen, welche wir mit diesem gemacht
haben. Außerdem schauen wir uns die Anbindung von APIs via dem OpenAPI Standard durch das MCP an LLMs an.

![MCP meets OpenAPI - ein Erfahrungsbericht](/img/blogs/llm-openapi.png)

## Model Context Protocol

Das Model Context Protocol (MCP) ist eine Definition zur Bereitstellung von Kontext aus Anwendungen für LLMs. Vereinfacht  gesagt beinhaltet das Protokoll Informationen, wie ein LLM eine Software (oftmals Schnittstellen) bedienen kann.

Dabei liegt es nahe, dass zur Definition eines MCP einer Anwendung bereits auf bestehende Strukturen, wie der OpenAPI  Standard zurückgegriffen wird. Bevor wir MCP und OpenAPI jedoch zusammenbringen schauen wir als erstes auf ein paar  Details des MCP.

### Kommunikationsmodell des MCP

Die Kommunikation im Rahmen des MCP läuft als Client-Server Kommunikation ab. Der Client ist in diesem Fall das LLM,  der Server ist eine Abstraktionsschicht der Anwendung, die bedient werden soll. Diese Schicht gibt an, wie der Client die dahinterliegende Anwendung bedienen kann.

![Genereller Aufbau der MCP Architektur](/img/blogs/mcp_fastapi/architecture.png)

Dabei kann die dahinterliegende Anwendung alles mögliche sein - eine Datenbank / Datenquelle, eine komplexe Anwendung, oder eine Schnittstelle. Als MCP Host wird hierbei das Programm bezeichnet, welches den MCP Client ausführt (z.B. Claude Desktop, ChatGPT).

![Kommunikationsablauf des MCP](/img/blogs/mcp_fastapi/communication.png)

**Wichtig** - die Grafik zeigt eine bidirektionale Kommunikation zwischen Client und Server. Das bedeutet, dass unser MCP Server aus dem Internet erreichbar sein muss. Lokal laufende MCP Server benötigen ein entsprechendes Setup, welche sie für die zumeist im Internet laufenden MCP Clients verfügbar macht (z.B. Claude Desktop oder Ngrok).

### Resourcen und Tools im MCP

Ich möchte nicht zu tief in die Begrifflichkeiten des MCP einsteigen - alle Details können in der [offiziellen Dokumentation](https://modelcontextprotocol.io/) gelesen werden. Wichtig für den Kontext des Blogposts sind vor allem
**Resources** und **Tools**.

[Resources](https://modelcontextprotocol.io/docs/concepts/resources) sind vereinfacht gesprochen Datenquellen. Sie beschreiben wie der Client (das LLM) Daten von dem Server abrufen kann. Alle Formen von Daten sind denkbar: Text,
Binärdaten, Bilder, Ton, Videos, strukturiert oder unstrukturiert. Für den Zugriff auf konkrete Resourcen werden i.d.R. *Resource Templates* verwendet. Diese erlauben dann Zugriff auf bestimmte Resourcen - beispielsweise "Gib mir die Bestellung mit der Nummer *X341*.".

[Tools](https://modelcontextprotocol.io/docs/concepts/tools) erlauben die Ausführung von Aktionen. Hierdurch wird den LLMs die Möglichkeit gegeben Aktionen mit laufenden Diensten durchzuführen. Das Anlegen oder Manipulieren eines Datensatzes, die Berechnung einer Aufgabe, das Auslösen einer Bestellung oder die Manipulation eines Bildes. Alles ist denkbar.

### Verknüpfung eines LLM und einer Anwendung via MCP

Mit der Beschreibung von Resourcen und Tools verspricht das MCP nun, dass LLM in sinnvoller Art und Weise Anwendungen bedienen können. Sie heben Effizienzen und schaffen defacto eine neue Schnittstelle sowohl in der Maschine-Maschine als auch Mensch-Maschine Kommunikation. Schaut man in die Details zur Beschreibung Resourcen und Tools fällt auf, dass viele Informationen, welche für das MCP gebraucht werden, bereits in bestehenden Standard wie OpenAPI vorhanden sind. Die Beschreibung der Strukturen ist in beiden Fällen JSON basiert. Natürlich unterscheidet sich der Aufbau - hier kommt fastmcp ins Spiel.

Im Folgenden Teil haben wir das Python Paket [fastmcp](https://gofastmcp.com/getting-started/welcome) erkundet und Teilen unsere Erkenntnisse.

## fastmcp - Das Pythonic MCP Paket

`fastmcp` ist eine Framework zur Implementierung des MCP Protokoll, geschrieben in Python. Version 1 des Paketes wurde in das offizielle Python SDK aufgenommen. Die, zum Zeitpunkt des Blogposts, aktuelle Version 2 konzentriert sich nun hauptsächlich auf gute Handhabbarkeit und einem möglichst kompletten Feature-Set.

Beim durchschauen der Dokumentation fällt direkt auf, dass es eine dedizierte Seite für die Integration von [OpenAPI](https://gofastmcp.com/servers/openapi) gibt. Das initiale Beispiel erscheint denkbar einfach:

```python
import httpx
from fastmcp import FastMCP

# Create an HTTP client for your API
client = httpx.AsyncClient(base_url="https://blueshoe.youtrack.cloud/api/", headers={
    "Authorization": "###############",
    "Accept": "application/json",
})

# Load your OpenAPI spec
openapi_spec = httpx.get("https://blueshoe.youtrack.cloud/api/openapi.json").json()

# Create the MCP server
mcp = FastMCP.from_openapi(
    openapi_spec=openapi_spec,
    client=client,
    name="blueshoe-youtrack",
)

if __name__ == "__main__":
    mcp.run()
```

Der Server bekommt eine URL mit dem OpenAPI JSON und eine Client Objekt zur Bedienung der API.

**Meine Idee:** ich möchte unser Ticket-System YouTrack, welches wir für das Projektmanagement bei Blueshoe einsetzen via LLM bedienbar machen. Los geht's.

Das funktioniert problemlos - nun wie können LLMs mit meinem Server kommunizieren? Die Dokumentation gibt hier 2 Möglichkeiten - Claude Desktop oder Ngrok. Wo liegen die Unterschiede?

### MCP Lokal oder Remote?

`fastmcp` erlaubt es den geschriebenen Server einfach in das lokal installierte Programm Claude Desktop zu installieren. Die Kommunikation läuft dann per Stdio. Alternativ kann der Server an einen Port gebunden werden und die Kommunikation läuft dann per SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)). Bei der Alternative kommt [Ngrok](https://ngrok.com/) ins Spiel. Ngrok bietet einfache Möglichkeiten lokale Programme ins Internet zu exponieren. Meine ersten Versuche startete ich mit Claude Desktop.

## MCP via Claude Desktop

`fastmcp` kommt mit einem Kommando zum Installieren des MCP Servers in Claude Desktop. Hierbei befolgenden wie hauptsächlich die [Dokumentation](https://gofastmcp.com/integrations/claude-desktop) zur Anbindung an Claude Desktop. Also los:

```shell
fastmcp install server.py
```

Beim Start von Claude Desktop erschien dann folgende Meldung:

![Claude Desktop Error](/img/blogs/mcp_fastapi/claude_1.png)

Erm, okay? Was ist das Problem? Ich starte den Server manuell. Funktioniert. Nach kurzer Untersuchung stelle ich fest: Das Installationskommando von fastmcp ist nicht sonderlich smart:

![Claude Desktop fastmcp Installation](/img/blogs/mcp_fastapi/claude_2.png)

Leider wird durch das Installationskommando nicht der richtige Python-Interpreter ausgewählt. Dies führt dazu, dass das Skript nicht ausgeführt werden kann.

Hinweis: Ich habe hier ein kleines Stück des Pfades ausgeschnitten.

Okay, dies lässt sich einfach beheben. Im Verzeichnis meines Projektes führe ich folgendes Kommando aus:

```shell
which python3
```

Diesen Interpreter hinterlege ich dann anstelle von [uv](https://github.com/astral-sh/uv) in den Konfigurationsdatei von Claude Desktop. Als Parameter wird dann nur der Pfad zur `server.py` eingetragen.

Problem gelöst! Claude Desktop startet ohne Probleme. Ich stelle eine Frage - welches Tickets wurden heute bearbeitet?

![Claude Desktop fastmcp Installation](/img/blogs/mcp_fastapi/claude_3.png)

Ahja. Mist! Es stellt sich heraus, dass so eine, doch recht umfangreiche, OpenAPI Spezifikation direkt mal die "Längenlimits" sprengt. Umfangreich deutet ja erstmal auf eine recht gute Beschreibung hin. Ich halte viel von Jetbrains und ihren Produkten, entsprechend war meine Hoffnung hier, dass der Input des YouTrack OpenAPI sich hervorragend für mein Experiment eignet.

Ich habe noch weitere Modelle getestet, inkl. bezahlter Varianten. Leider laufe ich häufig in Limitierung von Token oder auch Ratelimits. Mein persönlicher Eindruck an dieser Stelle war von Ohnmacht geprägt. Alles easy zusammengesteckt, aber wie kann ich den Problemen auf den Grund gehen? Debugging habe ich dann in meiner Server-Skript via `print` gemacht, keine besonders nette Erfahrung.

## MCP via Client Skript & Ngrok

Okay, Schluss mit den UIs - dann skripten wir unseren Client eben.

```python
import anthropic
from rich import print

# Your server URL (replace with your actual URL)
url = 'https:/#####################.ngrok-free.app'

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-3-5-haiku-20241022",
    max_tokens=1000,
    messages=[{"role": "user", "content": "What issues have been edited on Blueshoe YouTrack today?"}],
    mcp_servers=[
        {
            "type": "url",
            "url": f"{url}/sse",
            "name": "youtrack",
        }
    ],
    extra_headers={
        "anthropic-beta": "mcp-client-2025-04-04"
    }
)

print(response.content)
```

Mit ngrok machen wir unseren Server ins Internet verfügbar:

```shell
ngrok http 8000
```

Das Client Skript bekommt die entsprechende Adresse und unsere Nachricht. Was wurde denn heute so in unserem YouTrack bearbeitet?

Ein paar interessante Ausgaben finden sich im Log:

```python
BetaMCPToolUseBlock(
      id='mcptoolu_01JqQroumE3gHkVnYFZzRc7C',
      input={'query': 'updated: today'},
      name='POST_searchassist',
      server_name='youtrack',
      type='mcp_tool_use'
  )
```

Ohlala - eine Query `updated: today` - das sieht doch gut aus, oder?

Leider nicht - die schlussendliche Antwort sieht ungefähr so aus:

> I apologize for the persistent errors. It seems there might be an issue with the YouTrack API tools at the moment.
> Without being able to directly query the system, I can provide some general advice: To find issues edited today in
> YouTrack, you would typically use a search query like "updated: today" in the YouTrack interface.

Benutz einfach das YouTrack UI! Leider kam das LLM auf keinen grünen Zweig bei der Benutzung der YouTrack API. Nachdem ich anfangs in Authentifizierungsprobleme gelaufen bin, welche ich alle beheben konnte, hatte das LLM eigentlich freie Bahn. Leider war es nicht im Stande eine gescheite API Abfrage zu formulieren. Auch vermeintlich simple Abfragen wie - `Wieviele Tickets wurden heute bearbeitet?` (wir wollen also "nur" eine Zahl) - haben nicht funktioniert.

## Fazit zu MCP mit OpenAPI

Das Model Context Protocol ist eine gute Systematisierung zur Kommunikation von LLMs mit Bestandssystemen. Es bedeutet allerdings nicht, dass die Anbindung von Datenbanken oder Awendungen mit einem Fingerschnipsen erledigt sind. Selbst Schnittstellen mit hervorragenden OpenAPI Schemas können nicht ohne Weiteres integriert werden - es braucht hier entsprechendes Finetuning, sodass ein LLM gute Ergebnisse liefern kann.

[Best Practices](https://modelcontextprotocol.io/docs/concepts/tools#best-practices) zur Erstellung von MCP Strukturen sind bereits vorhanden. Ein OpenAPI Schema kann die Grundlage für eine Integration bilden - allerdings ersetzt diese nicht die Implementierung.

Das Thema MCP ist **nicht** Plug'n Play. Es braucht auch hier gutes Engineering und klare Ziele, welche mit einer Integration verfolgt werden. Ich werde das Thema jedoch weiter verfolgen, vermutlich auch in einem weiteren Blogpost.

Eine Frage, welche ich mir als Autor von Software-Projekten stelle - wie testet man diese Integrationen eigentlich zuverlässig? Die Dokumentation von fastmcp erscheint mir im Bereich [Testing](https://gofastmcp.com/patterns/testing) etwas kurz. Wenn ihr da etwas wisst oder kennt, teilt das gerne in den Kommentaren.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
