IntermediateMCPTool IntegrationPython

MCP: Model Context Protocol Guide

MCP er en åben standard for at forbinde LLM'er med externe data og tools. Tænk på det som USB-C for AI - en universel connector.

18. marts 202615 min læsetid
Netværksvisualisering - Model Context Protocol forbinder LLMs med tools og data
Foto: Google DeepMind / Unsplash

TL;DR

MCP lader dig eksponere tools og data som en server, som enhver MCP-compatible klient (Claude Desktop, Claude Code, IDEs) kan bruge. Du bygger serveren, klienten opdager automatisk dine capabilities.

mcp_minimal.pypython
1from mcp.server.fastmcp import FastMCP
2
3mcp = FastMCP("my-tools")
4
5@mcp.tool()
6def add(a: int, b: int) -> int:
7 """Læg to tal sammen."""
8 return a + b
9
10mcp.run() # Start MCP server

Prerequisites

terminalbash
1pip install mcp # Python SDK
2# eller
3npm install @modelcontextprotocol/sdk # TypeScript SDK
  • • Python 3.11+ eller Node.js 18+
  • • Claude Desktop eller Claude Code (som MCP klient)
  • • Grundlæggende kendskab til Claude API og tool use

Hvad er MCP?

Model Context Protocol (MCP) er en åben standard udviklet af Anthropic. Den løser et fundamentalt problem: hvordan forbinder man LLM'er med eksterne systemer på en standardiseret måde?

Før MCP skulle hver AI-applikation bygge sine egne integrations. Med MCP bygger du en server een gang, og den virker med alle MCP-compatible klienter.

MCP Arkitekturen

Host (Claude Desktop / IDE)
    |
    v
MCP Client  <--->  MCP Server  <--->  External Systems
    |                   |
    |              Tools, Resources,
    |              Prompts
    v
  LLM (Claude)

MCP har tre kernekoncepter:

  • Tools - Funktioner LLM'en kan kalde (database queries, API kald, beregninger)
  • Resources - Data LLM'en kan læse (filer, database rows, API responses)
  • Prompts - Predefinerede prompt-templates brugere kan aktivere

Byg din første MCP Server

Lad os bygge en MCP server der eksponerer et par nyttige tools. FastMCP er den anbefalede måde at bygge servere på i Python:

weather_server.pypython
1from mcp.server.fastmcp import FastMCP
2import httpx
3from datetime import datetime
4
5mcp = FastMCP("weather-tools")
6
7@mcp.tool()
8def get_weather(city: str) -> str:
9 """Hent aktuel vejrudsigt for en by.
10
11 Args:
12 city: Byens navn, f.eks. 'Copenhagen'
13 """
14 # Using Open-Meteo (free, no API key needed)
15 geo = httpx.get(
16 "https://geocoding-api.open-meteo.com/v1/search",
17 params={"name": city, "count": 1}
18 ).json()
19
20 if not geo.get("results"):
21 return f"Kunne ikke finde byen: {city}"
22
23 lat = geo["results"][0]["latitude"]
24 lon = geo["results"][0]["longitude"]
25
26 weather = httpx.get(
27 "https://api.open-meteo.com/v1/forecast",
28 params={
29 "latitude": lat,
30 "longitude": lon,
31 "current": "temperature_2m,wind_speed_10m,weather_code"
32 }
33 ).json()
34
35 current = weather["current"]
36 return (
37 f"Vejr i {city}: "
38 f"{current['temperature_2m']}C, "
39 f"vind {current['wind_speed_10m']} km/t"
40 )
41
42@mcp.tool()
43def get_time(timezone: str = "Europe/Copenhagen") -> str:
44 """Hent aktuel tid i en given tidszone.
45
46 Args:
47 timezone: IANA timezone, f.eks. 'Europe/Copenhagen'
48 """
49 from zoneinfo import ZoneInfo
50 now = datetime.now(ZoneInfo(timezone))
51 return now.strftime("%Y-%m-%d %H:%M:%S %Z")
52
53if __name__ == "__main__":
54 mcp.run()

