---
# System prepended metadata

title: mssql-mcp-server 設定 for windows part1
tags: [MCP]

---

# mssql-mcp-server 設定 for windows pat1

來源: https://github.com/c0h1b4/mssql-mcp-server
這個原本應該是給 linux 環境使用
windows 環境無法直接執行，所以有以下的修改
<div style='color:red;'>
    ※ 提醒需要先安裝
    <a href='https://nodejs.org/zh-tw/download'> Node.js </a>
    才能執行下面的操作<br/>
</div>

## 修改程式

### src/index.ts

:::spoiler 原本
```js
#!/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);
}

}
```
:::
:::spoiler 修改
```js
#!/usr/bin/env node
import dotenv from 'dotenv';
dotenv.config();
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;
  }

  // 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 {
    const host = args.host ?? process.env.MSSQL_HOST;
    const port = args.port ?? parseInt(process.env.MSSQL_PORT || "1433");
    const database = args.database ?? process.env.MSSQL_DATABASE;
    const user = args.username ?? process.env.MSSQL_USER;
    const password = args.password ?? process.env.MSSQL_PASSWORD;
    const encrypt = args.encrypt !== undefined
      ? args.encrypt
      : process.env.MSSQL_ENCRYPT === "true";
    const trustServerCert = args.trustServerCertificate !== undefined
      ? args.trustServerCertificate
      : process.env.MSSQL_TRUST_SERVER_CERTIFICATE === "true";

    if (!host || !user || !password) {
      throw new McpError(ErrorCode.InvalidRequest, "Missing connection info: host/user/password");
    }

    return {
      server: host,
      port,
      database,
      user,
      password,
      options: {
        encrypt,
        trustServerCertificate: trustServerCert,
      },
    };
  }

  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']
            },
          },
        ],
      })
    );

    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');
  }
}

const server = new MssqlServer();
void server.run().catch(console.error);

```
:::

### package.json
原本↓
```json
"scripts": {
    "build": "tsc && chmod +x build/index.js",
    "start": "node build/index.js",
    "dev": "tsx watch src/index.ts",
    "lint": "eslint . --ext .ts",
    "format": "prettier --write \"src/**/*.ts\"",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage"
},
"dependencies": {
    "@modelcontextprotocol/sdk": "^0.1.0",
    "mssql": "^10.0.1"
  }
```
修改↓
```json
 "scripts": {
    "build": "tsc", // 拿掉 && chmod +x build/index.js
    "start": "node build/index.js",
    "dev": "tsx watch src/index.ts",
    "lint": "eslint . --ext .ts",
    "format": "prettier --write \"src/**/*.ts\"",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage"
  },
"dependencies": {
    "@modelcontextprotocol/sdk": "^1.10.1", // 抓最新的
    "mssql": "^10.0.1"
  }
```
``` @modelcontextprotocol/sdk ``` 版本號從這裡查: https://www.npmjs.com/package/@modelcontextprotocol/sdk

### tsconfig.json

原本↓
```json
"exclude": ["node_modules", "build"]
```

修改↓ (build 的時候過濾掉測試檔)
```json
"exclude": ["node_modules", "build", "src/index.test.ts","src/__tests__/server.test.ts"]
```

## 安裝

開啟 mssql-mcp-server 資料夾
在上方路徑的地方輸入 cmd

![image](https://hackmd.io/_uploads/BkWYBW-Jgx.png)

![image](https://hackmd.io/_uploads/By5jBZ-yeg.png)


![image](https://hackmd.io/_uploads/B1qneJW1gl.png)

輸入指令
``` cmd
npm install && npm install dotenv --save && npm run build
```
看到這個畫面代表執行成功
![image](https://hackmd.io/_uploads/S1YcIfS1le.png)

確認一下 mssql-mcp-server/build/src/index.js 有沒有出現
![image](https://hackmd.io/_uploads/HJl4Ub-yeg.png)

測試一下能不能執行 ``` node build/src/index.js ```

看到這個畫面代表前面的設定已完成，然後按 crtl+c 結束這個指令
![image](https://hackmd.io/_uploads/B1z_nebylg.png)

[mssql-mcp-server 設定 for windows part2 (設定到 claude desktop)](https://hackmd.io/@maddie-wang/BkL_EMHkle)
