Skip to main content

mcp-tool-design

Design MCP tools and gateway interfaces for the dotcontext server

معلومات المصدر

المستودع
vinilana/dotcontext
آخر نشاط في المصدر
٢٢ مارس ٢٠٢٦ في ٠٠:٢٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥٧٠
التفرعات
٩٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
type
skill
name
MCP Tool Design
description
Design MCP tools and gateway interfaces for the dotcontext server
skillSlug
api-design
phases
["P","R"]
generated
2026-03-18T00:00:00.000Z
status
filled
scaffoldVersion
2.0.0
# MCP Tool Design Guidance for designing and extending MCP (Model Context Protocol) tools exposed by `AIContextMCPServer` in `src/services/mcp/mcpServer.ts`. ## When to Use - Adding a new MCP tool or gateway action to the server - Refactoring the existing 9-tool surface (5 consolidated gateways + 4 dedicated workflow tools) - Changing Zod input schemas for existing tools - Adding new resource templates (e.g., `context://`, `file://`, `workflow://`) - Designing a new gateway handler in `src/services/mcp/gateway/` ## Architecture Overview The MCP server follows a **consolidated gateway** pattern to minimize cognitive load for AI agents: ``` AIContextMCPServer (mcpServer.ts) registerGatewayTools() -> explore (read, list, analyze, search, getStructure) -> context (check, init, fill, fillSingle, listToFill, getMap, buildSemantic, scaffoldPlan) -> sync (exportRules, exportDocs, exportAgents, exportContext, exportSkills, reverseSync, importDocs, importAgents, importSkills) -> plan (link, getLinked, getDetails, getForPhase, updatePhase, recordDecision, updateStep, getStatus, syncMarkdown, commitPhase) -> agent (discover, getInfo, orchestrate, getSequence, getDocs, getPhaseDocs, listTypes) -> skill (list, getContent, getForPhase, scaffold, export, fill) -> workflow-init / workflow-status / workflow-advance / workflow-manage ``` Each gateway dispatches to a handler in `src/services/mcp/gateway/<name>.ts`. The handler receives typed params and an options object with `repoPath`. ## Instructions ### 1. Decide: New Gateway vs. New Action - **New action on existing gateway**: Preferred. Add an action variant to the existing `z.enum([...])` and extend the handler switch. - **New dedicated tool**: Only when the domain is distinct enough to warrant its own tool (like `workflow-*` was split out for clarity). - **Rule of thumb**: Keep the total tool count under 12 to avoid overwhelming AI agent tool selection. ### 2. Define the Input Schema with Zod All MCP tool inputs use Zod v4 schemas (imported from `zod`). Follow the existing pattern: ```typescript inputSchema: { action: z.enum(['existingAction', 'newAction']) .describe('Action to perform'), newParam: z.string().optional() .describe('(newAction) What this param does'), } ``` Key conventions: - Every parameter gets a `.describe()` with the action prefix in parentheses: `(actionName)` - Use `z.enum()` for constrained values, `z.array(z.string())` for lists - Mark all action-specific params as `.optional()` since different actions use different params - Import shared enums from `../../workflow` (e.g., `PREVC_ROLES`, `AGENT_TYPES`) ### 3. Create the Gateway Handler Add a new file in `src/services/mcp/gateway/` or extend an existing one: ```typescript // src/services/mcp/gateway/myGateway.ts import { createJsonResponse, createErrorResponse, type MCPToolResponse } from './response'; export type MyAction = 'doThing' | 'doOther'; export interface MyParams { action: MyAction; repoPath?: string; // action-specific params } export interface MyOptions { repoPath: string; } export async function handleMy(params: MyParams, options: MyOptions): Promise<MCPToolResponse> { switch (params.action) { case 'doThing': return createJsonResponse({ success: true, message: 'Done' }); default: return createErrorResponse(`Unknown action: ${params.action}`); } } ``` ### 4. Response Format Use the three helpers from `src/services/mcp/gateway/response.ts`: - `createJsonResponse(data)` -- structured JSON for programmatic consumption - `createErrorResponse(message)` -- sets `isError: true` - `createTextResponse(text)` -- plain text for human-readable output All responses conform to `MCPToolResponse` with `content: [{ type: 'text', text }]`. ### 5. Wire It Up in mcpServer.ts Register the tool in `registerGatewayTools()` using the `wrap()` helper for automatic action logging: ```typescript this.server.registerTool('my-tool', { description: `Description with action list...`, inputSchema: { /* Zod schemas */ } }, wrap('my-tool', async (params): Promise<MCPToolResponse> => { return handleMy(params as MyParams, { repoPath: this.getRepoPath() }); })); ``` ### 6. Re-export from gatewayTools.ts Add your handler, types, and params to the re-export barrel in `src/services/mcp/gatewayTools.ts` and `src/services/mcp/gateway/index.ts`. ### 7. Test Write tests in `src/services/mcp/` following the pattern in `mcpServer.test.ts`. Since MCP tools require stdio transport, test the handler functions directly: ```typescript import { handleMy } from './gateway/myGateway'; it('should handle doThing action', async () => { const result = await handleMy( { action: 'doThing' }, { repoPath: tempDir } ); const payload = JSON.parse(result.content[0].text); expect(payload.success).toBe(true); }); ``` ## Design Checklist - [ ] Action names are verbs or verb phrases (e.g., `getStatus`, `buildSemantic`, `exportRules`) - [ ] All params have `.describe()` annotations with action prefix - [ ] Handler returns `MCPToolResponse` via response helpers - [ ] `repoPath` resolution uses `this.getRepoPath(params.repoPath)` for caching - [ ] Tool description includes a complete action list for AI discoverability - [ ] New types are exported through the gateway barrel file - [ ] Action logging works via the `wrap()` helper - [ ] Total tool count stays manageable (currently 9) ## Common Pitfalls - **Do not** use `process.cwd()` directly in handlers; always use the `repoPath` from options - **Do not** add required params that are only needed for one action; use `.optional()` and validate inside the handler - **Do not** return raw errors; wrap them with `createErrorResponse()` for consistent error shape - **Do not** log to stdout in MCP mode; use `process.stderr.write()` to avoid corrupting the MCP protocol
عرض على GitHub