SQL Server MCP

Um MCP entry para cada SQL Server que você administra. As conexões ficam em um único arquivo de configuração agrupado por cliente ou ambiente, recarregadas a quente sem reiniciar o agente, e cada resposta indica qual servidor respondeu. Além de executar consultas, retorna planos de execução, layouts de índices e código-fonte de stored procedures. Feito para DBAs e consultores que gerenciam dezenas de instâncias, e não apenas um único banco de dados. Instale com: npx -y @cevelas/mcp-sqlserver

Documentação

SQL Server MCP para quem administra dezenas de instâncias

npm CI License: MIT Node.js MCP

Uma entrada MCP, todos os SQL Server que você administra. As conexões ficam em um único connections.json, agrupadas por cliente ou ambiente, recarregadas a quente sem reiniciar seu agente de IA — além de planos de execução, auditorias de índice e análise de stored procedures.

Feito para DBAs e consultores, não para uma demonstração contra um único banco localhost.

Instalação

Adicione isto à configuração MCP do seu agente de IA:

{
  "mcpServers": {
    "sqlserver": {
      "command": "npx",
      "args": ["-y", "@cevelas/mcp-sqlserver"]
    }
  }
}

Depois crie seu arquivo de conexões e reinicie o agente:

npx -y @cevelas/mcp-sqlserver --init

Isso grava ~/.mcp-sqlserver/connections.json a partir de um modelo comentado. Edite-o e peça ao seu agente para "listar todas as conexões SQL Server".

Onde cada agente guarda sua configuração MCP
AgenteArquivo de configuração
Claude Desktop (Windows)%APPDATA%\Claude\claude_desktop_config.json
Claude Desktop (macOS)~/Library/Application Support/Claude/claude_desktop_config.json
Claude Codeclaude mcp add sqlserver -- npx -y @cevelas/mcp-sqlserver
VS Code / Copilot.vscode/mcp.json
Cursor~/.cursor/mcp.json

Qualquer agente compatível com MCP funciona — ChatGPT, Gemini, Copilot, Cline, Zed e outros aceitam o mesmo par command / args.

Por que este

A maioria dos servidores MCP para SQL Server aceita uma única string de conexão. Isso é suficiente para um banco. Mas desmorona quando você administra trinta bancos em oito clientes, porque cada instância precisa de sua própria entrada na configuração do agente, suas próprias credenciais e seu próprio reinício quando algo muda.

Servidores de DSN únicoEste
Instâncias por entrada MCP1todas elas
Organizado por cliente ou ambienteconnectionGroup
Adicionar ou alterar uma conexãoeditar config do agente, reiniciareditar um arquivo, reload_connections
Qual servidor respondeu?você assumeno metadata de cada resposta
Além de SELECTplanos de execução, layout de índices, código-fonte de SP
Trilho de segurança somente leitura"readOnly": true por conexão

Conexões

{
  "connections": [
    {
      "name": "acme-prod",
      "connectionGroup": "Acme Corp",
      "description": "Production - head office",
      "server": "192.168.1.10\\SQLEXPRESS",
      "database": "AcmeDB_Prod",
      "user": "app_reader",
      "password": "${env:ACME_PROD_PASSWORD}",
      "port": 1433,
      "encrypt": true,
      "trustServerCertificate": false,
      "readOnly": true
    }
  ]
}
CampoObrigatórioObservações
namesimÚnico; é o que você diz ao agente
serversimHostname, IP ou host\instance
connectionGroupnãoCliente, projeto ou ambiente. Agrupa a listagem
descriptionnãoExibido em list_connections e em cada resposta
databasenãoPadrão: o banco padrão do login
user, passwordnãoOmita para autenticação de domínio ou Entra ID
portnãoPadrão: 1433
encrypt, trustServerCertificatenãoencrypt tem padrão true
readOnlynãoRejeita instruções de escrita — veja abaixo

Qualquer outra coisa que você colocar aqui é passada diretamente para mssql, então requestTimeout, connectionTimeout, pool, authentication e um objeto options aninhado funcionam.

Mantendo senhas fora do arquivo

Qualquer string pode referenciar uma variável de ambiente:

