Usar SQL MCP Server com modelos locais

Importante

O SQL Model Context Protocol (MCP) Server está disponível na versão 1.7 do Data API builder. Para as capacidades mais recentes e correções de bugs, utilize a versão preview 2.0.

O SQL Model Context Protocol (MCP) Server funciona com qualquer cliente compatível com MCP, não apenas com serviços de IA alojados na cloud. Se o seu ambiente restringir o acesso a modelos de linguagem de grande dimensão (LLM) na nuvem — algo comum nos setores da saúde, defesa, finanças, energia e marítimo — pode ligar-se a um modelo local disponibilizado através do Ollama ou de ferramentas semelhantes. Este guia aborda a configuração, configuração de metadados de campo e padrões de prompt que tornam os pequenos modelos locais fiáveis.

Pré-requisitos

  • Data API builder CLI instalado e configurado com pelo menos uma entidade. Instale a CLI.
  • Ollama com um modelo que suporta a chamada de ferramentas (por exemplo, qwen3:8b, llama3.1:8b).
  • Python 3.10+ com os pacotes mcp e ollama.
  • Uma instância de SQL Server a correr com dados.

Passo 1: Configurar metadados de campo

Os metadados de campo são o passo de configuração mais importante para a precisão local do modelo. Sem nomes de campos e descrições, os agentes veem apenas nomes de entidades e adivinham incorretamente os nomes das colunas.

Warning

Se este passo for omitido, produz-se um servidor MCP que, embora funcione tecnicamente, é funcionalmente inutilizável por qualquer modelo que leia as respostas das ferramentas. O modelo não dispõe de informação sobre as suas colunas.

Adicione a sua entidade com uma descrição e depois adicione descrições de campos que incluam valores válidos para colunas restritas:

dab add ServerInventory \
  --source dbo.ServerInventory \
  --permissions "anonymous:read" \
  --description "SQL Server instance inventory with version, environment, and sizing data"

dab update ServerInventory \
  --fields.name InstanceName --fields.primary-key true \
  --fields.description "SQL Server instance name (e.g., YOURSERVER01)"

dab update ServerInventory \
  --fields.name Environment \
  --fields.description "Deployment environment. Valid values: Prod, Dev, Test, UAT"

Para a referência completa da CLI e as melhores práticas — incluindo valores restritos, descrições de parâmetros e padrões de script — veja Adicionar descrições às entidades.

Note

A dab update CLI trata as vírgulas como separadores de argumentos. Se a sua descrição tiver vírgulas, edite dab-config.json diretamente em vez disso.

Passo 2: Iniciar SQL MCP Server

dab start

O SQL MCP Server escuta em http://localhost:5000/mcp usando transporte HTTP streamable por predefinição. Qualquer cliente que implemente o protocolo MCP pode ligar-se a este endpoint.

Passo 3: Ligue o seu modelo local

Constrói um cliente MCP que ligue o teu modelo Ollama ao SQL MCP Server. O seguinte exemplo Python utiliza o SDK Python MCP e o pacote ollama.

Instalar dependências

pip install mcp ollama

Estrutura mínima em Python

import asyncio
import json
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
import ollama

MCP_URL = "http://localhost:5000/mcp"
MODEL = "qwen3:8b"

async def get_schema(session: ClientSession) -> str:
    """Call describe_entities and format results for the system prompt."""
    result = await session.call_tool("describe_entities", arguments={})
    entities = json.loads(result.content[0].text)
    lines = []
    for entity in entities.get("entities", []):
        fields = ", ".join(
            f"{f['name']} ({f.get('description', 'no description')})"
            for f in entity.get("fields", [])
        )
        lines.append(f"- {entity['name']}: {entity.get('description', '')}")
        if fields:
            lines.append(f"  Fields: {fields}")
    return "\n".join(lines)

