diff --git a/apps/mcp/src/server/client/index.ts b/apps/mcp/src/server/client/index.ts index 0beb9f8d..220eea92 100644 --- a/apps/mcp/src/server/client/index.ts +++ b/apps/mcp/src/server/client/index.ts @@ -377,7 +377,9 @@ export class SupermemoryClient { case 402: throw new Error("Memory limit reached. Upgrade at supermemory.ai") case 403: - throw new Error("Access forbidden.") + throw new Error( + `Access forbidden: you don't have access to container tag '${this.containerTag}', or it doesn't exist. Use listSpaces to see the available container tags.`, + ) case 404: throw new Error("Not found.") case 429: diff --git a/apps/mcp/src/server/tools/search-memory.ts b/apps/mcp/src/server/tools/search-memory.ts index 0c7ca491..a4b7431b 100644 --- a/apps/mcp/src/server/tools/search-memory.ts +++ b/apps/mcp/src/server/tools/search-memory.ts @@ -1,6 +1,10 @@ import { z } from "zod" import { getMemoryText } from "../client" import type { ToolDeps } from "./types" +import { + containerTagExists, + unknownContainerTagError, +} from "./validate-container-tag" export function register(deps: ToolDeps) { const containerTagField: Record = deps.rbac @@ -43,6 +47,12 @@ export function register(deps: ToolDeps) { ), ) } + if ( + args.containerTag && + !(await containerTagExists(deps, args.containerTag)) + ) { + return deps.errorResult(unknownContainerTagError(args.containerTag)) + } const effectiveTag = await deps.resolveContainerTag(args.containerTag) const client = deps.getClient(effectiveTag) diff --git a/apps/mcp/src/server/tools/set-active-tag.ts b/apps/mcp/src/server/tools/set-active-tag.ts index bc43fe6a..31e65441 100644 --- a/apps/mcp/src/server/tools/set-active-tag.ts +++ b/apps/mcp/src/server/tools/set-active-tag.ts @@ -2,6 +2,10 @@ import { registerAppTool } from "@modelcontextprotocol/ext-apps/server" import { z } from "zod" import { SUPERMEMORY_RESOURCE_URI, type ViewMessage } from "../../shared/types" import type { ToolDeps } from "./types" +import { + containerTagExists, + unknownContainerTagError, +} from "./validate-container-tag" export function register(deps: ToolDeps) { registerAppTool( @@ -26,6 +30,13 @@ export function register(deps: ToolDeps) { new Error(`No access to container tag '${containerTag}'.`), ) } + try { + if (!(await containerTagExists(deps, containerTag))) { + return deps.errorResult(unknownContainerTagError(containerTag)) + } + } catch (error) { + return deps.errorResult(error) + } await deps.storage.put("activeContainerTag", containerTag) const sc: ViewMessage = { view: "confirmation", diff --git a/apps/mcp/src/server/tools/validate-container-tag.ts b/apps/mcp/src/server/tools/validate-container-tag.ts new file mode 100644 index 00000000..5ba0c860 --- /dev/null +++ b/apps/mcp/src/server/tools/validate-container-tag.ts @@ -0,0 +1,21 @@ +import type { ToolDeps } from "./types" + +/** + * Checks whether a container tag actually exists for this user. + * Fast path is the cached tag list from init; on a miss we re-fetch once so + * tags created after the session started are not falsely rejected. + */ +export async function containerTagExists( + deps: ToolDeps, + containerTag: string, +): Promise { + if (deps.cachedContainerTags().includes(containerTag)) return true + await deps.refreshContainerTags() + return deps.cachedContainerTags().includes(containerTag) +} + +export function unknownContainerTagError(containerTag: string): Error { + return new Error( + `Container tag '${containerTag}' does not exist. Use listSpaces to see the available container tags.`, + ) +}