Connect til Claude Desktop

For at bruge din MCP server med Claude Desktop, tilføj den til konfigurationsfilen:

claude_desktop_config.jsonjson
1{
2 "mcpServers": {
3 "weather": {
4 "command": "python",
5 "args": ["/path/to/weather_server.py"]
6 }
7 }
8}

Konfigurationsfilen ligger:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%/Claude/claude_desktop_config.json

Genstart Claude Desktop, og dine tools er nu tilgængelige. Claude kan automatisk se og bruge dem når det er relevant.

Resources: Eksponere Data

Resources giver LLM'en læse-adgang til data. De opdages automatisk af klienten:

data_server.pypython
1from mcp.server.fastmcp import FastMCP
2import sqlite3
3
4mcp = FastMCP("data-server")
5
6# Static resource
7@mcp.resource("config://app")
8def get_config() -> str:
9 """Returner applikationens konfiguration."""
10 return """
11 App: MyApp v2.1
12 Environment: production
13 Database: PostgreSQL 16
14 Cache: Redis 7
15 """
16
17# Dynamic resource with URI template
18@mcp.resource("db://customers/{customer_id}")
19def get_customer(customer_id: str) -> str:
20 """Hent kundedata fra database.
21
22 Args:
23 customer_id: Unikt kunde-ID
24 """
25 conn = sqlite3.connect("customers.db")
26 cursor = conn.execute(
27 "SELECT name, email, plan FROM customers WHERE id = ?",
28 (customer_id,)
29 )
30 row = cursor.fetchone()
31 conn.close()
32
33 if not row:
34 return f"Kunde {customer_id} ikke fundet"
35
36 return f"Navn: {row[0]}\nEmail: {row[1]}\nPlan: {row[2]}"
37
38# Tool that works with resources
39@mcp.tool()
40def search_customers(query: str) -> str:
41 """Søg efter kunder i databasen.
42
43 Args:
44 query: Søgeord (navn eller email)
45 """
46 conn = sqlite3.connect("customers.db")
47 cursor = conn.execute(
48 "SELECT id, name, email FROM customers WHERE name LIKE ? OR email LIKE ? LIMIT 10",
49 (f"%{query}%", f"%{query}%")
50 )
51 results = cursor.fetchall()
52 conn.close()
53
54 if not results:
55 return "Ingen kunder fundet"
56
57 return "\n".join(
58 f"ID: {r[0]}, Navn: {r[1]}, Email: {r[2]}"
59 for r in results
60 )

MCP Server i TypeScript

TypeScript SDK'et er ligeledes velunderstøttet. Her er det samme weather-eksempel:

weather_server.tstypescript
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
4const server = new McpServer({
5 name: "weather-tools",
6 version: "1.0.0",
7});
8
9server.tool(
10 "get_weather",
11 "Hent aktuel vejrudsigt for en by",
12 { city: { type: "string", description: "Byens navn" } },
13 async ({ city }) => {
14 const geoRes = await fetch(
15 `https://geocoding-api.open-meteo.com/v1/search?name=${city}&count=1`
16 );
17 const geo = await geoRes.json();
18
19 if (!geo.results?.length) {
20 return { content: [{ type: "text", text: `By ikke fundet: ${city}` }] };
21 }
22
23 const { latitude, longitude } = geo.results[0];
24 const weatherRes = await fetch(
25 `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,wind_speed_10m`
26 );
27 const weather = await weatherRes.json();
28 const { temperature_2m, wind_speed_10m } = weather.current;
29
30 return {
31 content: [{
32 type: "text",
33 text: `Vejr i ${city}: ${temperature_2m}C, vind ${wind_speed_10m} km/t`
34 }]
35 };
36 }
37);
38
39const transport = new StdioServerTransport();
40await server.connect(transport);

