mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-09 03:18:04 +00:00
fix(mcp): reject nonexistent container tags in set-active-tag and search_memory
set-active-tag accepted any tag string even if it did not exist, and search_memory surfaced a generic "Access forbidden" 403 for unknown tags. Both tools now validate the tag against the user's container tag list and return a clear "does not exist" error pointing at listSpaces. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
440e9e94bd
commit
df671c6e41
4 changed files with 45 additions and 1 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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<string, z.ZodTypeAny> = 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
21
apps/mcp/src/server/tools/validate-container-tag.ts
Normal file
21
apps/mcp/src/server/tools/validate-container-tag.ts
Normal file
|
|
@ -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<boolean> {
|
||||
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.`,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue