Skip to main content
Glama

DollhouseMCP

by DollhouseMCP
ServerSetup.tsโ€ข8.32 kB
/** * Server setup and initialization */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js"; import { ToolRegistry } from './tools/ToolRegistry.js'; import { getPersonaExportImportTools } from './tools/PersonaTools.js'; import { getElementTools } from './tools/ElementTools.js'; import { getCollectionTools } from './tools/CollectionTools.js'; // import { getUserTools } from './tools/UserTools.js'; // DEPRECATED - replaced by dollhouse_config // import { getConfigTools } from './tools/ConfigTools.js'; // DEPRECATED - replaced by dollhouse_config import { getConfigToolsV2 } from './tools/ConfigToolsV2.js'; import { getAuthTools } from './tools/AuthTools.js'; import { getPortfolioTools } from './tools/PortfolioTools.js'; import { getBuildInfoTools } from './tools/BuildInfoTools.js'; import { getEnhancedIndexTools } from './tools/EnhancedIndexTools.js'; import { IToolHandler } from './types.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; import { logger } from '../utils/logger.js'; import { ToolDiscoveryCache } from '../utils/ToolCache.js'; // ConfigWizardCheck import removed - auto-trigger disabled for v1.8.0 export class ServerSetup { private toolRegistry: ToolRegistry; private toolCache: ToolDiscoveryCache; // wizardCheck removed - auto-trigger disabled for v1.8.0 constructor() { this.toolRegistry = new ToolRegistry(); this.toolCache = new ToolDiscoveryCache(); } /** * Initialize the server with all tools and handlers */ setupServer(server: Server, instance: IToolHandler): void { // wizardCheck parameter removed - auto-trigger disabled for v1.8.0 // Register all tools this.registerTools(instance); // Setup request handlers this.setupListToolsHandler(server); this.setupCallToolHandler(server); } /** * Register all tool categories and invalidate cache */ private registerTools(instance: IToolHandler): void { // Register element tools (new generic tools for all element types) this.toolRegistry.registerMany(getElementTools(instance)); // Register persona export/import tools (core functionality moved to element tools) this.toolRegistry.registerMany(getPersonaExportImportTools(instance)); // Register collection tools this.toolRegistry.registerMany(getCollectionTools(instance)); // DEPRECATED: Old user tools - replaced by dollhouse_config // Comment out to remove from tool list, but keep for reference during transition // this.toolRegistry.registerMany(getUserTools(instance)); // Register auth tools this.toolRegistry.registerMany(getAuthTools(instance)); // Portfolio tools (including sync_portfolio with new safety features) this.toolRegistry.registerMany(getPortfolioTools(instance)); // DEPRECATED: Old config tools - replaced by dollhouse_config // Comment out to remove from tool list, but keep for reference during transition // this.toolRegistry.registerMany(getConfigTools(instance)); // Register new unified config and sync tools this.toolRegistry.registerMany(getConfigToolsV2(instance)); // Register build info tools this.toolRegistry.registerMany(getBuildInfoTools(instance)); // Register Enhanced Index tools (semantic search and relationships) this.toolRegistry.registerMany(getEnhancedIndexTools(instance)); // Invalidate cache since tools have changed this.toolCache.invalidateToolList(); logger.debug('ToolDiscoveryCache: Cache invalidated due to tool registration'); } /** * Setup the ListToolsRequest handler with caching */ private setupListToolsHandler(server: Server): void { server.setRequestHandler(ListToolsRequestSchema, async () => { const startTime = Date.now(); // Try to get cached tools first let tools = this.toolCache.getToolList(); if (!tools) { // Cache miss - fetch tools from registry tools = this.toolRegistry.getAllTools(); // Cache the results for future requests this.toolCache.setToolList(tools); const duration = Date.now() - startTime; logger.info('ToolDiscoveryCache: Cache miss - fetched and cached tools', { toolCount: tools.length, duration: `${duration}ms`, source: 'registry' }); } else { const duration = Date.now() - startTime; logger.debug('ToolDiscoveryCache: Cache hit - returned cached tools', { toolCount: tools.length, duration: `${duration}ms`, source: 'cache' }); } return { tools }; }); } /** * Setup the CallToolRequest handler */ private setupCallToolHandler(server: Server): void { server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const handler = this.toolRegistry.getHandler(name); if (!handler) { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${name}` ); } // Normalize Unicode in all string arguments to prevent security bypasses const normalizedArgs = this.normalizeArgumentsUnicode(args, name); const response = await handler(normalizedArgs); // Wizard auto-trigger removed for v1.8.0 // Manual wizard still available via config tool with action: 'wizard' return response; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Error executing tool ${name}: ${error}` ); } }); } /** * Recursively normalize Unicode in all string values within arguments */ private normalizeArgumentsUnicode(args: any, toolName: string): any { if (args === null || args === undefined) { return args; } if (typeof args === 'string') { const result = UnicodeValidator.normalize(args); if (result.detectedIssues && result.detectedIssues.length > 0) { logger.warn(`Unicode security issues detected in tool ${toolName}:`, { issues: result.detectedIssues, severity: result.severity }); } return result.normalizedContent; } if (Array.isArray(args)) { return args.map(item => this.normalizeArgumentsUnicode(item, toolName)); } if (typeof args === 'object') { const normalized: any = {}; for (const [key, value] of Object.entries(args)) { // Normalize both keys and values to prevent Unicode attacks in property names const normalizedKey = typeof key === 'string' ? UnicodeValidator.normalize(key).normalizedContent : key; normalized[normalizedKey] = this.normalizeArgumentsUnicode(value, toolName); } return normalized; } // For non-string primitive types, return as-is return args; } /** * Get the tool registry */ getToolRegistry(): ToolRegistry { return this.toolRegistry; } /** * Get the tool discovery cache */ getToolCache(): ToolDiscoveryCache { return this.toolCache; } /** * Invalidate the tool discovery cache (useful for external tool changes) */ invalidateToolCache(): void { this.toolCache.invalidateToolList(); logger.info('ToolDiscoveryCache: Cache manually invalidated'); // Log security event for audit trail SecurityMonitor.logSecurityEvent({ type: 'TOOL_CACHE_INVALIDATED', severity: 'LOW', source: 'ServerSetup.invalidateToolCache', details: 'Tool discovery cache manually invalidated' }); } /** * Log current cache performance metrics */ logCachePerformance(): void { this.toolCache.logPerformance(); } /** * Get cache statistics for monitoring */ getCacheStatistics() { return { toolCache: this.toolCache.getStats() }; } }

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/DollhouseMCP/DollhouseMCP'

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