Sample Server
README.md
# MCP-demo med Python, FastMCP, Claude Desktop og Cursor
Dette repo viser et simpelt eksempel på en lokal MCP-server skrevet i Python med FastMCP.
Eksemplet udstiller tre MCP-tools:
```text
get_weather
calculate
convert_currency
```
Formålet er at vise, hvordan en AI-applikation som Claude Desktop eller Cursor kan bruge eksterne funktioner gennem MCP.
## Kort forklaring
MCP står for Model Context Protocol.
I dette eksempel er rollerne:
| Rolle | I dette eksempel |
|---|---|
| MCP host | Claude Desktop eller Cursor |
| MCP client | Den interne MCP-forbindelse i Claude/Cursor |
| MCP server | Python-programmet `server.py` |
| Tools | Funktionerne `get_weather`, `calculate` og `convert_currency` |
Claude Desktop og Cursor starter Python-programmet som en lokal MCP-server. Serveren kører via `stdio`, så den kommunikerer gennem standard input/output i stedet for HTTP.
## Hvorfor er eksemplet relevant?
Eksemplet viser, at MCP ikke bare handler om at kalde en funktion. Det handler om at standardisere forbindelsen mellem AI-applikationer og eksterne capabilities.
I stedet for at hver AI-app skal specialintegreres med hvert værktøj, kan værktøjer udstilles som MCP-servere.
Det giver en mere modulær arkitektur:
```text
AI-applikation
|
MCP client
|
MCP server
|
Lokale tools, filer, API'er eller databaser
```
## Projektstruktur
```text
MCP_Test/
├── server.py
├── pyproject.toml
├── uv.lock
└── .venv/
```
## Forudsætninger
Du skal have installeret:
```text
Python
uv
Claude Desktop og/eller Cursor
```
Tjek at `uv` virker:
```powershell
uv --version
```
Find eventuelt den fulde sti til `uv`:
```powershell
where.exe uv
```
Eksempel:
```text
C:\Users\mikc\.local\bin\uv.exe
```
## Opret projektet
Stå i projektmappen:
```powershell
cd C:\Users\mikc\IdeaProjects\MCP_Test
```
Hvis projektet ikke allerede har en `pyproject.toml`, så kør:
```powershell
uv init --bare
```
Installer FastMCP:
```powershell
uv add fastmcp
```
## server.py
Gem denne fil som:
```text
C:\Users\mikc\IdeaProjects\MCP_Test\server.py
```
```python
from fastmcp import FastMCP
# MCP-serveren er den del, der udstiller capabilities til en AI-applikation.
#
# I dette eksempel er rollerne:
# - Claude Desktop eller Cursor = MCP host
# - Deres interne forbindelse til denne proces = MCP client
# - Dette Python-program = MCP server
#
# Navnet "Sample Server" vises i hosten, så brug et navn der er let at genkende.
mcp = FastMCP("Sample Server")
# @mcp.tool() gør funktionen til en MCP capability af typen tool.
#
# Et tool er en handling eller funktion, som AI'en kan kalde.
#
# Discovery:
# Hosten kan opdage tool-navn, parametre og docstring.
# Derfor er tydelige funktionsnavne, simple parametre og gode docstrings vigtige.
@mcp.tool()
def get_weather(location: str) -> str:
"""Get the current weather for a specified location."""
# Demo-tool:
# Dette henter ikke rigtigt vejr fra et API.
#
# Det viser blot, hvordan et tool kan modtage input fra hosten
# og returnere et resultat tilbage til AI'ens kontekst.
return f"Weather in {location}: Sunny, 72°F"
# Et lille og afgrænset tool.
#
# Designpointen er:
# Lav hellere flere små tools end én stor funktion, der prøver at gøre alt.
@mcp.tool()
def calculate(expression: str) -> float | str:
"""Calculate the result of a mathematical expression."""
try:
# Kun til demo:
# eval() bør ikke bruges i rigtig produktion,
# fordi brugeren potentielt kan sende farlig kode.
#
# I undervisning er det dog et simpelt eksempel på:
# prompt -> tool call -> execution -> resultat tilbage til hosten.
return eval(expression)
except Exception as e:
# Fejlhåndtering er vigtig, fordi MCP-clienten skal kunne få
# et klart svar tilbage, hvis execution fejler.
return f"Error calculating expression: {str(e)}"
# Endnu et lille tool med tydelige parametre.
#
# AI'en kan se parameterlisten og bruge den til at kalde funktionen korrekt.
@mcp.tool()
def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
"""Convert amount from one currency to another."""
# Demo-data:
# I en rigtig MCP-server kunne dette være et kald til et eksternt API,
# en database eller et internt system.
#
# Det viser pointen om, at MCP-serveren kan skjule kompleksitet
# bag et simpelt tool-interface.
rates = {
"USD": 1.0,
"EUR": 0.85,
"GBP": 0.73,
"JPY": 110.0,
"INR": 83.0
}
if from_currency not in rates or to_currency not in rates:
return f"Unsupported currency pair: {from_currency} to {to_currency}"
converted = amount * (rates[to_currency] / rates[from_currency])
return f"{amount} {from_currency} = {converted:.2f} {to_currency}"
# MCP lifecycle:
#
# FastMCP håndterer:
# - initialization
# - discovery
# - execution
# - termination
#
# Når Claude Desktop eller Cursor starter serveren,
# kommunikerer de med denne proces via stdio.
#
# mcp.run() uden argumenter bruger stdio som standard.
# Det passer derfor til både Claude Desktop og Cursor.
if __name__ == "__main__":
mcp.run()
```
## Test serveren lokalt
Kør:
```powershell
cd C:\Users\mikc\IdeaProjects\MCP_Test
uv run server.py
```
Hvis terminalen bare står stille, er det normalt.
En `stdio`-MCP-server venter på, at en host, fx Claude Desktop eller Cursor, kommunikerer med den.
Stop serveren igen med:
```text
Ctrl + C
```
## Opsætning i Claude Desktop
Claude Desktop bruger filen:
```text
C:\Users\mikc\AppData\Roaming\Claude\claude_desktop_config.json
```
Du kan åbne mappen med:
```powershell
explorer $env:APPDATA\Claude
```
Hvis filen allerede findes, skal du ikke nødvendigvis slette indholdet. Du skal tilføje `mcpServers` på samme niveau som de andre hovedfelter.
Eksempel med fuld sti til `uv`:
```json
{
"mcpServers": {
"sample_mcp": {
"command": "C:\\Users\\mikc\\.local\\bin\\uv.exe",
"args": [
"--directory",
"C:\\Users\\mikc\\IdeaProjects\\MCP_Test",
"run",
"server.py"
]
}
}
}
```
Hvis din fil allerede indeholder andet indhold, fx `preferences`, kan den se sådan her ud:
```json
{
"preferences": {
"remoteToolsDeviceName": "z4020"
},
"coworkUserFilesPath": "C:\\Users\\mikc\\Claude",
"mcpServers": {
"sample_mcp": {
"command": "C:\\Users\\mikc\\.local\\bin\\uv.exe",
"args": [
"--directory",
"C:\\Users\\mikc\\IdeaProjects\\MCP_Test",
"run",
"server.py"
]
}
}
}
```
Vigtigt:
```text
mcpServers skal ikke ligge inde i preferences.
mcpServers skal ligge på øverste niveau i JSON-filen.
```
Efter ændringer:
```text
1. Gem filen
2. Luk Claude Desktop helt
3. Åbn Claude Desktop igen
```
## Test i Claude Desktop
Skriv fx:
```text
Brug get_weather med location Copenhagen
```
eller:
```text
Brug calculate til at regne 12 * 8 + 4
```
eller:
```text
Brug convert_currency til at konvertere 100 USD til EUR
```
Claude kan spørge om tilladelse til at bruge værktøjet. Godkend kaldet.
## Opsætning i Cursor
Cursor bruger typisk denne fil:
```text
C:\Users\mikc\.cursor\mcp.json
```
Du kan også finde opsætningen i Cursor under:
```text
Settings / Customize
Tools & MCPs
```
Brug denne `mcp.json`:
```json
{
"mcpServers": {
"sample_mcp": {
"type": "stdio",
"command": "C:\\Users\\mikc\\.local\\bin\\uv.exe",
"args": [
"--directory",
"C:\\Users\\mikc\\IdeaProjects\\MCP_Test",
"run",
"server.py"
]
}
}
}
```
Gem filen.
Gå derefter til:
```text
Settings / Customize
Tools & MCPs
Home MCP Servers
sample_mcp
```
Du bør kunne se disse tools:
```text
get_weather
calculate
convert_currency
```
## Test i Cursor
Åbn Cursor-chatten.
Brug ikke kun ren Ask-mode, hvis Cursor ikke vil kalde tools. Vælg i stedet en agent-/composer-tilstand, eller tilføj MCP-serveren via:
```text
+
MCP Servers
sample_mcp
```
Test med:
```text
Brug MCP-tool get_weather med location Copenhagen
```
eller:
```text
Kald sample_mcp calculate med expression "12 * 8 + 4"
```
eller:
```text
Kald sample_mcp convert_currency med amount 100, from_currency USD og to_currency EUR
```
## Typiske fejl og løsninger
### Fejl: uv findes ikke
Hvis Claude eller Cursor ikke kan finde `uv`, så find den fulde sti:
```powershell
where.exe uv
```
Eksempel:
```text
C:\Users\mikc\.local\bin\uv.exe
```
Brug derefter den fulde sti i configen:
```json
"command": "C:\\Users\\mikc\\.local\\bin\\uv.exe"
```
### Fejl: pyproject.toml mangler
Hvis du får:
```text
No pyproject.toml found
```
så opret projektfilen:
```powershell
uv init --bare
```
og installer FastMCP:
```powershell
uv add fastmcp
```
### Fejl: adgang nægtet til .venv
Hvis du får en fejl om adgang til `.venv`, så kan miljøet være låst af en terminal eller IDE.
Prøv:
```powershell
deactivate
Remove-Item -Recurse -Force .venv
uv add fastmcp
```
Luk eventuelt Cursor, IntelliJ eller andre terminaler, der bruger projektet.
### Fejl: den angivne sti blev ikke fundet
Tjek at projektmappen findes:
```powershell
Test-Path C:\Users\mikc\IdeaProjects\MCP_Test
```
Tjek at `server.py` findes:
```powershell
Test-Path C:\Users\mikc\IdeaProjects\MCP_Test\server.py
```
Begge skal give:
```text
True
```
### Ændringer i server.py slår ikke igennem
Hvis du ændrer i `server.py`, skal MCP-serveren genstartes.
I Claude Desktop:
```text
Luk Claude helt og åbn igen
```
I Cursor:
```text
Slå MCP-serveren fra og til igen
```
eller genstart Cursor.
## Undervisningspointer
Dette eksempel kan bruges til at forklare flere centrale MCP-begreber.
### Host, client og server
Claude Desktop og Cursor er hosts. De har en MCP-client indbygget, som taler med MCP-serveren.
Python-filen `server.py` er MCP-serveren.
### Capabilities og tools
Funktionerne med `@mcp.tool()` bliver til capabilities af typen tools.
Tools får AI'en til at gøre noget, fx beregne, konvertere eller hente data.
### Discovery
Claude og Cursor kan opdage, hvilke tools serveren tilbyder.
Derfor er dette vigtigt:
```text
Gode funktionsnavne
Simple parametre
Klare docstrings
```
### Execution
Når brugeren skriver en prompt, kan AI'en vælge et relevant tool.
Flowet er:
```text
Bruger skriver prompt
AI vurderer behov for tool
MCP-client kalder MCP-server
Python-funktionen udføres
Resultatet sendes tilbage til AI'en
AI'en formulerer svaret
```
### Små tools frem for ét stort tool
Dette eksempel har tre små tools:
```text
get_weather
calculate
convert_currency
```
Det er bedre end én stor funktion, der prøver at gøre alt.
Små tools er lettere at forstå, teste, fejlfinde og genbruge.
## Forslag til videreudvikling
Når grundeksemplet virker, kan man udvide med:
```text
Read-only taskliste fra JSON-fil
Opslag i lokal SQLite-database
GitHub issue-helper
MongoDB read-only query
API-kald til rigtig vejrservice
Code review prompt
```
Start gerne med read-only eksempler, før der laves tools med sideeffekter som oprettelse, sletning eller afsendelse.
## Afsluttende pointe
MCP gør AI til en del af en softwarearkitektur.
Det handler derfor ikke kun om at skrive gode prompts, men om at designe:
```text
værktøjer
grænser
adgang
ansvar
fejlhåndtering
sikkerhed
```
Det gør MCP relevant for både programmering, systemudvikling, softwarearkitektur og IT-sikkerhed.TDQS
B3.2/5.0
Scored across 3 tools
Disambiguation5/5
Each tool targets a completely different task (mathematical calculation, currency conversion, and weather retrieval), so there is no ambiguity in purpose.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern (calculate, convert_currency, get_weather), making them predictable and easy to understand.
Tool Count4/5
Three tools is a reasonable number for a utility server, though the set feels slightly sparse for a general-purpose toolkit.
Completeness2/5
The tools form a disjoint set with no clear domain; they cover only a few random utilities, leaving obvious gaps for a general-purpose server.
Maintenance
ActivityInactive
ResponsivenessNo issues