Skip to main content
Glama
index.ts4.28 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { createExecuteSqlToolHandler } from "./execute-sql.js"; import { createSearchDatabaseObjectsToolHandler, searchDatabaseObjectsSchema } from "./search-objects.js"; import { ConnectorManager } from "../connectors/manager.js"; import { getToolMetadataForSource } from "../utils/tool-metadata.js"; import { normalizeSourceId } from "../utils/normalize-id.js"; import { isReadOnlySQL } from "../utils/allowed-keywords.js"; import { customToolRegistry } from "./custom-tool-registry.js"; import { createCustomToolHandler, buildZodSchemaFromParameters } from "./custom-tool-handler.js"; import type { ToolConfig } from "../types/config.js"; /** * Register all tool handlers with the MCP server * Creates tools for each configured database source, plus custom tools from TOML * @param server - The MCP server instance */ export function registerTools(server: McpServer): void { // Get all configured source IDs const sourceIds = ConnectorManager.getAvailableSourceIds(); if (sourceIds.length === 0) { throw new Error("No database sources configured"); } // Register tools for each source for (const sourceId of sourceIds) { const isDefault = sourceIds[0] === sourceId; const sourceConfig = ConnectorManager.getSourceConfig(sourceId); const dbType = sourceConfig?.type || "database"; // 1. execute_sql tool (existing) const executeSqlMetadata = getToolMetadataForSource(sourceId); server.registerTool( executeSqlMetadata.name, { description: executeSqlMetadata.description, inputSchema: executeSqlMetadata.schema, annotations: executeSqlMetadata.annotations, }, createExecuteSqlToolHandler(sourceId) ); // 2. search_objects tool (unified search and list) const searchToolName = sourceId === "default" ? "search_objects" : `search_objects_${normalizeSourceId(sourceId)}`; const searchToolTitle = isDefault ? `Search Database Objects (${dbType})` : `Search Database Objects on ${sourceId} (${dbType})`; const searchToolDescription = `Search and list database objects (schemas, tables, columns, procedures, indexes) on the '${sourceId}' ${dbType} database${isDefault ? " (default)" : ""}. Supports SQL LIKE patterns (default: '%' for all), filtering, and token-efficient progressive disclosure.`; server.registerTool( searchToolName, { description: searchToolDescription, inputSchema: searchDatabaseObjectsSchema, annotations: { title: searchToolTitle, readOnlyHint: true, destructiveHint: false, idempotentHint: true, // Operation is read-only and idempotent openWorldHint: true, }, }, createSearchDatabaseObjectsToolHandler(sourceId) ); } // Register custom tools from TOML configuration // The registry was already initialized and validated by server.ts if (customToolRegistry.isInitialized()) { const validatedTools = customToolRegistry.getTools(); console.error(`Registering ${validatedTools.length} custom tool(s) from configuration...`); for (const toolConfig of validatedTools) { const sourceConfig = ConnectorManager.getSourceConfig(toolConfig.source); const dbType = sourceConfig?.type || "database"; // Determine if the tool is read-only based on its SQL statement // Use the shared isReadOnlySQL function for consistent behavior with execute-sql const isReadOnly = isReadOnlySQL(toolConfig.statement, dbType); // Build Zod schema object (same format as built-in tools) const zodSchema = buildZodSchemaFromParameters(toolConfig.parameters); server.registerTool( toolConfig.name, { description: toolConfig.description, inputSchema: zodSchema, annotations: { title: `${toolConfig.name} (${dbType})`, readOnlyHint: isReadOnly, destructiveHint: !isReadOnly, idempotentHint: isReadOnly, openWorldHint: false, }, }, createCustomToolHandler(toolConfig) ); console.error(` - ${toolConfig.name} → ${toolConfig.source} (${dbType})`); } } }

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/bytebase/dbhub'

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