sequelae-mcp
Version:
Let Claude, Cursor, and other AI agents run real SQL queries on live Postgres databases. No more copy-pasting SQL, stale schema docs, or hallucinated DB adapters — just raw, real-time access. Now with MCP support!
176 lines • 6.6 kB
JavaScript
;
/**
* MCP Tool Server for SQL Agent
* This module handles tool discovery and registration for MCP protocol
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.McpToolHandler = exports.SQL_AGENT_TOOLS = exports.SqlAgentMcpServer = void 0;
const tool_definition_1 = require("./tool-definition");
const tool_handler_1 = require("./tool-handler");
const rate_limiter_1 = require("../utils/rate-limiter");
class SqlAgentMcpServer {
constructor(rateLimiterOptions) {
this.handler = new tool_handler_1.McpToolHandler();
// Initialize rate limiter if options provided
if (rateLimiterOptions) {
this.rateLimiter = new rate_limiter_1.RateLimiter(rateLimiterOptions);
// Clean up expired records every minute
this.cleanupInterval = setInterval(() => {
this.rateLimiter?.cleanup();
}, 60000);
}
}
/**
* Get server information
*/
getServerInfo() {
return {
name: 'sequelae-mcp',
version: '1.0.0',
description: 'PostgreSQL query executor for AI assistants',
};
}
/**
* List available tools (for MCP discovery)
*/
listTools() {
return {
tools: tool_definition_1.SQL_AGENT_TOOLS.map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
})),
};
}
/**
* Handle incoming MCP requests
*/
async handleRequest(request) {
// Validate request structure
if (!request || typeof request !== 'object') {
return {
error: {
code: -32600,
message: 'Invalid request',
},
};
}
const req = request;
const method = req.method;
const params = req.params;
try {
switch (method) {
case 'initialize':
return {
serverInfo: this.getServerInfo(),
capabilities: {
tools: {},
},
};
case 'tools/list':
return this.listTools();
case 'tools/call':
if (!params || !params.name || !params.arguments) {
throw new Error('Invalid tool call parameters');
}
// Check rate limit if enabled
if (this.rateLimiter) {
// Use a connection identifier (could be enhanced with actual connection ID)
const identifier = 'default'; // In real implementation, this would be from connection context
const toolName = params.name;
const limitCheck = this.rateLimiter.checkLimit(identifier, toolName);
if (!limitCheck.allowed) {
return {
error: {
code: -32000,
message: 'Rate limit exceeded',
data: {
retryAfter: limitCheck.retryAfter,
usage: this.rateLimiter.getUsage(identifier),
},
},
};
}
}
return await this.handler.handleToolCall({
tool: params.name,
arguments: params.arguments,
});
default:
return {
error: {
code: -32601,
message: `Method not found: ${method}`,
},
};
}
}
catch (error) {
return {
error: {
code: -32603,
message: error instanceof Error ? error.message : 'Internal error',
},
};
}
}
/**
* Start the MCP server (stdio mode)
*/
async start() {
process.stdin.setEncoding('utf8');
let buffer = '';
process.stdin.on('data', async (chunk) => {
buffer += chunk;
// Look for complete JSON-RPC messages
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.trim()) {
try {
const request = JSON.parse(line);
const response = await this.handleRequest(request);
// Add JSON-RPC fields
const jsonRpcResponse = {
jsonrpc: '2.0',
id: request.id || null,
...response,
};
process.stdout.write(JSON.stringify(jsonRpcResponse) + '\n');
}
catch (_error) {
const errorResponse = {
jsonrpc: '2.0',
id: null,
error: {
code: -32700,
message: 'Parse error',
},
};
process.stdout.write(JSON.stringify(errorResponse) + '\n');
}
}
}
});
process.stdin.on('end', () => {
this.close();
});
}
/**
* Close the server and cleanup
*/
async close() {
// Clear rate limiter cleanup interval
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
}
await this.handler.close();
}
}
exports.SqlAgentMcpServer = SqlAgentMcpServer;
// Export everything needed for MCP
var tool_definition_2 = require("./tool-definition");
Object.defineProperty(exports, "SQL_AGENT_TOOLS", { enumerable: true, get: function () { return tool_definition_2.SQL_AGENT_TOOLS; } });
var tool_handler_2 = require("./tool-handler");
Object.defineProperty(exports, "McpToolHandler", { enumerable: true, get: function () { return tool_handler_2.McpToolHandler; } });
//# sourceMappingURL=index.js.map