From 4be0a41eaa106f823e4e5f384afcfcc18c7b15b6 Mon Sep 17 00:00:00 2001 From: nnhhoang Date: Fri, 17 Apr 2026 03:48:44 +0700 Subject: [PATCH] fix(memory): rename MCP tool names to comply with strict client naming regex MCP clients like Antigravity enforce the tool-name pattern ^[a-zA-Z0-9_-]{1,64}$, which rejects the existing memory.storeKnowledge, memory.updateKnowledge, and memory.searchKnowledge tool names because of the dot separator. Rename to memory_storeKnowledge, memory_updateKnowledge, memory_searchKnowledge so the server is loadable across all MCP clients. To keep existing users on older init templates from breaking, the CallTool dispatcher also accepts the deprecated dotted names as backward-compat aliases. The aliases can be removed in the next major. Exports the TOOLS array and adds a unit test that asserts every registered tool name satisfies the MCP naming regex, guarding against future regressions when new tools are added. Updates README examples and all per-agent remember command templates (Claude, Cursor, Codex, Gemini, Antigravity, GitHub Copilot, generic agent workflows) to reference the new names. Historical design docs under docs/ai/ are intentionally left unchanged as frozen records. Fixes #40 --- .agent/workflows/remember.md | 2 +- .claude/commands/remember.md | 2 +- .codex/commands/remember.md | 2 +- .cursor/commands/remember.md | 2 +- .gemini/commands/remember.toml | 2 +- .github/prompts/remember.prompt.md | 2 +- commands/remember.md | 2 +- packages/cli/templates/commands/remember.md | 2 +- packages/memory/README.md | 4 ++-- packages/memory/src/server.ts | 16 +++++++++------ packages/memory/tests/unit/server.test.ts | 22 +++++++++++++++++++++ 11 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 packages/memory/tests/unit/server.test.ts diff --git a/.agent/workflows/remember.md b/.agent/workflows/remember.md index b54bac19..b15a3ca1 100644 --- a/.agent/workflows/remember.md +++ b/.agent/workflows/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/.claude/commands/remember.md b/.claude/commands/remember.md index b54bac19..b15a3ca1 100644 --- a/.claude/commands/remember.md +++ b/.claude/commands/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/.codex/commands/remember.md b/.codex/commands/remember.md index b54bac19..b15a3ca1 100644 --- a/.codex/commands/remember.md +++ b/.codex/commands/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/.cursor/commands/remember.md b/.cursor/commands/remember.md index b54bac19..b15a3ca1 100644 --- a/.cursor/commands/remember.md +++ b/.cursor/commands/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/.gemini/commands/remember.toml b/.gemini/commands/remember.toml index 267858f4..fb0bbdfc 100644 --- a/.gemini/commands/remember.toml +++ b/.gemini/commands/remember.toml @@ -4,6 +4,6 @@ prompt='''Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed.''' diff --git a/.github/prompts/remember.prompt.md b/.github/prompts/remember.prompt.md index b54bac19..b15a3ca1 100644 --- a/.github/prompts/remember.prompt.md +++ b/.github/prompts/remember.prompt.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/commands/remember.md b/commands/remember.md index b54bac19..b15a3ca1 100644 --- a/commands/remember.md +++ b/commands/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/packages/cli/templates/commands/remember.md b/packages/cli/templates/commands/remember.md index b54bac19..b15a3ca1 100644 --- a/packages/cli/templates/commands/remember.md +++ b/packages/cli/templates/commands/remember.md @@ -7,6 +7,6 @@ Help me store it in the knowledge memory service. 1. **Capture Knowledge** — If not already provided, ask for: a short explicit title (5-12 words), detailed content (markdown, examples encouraged), optional tags (keywords like "api", "testing"), and optional scope (`global`, `project:`, `repo:`). If vague, ask follow-ups to make it specific and actionable. 2. **Search Before Store** — Check for existing similar entries first with `npx ai-devkit@latest memory search --query ""` to avoid duplicates. 3. **Validate Quality** — Ensure it is specific and reusable (not generic advice). Avoid storing secrets or sensitive data. -4. **Store** — Call `memory.storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. +4. **Store** — Call `memory_storeKnowledge` with title, content, tags, scope. If MCP tools are unavailable, use `npx ai-devkit@latest memory store` instead. 5. **Confirm** — Summarize what was saved and offer to retrieve related memory entries when helpful. 6. **Next Command Guidance** — Continue with the current lifecycle phase command (`/execute-plan`, `/check-implementation`, `/writing-test`, etc.) as needed. diff --git a/packages/memory/README.md b/packages/memory/README.md index 8350a806..2dd893e7 100644 --- a/packages/memory/README.md +++ b/packages/memory/README.md @@ -38,7 +38,7 @@ Add to your MCP client configuration (e.g., Claude Code, Cursor): ```json { - "tool": "memory.storeKnowledge", + "tool": "memory_storeKnowledge", "arguments": { "title": "Always use Response DTOs for API endpoints", "content": "When building REST APIs, always use Response DTOs instead of returning domain entities directly.", @@ -52,7 +52,7 @@ Add to your MCP client configuration (e.g., Claude Code, Cursor): ```json { - "tool": "memory.searchKnowledge", + "tool": "memory_searchKnowledge", "arguments": { "query": "building an API endpoint", "contextTags": ["api"], diff --git a/packages/memory/src/server.ts b/packages/memory/src/server.ts index 843055d7..87893bb7 100644 --- a/packages/memory/src/server.ts +++ b/packages/memory/src/server.ts @@ -14,7 +14,7 @@ const SERVER_NAME = 'ai-devkit-memory'; const SERVER_VERSION = '0.1.0'; const STORE_TOOL = { - name: 'memory.storeKnowledge', + name: 'memory_storeKnowledge', description: 'Store a new knowledge item. Use this to save actionable guidelines, rules, or patterns for future reference.', inputSchema: { type: 'object' as const, @@ -42,7 +42,7 @@ const STORE_TOOL = { }; const UPDATE_TOOL = { - name: 'memory.updateKnowledge', + name: 'memory_updateKnowledge', description: 'Update an existing knowledge item by ID. Use this to correct outdated or inaccurate knowledge.', inputSchema: { type: 'object' as const, @@ -74,7 +74,7 @@ const UPDATE_TOOL = { }; const SEARCH_TOOL = { - name: 'memory.searchKnowledge', + name: 'memory_searchKnowledge', description: 'Search for relevant knowledge based on a task description. Returns ranked results.', inputSchema: { type: 'object' as const, @@ -101,6 +101,8 @@ const SEARCH_TOOL = { }, }; +export const TOOLS = [STORE_TOOL, UPDATE_TOOL, SEARCH_TOOL]; + export function createServer(): Server { const server = new Server( { @@ -126,7 +128,9 @@ export function createServer(): Server { const { name, arguments: args } = request.params; try { - if (name === 'memory.storeKnowledge') { + // Backward-compat: accept deprecated dotted names so agents with + // stale prompts/templates continue to work. Remove in next major. + if (name === 'memory_storeKnowledge' || name === 'memory.storeKnowledge') { const input = args as unknown as StoreKnowledgeInput; const result = storeKnowledge(input); return { @@ -139,7 +143,7 @@ export function createServer(): Server { }; } - if (name === 'memory.updateKnowledge') { + if (name === 'memory_updateKnowledge' || name === 'memory.updateKnowledge') { const input = args as unknown as UpdateKnowledgeInput; const result = updateKnowledge(input); return { @@ -152,7 +156,7 @@ export function createServer(): Server { }; } - if (name === 'memory.searchKnowledge') { + if (name === 'memory_searchKnowledge' || name === 'memory.searchKnowledge') { const input = args as unknown as SearchKnowledgeInput; const result = searchKnowledge(input); return { diff --git a/packages/memory/tests/unit/server.test.ts b/packages/memory/tests/unit/server.test.ts new file mode 100644 index 00000000..f8505313 --- /dev/null +++ b/packages/memory/tests/unit/server.test.ts @@ -0,0 +1,22 @@ +import { TOOLS } from '../../src/server'; + +describe('MCP server tool names', () => { + const MCP_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/; + + it('should register at least one tool', () => { + expect(TOOLS.length).toBeGreaterThan(0); + }); + + it.each(TOOLS.map(tool => [tool.name, tool]))( + 'tool name "%s" should satisfy MCP client naming regex ^[a-zA-Z0-9_-]{1,64}$', + (name) => { + expect(name).toMatch(MCP_TOOL_NAME_PATTERN); + } + ); + + it('should not contain duplicate tool names', () => { + const names = TOOLS.map(tool => tool.name); + const unique = new Set(names); + expect(unique.size).toBe(names.length); + }); +});