async def run(user_question: str):
    async with streamable_http_client(MCP_URL) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # Preinject schema into the system prompt
            schema_text = await get_schema(session)
            system_prompt = f"""You query a SQL database through MCP tools.

Available entities:
{schema_text}

Rules:
- Use the exact field names shown above.
- Answer count questions with the count only.
- Do not produce summaries unless asked.
- Do not invent example data. Only return data from tool responses.
- If no results, say "No results found" and stop.
"""
            # Get available tools for Ollama
            tools_result = await session.list_tools()
            ollama_tools = [
                {
                    "type": "function",
                    "function": {
                        "name": t.name,
                        "description": t.description or "",
                        "parameters": t.inputSchema,
                    },
                }
                for t in tools_result.tools
            ]

            messages = [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_question},
            ]

            # Chat loop: let the model call tools until it produces a final answer
            while True:
                response = ollama.chat(
                    model=MODEL, messages=messages, tools=ollama_tools
                )
                msg = response["message"]
                messages.append(msg)

                if not msg.get("tool_calls"):
                    print(msg["content"])
                    break

                for tc in msg["tool_calls"]:
                    result = await session.call_tool(
                        tc["function"]["name"],
                        arguments=tc["function"]["arguments"],
                    )
                    messages.append(
                        {
                            "role": "tool",
                            "content": result.content[0].text,
                        }
                    )

asyncio.run(run("How many SQL 2019 servers are in production?"))

Esta estrutura gere o ciclo completo: injeção prévia de esquemas, descoberta de ferramentas, invocação de ferramentas em múltiplas interações e extração da resposta final. Ajuste MODEL e MCP_URL ao seu ambiente.

Injetar previamente o esquema ao iniciar

Pequenos modelos locais (com menos de 14 mil milhões de parâmetros) produzem chamadas a ferramentas mais fiáveis quando os metadados do esquema estão no prompt do sistema antes de a conversa começar. Em vez de depender do modelo para chamar describe_entities por si só durante a conversa, chame-o no arranque da infraestrutura de teste e injete o resultado.

Porque é que a pré-injeção é importante

Abordagem Comportamento com modelos pequenos
Descoberta dinâmica O modelo tem de decidir chamar describe_entities primeiro, depois interpretar os resultados e depois chamar a ferramenta certa com os nomes corretos dos campos. Múltiplos pontos de falha.
Pré-injeção O modelo vê imediatamente nomes de entidades, nomes de campos e descrições. Efetua corretamente as chamadas de ferramentas à primeira tentativa.

O exemplo do arnês na secção anterior demonstra este padrão. A função get_schema() chama describe_entities uma vez no arranque e formata o resultado no prompt de sistema.

Tip

Modelos de cloud maiores (GPT-4o, Claude) normalmente descobrem o esquema durante a conversa sem pré-injeção. Este padrão é mais valioso para modelos abaixo dos parâmetros 14B.

Restringir as respostas do modelo

Um modelo pode fazer uma chamada correta à ferramenta, recuperar os dados corretos e ainda assim produzir uma resposta errada. Por exemplo, um modelo perguntado "quantos servidores de produção?" poderia recuperar corretamente 16 linhas e depois responder com um resumo executivo de 40 linhas contendo exemplos alucinados em vez do número 16.

Adicione regras negativas explícitas ao seu prompt do sistema:

Rules:
- Answer count questions with the count only.
- Do not produce summaries unless the user asks for one.
- Do not invent example data. Only return data from tool responses.
- If a tool returns no results, say "No results found" and stop.

A fidelidade da invocação de ferramentas e a disciplina das respostas são problemas diferentes. O DAB garante uma recuperação exata de dados através da camada de ferramentas. A sua estrutura de prompts controla a forma como o modelo apresenta os resultados.

Considerations

Tópico Detalhes
Equipamento A invocação de ferramentas funciona com hardware modesto. Um modelo com 8 mil milhões de parâmetros numa GPU Nvidia para o consumidor (8 GB de memória de vídeo) produz resultados úteis. Espere uma latência de dezenas de segundos por pergunta, o que se adequa a cargas de trabalho em lote.
Batch vs. interativo Modelos pequenos são bem adequados para processamento em lote (relatórios de desempenho, consultas de inventário) onde a tolerância à latência é mais elevada.
Disponibilidade de ferramentas aggregate_records está disponível apenas na versão 2.0 preview e posteriormente. Na versão 1.7.x, as consultas de contagem e agregação obrigam o modelo a ler todas as linhas correspondentes. Consulte a disponibilidade de ferramentas por versão.
Transportes Os modelos locais ligam-se através de HTTP de transmissão a /mcp. O transporte padrão de entrada/saída (stdio) é uma alternativa para configurações de processo único.
Authentication Para o desenvolvimento local, use permissões anonymous. Para produção, configure a autenticação adequada ao seu ambiente.