UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

122 lines 16.3 kB
/** * Server setup and initialization */ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js"; import { ToolRegistry } from './tools/ToolRegistry.js'; import { getPersonaTools } from './tools/PersonaTools.js'; import { getElementTools } from './tools/ElementTools.js'; import { getCollectionTools } from './tools/CollectionTools.js'; import { getUserTools } from './tools/UserTools.js'; import { getUpdateTools } from './tools/UpdateTools.js'; import { getConfigTools } from './tools/ConfigTools.js'; import { getAuthTools } from './tools/AuthTools.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; import { logger } from '../utils/logger.js'; export class ServerSetup { toolRegistry; constructor() { this.toolRegistry = new ToolRegistry(); } /** * Initialize the server with all tools and handlers */ setupServer(server, instance) { // Register all tools this.registerTools(instance); // Setup request handlers this.setupListToolsHandler(server); this.setupCallToolHandler(server); } /** * Register all tool categories */ registerTools(instance) { // Register element tools (new generic tools for all element types) this.toolRegistry.registerMany(getElementTools(instance)); // Register persona tools (legacy - kept for backward compatibility) this.toolRegistry.registerMany(getPersonaTools(instance)); // Register collection tools this.toolRegistry.registerMany(getCollectionTools(instance)); // Register user tools this.toolRegistry.registerMany(getUserTools(instance)); // Register auth tools this.toolRegistry.registerMany(getAuthTools(instance)); // Register update tools this.toolRegistry.registerMany(getUpdateTools(instance)); // Register config tools this.toolRegistry.registerMany(getConfigTools(instance)); } /** * Setup the ListToolsRequest handler */ setupListToolsHandler(server) { server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: this.toolRegistry.getAllTools() }; }); } /** * Setup the CallToolRequest handler */ setupCallToolHandler(server) { 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); return await handler(normalizedArgs); } 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 */ normalizeArgumentsUnicode(args, toolName) { 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 = {}; 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() { return this.toolRegistry; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVyU2V0dXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL1NlcnZlclNldHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBR0gsT0FBTyxFQUFFLHFCQUFxQixFQUFFLFNBQVMsRUFBRSxzQkFBc0IsRUFBRSxRQUFRLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN4SCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzFELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN4RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLE1BQU0sT0FBTyxXQUFXO0lBQ2QsWUFBWSxDQUFlO0lBRW5DO1FBQ0UsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVcsQ0FBQyxNQUFjLEVBQUUsUUFBc0I7UUFDaEQscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFN0IseUJBQXlCO1FBQ3pCLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNuQyxJ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TyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzNCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2VydmVyIHNldHVwIGFuZCBpbml0aWFsaXphdGlvblxuICovXG5cbmltcG9ydCB7IFNlcnZlciB9IGZyb20gXCJAbW9kZWxjb250ZXh0cHJvdG9jb2wvc2RrL3NlcnZlci9pbmRleC5qc1wiO1xuaW1wb3J0IHsgQ2FsbFRvb2xSZXF1ZXN0U2NoZW1hLCBFcnJvckNvZGUsIExpc3RUb29sc1JlcXVlc3RTY2hlbWEsIE1jcEVycm9yIH0gZnJvbSBcIkBtb2RlbGNvbnRleHRwcm90b2NvbC9zZGsvdHlwZXMuanNcIjtcbmltcG9ydCB7IFRvb2xSZWdpc3RyeSB9IGZyb20gJy4vdG9vbHMvVG9vbFJlZ2lzdHJ5LmpzJztcbmltcG9ydCB7IGdldFBlcnNvbmFUb29scyB9IGZyb20gJy4vdG9vbHMvUGVyc29uYVRvb2xzLmpzJztcbmltcG9ydCB7IGdldEVsZW1lbnRUb29scyB9IGZyb20gJy4vdG9vbHMvRWxlbWVudFRvb2xzLmpzJztcbmltcG9ydCB7IGdldENvbGxlY3Rpb25Ub29scyB9IGZyb20gJy4vdG9vbHMvQ29sbGVjdGlvblRvb2xzLmpzJztcbmltcG9ydCB7IGdldFVzZXJUb29scyB9IGZyb20gJy4vdG9vbHMvVXNlclRvb2xzLmpzJztcbmltcG9ydCB7IGdldFVwZGF0ZVRvb2xzIH0gZnJvbSAnLi90b29scy9VcGRhdGVUb29scy5qcyc7XG5pbXBvcnQgeyBnZXRDb25maWdUb29scyB9IGZyb20gJy4vdG9vbHMvQ29uZmlnVG9vbHMuanMnO1xuaW1wb3J0IHsgZ2V0QXV0aFRvb2xzIH0gZnJvbSAnLi90b29scy9BdXRoVG9vbHMuanMnO1xuaW1wb3J0IHsgSVRvb2xIYW5kbGVyIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBTZXJ2ZXJTZXR1cCB7XG4gIHByaXZhdGUgdG9vbFJlZ2lzdHJ5OiBUb29sUmVnaXN0cnk7XG4gIFxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLnRvb2xSZWdpc3RyeSA9IG5ldyBUb29sUmVnaXN0cnkoKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIHNlcnZlciB3aXRoIGFsbCB0b29scyBhbmQgaGFuZGxlcnNcbiAgICovXG4gIHNldHVwU2VydmVyKHNlcnZlcjogU2VydmVyLCBpbnN0YW5jZTogSVRvb2xIYW5kbGVyKTogdm9pZCB7XG4gICAgLy8gUmVnaXN0ZXIgYWxsIHRvb2xzXG4gICAgdGhpcy5yZWdpc3RlclRvb2xzKGluc3RhbmNlKTtcbiAgICBcbiAgICAvLyBTZXR1cCByZXF1ZXN0IGhhbmRsZXJzXG4gICAgdGhpcy5zZXR1cExpc3RUb29sc0hhbmRsZXIoc2VydmVyKTtcbiAgICB0aGlzLnNldHVwQ2FsbFRvb2xIYW5kbGVyKHNlcnZlcik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhbGwgdG9vbCBjYXRlZ29yaWVzXG4gICAqL1xuICBwcml2YXRlIHJlZ2lzdGVyVG9vbHMoaW5zdGFuY2U6IElUb29sSGFuZGxlcik6IHZvaWQge1xuICAgIC8vIFJlZ2lzdGVyIGVsZW1lbnQgdG9vbHMgKG5ldyBnZW5lcmljIHRvb2xzIGZvciBhbGwgZWxlbWVudCB0eXBlcylcbiAgICB0aGlzLnRvb2xSZWdpc3RyeS5yZWdpc3Rlck1hbnkoZ2V0RWxlbWVudFRvb2xzKGluc3RhbmNlKSk7XG4gICAgXG4gICAgLy8gUmVnaXN0ZXIgcGVyc29uYSB0b29scyAobGVnYWN5IC0ga2VwdCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSlcbiAgICB0aGlzLnRvb2xSZWdpc3RyeS5yZWdpc3Rlck1hbnkoZ2V0UGVyc29uYVRvb2xzKGluc3RhbmNlKSk7XG4gICAgXG4gICAgLy8gUmVnaXN0ZXIgY29sbGVjdGlvbiB0b29sc1xuICAgIHRoaXMudG9vbFJlZ2lzdHJ5LnJlZ2lzdGVyTWFueShnZXRDb2xsZWN0aW9uVG9vbHMoaW5zdGFuY2UpKTtcbiAgICBcbiAgICAvLyBSZWdpc3RlciB1c2VyIHRvb2xzXG4gICAgdGhpcy50b29sUmVnaXN0cnkucmVnaXN0ZXJNYW55KGdldFVzZXJUb29scyhpbnN0YW5jZSkpO1xuICAgIFxuICAgIC8vIFJlZ2lzdGVyIGF1dGggdG9vbHNcbiAgICB0aGlzLnRvb2xSZWdpc3RyeS5yZWdpc3Rlck1hbnkoZ2V0QXV0aFRvb2xzKGluc3RhbmNlKSk7XG4gICAgXG4gICAgLy8gUmVnaXN0ZXIgdXBkYXRlIHRvb2xzXG4gICAgdGhpcy50b29sUmVnaXN0cnkucmVnaXN0ZXJNYW55KGdldFVwZGF0ZVRvb2xzKGluc3RhbmNlKSk7XG4gICAgXG4gICAgLy8gUmVnaXN0ZXIgY29uZmlnIHRvb2xzXG4gICAgdGhpcy50b29sUmVnaXN0cnkucmVnaXN0ZXJNYW55KGdldENvbmZpZ1Rvb2xzKGluc3RhbmNlKSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXR1cCB0aGUgTGlzdFRvb2xzUmVxdWVzdCBoYW5kbGVyXG4gICAqL1xuICBwcml2YXRlIHNldHVwTGlzdFRvb2xzSGFuZGxlcihzZXJ2ZXI6IFNlcnZlcik6IHZvaWQge1xuICAgIHNlcnZlci5zZXRSZXF1ZXN0SGFuZGxlcihMaXN0VG9vbHNSZXF1ZXN0U2NoZW1hLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0b29sczogdGhpcy50b29sUmVnaXN0cnkuZ2V0QWxsVG9vbHMoKVxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldHVwIHRoZSBDYWxsVG9vbFJlcXVlc3QgaGFuZGxlclxuICAgKi9cbiAgcHJpdmF0ZSBzZXR1cENhbGxUb29sSGFuZGxlcihzZXJ2ZXI6IFNlcnZlcik6IHZvaWQge1xuICAgIHNlcnZlci5zZXRSZXF1ZXN0SGFuZGxlcihDYWxsVG9vbFJlcXVlc3RTY2hlbWEsIGFzeW5jIChyZXF1ZXN0KSA9PiB7XG4gICAgICBjb25zdCB7IG5hbWUsIGFyZ3VtZW50czogYXJncyB9ID0gcmVxdWVzdC5wYXJhbXM7XG4gICAgICBcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSB0aGlzLnRvb2xSZWdpc3RyeS5nZXRIYW5kbGVyKG5hbWUpO1xuICAgICAgICBcbiAgICAgICAgaWYgKCFoYW5kbGVyKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IE1jcEVycm9yKFxuICAgICAgICAgICAgRXJyb3JDb2RlLk1ldGhvZE5vdEZvdW5kLFxuICAgICAgICAgICAgYFVua25vd24gdG9vbDogJHtuYW1lfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBOb3JtYWxpemUgVW5pY29kZSBpbiBhbGwgc3RyaW5nIGFyZ3VtZW50cyB0byBwcmV2ZW50IHNlY3VyaXR5IGJ5cGFzc2VzXG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRBcmdzID0gdGhpcy5ub3JtYWxpemVBcmd1bWVudHNVbmljb2RlKGFyZ3MsIG5hbWUpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIGF3YWl0IGhhbmRsZXIobm9ybWFsaXplZEFyZ3MpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgTWNwRXJyb3IpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgdGhyb3cgbmV3IE1jcEVycm9yKFxuICAgICAgICAgIEVycm9yQ29kZS5JbnRlcm5hbEVycm9yLFxuICAgICAgICAgIGBFcnJvciBleGVjdXRpbmcgdG9vbCAke25hbWV9OiAke2Vycm9yfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlY3Vyc2l2ZWx5IG5vcm1hbGl6ZSBVbmljb2RlIGluIGFsbCBzdHJpbmcgdmFsdWVzIHdpdGhpbiBhcmd1bWVudHNcbiAgICovXG4gIHByaXZhdGUgbm9ybWFsaXplQXJndW1lbnRzVW5pY29kZShhcmdzOiBhbnksIHRvb2xOYW1lOiBzdHJpbmcpOiBhbnkge1xuICAgIGlmIChhcmdzID09PSBudWxsIHx8IGFyZ3MgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgfVxuICAgIFxuICAgIGlmICh0eXBlb2YgYXJncyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGFyZ3MpO1xuICAgICAgaWYgKHJlc3VsdC5kZXRlY3RlZElzc3VlcyAmJiByZXN1bHQuZGV0ZWN0ZWRJc3N1ZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBsb2dnZXIud2FybihgVW5pY29kZSBzZWN1cml0eSBpc3N1ZXMgZGV0ZWN0ZWQgaW4gdG9vbCAke3Rvb2xOYW1lfTpgLCB7XG4gICAgICAgICAgaXNzdWVzOiByZXN1bHQuZGV0ZWN0ZWRJc3N1ZXMsXG4gICAgICAgICAgc2V2ZXJpdHk6IHJlc3VsdC5zZXZlcml0eVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQubm9ybWFsaXplZENvbnRlbnQ7XG4gICAgfVxuICAgIFxuICAgIGlmIChBcnJheS5pc0FycmF5KGFyZ3MpKSB7XG4gICAgICByZXR1cm4gYXJncy5tYXAoaXRlbSA9PiB0aGlzLm5vcm1hbGl6ZUFyZ3VtZW50c1VuaWNvZGUoaXRlbSwgdG9vbE5hbWUpKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHR5cGVvZiBhcmdzID09PSAnb2JqZWN0Jykge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZDogYW55ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhhcmdzKSkge1xuICAgICAgICAvLyBOb3JtYWxpemUgYm90aCBrZXlzIGFuZCB2YWx1ZXMgdG8gcHJldmVudCBVbmljb2RlIGF0dGFja3MgaW4gcHJvcGVydHkgbmFtZXNcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEtleSA9IHR5cGVvZiBrZXkgPT09ICdzdHJpbmcnID8gXG4gICAgICAgICAgVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoa2V5KS5ub3JtYWxpemVkQ29udGVudCA6IGtleTtcbiAgICAgICAgbm9ybWFsaXplZFtub3JtYWxpemVkS2V5XSA9IHRoaXMubm9ybWFsaXplQXJndW1lbnRzVW5pY29kZSh2YWx1ZSwgdG9vbE5hbWUpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5vcm1hbGl6ZWQ7XG4gICAgfVxuICAgIFxuICAgIC8vIEZvciBub24tc3RyaW5nIHByaW1pdGl2ZSB0eXBlcywgcmV0dXJuIGFzLWlzXG4gICAgcmV0dXJuIGFyZ3M7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHRvb2wgcmVnaXN0cnlcbiAgICovXG4gIGdldFRvb2xSZWdpc3RyeSgpOiBUb29sUmVnaXN0cnkge1xuICAgIHJldHVybiB0aGlzLnRvb2xSZWdpc3RyeTtcbiAgfVxufSJdfQ==