diff --git a/apps/docs/supermemory-mcp/mcp.mdx b/apps/docs/supermemory-mcp/mcp.mdx index 3a5eded1..bbdefb01 100644 --- a/apps/docs/supermemory-mcp/mcp.mdx +++ b/apps/docs/supermemory-mcp/mcp.mdx @@ -46,9 +46,9 @@ Your assistant chooses these tools automatically. Use this table when you need t | Tool | Use it for | Inputs | Result | | --- | --- | --- | --- | -| `search_memory` | Semantic recall from one space | `query` (required), `containerTag` | Matching memories | -| `get_profile` | Stable and recent profile context for one space | `containerTag` | Profile facts | -| `add_memory` | Save information or forget outdated information | `content` (required), `action` (`save` or `forget`), `containerTag` | Save or forget confirmation | +| `searchMemory` | Semantic recall from one space | `query` (required), `containerTag` | Matching memories | +| `getProfile` | Stable and recent profile context for one space | `containerTag` | Profile facts | +| `addMemory` | Save information or forget outdated information | `content` (required), `action` (`save` or `forget`), `containerTag` | Save or forget confirmation | | `listDocuments` | Browse stored source documents and their summaries | `page`, `limit`, `containerTag` | Document IDs, titles, types, status, dates, and summaries | | `getDocument` | Read the available content of one document | `documentId` (required) | Document metadata, summary, and available content | | `listMemories` | Browse recent extracted memory entries and their source document IDs | `page`, `limit`, `containerTag` | Memory IDs, text, versions, and source document IDs | @@ -57,12 +57,12 @@ Your assistant chooses these tools automatically. Use this table when you need t ### Search -`search_memory` accepts a natural-language query and returns semantically relevant memories. It does not include the space profile. Use `get_profile` when the assistant needs stable facts or recent context that search did not return. +`searchMemory` accepts a natural-language query and returns semantically relevant memories. It does not include the space profile. Use `getProfile` when the assistant needs stable facts or recent context that search did not return. Use the retrieval tools for different questions: -- Use `search_memory` to answer a question from remembered context. -- Use `get_profile` for who-the-user-is, preferences, and recent context. +- Use `searchMemory` to answer a question from remembered context. +- Use `getProfile` for who-the-user-is, preferences, and recent context. - Use `listDocuments` to discover stored sources, then `getDocument` to read one source in full. - Use `listMemories` to inspect the extracted memory entries themselves, including their IDs and source document IDs. @@ -70,9 +70,9 @@ Use the retrieval tools for different questions: ### Save or forget -`add_memory` saves the supplied `content` by default. Set `action` to `forget` when a fact is outdated or should be removed. There is no separate forget tool. +`addMemory` saves the supplied `content` by default. Set `action` to `forget` when a fact is outdated or should be removed. There is no separate forget tool. -If the content is already final, the assistant should use `add_memory`. If you want to review, edit, or choose a space before saving, it should open the `guided-save` widget instead. +If the content is already final, the assistant should use `addMemory`. If you want to review, edit, or choose a space before saving, it should open the `guided-save` widget instead. ### Access control diff --git a/apps/mcp/README.md b/apps/mcp/README.md index 55ff4b1d..19a8568f 100644 --- a/apps/mcp/README.md +++ b/apps/mcp/README.md @@ -48,14 +48,14 @@ The client discovers the OAuth authorization server through | Tool | Purpose | | --- | --- | -| `search_memory` | Search memories in a space | -| `get_profile` | Get stable and recent profile context for a space | +| `searchMemory` | Search memories in a space | +| `getProfile` | Get stable and recent profile context for a space | | `listDocuments` | List document metadata and summaries in a space | | `getDocument` | Read one document's available content by ID | | `listMemories` | List extracted memory entries and their source document IDs | | `listSpaces` | List spaces visible to the authenticated account | | `whoAmI` | Return identity, access, and active-space context | -| `add_memory` | Save or forget a memory | +| `addMemory` | Save or forget a memory | ### MCP App launchers diff --git a/apps/mcp/e2e/discovery.test.ts b/apps/mcp/e2e/discovery.test.ts index be9ccbb0..4c9bc347 100644 --- a/apps/mcp/e2e/discovery.test.ts +++ b/apps/mcp/e2e/discovery.test.ts @@ -8,10 +8,10 @@ import { } from "./helpers" const EXPECTED_TOOLS = [ - "add_memory", + "addMemory", "fetch-graph-data", "getDocument", - "get_profile", + "getProfile", "guided-save", "listDocuments", "listMemories", @@ -19,7 +19,7 @@ const EXPECTED_TOOLS = [ "memory-graph", "prepare-file-upload", "save-memory", - "search_memory", + "searchMemory", "select-space", "set-active-tag", "upload-file", @@ -28,8 +28,8 @@ const EXPECTED_TOOLS = [ const describeWithAuth = describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE) const READ_ONLY_TOOL_NAMES = [ - "search_memory", - "get_profile", + "searchMemory", + "getProfile", "listDocuments", "listMemories", "getDocument", @@ -76,9 +76,9 @@ describeWithAuth("MCP — discovery & identity", () => { } }) - it("marks add_memory as mutating", async () => { + it("marks addMemory as mutating", async () => { const { tools } = await s.client.listTools() - const memory = tools.find((t) => t.name === "add_memory") + const memory = tools.find((t) => t.name === "addMemory") expect(memory?.annotations).toMatchObject(MEMORY_TOOL_ANNOTATIONS) }) diff --git a/apps/mcp/e2e/helpers.ts b/apps/mcp/e2e/helpers.ts index 0118106d..48797503 100644 --- a/apps/mcp/e2e/helpers.ts +++ b/apps/mcp/e2e/helpers.ts @@ -223,7 +223,7 @@ export async function recallUntil( } = {}, ): Promise { for (let i = 0; i < tries; i++) { - const res = await callTool(client, "search_memory", { + const res = await callTool(client, "searchMemory", { query, ...(containerTag ? { containerTag } : {}), }) diff --git a/apps/mcp/e2e/list-memories.test.ts b/apps/mcp/e2e/list-memories.test.ts index e171cc9b..90187fa1 100644 --- a/apps/mcp/e2e/list-memories.test.ts +++ b/apps/mcp/e2e/list-memories.test.ts @@ -54,7 +54,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)( afterAll(async () => { for (const memory of createdMemories) { - await callTool(session.client, "add_memory", { + await callTool(session.client, "addMemory", { content: memory.content, action: "forget", containerTag: memory.containerTag, diff --git a/apps/mcp/e2e/memory.test.ts b/apps/mcp/e2e/memory.test.ts index 0cd64ff2..0602ab46 100644 --- a/apps/mcp/e2e/memory.test.ts +++ b/apps/mcp/e2e/memory.test.ts @@ -18,7 +18,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => }) afterAll(async () => { for (const { content, containerTag } of created) { - await callTool(s.client, "add_memory", { + await callTool(s.client, "addMemory", { content, action: "forget", ...(containerTag ? { containerTag } : {}), @@ -32,7 +32,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => const content = `e2e round-trip. token=${marker}. The test fruit is dragonfruit.` created.push({ content }) - const save = await callTool(s.client, "add_memory", { + const save = await callTool(s.client, "addMemory", { content, action: "save", }) @@ -43,8 +43,8 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => expect(found, `recall never returned marker ${marker}`).not.toBeNull() }, 120_000) - it("search_memory does not include profile sections", async () => { - const res = await callTool(s.client, "search_memory", { + it("searchMemory does not include profile sections", async () => { + const res = await callTool(s.client, "searchMemory", { query: "dragonfruit", }) expect(res.isError).toBeFalsy() @@ -53,8 +53,8 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => expect(txt).toMatch(/## Matching memories|No matching memories found/i) }, 30_000) - it("get_profile returns profile sections", async () => { - const res = await callTool(s.client, "get_profile", {}) + it("getProfile returns profile sections", async () => { + const res = await callTool(s.client, "getProfile", {}) expect(res.isError).toBeFalsy() const txt = textOf(res) expect(txt).toMatch( @@ -64,7 +64,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => // Hybrid search returns nearest matches even for unrelated queries — assert it responds gracefully, not empty. it("recall responds gracefully for an unmatched query", async () => { - const res = await callTool(s.client, "search_memory", { + const res = await callTool(s.client, "searchMemory", { query: `zzz-no-such-memory-${randomUUID()}`, }) expect(res.isError).toBeFalsy() @@ -78,11 +78,11 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => const content = `e2e forget target. token=${marker}. Secret animal is axolotl.` created.push({ content }) - await callTool(s.client, "add_memory", { content, action: "save" }) + await callTool(s.client, "addMemory", { content, action: "save" }) const found = await recallUntil(s.client, "secret animal axolotl", marker) expect(found, "memory should exist before forget").not.toBeNull() - const forgotten = await callTool(s.client, "add_memory", { + const forgotten = await callTool(s.client, "addMemory", { content, action: "forget", }) @@ -98,7 +98,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => const content = `e2e scoping. token=${marker}. Project color is teal.` created.push({ content, containerTag: tagA }) - await callTool(s.client, "add_memory", { + await callTool(s.client, "addMemory", { content, action: "save", containerTag: tagA, @@ -119,7 +119,7 @@ describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE)("MCP — memory behaviors", () => }, 120_000) it("returns an error result for a missing required argument", async () => { - const res = await callTool(s.client, "search_memory", {}) + const res = await callTool(s.client, "searchMemory", {}) expect(res.isError).toBe(true) expect(textOf(res).length).toBeGreaterThan(0) }) diff --git a/apps/mcp/e2e/space-scope.test.ts b/apps/mcp/e2e/space-scope.test.ts index 3b5c013b..7f914b0a 100644 --- a/apps/mcp/e2e/space-scope.test.ts +++ b/apps/mcp/e2e/space-scope.test.ts @@ -21,17 +21,15 @@ describeWithAuth("MCP - space scoping", () => { const scopedTools = (await scoped.client.listTools()).tools const plainTools = (await plain.client.listTools()).tools - expect(propsOf(plainTools, "add_memory")).toHaveProperty("containerTag") - expect(propsOf(plainTools, "search_memory")).toHaveProperty( - "containerTag", - ) - expect(propsOf(plainTools, "get_profile")).toHaveProperty("containerTag") + expect(propsOf(plainTools, "addMemory")).toHaveProperty("containerTag") + expect(propsOf(plainTools, "searchMemory")).toHaveProperty("containerTag") + expect(propsOf(plainTools, "getProfile")).toHaveProperty("containerTag") - expect(propsOf(scopedTools, "add_memory")).toHaveProperty("containerTag") - expect(propsOf(scopedTools, "search_memory")).toHaveProperty( + expect(propsOf(scopedTools, "addMemory")).toHaveProperty("containerTag") + expect(propsOf(scopedTools, "searchMemory")).toHaveProperty( "containerTag", ) - expect(propsOf(scopedTools, "get_profile")).toHaveProperty("containerTag") + expect(propsOf(scopedTools, "getProfile")).toHaveProperty("containerTag") } finally { await scoped.close() await plain.close() diff --git a/apps/mcp/src/server/analytics.test.ts b/apps/mcp/src/server/analytics.test.ts index ac016419..7b72689d 100644 --- a/apps/mcp/src/server/analytics.test.ts +++ b/apps/mcp/src/server/analytics.test.ts @@ -44,7 +44,7 @@ describe("MCP tool analytics", () => { })) server.registerTool( - "search_memory", + "searchMemory", { inputSchema: z.object({ query: z.string(), containerTag: z.string() }), }, @@ -61,7 +61,7 @@ describe("MCP tool analytics", () => { expect(record).toHaveBeenCalledOnce() expect(record).toHaveBeenCalledWith( expect.objectContaining({ - toolName: "search_memory", + toolName: "searchMemory", surface: "model_tool", outcome: "success", spaceExplicit: true, diff --git a/apps/mcp/src/server/analytics.ts b/apps/mcp/src/server/analytics.ts index 49e9b1e2..5c619d7d 100644 --- a/apps/mcp/src/server/analytics.ts +++ b/apps/mcp/src/server/analytics.ts @@ -33,14 +33,14 @@ type ClientInfoResolver = ( ) => { name: string; version?: string } | null const TOOL_SURFACES: Record = { - search_memory: "model_tool", - get_profile: "model_tool", + searchMemory: "model_tool", + getProfile: "model_tool", listDocuments: "model_tool", getDocument: "model_tool", listMemories: "model_tool", listSpaces: "model_tool", whoAmI: "model_tool", - add_memory: "model_tool", + addMemory: "model_tool", "select-space": "app_launcher", "memory-graph": "app_launcher", "guided-save": "app_launcher", diff --git a/apps/mcp/src/server/tools/add-memory.ts b/apps/mcp/src/server/tools/add-memory.ts index c708deb5..041008df 100644 --- a/apps/mcp/src/server/tools/add-memory.ts +++ b/apps/mcp/src/server/tools/add-memory.ts @@ -15,7 +15,7 @@ export function register(deps: ToolDeps) { }) deps.server.registerTool( - "add_memory", + "addMemory", { description: "Add (save) or forget a memory in the user's ACTIVE space. Defaults to 'save'. The target space is the one the user selected via select-space; pass containerTag only to override it. Use 'forget' when information is outdated or the user asks to remove it.", diff --git a/apps/mcp/src/server/tools/get-profile.test.ts b/apps/mcp/src/server/tools/get-profile.test.ts index 7c7a92f5..b101f0df 100644 --- a/apps/mcp/src/server/tools/get-profile.test.ts +++ b/apps/mcp/src/server/tools/get-profile.test.ts @@ -34,11 +34,11 @@ function registerProfile(client: { }), } as unknown as ToolDeps) - if (!handler) throw new Error("get_profile was not registered") + if (!handler) throw new Error("getProfile was not registered") return handler } -describe("get_profile", () => { +describe("getProfile", () => { it("returns stable and recent profile facts for the resolved space", async () => { const handler = registerProfile({ getProfile: async () => ({ diff --git a/apps/mcp/src/server/tools/get-profile.ts b/apps/mcp/src/server/tools/get-profile.ts index c84b0a46..870b6932 100644 --- a/apps/mcp/src/server/tools/get-profile.ts +++ b/apps/mcp/src/server/tools/get-profile.ts @@ -11,11 +11,11 @@ export function register(deps: ToolDeps) { }) deps.server.registerTool( - "get_profile", + "getProfile", { title: "Get Profile", description: - "Get the stable and recent profile for one space — long-lived facts plus recent context. search_memory does not include this. After searching, call this if matching memories are not enough and you need who-the-user-is, preferences, or recent context. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space. Use whoAmI for account identity and access, not profile facts.", + "Get the stable and recent profile for one space — long-lived facts plus recent context. searchMemory does not include this. After searching, call this if matching memories are not enough and you need who-the-user-is, preferences, or recent context. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space. Use whoAmI for account identity and access, not profile facts.", inputSchema, outputSchema: getProfileOutputSchema, annotations: READ_ONLY_TOOL_ANNOTATIONS, diff --git a/apps/mcp/src/server/tools/guided-save.ts b/apps/mcp/src/server/tools/guided-save.ts index c3f3c042..7eb1d793 100644 --- a/apps/mcp/src/server/tools/guided-save.ts +++ b/apps/mcp/src/server/tools/guided-save.ts @@ -11,7 +11,7 @@ export function register(deps: ToolDeps) { { title: "Add Memory", description: - "Open an interactive form when the user wants to draft, review, edit, or choose the target space before saving information to Supermemory. Use this when the user wants to add a memory but has not supplied final content, or explicitly wants to review supplied content before saving. If the user provides the exact content and asks to save it immediately, use add_memory instead.", + "Open an interactive form when the user wants to draft, review, edit, or choose the target space before saving information to Supermemory. Use this when the user wants to add a memory but has not supplied final content, or explicitly wants to review supplied content before saving. If the user provides the exact content and asks to save it immediately, use addMemory instead.", inputSchema: z.object({ prefill: z .string() diff --git a/apps/mcp/src/server/tools/list-memories.ts b/apps/mcp/src/server/tools/list-memories.ts index 37c36b07..e5eafd22 100644 --- a/apps/mcp/src/server/tools/list-memories.ts +++ b/apps/mcp/src/server/tools/list-memories.ts @@ -33,7 +33,7 @@ export function register(deps: ToolDeps) { { title: "List Memories", description: - "List the latest extracted memory entries in one space, including stable memory IDs, version information, and source document IDs. This lists memories directly, not documents. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space. Use search_memory instead for semantic recall.", + "List the latest extracted memory entries in one space, including stable memory IDs, version information, and source document IDs. This lists memories directly, not documents. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space. Use searchMemory instead for semantic recall.", inputSchema, outputSchema: listMemoriesOutputSchema, annotations: READ_ONLY_TOOL_ANNOTATIONS, diff --git a/apps/mcp/src/server/tools/search-memory.test.ts b/apps/mcp/src/server/tools/search-memory.test.ts index ed65a770..fe36ecde 100644 --- a/apps/mcp/src/server/tools/search-memory.test.ts +++ b/apps/mcp/src/server/tools/search-memory.test.ts @@ -46,11 +46,11 @@ function registerSearch(client: { }), } as unknown as ToolDeps) - if (!handler) throw new Error("search_memory was not registered") + if (!handler) throw new Error("searchMemory was not registered") return handler } -describe("search_memory", () => { +describe("searchMemory", () => { it("returns matching memories without fetching or including profile", async () => { const getProfile = vi.fn() const handler = registerSearch({ diff --git a/apps/mcp/src/server/tools/search-memory.ts b/apps/mcp/src/server/tools/search-memory.ts index 67fb5d17..1f0ec520 100644 --- a/apps/mcp/src/server/tools/search-memory.ts +++ b/apps/mcp/src/server/tools/search-memory.ts @@ -18,10 +18,10 @@ export function register(deps: ToolDeps) { }) deps.server.registerTool( - "search_memory", + "searchMemory", { description: - "Search memories in one space with a natural-language query. Returns matching memories only — not the space profile. If you need who-the-user-is, preferences, or recent context after searching, call get_profile. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space.", + "Search memories in one space with a natural-language query. Returns matching memories only — not the space profile. If you need who-the-user-is, preferences, or recent context after searching, call getProfile. When the user names a space, resolve it with listSpaces and pass containerTag; otherwise use the active space.", inputSchema, outputSchema: searchMemoryOutputSchema, annotations: READ_ONLY_TOOL_ANNOTATIONS,