can1357/oh-my-pi · error

mcp:// URL requires a resource URI: mcp://<resource-uri>

Error message

mcp:// URL requires a resource URI: mcp://<resource-uri>

What it means

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.

Source

Thrown at packages/coding-agent/src/internal-urls/mcp-protocol.ts:38

	return { literalChars, expressionCount };
}

function extractResourceUri(url: InternalUrl): string {
	const scheme = url.protocol.replace(/:$/, "").toLowerCase();
	if (scheme !== "mcp") {
		// Server-advertised native URI (hierarchical or opaque). Preserve the
		// input byte-for-byte: `resolveTargetServer` matches by exact string
		// equality, so e.g. `catalog://root/` must keep its trailing slash.
		return url.rawHref ?? url.href;
	}
	// Legacy `mcp://<resource-uri>` wrapper: reconstruct the wrapped URI and
	// elide a bare trailing `/` that URL parsing adds to host-only forms.
	const host = url.rawHost || url.hostname;
	const rawPathname = url.rawPathname ?? url.pathname;
	const hasPath = rawPathname && rawPathname !== "/";
	const uri = `${host}${hasPath ? rawPathname : ""}${url.search}${url.hash}`.trim();
	if (!uri) {
		throw new Error("mcp:// URL requires a resource URI: mcp://<resource-uri>");
	}
	return uri;
}

function resolveTargetServer(mcpManager: MCPManager, uri: string): string | undefined {
	const servers = mcpManager.getConnectedServers();
	for (const name of servers) {
		const serverResources = mcpManager.getServerResources(name);
		if (serverResources?.resources.some(r => r.uri === uri)) {
			return name;
		}
	}

	let bestTemplateMatch:
		| {
				serverName: string;
				literalChars: number;
				expressionCount: number;

View on GitHub (pinned to 9690622007)

Solutions

  1. 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.
  2. Look up the exact resource URI via MCPManager.getServerResources(name) and embed it verbatim in the mcp:// URL.
  3. Fix the code that emptied the URL before resolution — keep the full original href.

Example fix

// before
resolve("mcp://");
// after
resolve("mcp://catalog://root/data");
Defensive patterns

Strategy: validation

Validate before calling

const rest = url.slice('mcp://'.length);
if (!rest || rest === '/') throw new Error('mcp:// URL must embed a resource URI: mcp://<resource-uri>');

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/25a4aca87375eea2. Report an issue: GitHub.