AI Engineering Academy · Lektion

Ihren ersten MCP-Server entwickeln

Verwenden Sie das Python MCP SDK, um einen Server zu erstellen, der Ressourcen, Tools und Prompts bereitstellt, und verbinden Sie ihn anschließend mit Claude Desktop, um ihn durchgängig in Aktion zu sehen.

Lektion 2 von 413 Schritte

Ihren ersten MCP-Server entwickeln ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Projekt einrichten für einen MCP-Server

Für die Entwicklung eines MCP-Servers in Python benötigen Sie das mcp-SDK und eine Python-Umgebung. Sie erstellen einen Server, mit dem sich Claude Desktop oder jeder andere MCP-Client über stdio verbinden kann. Installieren Sie zunächst das Paket und erstellen Sie Ihre Serverdatei.

# Create a project directory
# mkdir my_mcp_server && cd my_mcp_server

# Create a virtual environment
# python -m venv venv && source venv/bin/activate

# Install the MCP SDK
# pip install mcp httpx

# Project structure:
# my_mcp_server/
#   server.py          <- Your MCP server
#   requirements.txt
#   README.md

Serverobjekt erstellen

Importieren Sie das Paket mcp und erstellen Sie eine Server-Instanz mit dem Namen Ihres Servers. Dieser Name wird den Clients in ihrer MCP-Serverliste angezeigt – wählen Sie daher eine aussagekräftige Bezeichnung. Das Serverobjekt ist der Einstiegspunkt für die Registrierung all Ihrer Tools, Ressourcen und Prompts.

# server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import asyncio
import httpx

# Create the server — name is shown in Claude Desktop
app = Server('weather-server')

# --- Tool registrations go here ---

# Entry point
if __name__ == '__main__':
    asyncio.run(stdio_server(app))

Tools mit @app.list_tools() registrieren

Der Decorator @app.list_tools() registriert einen Handler, der die Liste der verfügbaren Tools zurückgibt, wenn der Client danach fragt. Jedes Tool wird mit einem Namen, einer Beschreibung und einem inputSchema definiert – dem JSON Schema, das seine Parameter beschreibt. Der Client sendet diese Liste an das LLM, damit es weiß, welche Tools es aufrufen kann.

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name='get_weather',
            description='Get current weather for a city. Use when the user asks about weather in a specific location.',
            inputSchema={
                'type': 'object',
                'properties': {
                    'city': {
                        'type': 'string',
                        'description': 'City name, e.g. London or New York'
                    },
                    'units': {
                        'type': 'string',
                        'enum': ['metric', 'imperial'],
                        'description': 'Temperature units. Default is metric.'
                    }
                },
                'required': ['city']
            }
        ),
        types.Tool(
            name='list_cities',
            description='Return a list of major cities the user can query weather for.',
            inputSchema={'type': 'object', 'properties': {}, 'required': []}
        )
    ]

Tool-Ausführung implementieren

Der Decorator @app.call_tool() übernimmt die Ausführung von Tools. Wenn der Client ein Tool aufruft, empfängt dieser Handler den Toolnamen und die Argumente. Führen Sie die entsprechende Logik aus und geben Sie eine Liste von TextContent-Objekten zurück, die den Ergebnistext enthalten.

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == 'list_cities':
        cities = ['London', 'New York', 'Tokyo', 'Paris', 'Sydney']
        return [types.TextContent(type='text', text=', '.join(cities))]

    if name == 'get_weather':
        city = arguments['city']
        units = arguments.get('units', 'metric')
        unit_symbol = 'C' if units == 'metric' else 'F'

        # Call real weather API (stub here)
        async with httpx.AsyncClient() as client:
            # Replace with actual API call
            result = f'{city}: 18{chr(176)}{unit_symbol}, partly cloudy, humidity 65%'

        return [types.TextContent(type='text', text=result)]

    raise ValueError(f'Unknown tool: {name}')

Ressourcen bereitstellen