"password": "${env:ACME_PROD_PASSWORD}"

Uma conexão que referencia uma variável que você não definiu fica desabilitada, e list_connections informa tanto a conexão quanto a variável ausente. Deixar o literal no lugar apenas adiaria a falha para o momento da conexão, onde ela chega como Login failed for user e não diz nada.

Você também pode pular o arquivo por completo e passar tudo pela configuração do agente, o que mantém as credenciais em um só lugar com o restante dos seus segredos MCP:

{
  "mcpServers": {
    "sqlserver": {
      "command": "npx",
      "args": ["-y", "@cevelas/mcp-sqlserver"],
      "env": {
        "MSSQL_MCP_CONNECTIONS_JSON": "{\"connections\":[{\"name\":\"prod\",\"server\":\"10.0.0.1\",\"database\":\"App\",\"user\":\"reader\",\"password\":\"...\"}]}"
      }
    }
  }
}

Onde o arquivo é procurado

Em ordem, o primeiro que encontrar vence:

  1. --connections <path>
  2. $MSSQL_MCP_CONNECTIONS — um caminho
  3. $MSSQL_MCP_CONNECTIONS_JSON — o próprio JSON, inline
  4. ./connections.json no diretório de trabalho
  5. ~/.mcp-sqlserver/connections.json
  6. connections.json ao lado do pacote instalado

Um caminho informado explicitamente via 1 ou 2 que não existe é um erro — o servidor não vai silenciosamente cair para outro arquivo e falar com o banco errado.

Autenticação de domínio Windows e Entra ID

O driver tedious incluído suporta NTLM e a família Entra ID (Azure AD). Adicione domain para NTLM:

{
  "name": "warehouse",
  "server": "dwh.corp.local",
  "database": "DWH",
  "domain": "CORP",
  "user": "svc_analytics",
  "password": "${env:DWH_PASSWORD}"
}
{
  "name": "azure-sql",
  "server": "myserver.database.windows.net",
  "database": "reporting",
  "encrypt": true,
  "authentication": {
    "type": "azure-active-directory-password",
    "options": { "userName": "${env:AZURE_USER}", "password": "${env:AZURE_PASSWORD}" }
  }
}

Autenticação totalmente integrada — uma conexão confiável sem senha alguma — exige o driver nativo msnodesqlv8, que não é incluído porque quebraria a instalação de uma linha em máquinas sem toolchain de build. NTLM com uma conta de serviço explícita é o caminho suportado.

Ferramentas

FerramentaArgumentosO que faz
list_connectionsTodas as conexões, agrupadas
reload_connectionsRelê o arquivo, descarta pools abertos
queryconnection, sqlExecuta uma consulta
get_schemaconnection, table?Colunas, tipos, nulabilidade, padrões
get_indexesconnection, tableÍndices, tipos, colunas-chave e incluídas
get_execution_planconnection, sqlSHOWPLAN_XML — o plano, sem executar a consulta
get_stored_procedureconnection, nameCódigo-fonte de uma stored procedure

Toda resposta traz a conexão de onde veio:

{
  "metadata": {
    "connection": "acme-prod",
    "connectionGroup": "Acme Corp",
    "description": "Production - head office",
    "server": "192.168.1.10\\SQLEXPRESS",
    "database": "AcmeDB_Prod"
  },
  "data": [ ... ]
}

Com trinta conexões em jogo, essa linha é o que diz que a resposta veio do cliente que você queria.

O que isso proporciona

Coisas tediosas de fazer à mão viram uma frase para o agente:

  • "Por que esta stored procedure está lenta?"get_stored_procedure para o código-fonte, get_execution_plan para o plano, get_indexes para o que está faltando.
  • "Compare o esquema de Orders entre acme-prod e acme-qa"get_schema em ambos, o agente faz o diff.
  • "Quais índices desta tabela nunca cobrem nada?"get_indexes mais as consultas que você quer.
  • "Adicionei um cliente ao connections.json"reload_connections, sem reiniciar.

Conexões somente leitura

"readOnly": true

