pmi-mcp-server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pmi-mcp-serverexecute SELECT TOP 10 * FROM Orders ORDER BY OrderDate DESC"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
PMI MCP Server for SQL Server
Server MCP in Python che espone il tool execute_query e inoltra il testo SQL
ricevuto direttamente a Microsoft SQL Server tramite pyodbc.
Il server non analizza, riscrive, filtra o limita le query. Autorizzazioni, permessi e guardrail SQL sono responsabilità del database e dell'utenza usata nella stringa di connessione.
Piattaforme supportate
Il codice del server è indipendente dal sistema operativo ed è predisposto per:
Windows 10/11 e Windows Server
macOS Intel e Apple Silicon
Linux nelle distribuzioni supportate dal Microsoft ODBC Driver 18
La matrice CI esegue i test su Windows, macOS e Ubuntu.
Related MCP server: SQL Server MCP Server
Requisiti comuni
Python 3.10 o successivo
Microsoft ODBC Driver 18 for SQL Server
Un ODBC driver manager (
unixODBC) su macOS/Linux; su Windows è già incluso nel sistema operativoAccesso a un'istanza Microsoft SQL Server
Driver ODBC
Windows
Installa il Microsoft Visual C++ Redistributable adatto all'architettura del sistema, se non è già presente.
Scarica e installa Microsoft ODBC Driver 18 for SQL Server scegliendo x64, x86 oppure ARM64 in base al sistema.
Verifica da PowerShell che il driver sia registrato:
Get-OdbcDriver -Name "ODBC Driver 18 for SQL Server"Python e il driver ODBC devono avere architetture compatibili. In una normale installazione Windows x64, usa Python x64 e il driver x64.
macOS
Con Homebrew:
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
HOMEBREW_ACCEPT_EULA=Y brew install msodbcsql18Il pacchetto installa anche unixODBC come dipendenza.
Linux
Microsoft pubblica pacchetti per Ubuntu, Debian, RHEL, Oracle Linux, SLES, Alpine e Azure Linux. Segui la procedura ufficiale per la distribuzione utilizzata. Ad esempio, dopo aver configurato il repository Microsoft su Ubuntu/Debian:
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-devInstallazione Python
Con uv:
uv syncCon pip su macOS/Linux:
python -m venv .venv
source .venv/bin/activate
python -m pip install -e .Con pip da PowerShell su Windows:
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e .Configurazione
Usa .env.example come riferimento e passa le variabili nell'ambiente del
processo MCP. La sola variabile obbligatoria è:
SQLSERVER_CONNECTION_STRING=DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=my_database;UID=my_user;PWD=my_password;Encrypt=yes;TrustServerCertificate=noVariabili opzionali:
Variabile | Default | Descrizione |
|
| Se |
|
| Timeout della connessione in secondi |
|
|
|
|
| Host usato con Streamable HTTP |
|
| Porta usata con Streamable HTTP |
| — | Token opzionale, lungo almeno 32 caratteri, richiesto a ogni chiamata HTTP |
| — | Percorso del certificato TLS in formato PEM |
| — | Percorso della chiave privata TLS in formato PEM |
| — | Password opzionale della chiave privata |
Il file .env non viene caricato automaticamente dal processo: configura le
variabili nel client MCP o impostale nell'ambiente prima dell'avvio. Questo
evita differenze di caricamento tra Windows e sistemi Unix.
Su Windows è possibile usare anche l'autenticazione integrata dell'identità che avvia il processo MCP:
SQLSERVER_CONNECTION_STRING=DRIVER={ODBC Driver 18 for SQL Server};SERVER=my-server;DATABASE=my_database;Trusted_Connection=yes;Encrypt=yes;TrustServerCertificate=noPer verificare che Python rilevi il driver installato:
python -c "import pyodbc; print(pyodbc.drivers())"L'output deve includere ODBC Driver 18 for SQL Server.
Autenticazione Bearer
Imposta MCP_BEARER_TOKEN per proteggere tutte le richieste Streamable HTTP.
Il token deve contenere almeno 32 caratteri. Puoi generarne uno casuale su tutte
le piattaforme con Python:
python -c "import secrets; print(secrets.token_urlsafe(32))"Esempio di avvio:
MCP_TRANSPORT=streamable-http \
MCP_BEARER_TOKEN='inserire-un-token-casuale-di-almeno-32-caratteri' \
SQLSERVER_CONNECTION_STRING='...' \
uv run pmi-mcp-serverIl client deve inviare questo header:
Authorization: Bearer inserire-un-token-casuale-di-almeno-32-caratteriUna richiesta priva del token corretto riceve 401 Unauthorized. Il confronto
avviene in tempo costante e il token non viene scritto nei log. Se la variabile
non è configurata, l'autenticazione HTTP resta disabilitata. Usa sempre HTTPS
quando il token attraversa una rete non fidata.
HTTPS
Il trasporto Streamable HTTP usa HTTPS automaticamente quando sono configurati
entrambi MCP_TLS_CERT_FILE e MCP_TLS_KEY_FILE. Se uno dei due manca o il
percorso non esiste, il server termina subito con un errore di configurazione.
I percorsi possono usare la sintassi nativa di Windows, macOS o Linux.
Esempio macOS/Linux:
MCP_TRANSPORT=streamable-http \
MCP_HOST=127.0.0.1 \
MCP_PORT=8443 \
MCP_TLS_CERT_FILE=/percorso/server-cert.pem \
MCP_TLS_KEY_FILE=/percorso/server-key.pem \
SQLSERVER_CONNECTION_STRING='...' \
uv run pmi-mcp-serverEsempio Windows PowerShell:
$env:MCP_TRANSPORT = "streamable-http"
$env:MCP_HOST = "127.0.0.1"
$env:MCP_PORT = "8443"
$env:MCP_BEARER_TOKEN = "inserire-un-token-casuale-di-almeno-32-caratteri"
$env:MCP_TLS_CERT_FILE = "C:\certificati\server-cert.pem"
$env:MCP_TLS_KEY_FILE = "C:\certificati\server-key.pem"
$env:SQLSERVER_CONNECTION_STRING = "..."
.\.venv\Scripts\pmi-mcp-server.exeIl client si collega quindi a https://127.0.0.1:8443/mcp. Il certificato deve
contenere l'indirizzo o il nome host usato dal client nel campo Subject
Alternative Name e deve essere considerato attendibile dal sistema del client.
Per ambienti di produzione è generalmente preferibile terminare TLS su un
reverse proxy o load balancer e lasciare il server MCP su una rete privata.
Esempio generico di client MCP con URL e Bearer token:
{
"mcpServers": {
"sql-server": {
"url": "https://127.0.0.1:8443/mcp",
"headers": {
"Authorization": "Bearer inserire-un-token-casuale-di-almeno-32-caratteri"
}
}
}
}La sintassi esatta degli header e l'eventuale lettura del token da una variabile d'ambiente dipendono dal client MCP utilizzato. Non salvare token reali nel repository.
Avvio
macOS/Linux
Trasporto locale stdio:
SQLSERVER_CONNECTION_STRING='...' uv run pmi-mcp-serverTrasporto Streamable HTTP:
MCP_TRANSPORT=streamable-http MCP_PORT=8000 \
SQLSERVER_CONNECTION_STRING='...' uv run pmi-mcp-serverL'endpoint predefinito è http://127.0.0.1:8000/mcp.
Windows PowerShell
Trasporto locale stdio:
$env:SQLSERVER_CONNECTION_STRING = "DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=my_database;UID=my_user;PWD=my_password;Encrypt=yes;TrustServerCertificate=no"
.\.venv\Scripts\pmi-mcp-server.exeTrasporto Streamable HTTP:
$env:MCP_TRANSPORT = "streamable-http"
$env:MCP_HOST = "127.0.0.1"
$env:MCP_PORT = "8000"
$env:SQLSERVER_CONNECTION_STRING = "DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=my_database;UID=my_user;PWD=my_password;Encrypt=yes;TrustServerCertificate=no"
.\.venv\Scripts\pmi-mcp-server.exeConfigurazione del client MCP
macOS/Linux:
{
"mcpServers": {
"sql-server": {
"command": "uv",
"args": [
"--directory",
"/percorso/assoluto/pmi-mcp-server",
"run",
"pmi-mcp-server"
],
"env": {
"SQLSERVER_CONNECTION_STRING": "DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=my_database;UID=my_user;PWD=my_password;Encrypt=yes;TrustServerCertificate=no"
}
}
}
}Windows (nei file JSON i backslash devono essere duplicati):
{
"mcpServers": {
"sql-server": {
"command": "C:\\percorso\\pmi-mcp-server\\.venv\\Scripts\\pmi-mcp-server.exe",
"args": [],
"env": {
"SQLSERVER_CONNECTION_STRING": "DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost,1433;DATABASE=my_database;UID=my_user;PWD=my_password;Encrypt=yes;TrustServerCertificate=no"
}
}
}
}Tool MCP
execute_query
Input:
{
"query": "SELECT TOP (10) * FROM dbo.Customers"
}Output:
{
"result_sets": [
{
"columns": ["CustomerId", "Name"],
"rows": [[1, "Acme"]],
"row_count": 1
}
]
}Il tool restituisce tutti i result set. decimal, date/ore e UUID vengono
serializzati come stringhe; i valori binari sono codificati in Base64. Le query
senza righe restituiscono comunque un result set con columns e rows vuoti.
Guardrail SQL
Il server inoltra il testo SQL senza analizzarlo. I controlli devono quindi essere applicati da SQL Server secondo il principio del privilegio minimo.
Architettura consigliata
Crea un database di reporting separato, ad esempio
McpReporting. Non collegare l'utenza MCP direttamente al database transazionale.Popola il database tramite ETL, replica o snapshot gestiti da un'identità diversa da quella MCP.
Crea uno schema di esposizione per ogni reparto, ad esempio
sales,financeehr.Inserisci negli schemi di reparto esclusivamente viste. Conserva le tabelle materializzate in schemi interni, non accessibili all'utenza MCP.
Crea un login, un utente e un ruolo differenti per ogni reparto. Se più reparti devono essere isolati, avvia un'istanza MCP per reparto con la sua stringa di connessione.
Concedi
SELECTalle singole viste, non all'intero schema. UnGRANT SELECT ON SCHEMAcomprenderebbe anche eventuali tabelle aggiunte in futuro.Non aggiungere l'utenza ai ruoli
db_owner,db_datareader,db_datawriter,db_ddladmin,db_securityadminosysadmin.
Le viste sono utilizzabili come barriera di sicurezza senza concedere accesso
diretto alle tabelle sottostanti. Quando possibile, usa SCHEMABINDING, elenca
esplicitamente le colonne ed escludi o maschera i dati sensibili.
1. Database e schemi separati
Esegui come amministratore e sostituisci nomi e oggetti di esempio:
USE [master];
GO
IF DB_ID(N'McpReporting') IS NULL
BEGIN
CREATE DATABASE [McpReporting];
END;
GO
USE [McpReporting];
GO
-- Schemi interni: contengono le tabelle alimentate dall'ETL.
CREATE SCHEMA [internal_sales] AUTHORIZATION [dbo];
GO
CREATE SCHEMA [internal_finance] AUTHORIZATION [dbo];
GO
CREATE SCHEMA [internal_hr] AUTHORIZATION [dbo];
GO
-- Schemi pubblicati: devono contenere esclusivamente viste.
CREATE SCHEMA [sales] AUTHORIZATION [dbo];
GO
CREATE SCHEMA [finance] AUTHORIZATION [dbo];
GO
CREATE SCHEMA [hr] AUTHORIZATION [dbo];
GOSe uno schema esiste già, ometti il relativo CREATE SCHEMA.
2. Esporre esclusivamente viste
Esempio per il reparto vendite:
USE [McpReporting];
GO
CREATE VIEW [sales].[v_customers]
WITH SCHEMABINDING
AS
SELECT
[CustomerId],
[CustomerName],
[CountryCode]
FROM [internal_sales].[Customers];
GO
CREATE VIEW [sales].[v_orders]
WITH SCHEMABINDING
AS
SELECT
[OrderId],
[CustomerId],
[OrderDate],
[NetAmount]
FROM [internal_sales].[Orders];
GONon usare SELECT * nelle viste. Con SCHEMABINDING, gli oggetti referenziati
devono trovarsi nello stesso database ed essere indicati con nome a due parti.
3. Utente e ruolo dedicati
Il login può essere SQL Server, Windows o Microsoft Entra. Dopo averlo creato con il sistema di identità scelto, mappalo nel solo database di reporting:
USE [McpReporting];
GO
CREATE USER [mcp_sales_user] FOR LOGIN [mcp_sales_login];
GO
CREATE ROLE [mcp_sales_reader] AUTHORIZATION [dbo];
GO
ALTER ROLE [mcp_sales_reader] ADD MEMBER [mcp_sales_user];
GO
GRANT CONNECT TO [mcp_sales_reader];
GONon creare lo stesso utente negli altri database e non concedere
CONNECT ANY DATABASE al login.
4. Consentire SELECT solo sulle viste autorizzate
La variante più restrittiva concede ogni vista esplicitamente:
USE [McpReporting];
GO
GRANT SELECT ON OBJECT::[sales].[v_customers]
TO [mcp_sales_reader];
GRANT SELECT ON OBJECT::[sales].[v_orders]
TO [mcp_sales_reader];
GO
-- Nessun accesso diretto alle tabelle interne.
DENY SELECT ON SCHEMA::[internal_sales]
TO [mcp_sales_reader];
DENY SELECT ON SCHEMA::[internal_finance]
TO [mcp_sales_reader];
DENY SELECT ON SCHEMA::[internal_hr]
TO [mcp_sales_reader];
GORipeti il modello con un ruolo diverso per finance e hr. Quando viene
pubblicata una nuova vista, concedila esplicitamente dopo la revisione.
5. Bloccare scrittura, esecuzione e DDL
L'assenza di permessi è già sufficiente a negare le operazioni; i DENY
seguenti rendono esplicita la policy e impediscono che permessi meno restrittivi
ereditati da altri ruoli le riabilitino:
USE [McpReporting];
GO
-- DML: blocca INSERT, UPDATE, DELETE e quindi anche MERGE.
DENY INSERT, UPDATE, DELETE
TO [mcp_sales_reader];
-- Stored procedure e funzioni eseguibili.
DENY EXECUTE
TO [mcp_sales_reader];
-- Controllo, modifica degli oggetti e cambio di proprietà.
DENY ALTER, CONTROL, TAKE OWNERSHIP, VIEW DEFINITION
TO [mcp_sales_reader];
-- Creazione di oggetti nel database.
DENY CREATE TABLE, CREATE VIEW, CREATE PROCEDURE, CREATE FUNCTION,
CREATE SYNONYM, CREATE TYPE, CREATE SCHEMA
TO [mcp_sales_reader];
GOQuesti permessi bloccano anche:
TRUNCATE TABLE, perché richiedeALTERsulla tabella;DROPeALTERdegli oggetti;SELECT ... INTOpermanente, perché l'utente non può creare tabelle;WITH ... INSERT,WITH ... UPDATE,WITH ... DELETEeWITH ... MERGE, perché mancano i relativi permessi DML;chiamate a stored procedure tramite
EXEC/EXECUTE.
WITH non è un permesso SQL Server separato: introduce una CTE che può essere
usata da SELECT, INSERT, UPDATE, MERGE o DELETE. Con questa policy è
consentita solo quando l'operazione finale è un SELECT autorizzato.
6. Rendere il database read-only, quando possibile
Per snapshot o database aggiornati solo tramite sostituzione completa, una
seconda barriera consiste nel renderli READ_ONLY dopo il caricamento:
USE [master];
GO
ALTER DATABASE [McpReporting]
SET READ_ONLY
WITH ROLLBACK IMMEDIATE;
GO
SELECT
[name],
[is_read_only]
FROM sys.databases
WHERE [name] = N'McpReporting';
GONon applicare questa opzione se l'ETL deve aggiornare continuamente lo stesso
database. In quel caso mantieni READ_WRITE, usa un'identità ETL separata e
lascia l'utente MCP con i soli permessi descritti sopra.
7. Query di collaudo
Esegui come amministratore questa verifica, che non modifica dati:
USE [McpReporting];
GO
EXECUTE AS USER = N'mcp_sales_user';
GO
-- Deve riuscire.
SELECT TOP (10)
[CustomerId],
[CustomerName]
FROM [sales].[v_customers];
-- Deve riuscire: WITH termina con SELECT.
WITH [recent_customers] AS
(
SELECT [CustomerId], [CustomerName]
FROM [sales].[v_customers]
)
SELECT *
FROM [recent_customers];
-- SELECT sulla vista deve valere 1; tutti gli altri controlli devono valere 0.
SELECT
HAS_PERMS_BY_NAME(
N'sales.v_customers', N'OBJECT', N'SELECT'
) AS [CanSelectPublishedView],
HAS_PERMS_BY_NAME(
N'internal_sales.Customers', N'OBJECT', N'SELECT'
) AS [CanSelectInternalTable],
HAS_PERMS_BY_NAME(
N'McpReporting', N'DATABASE', N'INSERT'
) AS [CanInsert],
HAS_PERMS_BY_NAME(
N'McpReporting', N'DATABASE', N'UPDATE'
) AS [CanUpdate],
HAS_PERMS_BY_NAME(
N'McpReporting', N'DATABASE', N'DELETE'
) AS [CanDelete],
HAS_PERMS_BY_NAME(
N'McpReporting', N'DATABASE', N'EXECUTE'
) AS [CanExecute],
HAS_PERMS_BY_NAME(
N'McpReporting', N'DATABASE', N'CREATE TABLE'
) AS [CanCreateTable];
GO
REVERT;
GOAccedi poi con il login MCP reale ed esegui singolarmente le query seguenti. Ognuna deve fallire per autorizzazione:
UPDATE [sales].[v_customers]
SET [CustomerName] = N'blocked'
WHERE [CustomerId] = -1;DELETE FROM [sales].[v_customers]
WHERE [CustomerId] = -1;WITH [target] AS
(
SELECT *
FROM [sales].[v_customers]
)
DELETE FROM [target]
WHERE [CustomerId] = -1;SELECT *
FROM [internal_sales].[Customers];CREATE TABLE [sales].[ShouldFail] ([Id] int NOT NULL);Verifica inoltre che la stringa SQLSERVER_CONNECTION_STRING del server MCP
utilizzi mcp_sales_login e punti esplicitamente a McpReporting.
Limite della policy basata sui permessi
I permessi SQL Server impediscono accesso, modifica ed esecuzione sugli oggetti,
ma non costituiscono una allowlist lessicale delle parole SQL: istruzioni di
sessione come SET o controllo di transazione possono essere accettate senza
consentire modifiche ai dati. Per bloccare sintatticamente qualsiasi testo che
non inizi con SELECT o WITH servirebbe anche un parser nel server o un proxy
SQL. La configurazione sopra mantiene invece i guardrail interamente nel
database, come previsto dal progetto, e rende inefficaci le operazioni non
autorizzate.
Riferimenti Microsoft: sicurezza tramite viste,
permessi sugli schema, CTE WITH e
database READ_ONLY.
Test
uv run --extra dev pytestSu Windows senza uv:
.\.venv\Scripts\python.exe -m pytestTool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Official Microsoft MCP Server to query Microsoft Entra data using natural language
MCP server for querying and analyzing data from ad platforms, analytics tools, and spreadsheets
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Related MCP Servers
- FlicenseAqualityDmaintenanceMCP server for connecting to SQL Server in readonly mode. Allows any MCP client to explore the schema and run SELECT queries against a SQL Server database.6-
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables querying SQL Server databases via tools for table search, SELECT execution, and table info retrieval.-
- AlicenseNot gradedqualityDmaintenanceMCP server for executing SQL queries and managing connections to Microsoft SQL Server databases.2,2891MIT
- FlicenseAqualityCmaintenanceLocal stdio MCP server for read-only Microsoft SQL Server access through Python and pyodbc, providing test connection, list tables, describe table, and query tools.4-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/diegoluppi1993/pmi-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server