{"record":{"id":"25a4aca87375eea2","repo":"can1357/oh-my-pi","slug":"mcp-url-requires-a-resource-uri-mcp-resourc","errorCode":null,"errorMessage":"mcp:// URL requires a resource URI: mcp://<resource-uri>","messagePattern":"mcp:// URL requires a resource URI: mcp://<resource-uri>","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/mcp-protocol.ts","lineNumber":38,"sourceCode":"\treturn { literalChars, expressionCount };\n}\n\nfunction extractResourceUri(url: InternalUrl): string {\n\tconst scheme = url.protocol.replace(/:$/, \"\").toLowerCase();\n\tif (scheme !== \"mcp\") {\n\t\t// Server-advertised native URI (hierarchical or opaque). Preserve the\n\t\t// input byte-for-byte: `resolveTargetServer` matches by exact string\n\t\t// equality, so e.g. `catalog://root/` must keep its trailing slash.\n\t\treturn url.rawHref ?? url.href;\n\t}\n\t// Legacy `mcp://<resource-uri>` wrapper: reconstruct the wrapped URI and\n\t// elide a bare trailing `/` that URL parsing adds to host-only forms.\n\tconst host = url.rawHost || url.hostname;\n\tconst rawPathname = url.rawPathname ?? url.pathname;\n\tconst hasPath = rawPathname && rawPathname !== \"/\";\n\tconst uri = `${host}${hasPath ? rawPathname : \"\"}${url.search}${url.hash}`.trim();\n\tif (!uri) {\n\t\tthrow new Error(\"mcp:// URL requires a resource URI: mcp://<resource-uri>\");\n\t}\n\treturn uri;\n}\n\nfunction resolveTargetServer(mcpManager: MCPManager, uri: string): string | undefined {\n\tconst servers = mcpManager.getConnectedServers();\n\tfor (const name of servers) {\n\t\tconst serverResources = mcpManager.getServerResources(name);\n\t\tif (serverResources?.resources.some(r => r.uri === uri)) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\tlet bestTemplateMatch:\n\t\t| {\n\t\t\t\tserverName: string;\n\t\t\t\tliteralChars: number;\n\t\t\t\texpressionCount: number;","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/mcp-protocol.ts#L20-L56","documentation":"The mcp:// scheme wraps an MCP resource URI in the URL authority/path (mcp://<resource-uri>). extractResourceUri reconstructs the wrapped URI from host+pathname+search+hash; if every part is empty — i.e. the caller passed the bare URL 'mcp://' — there is no resource URI to look up, so it throws with the expected usage form.","triggerScenarios":"Resolving the literal URL 'mcp://' via the internal-URL router's mcp handler; stripping the wrapped URI during URL parsing so hostname and pathname are both empty; template/placeholder not filled in before resolution.","commonSituations":"Copy-pasted links where the resource part was lost; code that trims everything after the scheme; agents emitting the scheme without a URI when the MCP resource list was empty.","solutions":["Include the wrapped resource URI in the URL, e.g. mcp://catalog://root or mcp://server/path/resource, matching a URI advertised by a connected MCP server.","Look up the exact resource URI via MCPManager.getServerResources(name) and embed it verbatim in the mcp:// URL.","Fix the code that emptied the URL before resolution — keep the full original href."],"exampleFix":"// before\nresolve(\"mcp://\");\n// after\nresolve(\"mcp://catalog://root/data\");","handlingStrategy":"validation","validationCode":"const rest = url.slice('mcp://'.length);\nif (!rest || rest === '/') throw new Error('mcp:// URL must embed a resource URI: mcp://<resource-uri>');","typeGuard":null,"tryCatchPattern":"try { resource = await handler.resolve(url, ctx); } catch (e) { if (String(e.message).includes('requires a resource URI')) { /* prompt for / look up a valid resource URI */ } else throw e; }","preventionTips":["Copy resource URIs verbatim from MCPManager.getServerResources(name) listings.","Never build mcp:// URLs from templates without verifying the URI placeholder was filled.","Preserve the full href — don't trim content after the scheme."],"tags":["mcp","url","validation"],"backgroundTag":"missing-resource-uri","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}