Rejeita INSERT, UPDATE, DELETE, MERGE, DROP, TRUNCATE, ALTER, CREATE, GRANT, EXEC, BACKUP, DBCC, OPENQUERY, DISABLE/ENABLE e afins antes de a consulta sair da sua máquina. Também exige que o lote comece com algo que leia — SELECT, WITH, DECLARE, SET, IF e assim por diante — porque T-SQL permite chamar um procedimento sem EXEC, e sp_rename 'dbo.Users','Users_old' não contém nenhuma palavra bloqueada.

Literais de string, comentários e identificadores entre colchetes são ignorados, então WHERE note = 'please delete this', SELECT [delete] FROM [Audit] e DECLARE @Create DATETIME passam. get_execution_plan continua funcionando, porque SHOWPLAN_XML retorna o plano sem executar nada.

Qualquer coisa que não seja um false explícito liga a proteção on — um "readOnly": "false" escrito à mão bloqueia a conexão em vez de abri-la silenciosamente, e avisa isso em list_connections.

Isto é um trilho de segurança, não uma fronteira de segurança. Impede que um agente "prestativo" corrija uma linha em produção. Não vai impedir alguém determinado a escrever. A proteção real é um login SQL que tenha apenas db_datareader:

CREATE LOGIN mcp_reader WITH PASSWORD = '...';
CREATE USER mcp_reader FOR LOGIN mcp_reader;
ALTER ROLE db_datareader ADD MEMBER mcp_reader;
GRANT VIEW DEFINITION TO mcp_reader;   -- for get_stored_procedure
GRANT SHOWPLAN TO mcp_reader;          -- for get_execution_plan

Use ambos.

Notas de segurança

  • connections.json guarda credenciais. Mantenha-o fora do controle de versão — o .gitignore incluído cobre connections*.json.
  • Prefira ${env:VAR} a senhas literais.
  • Dê a cada conexão o menor privilégio necessário. Não use sa.
  • Restrinja as permissões do arquivo: icacls connections.json /inheritance:r /grant:r "%USERNAME%:F" no Windows, chmod 600 connections.json em outros sistemas.
  • A ferramenta query executa qualquer SQL que o agente escrever. Esse é o propósito da ferramenta — trate as permissões da conexão como a fronteira, não a ferramenta.

Interface web

web/connections.html é uma página autônoma para editar connections.json sem escrever JSON à mão: arrastar e soltar entre grupos, duplicar uma conexão, seletor de grupo com autocompletar e salvamento automático pela File System Access API no Chrome e Edge. Sem build, sem dependências, totalmente opcional. Veja web/README.md.

Instalação com um clique no Claude Desktop

Pegue o pacote .mcpb do último release e arraste-o para as configurações de extensões do Claude Desktop. Ele pedirá o caminho para o seu connections.json e configurará tudo.

Atualizando da versão 2.x

Seu connections.json existente funciona sem alterações — todo campo novo é opcional e as ferramentas aceitam os mesmos argumentos. Duas coisas que vale saber:

  • Multi-conexão estava quebrada antes da 3.0. O servidor usava o pool de conexões global mssql, que ignora a configuração recebida depois que uma conexão já está aberta. Na prática, toda conexão após a primeira reutilizava silenciosamente o servidor e o banco da primeira. Se você dependia de resultados de mais de uma conexão em uma sessão, eles podem não ter vindo de onde você pensava. Corrigido na 3.0 com um pool por conexão.
  • Se a configuração do seu agente aponta para node C:\path\to\index.js, isso continua funcionando. A ordem de resolução do arquivo agora verifica esse caminho por último, então nada muda.

Desenvolvimento

npm install
npm test                     # unit tests, no database needed
node .github/scripts/smoke.mjs   # packs, installs and speaks MCP to the tarball

Contra um servidor real, nomeie uma conexão do seu próprio arquivo:

MSSQL_TEST_CONNECTION=local npm run test:integration

O driver mssql é injetado, então os testes de unidade simulam apenas essa fronteira — todo o resto é o caminho real do código. test/contract.test.js congela os nomes e argumentos das ferramentas para que um refactor não altere a superfície MCP por acidente.

Licença

MIT — veja LICENSE.

Autor

Christian Velasquez — @cvelasquez

Issues · Changelog · Sponsor