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.

174 lines 7.6 kB
import { z } from 'zod'; import { Range, TableEntry } from '../../../../domain/index.js'; import { v4 as uuidv4 } from 'uuid'; import { BaseTool } from './tool.js'; /** * Tool for updating tables. */ export class UpdateTableTool extends BaseTool { /** * Creates a new UpdateTableTool instance. * @param tableService The table service to use. */ constructor(tableService) { super(); this.tableService = tableService; } /** * Gets the name of the tool. * @returns The tool name. */ getToolName() { return 'update_table'; } /** * Gets the description of the tool. * @returns The tool description. */ getToolDescription() { return 'Update an existing random table. Table entries can include templates to reference other tables using the format {{reference-title::table-id::table-name::roll-number::separator}}.'; } /** * Gets the input schema for the tool. * @returns The input schema. */ getInputSchema() { return z.object({ tableId: z.string().describe('ID of the table to update'), updates: z .object({ name: z.string().optional().describe('New table name'), description: z.string().optional().describe('New table description'), entries: z .object({ add: z .array(z.object({ content: z .string() .describe('The content of this entry. Can include templates in the format {{reference-title::table-id::table-name::roll-number::separator}} to reference other tables.'), weight: z .number() .optional() .default(1) .describe('Probability weight (default: 1)'), range: z .object({ min: z.number().describe('Minimum value (inclusive)'), max: z.number().describe('Maximum value (inclusive)'), }) .optional() .describe('Optional range of values this entry corresponds to'), })) .optional() .describe('Entries to add'), update: z .array(z.object({ id: z.string().describe('ID of the entry to update'), updates: z .object({ content: z .string() .optional() .describe('New content. Can include templates in the format {{reference-title::table-id::table-name::roll-number::separator}} to reference other tables.'), weight: z.number().optional().describe('New weight'), range: z .object({ min: z.number().describe('Minimum value (inclusive)'), max: z.number().describe('Maximum value (inclusive)'), }) .optional() .describe('New range'), }) .describe('Updates to apply to the entry'), })) .optional() .describe('Entries to update'), remove: z.array(z.string()).optional().describe('IDs of entries to remove'), }) .optional() .refine(data => data === undefined || data.add !== undefined || data.update !== undefined || data.remove !== undefined, { message: "At least one of 'add', 'update', or 'remove' must be provided when updating entries", }) .describe('Entry updates'), }) .refine(data => data.name !== undefined || data.description !== undefined || data.entries !== undefined, { message: 'At least one update property (name, description, or entries) must be provided', }) .describe('Updates to apply to the table'), }); } /** * Gets the output schema for the tool. * @returns The output schema. */ getOutputSchema() { return z.object({ success: z.boolean().describe('Whether the update was successful'), }); } /** * Implements the tool execution logic. * @param args The validated tool arguments. * @returns The tool result. */ async executeImpl(args) { // Prepare the updates object const updates = {}; // Add name and description updates if provided if (args.updates.name !== undefined) { updates.name = args.updates.name; } if (args.updates.description !== undefined) { updates.description = args.updates.description; } // Add entry updates if provided if (args.updates.entries) { updates.entries = {}; // Add new entries if (args.updates.entries.add) { updates.entries.add = args.updates.entries.add.map(entry => { // Generate a unique ID for the entry const id = uuidv4(); // Create a Range object if range is provided const range = entry.range ? new Range(entry.range.min, entry.range.max) : undefined; // Create the TableEntry with all required parameters return new TableEntry(id, entry.content, entry.weight ?? 1, range); }); } // Update existing entries if (args.updates.entries.update) { updates.entries.update = args.updates.entries.update.map(({ id, updates: entryUpdatesData }) => { // Create a plain object with the properties to update const entryUpdates = {}; // Copy content if provided if (entryUpdatesData.content !== undefined) { entryUpdates.content = entryUpdatesData.content; } // Copy weight if provided if (entryUpdatesData.weight !== undefined) { entryUpdates.weight = entryUpdatesData.weight; } // Create Range object if range is provided if (entryUpdatesData.range !== undefined) { entryUpdates.range = new Range(entryUpdatesData.range.min, entryUpdatesData.range.max); } return { id, updates: entryUpdates, }; }); } // Remove entries if (args.updates.entries.remove) { updates.entries.remove = args.updates.entries.remove; } } // Call the table service to update the table await this.tableService.updateTable(args.tableId, updates); return { success: true }; } } //# sourceMappingURL=update-table-tool.js.map