Ressourcen sind statische oder dynamische Daten, die das Modell lesen kann – stellen Sie sie sich wie Dateien vor. Definieren Sie Ressourcen-URIs und implementieren Sie einen Ressourcenleser. Ressourcen werden dem Client als Elemente angezeigt, auf die die KI verweisen kann. Das ist beispielsweise für Konfigurationen, Dokumentation oder häufig abgerufene Daten-Snapshots nützlich.

@app.list_resources()
async def list_resources() -> list[types.Resource]:
    return [
        types.Resource(
            uri='weather://supported-cities',
            name='Supported Cities List',
            description='Complete list of cities available in this weather server.',
            mimeType='text/plain'
        )
    ]

@app.read_resource()
async def read_resource(uri: str) -> str:
    if uri == 'weather://supported-cities':
        cities = ['London', 'New York', 'Tokyo', 'Paris', 'Sydney', 'Dubai', 'Singapore']
        return '\n'.join(cities)
    raise ValueError(f'Unknown resource URI: {uri}')

Prompt-Vorlagen registrieren

Prompts sind wiederverwendbare Nachrichtenvorlagen, die Clients den Benutzern als Slash-Befehle oder Schnellaktionen anbieten. Sie akzeptieren Parameter und geben eine Liste von Nachrichten zurück, die zum anfänglichen Kontext einer Unterhaltung werden. Prompts eignen sich hervorragend, um komplexe Anweisungen zu hinterlegen, die Benutzer mit einem einzigen Befehl auslösen.

@app.list_prompts()
async def list_prompts() -> list[types.Prompt]:
    return [
        types.Prompt(
            name='weather-report',
            description='Generate a formatted weather report for a city.',
            arguments=[
                types.PromptArgument(name='city', description='City name', required=True)
            ]
        )
    ]

@app.get_prompt()
async def get_prompt(name: str, arguments: dict) -> types.GetPromptResult:
    if name == 'weather-report':
        city = arguments.get('city', 'London')
        return types.GetPromptResult(
            description=f'Weather report for {city}',
            messages=[
                types.PromptMessage(
                    role='user',
                    content=types.TextContent(
                        type='text',
                        text=f'Use the get_weather tool to look up {city} and give me a detailed weather report including what clothing I should wear.'
                    )
                )
            ]
        )
    raise ValueError(f'Unknown prompt: {name}')

Mit Claude Desktop verbinden

Um Ihren MCP-Server mit Claude Desktop zu verwenden, fügen Sie ihn der Claude-Desktop-Konfigurationsdatei hinzu. Unter macOS befindet sie sich unter ~/Library/Application Support/Claude/claude_desktop_config.json. Geben Sie den Befehl zum Starten Ihres Servers sowie alle benötigten Umgebungsvariablen an.

# ~/Library/Application Support/Claude/claude_desktop_config.json
# Add this JSON configuration:

# {
#   "mcpServers": {
#     "weather-server": {
#       "command": "/path/to/venv/bin/python",
#       "args": ["/path/to/my_mcp_server/server.py"],
#       "env": {
#         "WEATHER_API_KEY": "your_api_key_here"
#       }
#     }
#   }
# }

# After saving, restart Claude Desktop.
# Your server's tools will appear in Claude's tool list.

Server mit der MCP-CLI testen

Testen Sie Ihren Server mit dem MCP-Inspector oder CLI-Tools, bevor Sie ihn mit Claude Desktop verbinden. Der Befehl mcp dev startet Ihren Server und öffnet einen browserbasierten Inspector. Dort können Sie Tools manuell aufrufen und die unverarbeiteten Protokollnachrichten anzeigen lassen, wodurch sich Probleme leicht debuggen lassen.

# Install the MCP development tools
# pip install 'mcp[cli]'

# Start the inspector with your server
# mcp dev server.py

# The inspector opens at http://localhost:5173
# You can:
# - See all registered tools and their schemas
# - Call tools with custom arguments
# - Browse available resources
# - Test prompt templates
# - View the full JSON-RPC message exchange

Fehlerbehandlung in MCP-Servern

