Hmbown/CodeWhale · error

resource " " is not part of the bundled skill pack —…

Error message

resource "${params?.uri ?? ""}" is not part of the bundled skill pack — resources/list names the readable URIs

What it means

The computer-use MCP server implements resources/read by looking up the requested URI in the bundled `skillPack` array (the files exposed via resources/list). If no entry matches the given `params.uri`, it throws a paramError explaining that the resource is not part of the bundled skill pack and that resources/list names the readable URIs. It is a strict allow-list: only URIs exactly matching a bundled file can be read.

Solutions

  1. Call resources/list first and copy a uri from its response verbatim into resources/read.
  2. Check the client's cached URIs against the current server version — regenerate them from resources/list if the skill pack changed.
  3. Ensure the params object actually includes a `uri` field with the exact string (no path-style substitution, no case/trailing-slash differences).
  4. If the needed resource genuinely should exist, rebuild/update the plugin so skillPack contains it.

Example fix

// before
await mcp.request({ method: "resources/read", params: { uri: "docs/getting-started.md" } });
// after
const { resources } = await mcp.request({ method: "resources/list" });
const wanted = resources.find((r) => r.name === "getting-started.md");
await mcp.request({ method: "resources/read", params: { uri: wanted.uri } });
Defensive patterns

Strategy: validation

Validate before calling

// Before calling resources/read:
const { resources } = await client.listResources();
const readable = new Set(resources.map((r) => r.uri));
if (!readable.has(myUri)) {
  throw new Error(`URI "${myUri}" not offered; use one of: ${[...readable].join(", ")}`);
}

Type guard

function isKnownResourceUri(uri, resources) {
  return typeof uri === 'string' && resources.some((r) => r.uri === uri);
}

Try / catch

try {
  const res = await client.readResource({ uri });
} catch (err) {
  if (String(err.message).includes('not part of the bundled skill pack')) {
    const { resources } = await client.listResources();
    // re-read with resources[0].uri or surface the valid URIs to the user
  } else throw err;
}

Prevention

When it happens

Trigger: An MCP client calls resources/read with a uri that is not in skillPack: a stale URI cached from an older server version, a guessed/constructed URI, a file path instead of the pack's URI scheme, an omitted uri (params undefined yields "" in the message), or a URI with different casing/whitespace than the exact registered one.

Common situations: A client hard-coded resource URIs from an older plugin version before the skill pack changed; a developer tests resources/read with a local file path like /docs/skill.md instead of the pack's canonical URI; an LLM-driven client hallucinates a plausible URI; the request omits params entirely so uri falls back to the empty string.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/c2ff1bbfa539e4b7. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/mcp/server.mjs:1273

        experimental: { "io.modelcontextprotocol/skills": {} },
      },
      serverInfo: { name: SERVER_NAME, version: APP_VERSION, platforms: ["darwin", "win32", "linux", "harmonyos"], transports: ["local", "ssh", "hdc"] },
    };
  },
  "tools/list"() {
    // The advertised surface is what every session pays for; merged-away wire
    // names stay callable as aliases but are never listed. A capability grant
    // narrows the listing further, never widens it.
    const advertised = TOOLS.filter((t) => t.hidden !== true);
    if (!GRANT) return { tools: advertised };
    return { tools: advertised.filter((t) => t.name === "stop_computer_control" || GRANT.has(t.name) || (MERGED_EXPANSION[t.name] ?? []).some((wire) => GRANT.has(wire))) };
  },
  "resources/list"() {
    return { resources: skillPack.map(({ uri, rel, mime, size }) => ({ uri, name: rel, mimeType: mime, size })) };
  },
  "resources/read"(params) {
    const file = skillPack.find((f) => f.uri === params?.uri);
    if (!file) throw paramError(`resource "${params?.uri ?? ""}" is not part of the bundled skill pack — resources/list names the readable URIs`);
    return { contents: [{ uri: file.uri, mimeType: file.mime, text: file.text }] };
  },
  "skills/list"() {
    return {
      skills: [{
        uri: SKILL_ROOT_URI, name: SKILL_NAME, description: SKILL_DESCRIPTION,
        files: skillPack.map(({ uri, sha256, size }) => ({ uri, sha256, bytes: size })),
      }],
    };
  },
  "skills/get"(params) {
    const entry = skillPack.find((f) => f.uri === (params?.uri ?? SKILL_ROOT_URI));
    if (!entry) throw paramError(`skill "${params?.uri ?? ""}" is unknown — skills/list names the catalog`);
    return {
      skill: { uri: entry.uri, name: SKILL_NAME, description: SKILL_DESCRIPTION, frontmatter: entry.frontmatter, content: entry.text },
      manifest: skillPack.map(({ uri, sha256, size }) => ({ uri, sha256, bytes: size })),
    };
  },

View on GitHub (pinned to 73e0f67d83)