Skip to main content
Glama

MSSQL MCP Server

by knight0zh
index.ts7.28 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import type { CallToolRequest, ListToolsRequest } from '@modelcontextprotocol/sdk/types.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import sql from 'mssql'; interface QueryArgs { connectionString?: string; host?: string; port?: number; database?: string; username?: string; password?: string; query: string; encrypt?: boolean; trustServerCertificate?: boolean; } const isValidQueryArgs = (args: unknown): args is QueryArgs => { const candidate = args as Record<string, unknown>; if (typeof candidate !== 'object' || candidate === null) { return false; } // Query is required if (typeof candidate.query !== 'string') { return false; } // Either connectionString OR (host + username + password) must be provided if (candidate.connectionString !== undefined) { if (typeof candidate.connectionString !== 'string') { return false; } } else { if (typeof candidate.host !== 'string') { return false; } if (typeof candidate.username !== 'string') { return false; } if (typeof candidate.password !== 'string') { return false; } } // Optional parameters if (candidate.port !== undefined && typeof candidate.port !== 'number') { return false; } if (candidate.database !== undefined && typeof candidate.database !== 'string') { return false; } if (candidate.encrypt !== undefined && typeof candidate.encrypt !== 'boolean') { return false; } if ( candidate.trustServerCertificate !== undefined && typeof candidate.trustServerCertificate !== 'boolean' ) { return false; } return true; }; export class MssqlServer { private server: Server; private pools: Map<string, sql.ConnectionPool>; constructor() { this.server = new Server( { name: 'mssql-server', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); this.pools = new Map(); this.setupToolHandlers(); // Error handling this.server.onerror = (error): void => console.error('[MCP Error]', error); process.on('SIGINT', () => { void this.cleanup(); process.exit(0); }); } private async cleanup(): Promise<void> { const closePromises = Array.from(this.pools.values()).map((pool) => pool.close()); await Promise.all(closePromises); this.pools.clear(); await this.server.close(); } private getConnectionConfig(args: QueryArgs): sql.config { if (args.connectionString) { return { server: args.connectionString, // Using server instead of connectionString as per mssql types }; } if (!args.host) { throw new McpError( ErrorCode.InvalidRequest, 'Host is required when not using connection string' ); } return { server: args.host, port: args.port || 1433, database: args.database || 'master', user: args.username, password: args.password, options: { encrypt: args.encrypt ?? false, trustServerCertificate: args.trustServerCertificate ?? true, }, }; } private async getPool(config: sql.config): Promise<sql.ConnectionPool> { const key = JSON.stringify(config); let pool = this.pools.get(key); if (!pool) { pool = new sql.ConnectionPool(config); await pool.connect(); this.pools.set(key, pool); } return pool; } async handleQuery(args: QueryArgs): Promise<{ content: Array<{ type: string; text: string }> }> { try { const config = this.getConnectionConfig(args); const pool = await this.getPool(config); const result = await pool.request().query(args.query); return { content: [ { type: 'text', text: JSON.stringify(result.recordset, null, 2), }, ], }; } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new McpError(ErrorCode.InternalError, `Database error: ${message}`); } } private setupToolHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, (_request: ListToolsRequest) => Promise.resolve({ tools: [ { name: 'query', description: 'Execute a SQL query on a MSSQL database', inputSchema: { type: 'object', properties: { connectionString: { type: 'string', description: 'Full connection string (alternative to individual parameters)', }, host: { type: 'string', description: 'Database server hostname', }, port: { type: 'number', description: 'Database server port (default: 1433)', }, database: { type: 'string', description: 'Database name (default: master)', }, username: { type: 'string', description: 'Database username', }, password: { type: 'string', description: 'Database password', }, query: { type: 'string', description: 'SQL query to execute', }, encrypt: { type: 'boolean', description: 'Enable encryption (default: false)', }, trustServerCertificate: { type: 'boolean', description: 'Trust server certificate (default: true)', }, }, required: ['query'], oneOf: [ { required: ['connectionString'] }, { required: ['host', 'username', 'password'] }, ], }, }, ], }) ); this.server.setRequestHandler( CallToolRequestSchema, async ( request: CallToolRequest ): Promise<{ content: Array<{ type: string; text: string }> }> => { const params = request.params as { name: string; arguments: unknown }; if (params.name !== 'query') { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${params.name}`); } if (!isValidQueryArgs(params.arguments)) { throw new McpError(ErrorCode.InvalidRequest, 'Invalid query arguments'); } return this.handleQuery(params.arguments); } ); } async run(): Promise<void> { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('MSSQL MCP server running on stdio'); } } // Only start the server if this file is being run directly if (import.meta.url === `file://${process.argv[1]}`) { const server = new MssqlServer(); void server.run().catch(console.error); }

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/knight0zh/mssql-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server