MCP-Server dürfen bei ungültigen Eingaben niemals abstürzen. Umschließen Sie jede Tool-Ausführung mit try/except und geben Sie Fehlermeldungen als TextContent zurück, statt Exceptions auszulösen. Bei fatalen Fehlern (z. B. Konfigurationsproblemen oder fehlenden API-Schlüsseln) protokollieren Sie diese beim Start und lösen Sie sie aus, bevor der Server in seine Hauptschleife eintritt.

@app.call_tool()
async def call_tool_safe(name: str, arguments: dict) -> list[types.TextContent]:
    try:
        if name == 'get_weather':
            city = arguments.get('city')
            if not city:
                return [types.TextContent(type='text', text='Error: city argument is required.')]
            result = await fetch_weather(city, arguments.get('units', 'metric'))
            return [types.TextContent(type='text', text=result)]
        raise ValueError(f'Unknown tool: {name}')
    except httpx.TimeoutException:
        return [types.TextContent(type='text', text='Error: Weather API timed out. Try again.')]
    except Exception as e:
        return [types.TextContent(type='text', text=f'Error: {str(e)}')]

Logging für MCP-Server

Da MCP-Server über stdio mit dem Client kommunizieren, würden print-Anweisungen das Protokoll stören. Verwenden Sie für das Logging immer stderr – dieser Stream ist getrennt und beeinträchtigt den Austausch von MCP-Nachrichten nicht. Konfigurieren Sie das Python-Logging-Modul so, dass es nach stderr schreibt.

import logging
import sys

# Configure logging to stderr (NOT stdout — that's the MCP channel)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    stream=sys.stderr
)
logger = logging.getLogger('weather-server')

# In your tool handler:
# logger.info(f'Getting weather for {city}')
# logger.error(f'API call failed: {e}')

# Claude Desktop captures stderr to a log file:
# ~/Library/Logs/Claude/mcp-server-weather-server.log

MCP-Server paketieren

Geben Sie Ihren MCP-Server weiter, indem Sie ihn mit einer pyproject.toml paketieren und auf PyPI veröffentlichen oder ihn für Teams als Docker-Container verteilen. Verwenden Sie für alle Geheimnisse – API-Schlüssel und Datenbank-URLs – Umgebungsvariablen, damit die Serverkonfiguration vom Code getrennt bleibt. Dokumentieren Sie die erforderlichen Umgebungsvariablen und eine Beispielkonfiguration in einer übersichtlichen README.

Kurzer Test

Testen Sie Ihr Verständnis davon, wie man einen MCP-Server in Python entwickelt.

Zusammenfassung der Lektion

In dieser Lektion haben Sie gelernt: MCP-Server stellen Tools über die Decoratoren @app.list_tools() und @app.call_tool() bereit, Ressourcen und Prompts erweitern den Server um lesbare Daten und wiederverwendbare Vorlagen und das Logging muss stderr verwenden, damit der stdio-Kanal des MCP-Protokolls nicht beschädigt wird. Als Nächstes verbinden wir einen MCP-Server mit einer Datenbank und stellen dynamische Ressourcen mit Seitennummerierung bereit.

Kostenlos starten

Lerne Python mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
30
Lektionen
120

Häufig gestellte Fragen

Ist die Lektion „Ihren ersten MCP-Server entwickeln“ kostenlos?

Ja — der vollständige Text von „Ihren ersten MCP-Server entwickeln“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Ihren ersten MCP-Server entwickeln“?

Verwenden Sie das Python MCP SDK, um einen Server zu erstellen, der Ressourcen, Tools und Prompts bereitstellt, und verbinden Sie ihn anschließend mit Claude Desktop, um ihn durchgängig in Aktion zu… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Engineering Academy zu starten?

Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Ihren ersten MCP-Server entwickeln“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?

Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Was ist MCP und warum ist es wichtig?
  2. Ihren ersten MCP-Server entwickeln
  3. Datenbankressourcen über MCP bereitstellen
  4. Sicherheit und Authentifizierung in MCP
← Zurück zu AI Engineering Academy