[!NOTE] Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.
MCP Server-tutorial met uv en FastMCP: Een FeatureStoreLite-server bouwen
Dit tutorial over de MCP-server bouwt een kleine feature-store-server met FastMCP, start deze met uv en koppelt hem aan Claude Desktop.
TL;DR: Een kleine FastMCP-server is voldoende om een bruikbaar lokaal hulpprogramma beschikbaar te stellen voor een agent. Gebruik uv voor een reproduceerbare opstelling, houd de grenzen van de server beperkt, valideer invoer met getypeerde schema’s, en test het MCP-hulpprogramma voordat je het verbindt met een model.
Wat is een MCP-server?
Het Model Context Protocol (MCP) is een open standaard voor het verbinden van AI assistenten met externe gegevens en hulpmiddelen. Hiermee wordt een aparte, maatwerkintegratie voor elk hulpmiddel vervangen door één gemeenschappelijk stelsel van conventies.
In deze tutorial zullen we een FeatureStoreLite MCP-server bouwen. Deze server bevindt zich tussen een LLM en een feature store (een database met vooraf gerekende ML-kenmerken) en biedt hulpmiddelen om featurevectoren te queryen en op te slaan, waarbij de vectoren worden gekeyed op basis van gebruiker, product of document.
Waarom wordt dit gebouwd?
U bent een ML-engineer die een pipeline aan het debuggen is. In plaats van direct SQL te gebruiken of een snel script te schrijven om de waarden van features te controleren, stelt u aan Claude rechtstreeks de vraag: “Wat is de featurevector voor user_123?” of “Laat me de metadata van product_abc zien.” De MCP-server maakt dit mogelijk.
Waarom gebruiken uv?
We zullen gebruikmaken van UV om pakketten te installeren, afhankelijkheden op te lossen en de virtuele omgeving te beheren. Later, uv run --with mcp[cli] ... Het maakt het ook mogelijk voor de configuratie van Claude Desktop om zijn afhankelijkheden rechtstreeks te specificeren. Hierdoor is er geen aparte omgeving meer nodig die uit balans kan raken.
Overzicht van de architectuur
De vier onderdelen en hoe ze met elkaar samenwerken:
- De gebruiker stelt een vraag in natuurlijke taal.
- Claude Desktop is de MCP-client. Hij kiest op basis van de vraag een tool en roept deze aan.
- Onze
FastMCPDe server maakt de componenten beschikbaar.get_featureenstore_featureals MCP-tools. - SQLite dient als back-endopslag voor de featurevectoren.
2. Opzet en installatie
2.1. Installeren uv
Als je deze nog niet hebt uv, installeer het. De rest van de handleiding gaat ervan uit dat het op uw systeem staat. PATH.
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or via Homebrew
brew install uv
2.2. Het project initialiseren
Maak een nieuwe map aan en initialiseer een Python-project. uv init maakt een aan pyproject.toml voor u.
# Create project directory
mkdir mcp-featurestore
cd mcp-featurestore
# Initialize Python project
uv init
# Add the MCP SDK with CLI tools
uv add "mcp[cli]"
3. Het server opzetten
Twee bestanden, gescheiden op grond van functionaliteit:
database.pyhandelt SQLite-operaties af.featurestore_server.pyDefinieert de MCP-server.
3.1. De databaselaag (database.py)
Deze module beheert de SQLite-verbinding en een aantal hulpprogramma’s. Er worden twee voorbeeldregels in geplaatst zodat de server iets kan teruggeven bij de eerste aanvraag.
Creëer database.py:
# database.py
import json
import os
import sqlite3
def get_db_path() -> str:
"""Get the database path - always in the script's directory"""
script_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(script_dir, "features.db")
def init_db() -> None:
"""Initialize the feature store database with table and sample data"""
conn = sqlite3.connect(get_db_path())
conn.execute("""
CREATE TABLE IF NOT EXISTS features (
key TEXT PRIMARY KEY,
vector TEXT NOT NULL,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Sample data for experimentation
example_features = [
(
"user_123",
"[0.1, 0.2, -0.5, 0.8, 0.3, -0.1, 0.9, -0.4]",
json.dumps({"type": "user", "id": 123, "segment": "premium"}),
),
(
"product_abc",
"[0.7, -0.3, 0.4, 0.1, -0.8, 0.6, 0.2, -0.5]",
json.dumps({"type": "product", "id": "abc", "category": "electronics"}),
),
]
# Insert if not exists
for key, vector, metadata in example_features:
try:
conn.execute(
"INSERT INTO features (key, vector, metadata) VALUES (?, ?, ?)",
(key, vector, metadata),
)
except sqlite3.IntegrityError:
pass # Already exists
conn.commit()
conn.close()
def get_db_connection() -> sqlite3.Connection:
"""Get a database connection"""
return sqlite3.connect(get_db_path())
if __name__ == "__main__":
init_db()
print("✅ Database initialized successfully!")
De database initialiseren:
uv run python database.py
3.2. De MCP-server (featurestore_server.py)
FastMCP Dit doet het grootste deel van het werk. Door een eenvoudige Python-functie te decoreren, wordt deze geregistreerd als een MCP-tool of -resource. De docstring vormt de beschrijving die door de LLM wordt weergegeven; schrijf hem dus gericht op een LLM, en niet alleen voor mensen.
Creëer featurestore_server.py:
# featurestore_server.py
import json
from mcp.server.fastmcp import FastMCP
from database import get_db_connection, init_db
# Initialize the MCP Server
mcp = FastMCP("FeatureStoreLite")
# Ensure DB is ready when server starts
init_db()
@mcp.resource("schema://main")
def get_schema() -> str:
"""
Resource: Provide the database schema.
Resources are passive data that LLMs can read like files.
"""
conn = get_db_connection()
try:
schema = conn.execute(
"SELECT sql FROM sqlite_master WHERE type='table'"
).fetchall()
return "\n".join(sql[0] for sql in schema if sql[0]) or "No tables found."
finally:
conn.close()
@mcp.tool()
def store_feature(key: str, vector: str, metadata: str | None = None) -> str:
"""
Tool: Store a feature vector.
Tools are executable functions that LLMs can call to perform actions.
"""
conn = get_db_connection()
try:
# Validate that vector is valid JSON
json.loads(vector)
conn.execute(
"INSERT OR REPLACE INTO features (key, vector, metadata) VALUES (?, ?, ?)",
(key, vector, metadata),
)
conn.commit()
return f"Successfully stored feature '{key}'"
except json.JSONDecodeError:
return "Error: Vector must be a valid JSON array string (e.g., '[0.1, 0.2]')"
except Exception as e:
return f"Error: {str(e)}"
finally:
conn.close()
@mcp.tool()
def get_feature(key: str) -> str:
"""
Tool: Retrieve a feature vector by key.
"""
conn = get_db_connection()
try:
row = conn.execute(
"SELECT vector, metadata FROM features WHERE key = ?", (key,)
).fetchone()
if row:
return json.dumps(
{
"key": key,
"vector": json.loads(row[0]),
"metadata": json.loads(row[1]) if row[1] else None,
},
indent=2,
)
return f"Feature '{key}' not found."
finally:
conn.close()
@mcp.tool()
def list_features() -> str:
"""
Tool: List all available feature keys.
"""
conn = get_db_connection()
try:
rows = conn.execute("SELECT key FROM features").fetchall()
return json.dumps([row[0] for row in rows])
finally:
conn.close()
if __name__ == "__main__":
mcp.run()
4. Testen met de MCP Inspector
Voordat u dit integreert in Claude, controleert u eerst de server met de MCP Inspector. Het gaat om een eenvoudige webinterface waarmee u tools kunt aanroepen en resources rechtstreeks kunt lezen.
uv run mcp dev featurestore_server.py
Het commando start de server en opent de Inspector in uw browser (meestal op http://localhost:5173).
{width=“600”}
aanroepen get_feature met key="user_123". Als de server voor de seed‑rij JSON retourneert, werkt hij correct.
5. Aansluiten op Claude Desktop
Zodra de inspector bevestigt dat de server correct functioneert, registreer je hem bij Claude Desktop.
5.1. Claude configureren
Pas uw configuratiebestand van Claude Desktop aan:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%/Claude/claude_desktop_config.json
Voeg uw server toe aan de mcpServers object:
{
"mcpServers": {
"featurestore": {
"command": "uv",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"/ABSOLUTE/PATH/TO/mcp-featurestore/featurestore_server.py"
]
}
}
}
Belangrijk: de pad naar
featurestore_server.pyHet moet een absolute pad zijn. Een relatief pad zal stilletjes falen, omdat Claude Desktop wordt uitgevoerd vanuit een andere werkdirectory.
5.2. Hoe de interactie werkt
Dit is wat van begin tot eind wordt uitgevoerd wanneer Claude een functie moet opzoeken:
- Claude ziet de beschikbare hulpmiddelen (
get_feature,list_features, enzovoort). - Het bepaalt dat er gegevens uit de feature store nodig zijn voor deze vraag.
- Het maakt een tool call aan en stuurt deze naar uw server.
- De server voert de Python-functie uit en geeft het resultaat terug.
- Claude gebruikt dat resultaat om het eindantwoord op te stellen.
5.3. Voorbeeldvragen
Start Claude Desktop opnieuw op en probeer enkele prompts:
-
“Lijst alle beschikbare functies op.”
{width=“600”} -
“Haal de eigenschapsvector op voor user_123.”
{width=“600”} -
“Sla een nieuwe eigenschap voor ‘new_item’ op met vector [0.5, 0.5] en metadata {‘type’: ‘test’}.“
6. Probleemoplossing
Enkele foutmodi die het de moeite waard zijn om te kennen:
-
“Serververbinding is mislukt”:
- Controleer de logbestanden.
~/Library/Logs/Claude/mcp.logop macOS. - Controleer of de configuratie een absolute pad gebruikt, en niet een relatieve.
- Controleer
uvis op Claude Desktop’sPATH. Indien dit niet het geval is, geef dan de volledige binaire pad op.which uv(het zal u vertellen waar het zich bevindt).
- Controleer de logbestanden.
-
“Fout bij uitvoering van het hulpprogramma”:
- Repliceer dit in de Inspector met
uv run mcp dev featurestore_server.py. De Inspector toont de ruwe fout, die Claude Desktop doorgaans wegneemt. - Controleer of
features.dbwordt gegenereerd naastdatabase.py. Als uw werkdirectory verandert, zal de relatieve padnaam ten opzichte van het script inget_db_path()Dit is wat je redt.
- Repliceer dit in de Inspector met
7. Conclusie
Dat is alles: een FastMCP een server, een SQLite-backingstore, en een Claude Desktop-configuratie die naar een … verwijst uv run command. Dezelfde structuur is bruikbaar voor alles wat je in een Python-functie kunt opnemen. Vervang de SQLite-oproepen door een echte feature store, een interne API, of een model registry, zodat de server klein blijft.
Belangrijkste conclusies
- MCP vormt een grens voor de tool, maar is geen reden om elke interne functie zichtbaar te maken.
- Houd servertools klein, getypeerd en gemakkelijk te testen, zonder het gebruik van een LLM.
- Gebruik uv zodat de leeromgeving vanaf nul opnieuw kan worden opgebouwd.
- Beschouw de MCP-server als productiecoder zodra een agent deze kan aanroepen.