Prompts: Genanvendelige Templates

MCP prompts lader dig definere genanvendelige prompt-templates som brugere kan aktivere fra klienten:

prompts_server.pypython
1from mcp.server.fastmcp import FastMCP
2
3mcp = FastMCP("code-review-tools")
4
5@mcp.prompt()
6def review_code(code: str, language: str = "python") -> str:
7 """Generer en code review prompt.
8
9 Args:
10 code: Koden der skal reviewes
11 language: Programmeringssprog
12 """
13 return f"""Review denne {language} kode grundigt.
14
15Fokuser på:
161. Bugs og logiske fejl
172. Sikkerhedsproblemer
183. Performance issues
194. Kode-kvalitet og læsbarhed
205. Best practices for {language}
21
22Kode:
23```{language}
24{code}
25```
26
27Giv konkrete forbedringsforslag med kodeeksempler."""
28
29@mcp.prompt()
30def explain_error(error_message: str, context: str = "") -> str:
31 """Generer en prompt til at forklare en fejlbesked.
32
33 Args:
34 error_message: Den fulde fejlbesked
35 context: Ekstra kontekst om hvad der blev forsøget
36 """
37 prompt = f"Forklar denne fejl og hvordan den fikses:\n\n{error_message}"
38 if context:
39 prompt += f"\n\nKontekst: {context}"
40 return prompt

Avanceret: Composing MCP Servere

I praksis kører du flere MCP servere samtidig. Hver server håndterer et specifikt domæne:

claude_desktop_config.jsonjson
1{
2 "mcpServers": {
3 "weather": {
4 "command": "python",
5 "args": ["weather_server.py"]
6 },
7 "database": {
8 "command": "python",
9 "args": ["db_server.py"],
10 "env": {
11 "DATABASE_URL": "postgresql://localhost/mydb"
12 }
13 },
14 "github": {
15 "command": "npx",
16 "args": ["-y", "@modelcontextprotocol/server-github"],
17 "env": {
18 "GITHUB_TOKEN": "ghp_..."
19 }
20 },
21 "filesystem": {
22 "command": "npx",
23 "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
24 }
25 }
26}

MCP vs Direkte Tool Use

FeatureDirekte Tool UseMCP
SetupDefiner tools i API callSeparat server process
GenbrugPer applikationAlle MCP klienter
DiscoveryManuelAutomatisk
Best forSimple, app-specifikke toolsDelte tools, desktop apps
EcosystemDIY1000+ community servere

Community MCP Servere

Der er allerede et stort ecosystem af færdige MCP servere:

  • @modelcontextprotocol/server-github - GitHub repos, issues, PRs
  • @modelcontextprotocol/server-filesystem - Fil-operationer
  • @modelcontextprotocol/server-postgres - PostgreSQL queries
  • @modelcontextprotocol/server-slack - Slack beskeder og kanaler
  • @modelcontextprotocol/server-puppeteer - Browser automation

Find flere på MCP Servers repository.

Common Pitfalls

  • For brede tools - Definer specifikke tools frem for generelle. Claude vælger bedre med klare grænser.
  • Manglende beskrivelser - Tool descriptions er kritiske. LLM'en bruger dem til at forstå hvornår og hvordan.
  • Ingen error handling - Returner meningsfulde fejlbeskeder, ikke stack traces.
  • Sikkerhed - MCP servere kører lokalt men har adgang til dine systemer. Validerer altid input.
  • Timeout - Sæt timeouts på eksterne kald. En hængende MCP server blokerer hele klienten.

Næste skridt

MCP er stadig nyt, men det vokser hurtigt. Start med at bygge en simpel server til et af dine egne systemer. For at forstå det underliggende tool use pattern, læs vores AI Agent guide. Vil du bruge et framework i stedet, tjek LangChain guiden. Og for at give din MCP server adgang til custom data, kombiner med en RAG pipeline.