Skip to main content
Glama
NakiriYuuzu

MSSQL MCP Server

by NakiriYuuzu

execute-query

Execute SQL queries on a Microsoft SQL Server database using the MSSQL MCP Server. Specify queries and optional result limits to retrieve data securely and efficiently.

Instructions

執行 SQL 查詢語句

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNo結果筆數限制 (預設: 100)
queryYes要執行的 SQL 查詢語句

Implementation Reference

  • The primary handler function for the 'execute-query' tool. It checks connection, validates the query for safety using validateReadOnlyQuery, adds a TOP limit, executes the query via MSSQLManager.executeQuery, formats the result as a table using formatResultAsTable, and returns the output or error.
    async ({ query, limit }) => {
      try {
        if (!mssqlManager.isConnected()) {
          return {
            content: [
              {
                type: 'text' as const,
                text: '錯誤: 尚未連接到資料庫伺服器。請先使用 connect-database 工具建立連接。'
              }
            ]
          }
        }
    
        // 驗證查詢安全性
        const validation = validateReadOnlyQuery(query)
        if (!validation.isValid) {
          return {
            content: [
              {
                type: 'text' as const,
                text: `查詢被拒絕: ${validation.reason}`
              }
            ]
          }
        }
    
        // 加入 TOP 限制
        const finalQuery = addTopLimit(query, limit)
    
        const result = await mssqlManager.executeQuery(finalQuery)
    
        if (result.recordset.length === 0) {
          return {
            content: [
              {
                type: 'text' as const,
                text: '查詢執行成功,但沒有返回任何資料。'
              }
            ]
          }
        }
    
        // 使用改進的表格格式化
        const tableOutput = formatResultAsTable(result.recordset, limit)
    
        return {
          content: [
            {
              type: 'text' as const,
              text: `查詢執行成功:\n\n${tableOutput}`
            }
          ]
        }
      } catch (error) {
        return {
          content: [
            {
              type: 'text' as const,
              text: `查詢執行失敗: ${formatError(error)}`
            }
          ]
        }
      }
    }
  • Zod input schema for the 'execute-query' tool, defining the required 'query' string parameter and optional 'limit' number (default 100).
    inputSchema: {
      query: z.string().describe('要執行的 SQL 查詢語句'),
      limit: z.number().optional().default(100).describe('結果筆數限制 (預設: 100)'),
    }
  • src/index.ts:354-428 (registration)
    MCP server registration of the 'execute-query' tool, including name, title, description, input schema, and handler function.
    server.registerTool(
      'execute-query',
      {
        title: '執行查詢',
        description: '執行 SQL 查詢語句',
        inputSchema: {
          query: z.string().describe('要執行的 SQL 查詢語句'),
          limit: z.number().optional().default(100).describe('結果筆數限制 (預設: 100)'),
        }
      },
      async ({ query, limit }) => {
        try {
          if (!mssqlManager.isConnected()) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: '錯誤: 尚未連接到資料庫伺服器。請先使用 connect-database 工具建立連接。'
                }
              ]
            }
          }
    
          // 驗證查詢安全性
          const validation = validateReadOnlyQuery(query)
          if (!validation.isValid) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `查詢被拒絕: ${validation.reason}`
                }
              ]
            }
          }
    
          // 加入 TOP 限制
          const finalQuery = addTopLimit(query, limit)
    
          const result = await mssqlManager.executeQuery(finalQuery)
    
          if (result.recordset.length === 0) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: '查詢執行成功,但沒有返回任何資料。'
                }
              ]
            }
          }
    
          // 使用改進的表格格式化
          const tableOutput = formatResultAsTable(result.recordset, limit)
    
          return {
            content: [
              {
                type: 'text' as const,
                text: `查詢執行成功:\n\n${tableOutput}`
              }
            ]
          }
        } catch (error) {
          return {
            content: [
              {
                type: 'text' as const,
                text: `查詢執行失敗: ${formatError(error)}`
              }
            ]
          }
        }
      }
    )
  • MSSQLManager.executeQuery method: executes the SQL query using the mssql library's ConnectionPool.request().query() and returns structured QueryResult.
    async executeQuery(query: string): Promise<QueryResult> {
      if (!this.isConnected() || !this.pool) {
        throw new Error('尚未建立資料庫連接')
      }
    
      try {
        const request = this.pool.request()
        const result = await request.query(query)
        
        return {
          recordset: result.recordset || [],
          recordsets: result.recordsets ? (Array.isArray(result.recordsets) ? result.recordsets.map(rs => Array.from(rs)) : [Array.from(result.recordsets as any)]) : [],
          rowsAffected: Array.isArray(result.rowsAffected) ? result.rowsAffected : [result.rowsAffected || 0],
          output: result.output || {}
        }
      } catch (error) {
        throw new Error(`執行查詢失敗: ${error instanceof Error ? error.message : String(error)}`)
      }
    }
  • Utility function that validates the SQL query for read-only compliance, blocks dangerous keywords, checks permissions via environment variables, and prevents multi-statement queries.
    export function validateReadOnlyQuery(query: string): { isValid: boolean; reason?: string } {
      const trimmedQuery = query.trim().toLowerCase()
      
      // 檢查是否為空查詢
      if (!trimmedQuery) {
        return { isValid: false, reason: '查詢語句不能為空' }
      }
    
      // 檢查是否包含分號後的額外語句(防止 SQL 注入)
      const statements = query.split(';').filter(stmt => stmt.trim())
      if (statements.length > 1) {
        return { 
          isValid: false, 
          reason: '不允許執行多個 SQL 語句' 
        }
      }
    
      // 檢查環境變數權限設定
      const ALLOW_INSERT = process.env.MSSQL_ALLOW_INSERT === 'true'
      const ALLOW_UPDATE = process.env.MSSQL_ALLOW_UPDATE === 'true'
      const ALLOW_DELETE = process.env.MSSQL_ALLOW_DELETE === 'true'
      const DANGER_MODE = process.env.MSSQL_DANGER_MODE === 'true'
    
      // 如果啟用了 danger mode,允許所有操作
      if (DANGER_MODE) {
        process.stderr.write('[WARNING] Danger mode is enabled - allowing all SQL operations\n')
        return { isValid: true }
      }
    
      // 定義永遠危險的關鍵字(即使在 danger mode 下也應該謹慎)
      const alwaysDangerousKeywords = [
        'drop', 'truncate', 'alter', 'create', 
        'grant', 'revoke', 'deny', 'execute', 'exec',
        'sp_', 'xp_', 'backup', 'restore', 'rename'
      ]
    
      // 定義可選權限關鍵字
      const permissionKeywords = {
        insert: { allowed: ALLOW_INSERT, keyword: 'insert' },
        update: { allowed: ALLOW_UPDATE, keyword: 'update' },
        delete: { allowed: ALLOW_DELETE, keyword: 'delete' },
        merge: { allowed: ALLOW_INSERT && ALLOW_UPDATE, keyword: 'merge' },
        replace: { allowed: ALLOW_INSERT && ALLOW_DELETE, keyword: 'replace' }
      }
    
      // 檢查永遠危險的關鍵字
      for (const keyword of alwaysDangerousKeywords) {
        const pattern = new RegExp(`\\b${keyword}\\b`, 'i')
        if (pattern.test(trimmedQuery)) {
          return { 
            isValid: false, 
            reason: `查詢包含高危險關鍵字: ${keyword.toUpperCase()}。此操作被禁止。` 
          }
        }
      }
    
      // 檢查需要權限的關鍵字
      for (const [key, config] of Object.entries(permissionKeywords)) {
        const pattern = new RegExp(`\\b${config.keyword}\\b`, 'i')
        if (pattern.test(trimmedQuery)) {
          if (!config.allowed) {
            return { 
              isValid: false, 
              reason: `查詢包含 ${config.keyword.toUpperCase()} 操作,但未授予此權限。請設定環境變數 MSSQL_ALLOW_${key.toUpperCase()}=true 來啟用。` 
            }
          }
          // 如果有權限,記錄警告
          process.stderr.write(`[INFO] Executing ${config.keyword.toUpperCase()} operation with permission\n`)
          return { isValid: true }
        }
      }
    
      // 檢查是否為 SELECT 查詢
      if (!trimmedQuery.startsWith('select') && !trimmedQuery.startsWith('with')) {
        // 如果不是 SELECT 但也不包含上述關鍵字,可能是其他查詢類型
        return { 
          isValid: false, 
          reason: '僅允許 SELECT 查詢、WITH 子句查詢,或已授權的 DML 操作' 
        }
      }
    
      return { isValid: true }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions execution but doesn't specify whether this is read-only or can modify data, what permissions are required, potential rate limits, error handling, or output format. For a tool that executes arbitrary SQL queries, this lack of transparency is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise at just four Chinese characters, with zero wasted words. It's front-loaded with the core action and resource. While potentially too brief for completeness, it earns full marks for conciseness and structure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of executing arbitrary SQL queries, no annotations, no output schema, and sibling tools that suggest database operations, the description is inadequate. It doesn't address critical context like connection requirements, safety considerations, or what happens when queries fail. The description should do more to help an agent use this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with clear documentation for both parameters ('query' and 'limit'). The description doesn't add any meaningful semantic information beyond what the schema already provides, such as query syntax examples or limit implications. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description '執行 SQL 查詢語句' (Execute SQL query statement) clearly states the tool's action (execute) and resource (SQL query), but it's vague about scope and doesn't distinguish from siblings like 'describe-table' or 'list-tables' which also involve database operations. It provides basic purpose but lacks specificity about what kind of queries or databases it works with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'describe-table' or 'list-tables', nor does it mention prerequisites such as needing an active database connection. It simply states what the tool does without context about appropriate use cases or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

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/NakiriYuuzu/Mssql-Mcp'

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