IntermediateMCPTool IntegrationPython

MCP: Model Context Protocol Guide

MCP er en aaben standard for at forbinde LLM'er med externe data og tools. Taenk pa det som USB-C for AI - en universel connector.

18. marts 2026|15 min read
Netvaerksvisualisering - 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.py
1from mcp.server.fastmcp import FastMCP
2
3mcp = FastMCP("my-tools")
4
5@mcp.tool()
6def add(a: int, b: int) -> int:
7 """Laeg to tal sammen."""
8 return a + b
9
10mcp.run() # Start MCP server

Prerequisites

terminal
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)
  • • Grundlaeggende kendskab til Claude API og tool use

Hvad er MCP?

Model Context Protocol (MCP) er en aaben standard udviklet af Anthropic. Den loser et fundamentalt problem: hvordan forbinder man LLM'er med eksterne systemer pa en standardiseret maade?

Foer 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 laese (filer, database rows, API responses)
  • Prompts - Predefinerede prompt-templates brugere kan aktivere

Byg din foerste MCP Server

Lad os bygge en MCP server der eksponerer et par nyttige tools. FastMCP er den anbefalede maade at bygge servere pa i Python:

weather_server.py
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, tilfoej den til konfigurationsfilen:

claude_desktop_config.json
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 tilgaengelige. Claude kan automatisk se og bruge dem naar det er relevant.

Resources: Eksponere Data

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

data_server.py
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 """Soeg efter kunder i databasen.
42
43 Args:
44 query: Soegeord (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 velunderstaettet. Her er det samme weather-eksempel:

weather_server.ts
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.py
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 paa:
161. Bugs og logiske fejl
172. Sikkerhedsproblemer
183. Performance issues
194. Kode-kvalitet og laebarhed
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 forsoeget
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 koerer du flere MCP servere samtidig. Hver server haandterer et specifikt domaene:

claude_desktop_config.json
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 faerdige 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 pa MCP Servers repository.

Common Pitfalls

  • For brede tools - Definer specifikke tools frem for generelle. Claude vaelger bedre med klare graenser.
  • Manglende beskrivelser - Tool descriptions er kritiske. LLM'en bruger dem til at forstaa hvornaar og hvordan.
  • Ingen error handling - Returner meningsfulde fejlbeskeder, ikke stack traces.
  • Sikkerhed - MCP servere koerer lokalt men har adgang til dine systemer. Validerer altid input.
  • Timeout - Saet timeouts pa eksterne kald. En haengende MCP server blokerer hele klienten.

Naeste skridt

MCP er stadig nyt, men det vokser hurtigt. Start med at bygge en simpel server til et af dine egne systemer. For at forstaa det underliggende tool use pattern, laes 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.