modelcontextprotocol/servers · error · Error

Unknown resource

Error message

Unknown resource: ${uri.toString()}

What it means

Thrown by `parseResourceId` in the resource-template resolver when the URI neither starts with the text base nor the blob base. The first guard is a defensive check: a URI reaching this resolver is expected to match one of the two registered template prefixes (`demo://resource/dynamic/text` or `.../blob`). Reaching it with any other URI is treated as an unknown resource.

Solutions

  1. Ensure the requested URI matches one of the registered templates: `demo://resource/dynamic/text/{id}` or `demo://resource/dynamic/blob/{id}`.
  2. Use the resources/templates/list response to obtain valid URI templates rather than constructing them by hand.
  3. Route static (non-templated) resource URIs to the static resource handler, not the dynamic template resolver.

Example fix

// before
readResource('demo://resource/static/text/1')
// after
readResource('demo://resource/dynamic/text/1')
Defensive patterns

Strategy: validation

Validate before calling

const TEXT_BASE = 'demo://resource/dynamic/text';
const BLOB_BASE = 'demo://resource/dynamic/blob';
function isKnownDynamicUri(u: string): boolean {
  return u.startsWith(TEXT_BASE) || u.startsWith(BLOB_BASE);
}
// only route URIs that pass this check to the dynamic template handler

Type guard

function isDynamicResourceUri(uri: URL): boolean {
  const s = uri.toString();
  return s.startsWith('demo://resource/dynamic/text/') || s.startsWith('demo://resource/dynamic/blob/');
}

Prevention

When it happens

Trigger: A resources/read or template-completion request whose URI does not begin with `demo://resource/dynamic/text` or `demo://resource/dynamic/blob` — e.g. a client constructs `demo://resource/dynamic/other/1` or sends a static resource URI to the dynamic template handler.

Common situations: Misrouting requests to the wrong template handler, typos in hand-built URIs, or a client that strips/rewrites the scheme. Note the logic uses `&&` (both startsWith checks), so in practice this branch is hard to hit unless the URI matches neither prefix — which then falls into the else and validates the id; this specific throw is reached only when the URI is entirely foreign to both bases.

Related errors


AI-assisted analysis of modelcontextprotocol/servers@579c3903f3 (2026-09-01). Data as JSON: /api/errors/b71605bbcaf2a97c. Report an issue: GitHub.

Appendix: source

Thrown at src/everything/resources/templates.ts:149

 * that it is a positive integer.
 *
 * The SDK only routes URIs that match the registered template to the
 * resource handler, so by the time we get here the URI prefix is already
 * known to be one of `textUriBase` / `blobUriBase`. Only the resourceId
 * variable still needs validating.
 *
 * @param {URL} uri - The URI of the resource (used in the error message).
 * @param {Record<string, unknown>} variables - Context variables including resourceId.
 * @returns {number} The parsed and validated resource identifier as a positive integer.
 * @throws {Error} If the resourceId is not a finite positive integer.
 */
const parseResourceId = (uri: URL, variables: Record<string, unknown>) => {
  const idxStr = String((variables as any).resourceId ?? "");
  const idx = Number(idxStr);
  if (Number.isFinite(idx) && Number.isInteger(idx) && idx > 0) {
    return idx;
  }
  throw new Error(`Unknown resource: ${uri.toString()}`);
};

/**
 * Register resource templates with the MCP server.
 * - Text and blob resources, dynamically generated from the URI {resourceId} variable
 * - Any finite positive integer is acceptable for the resourceId variable
 * - List resources method will not return these resources
 * - These are only accessible via template URIs
 * - Both blob and text resources:
 *   - have content that is dynamically generated, including a timestamp
 *   - have different template URIs
 *     - Blob: "demo://resource/dynamic/blob/{resourceId}"
 *     - Text: "demo://resource/dynamic/text/{resourceId}"
 *
 * @param server
 */
export const registerResourceTemplates = (server: McpServer) => {
  // Register the text resource template

View on GitHub (pinned to 579c3903f3)