paperclipai/paperclip · error · ToolGatewayHttpError
mcp_${kind}_not_found
mcp_${kind}_not_found
Error message
Assigned MCP ${kind} was not found What it means
The tool gateway resolves MCP resources/prompts through opaque context handles (e.g. 'ctx:<connectionId>:<uri>') produced by earlier tools/list, resources/list, or prompts/list calls. When handling resources/read, resources/get, or prompts/get, it parses the handle back into a connection ID and looks the connection up among the agent's assigned connections. If the handle is malformed, belongs to a different/unassigned connection, or the connection was removed, it throws this 404 ToolGatewayHttpError with reason code mcp_resource_not_found or mcp_prompt_not_found.
Solutions
- Re-run tools/list / resources/list / prompts/list against the current connection set and use a freshly returned handle instead of a cached or hand-built one.
- Verify the MCP connection referenced by the handle is still assigned to this agent/company in the connections settings.
- If passing raw URIs/names, wrap them via the gateway's context-handle format (connectionId + value) as produced by the list endpoints.
- Check for stale clients holding handles across reconfiguration; refresh the session after changing connections.
Example fix
// before
await gateway.invoke({ method: "resources/read", params: { uri: "docs/readme" } });
// after
const { resources } = await gateway.invoke({ method: "resources/list", params: {} });
await gateway.invoke({ method: "resources/read", params: { uri: resources[0].uri } }); // use the returned context handle Defensive patterns
Strategy: validation
Validate before calling
function isValidResourceHandle(uri, assignedConnections) {
const m = /^ctx:[^:]+:(.+)$/.exec(String(uri ?? ""));
if (!m) return false;
return assignedConnections.some((c) => uri.startsWith(`ctx:${c.id}:`));
}
if (!isValidResourceHandle(params.uri, connections)) throw new Error("stale resource handle; re-list resources"); Type guard
const isContextHandle = (v) => typeof v === "string" && /^ctx:[A-Za-z0-9-]+:/.test(v);
Try / catch
try {
await gateway.invoke({ method: "resources/read", params: { uri } });
} catch (e) {
if (e.reasonCode === "mcp_resource_not_found" || e.reasonCode === "mcp_prompt_not_found") {
({ resources } = await gateway.invoke({ method: "resources/list", params: {} })); // refresh handles and retry
} else throw e;
} Prevention
- Always use handles returned by resources/list or prompts/list, never hand-built URIs.
- Refresh cached handles after any change to the agent's connection assignments.
- Re-list resources at the start of a session rather than reusing handles across sessions.
- Monitor for connection removal events and invalidate cached handles.
When it happens
Trigger: Calling resources/read or prompts/get with a uri/name that is not a valid context handle, references a connectionId that is no longer in the caller's assigned connection list, or references a connection that was deleted or unassigned between the list call and the read call.
Common situations: A developer caches a resource URI from a previous session and reuses it after the MCP connection was disconnected or reassigned; a hand-written URI is passed instead of the handle returned by resources/list; the agent's connection assignments changed mid-session so the handle's connectionId no longer resolves.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- error.reasonCode
- github_tool_unavailable
- grant_audience_denied
- local_stdio_missing_secret
- mcp_transport_unsupported
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/d70a8453ad607032.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:5348
prompts.push({
...record,
name: contextHandle("prompt", connection.id, record.name),
title: `${connection.name}: ${typeof record.title === "string" ? record.title : record.name}`,
});
}
}
return { prompts };
}
const kind = input.method === "resources/read" ? "resource" : "prompt";
const handle = parseContextHandle(
kind,
input.params?.[kind === "resource" ? "uri" : "name"],
);
const connection = handle
? connections.find((candidate) => candidate.id === handle.connectionId)
: null;
if (!handle || !connection) {
throw new ToolGatewayHttpError(
404,
`Assigned MCP ${kind} was not found`,
`mcp_${kind}_not_found`,
);
}
const params =
kind === "resource"
? { uri: handle.value }
: { name: handle.value, arguments: input.params?.arguments ?? {} };
const result = asRecord(
await callAssignedConnectionProtocol({
...input,
session,
connection,
method: input.method,
params,
}),
);View on GitHub (pinned to 3f1d897a7c)