index.ts•3.87 kB
#!/usr/bin/env node
/**
 * MCP Server for interacting with the BlazeSQL Natural Language Query API.
 * Exposes the BlazeSQL query functionality as an MCP tool using McpServer.
 */
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // Reverted import path
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Reverted import path
import 'dotenv/config'; // Load environment variables from .env file
import { queryBlazeSQL, BlazeSQLResponse } from './blazesql.js'; // Import the function and types
import { z } from "zod"; // Import Zod for schema validation
// --- API Key Loading ---
const apiKey = process.env.BLAZE_API_KEY;
if (!apiKey) {
    console.error("FATAL ERROR: BLAZE_API_KEY environment variable is not set.");
    console.error("Please create a .env file based on .env.example and add your API key.");
    process.exit(1); // Exit if the key is missing
}
console.error("API Key loaded successfully.");
// --- Server Initialization ---
const server = new McpServer( // Changed to McpServer
  {
    name: "BlazeSQL MCP Server",
    version: "0.2.0", // Updated version
  }
  // Capabilities are inferred by McpServer when tools are added
);
// --- Register Tool using server.tool() ---
server.tool(
    "blazesql_query", // Tool name
    {
        db_id: z.string().describe("The ID of the BlazeSQL database connection to query."),
        natural_language_request: z.string().describe("The query expressed in natural language (e.g., 'show me total users per city').")
    },
    // Tool handler function - TS should infer params type from raw shape now
    async (params) => {
        const { db_id, natural_language_request } = params;
        // Input validation is handled by Zod schema above
        console.error(`Executing BlazeSQL query for DB ID: ${db_id}`);
        console.error(`Natural Language Request: "${natural_language_request}"`);
        // Call the BlazeSQL API function - apiKey is guaranteed non-null here
        const result: BlazeSQLResponse = await queryBlazeSQL(db_id, natural_language_request, apiKey!);
        if (result.success) {
            console.error("BlazeSQL query successful. Returning structured results as formatted text.");
            // Format the output into a single text block with Markdown
            const outputText = `**Agent Response:**\n${result.agent_response}\n\n**Generated SQL:**\n\`\`\`sql\n${result.query ?? "-- No SQL query returned"}\n\`\`\`\n\n**Data Result (JSON):**\n\`\`\`json\n${JSON.stringify(result.data_result ?? {}, null, 2)}\n\`\`\`\n`;
            // Return a single text content block
            return {
                content: [
                    {
                        type: "text",
                        text: outputText
                    }
                ]
            };
        } else {
            // Handle API errors - Throwing an error is standard for tool failures
            console.error(`BlazeSQL API Error (Code ${result.error_code}): ${result.error}`);
            // Return error message as text content
            return {
                content: [
                    { type: "text", text: `BlazeSQL API Error: ${result.error}` }
                ],
                isError: true // Indicate it's an error response
            };
        }
    }
);
console.error(`Tool 'blazesql_query' registered using McpServer.`);
// --- Server Startup ---
console.error("BlazeSQL MCP Server configuring...");
/**
 * Start the server using stdio transport.
 */
async function main() {
  const transport = new StdioServerTransport();
  console.error("Connecting transport...");
  await server.connect(transport);
  console.error("BlazeSQL MCP Server is running and connected via stdio.");
}
main().catch((error) => {
  console.error("Server encountered fatal error:", error);
  process.exit(1);
});