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

  1. 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.
  2. Verify the MCP connection referenced by the handle is still assigned to this agent/company in the connections settings.
  3. If passing raw URIs/names, wrap them via the gateway's context-handle format (connectionId + value) as produced by the list endpoints.
  4. 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

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


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)