[!NOTE] Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.

MCP Tutorial de Servidor com uv e FastMCP: Criar um Servidor FeatureStoreLite

Este tutorial de servidor MCP permite criar um pequeno servidor de repositório de funcionalidades utilizando FastMCP, executá‑lo com o uv e integrá‑lo ao Claude Desktop.

TL;DR: Um servidor FastMCP pequeno é suficiente para expor uma ferramenta local útil a um agente. Utilize o uv para uma configuração reprodutível, mantenha os limites do servidor restritos, valide as entradas com esquemas tipados e teste a ferramenta MCP antes de a conectar a um modelo.


O que é um servidor MCP?

O Model Context Protocol (MCP) é um padrão aberto destinado a conectar assistentes AI a dados e ferramentas externas. Ele substitui a necessidade de uma integração personalizada separada para cada ferramenta, adotando em vez disso um conjunto único de convenções.

Neste tutorial, iremos construir um servidor FeatureStoreLite MCP. Este componente situa‑se entre um LLM e um repositório de características (um banco de dados com características ML pré‑calculadas), disponibilizando ferramentas para consultar e gravar vetores de características indexados por utilizador, produto ou documento.

Por que construir isto?

Você é um engenheiro ML a depurar um pipeline. Em vez de aceder diretamente ao SQL ou de escrever um script rápido para verificar os valores das features, pergunta diretamente ao Claude: “Qual é o vetor de features do utilizador_123?” ou “Mostre-me os metadados do produto_abc.” O servidor MCP é o que torna isso possível.

Por que utilizar uv?

Vamos utilizar UV para instalar pacotes, resolver dependências e gerir o ambiente virtual. Posteriormente, uv run --with mcp[cli] ... Permite também que a configuração do Claude Desktop declare diretamente a sua dependência. Isso elimina a necessidade de um ambiente separado que poderia ficar des sincronizado.

Visão geral da arquitetura

As quatro componentes e a forma como se integram:

MCP Arquitetura

  1. O utilizador faz uma pergunta em linguagem natural.
  2. O Claude Desktop é o cliente MCP. Ele seleciona uma ferramenta com base na pergunta e aciona-a.
  3. A nossa FastMCP o servidor expõe get_feature e store_feature como ferramentas MCP.
  4. O SQLite funciona como armazenamento de suporte para os vetores de características.

2. Configuração e Instalação

2.1. Instalar uv

Se ainda não possuir uvInstale-o. O resto do tutorial pressupõe que ele está no seu PATH.

# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Or via Homebrew
brew install uv

2.2. Inicializar o Projeto

Crie um novo diretório e inicialize um projeto em Python. uv init cria um pyproject.toml para si.

# 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. Construção do Servidor

Dois ficheiros, separados por domínio de responsabilidade:

  1. database.py lida com operações SQLite. featurestore_server.py Define o servidor MCP.

3.1. A camada de base de dados (database.py)

Este módulo gere a ligação ao SQLite e alguns auxiliares. Inicializamo-lo com duas linhas de exemplo para que o servidor tenha algo para retornar na primeira consulta.

Criar 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!")

Inicializar a base de dados:

uv run python database.py

3.2. O servidor MCP (featurestore_server.py)

FastMCP Realiza a maior parte do trabalho. Basta decorar uma função Python simples para que ela seja registada como uma ferramenta ou recurso MCP. A documentação torna‑se a descrição que o LLM exibe, pelo que deve ser redigida para um LLM, e não apenas para humanos.

Criar 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. Testes com o Inspetor MCP

Antes de ligar isto ao Claude, verifique se o servidor está em ordem utilizando o MCP Inspector. Trata‑se de uma pequena interface web para chamar ferramentas e aceder diretamente aos recursos.

uv run mcp dev featurestore_server.py

O comando inicia o servidor e abre o Inspector no seu navegador (geralmente em http://localhost:5173).

Inspektor{: style=“largura:600px; largura máxima:100%; altura:auto;”}

Chamada get_feature com key="user_123". Se for retornado o JSON para a linha de semente, o servidor está a funcionar corretamente.


5. Conexão ao Claude Desktop

Assim que o Inspector confirmar que o servidor está a funcionar, registe-o no Claude Desktop.

5.1. Configurar o Claude

Edite o ficheiro de configuração do seu Claude Desktop:

Adicione o seu servidor à mcpServers objeto:

{
    "mcpServers": {
        "featurestore": {
            "command": "uv",
            "args": [
                "run",
                "--with",
                "mcp[cli]",
                "mcp",
                "run",
                "/ABSOLUTE/PATH/TO/mcp-featurestore/featurestore_server.py"
            ]
        }
    }
}

Importante: o caminho para featurestore_server.py Tem de ser absoluto. Um caminho relativo falhará silenciosamente, uma vez que o Claude Desktop é executado a partir de um diretório de trabalho diferente.

5.2. Como funciona a interação

Eis o que é executado de ponta a ponta quando o Claude precisa de procurar uma funcionalidade:

MCP Fluxo de trabalho

  1. O Claude identifica as ferramentas disponíveis (get_feature, list_features, e assim por diante).
  2. Ele determina que a pergunta requer dados da feature store.
  3. Ele cria um tool call e envia‑o para o seu servidor.
  4. O servidor executa a função em Python e devolve o resultado.
  5. O Claude utiliza esse resultado para escrever a resposta final.

5.3. Exemplos de consultas

Reinicie o Claude Desktop e experimente alguns prompts:

  1. “Liste todas as funcionalidades disponíveis.” Questão 2{: style=“largura:600px; largura máxima:100%; altura:auto;”}

  2. “Obter o vetor de características para user_123.” Questão 3{: style=“largura:600px; largura máxima:100%; altura:auto;”}

  3. “Armazenar uma nova característica para ‘new_item’ com o vetor [0.5, 0.5] e os metadados {‘type’: ‘test’}.“


6. Resolução de Problemas

Alguns modos de falha que vale a pena conhecer:


7. Conclusão

Esse é o essencial: um FastMCP servidor, um armazenamento de suporte em SQLite e uma configuração do Claude Desktop que aponta para um uv run comando. A mesma estrutura funciona para qualquer elemento que possa ser envolvido numa função em Python. Substitua as chamadas ao SQLite por um repositório de funcionalidades real, um API interno ou um registo de modelos, e o servidor permanecerá compacto.

Principais Conclusões

  1. MCP representa uma fronteira entre ferramentas, e não um motivo para expor todas as funções internas.
  2. Mantenha as ferramentas do servidor pequenas, tipadas e fáceis de testar, sem a necessidade de um LLM.
  3. Utilize o uv para que o ambiente de tutorial possa ser recriado do zero.
  4. Trate o servidor MCP como código de produção assim que um agente puder chamá‑lo.

Referências