UNPKG

random-tables-mcp

Version:

An MCP (Model Context Protocol) server for managing and rolling on random-table assets used in tabletop RPGs. Create, update, and roll on random tables with support for nested tables, weighted entries, and range-based results.

161 lines 6.46 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { CreateTableTool, ListTablesTool, RollOnTableTool, UpdateTableTool, GetTableTool, CreateTemplateTool, GetTemplateTool, ListTemplateTool, UpdateTemplateTool, DeleteTemplateTool, EvaluateTemplateTool, } from './tools/index.js'; import { TableResource, TablesResource, TemplateResource, TemplatesResource, } from './resources/index.js'; /** * MCP Server implementation for Random Tables. */ export class McpServer { /** * Creates a new McpServer instance. * @param tableService The table service to use. * @param rollService The roll service to use. * @param templateService The roll template service to use. */ constructor(tableService, rollService, templateService) { this.tableService = tableService; this.rollService = rollService; this.templateService = templateService; this.server = new Server({ name: 'random-tables-server', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, }, }); // Check if resources can be used (defaults to false if not specified) const canUseResource = process.env.CAN_USE_RESOURCE === 'true'; // Initialize tools this.tools = [ new CreateTableTool(tableService), new RollOnTableTool(rollService), new UpdateTableTool(tableService), new ListTablesTool(tableService), new CreateTemplateTool(templateService), new GetTemplateTool(templateService), new ListTemplateTool(templateService), new UpdateTemplateTool(templateService), new DeleteTemplateTool(templateService), new EvaluateTemplateTool(templateService), ]; // Add GetTableTool if resources cannot be used if (!canUseResource) { this.tools.push(new GetTableTool(tableService)); } // Initialize resources this.resources = [new TablesResource(tableService), new TemplatesResource(templateService)]; // Add TableResource only if resources can be used if (canUseResource) { this.resources.push(new TableResource(tableService)); this.resources.push(new TemplateResource(templateService)); } } /** * Initializes the server by registering tools and resources. */ initialize() { this.registerTools(); this.registerResources(); } /** * Registers tools with the server. */ registerTools() { this.server.setRequestHandler(ListToolsRequestSchema, () => { return { tools: this.tools.map(tool => tool.getToolDefinition()), }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; const tool = this.tools.find(t => t.getName() === name); if (!tool) { throw new Error(`Unknown tool: ${name}`); } const result = await tool.execute(args); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: `Error: ${errorMessage}` }], isError: true, }; } }); } /** * Registers resources with the server. */ registerResources() { // Set up a handler for resource requests this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { try { const { uri } = request.params; // Find the resource that matches the URI pattern for (const resource of this.resources) { const uriPattern = resource.getUriPattern(); const match = this.matchUriPattern(uri, uriPattern); if (match) { const content = await resource.getContent(match); return { content: [{ type: 'text', text: JSON.stringify(content, null, 2) }], }; } } throw new Error(`No resource found for URI: ${uri}`); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: 'text', text: `Error: ${errorMessage}` }], isError: true, }; } }); } /** * Matches a URI against a pattern and extracts parameters. * @param uri The URI to match. * @param pattern The pattern to match against. * @returns An object with extracted parameters, or null if no match. */ matchUriPattern(uri, pattern) { // Convert pattern to regex const regexPattern = pattern.replace(/{([^}]+)}/g, '([^/]+)'); const regex = new RegExp(`^${regexPattern}$`); // Extract parameter names from pattern const paramNames = []; let match; const paramRegex = /{([^}]+)}/g; while ((match = paramRegex.exec(pattern)) !== null) { paramNames.push(match[1]); } // Match URI against regex const matches = uri.match(regex); if (!matches) { return null; } // Extract parameters const params = {}; for (let i = 0; i < paramNames.length; i++) { params[paramNames[i]] = matches[i + 1]; } return params; } /** * Starts the server. */ async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.warn('MCP Random Tables Server running on stdio'); } } //# sourceMappingURL=mcp-server.js.map