Skip to content

read_resource: optional extension_name causes silent probe-all across extensions #8988

@olaservo

Description

@olaservo

Describe the bug

The read_resource tool the Extension Manager exposes to the model treats extension_name as optional, and when the model omits it, the handler iterates every resource-capable extension, swallows every error, and returns the first match. This produces silent failures on URI collisions and silent loss of distinguishable errors (auth, transport, not-found, server-side). The tool description actively encourages the model to take this path.

A related but separate bug: the list_resources JSON schema declares extension_name, but the handler reads params.get("extension") — model calls passing extension_name are silently ignored and fall into the same fan-out.


To Reproduce

  1. Connect goose to two MCP servers that both expose a resource at the same URI (e.g. two filesystem-style servers both exposing file:///some/path, or two skill-style servers both exposing skill://example/SKILL.md).
  2. Start a session and ask the model to read that URI.
  3. Observe that the model calls read_resource with uri only (the tool description encourages this), and goose silently returns whichever extension happens to be hit first by the iteration order, with no indication that there was ambiguity.

To reproduce the related list_resources mismatch:

  1. Connect goose to multiple resource-capable extensions.
  2. Have the model call list_resources with {"extension_name": "<known>"}.
  3. Observe that the result is the multi-extension fan-out, not the filtered per-extension list. The extension_name argument was silently ignored because the handler reads extension.

Expected behavior

  • read_resource should require extension_name. The model already has the (extension, uri) pair available from list_resources, whose output at extension_manager.rs:1482 is formatted extension - name, uri: (uri).
  • When the extension is unknown, surface the existing "Extension '{}' not found. Here are the available extensions: …" error (already at extension_manager.rs:1394-1402).
  • The fan-out loop and Err(_) => continue should be removed entirely; the in-code TODO about URI collisions becomes moot.
  • list_resources's handler should read extension_name to match its declared schema. The field stays optional (list-all is the natural default for discovery), and only the parameter name needs to be reconciled.

Screenshots

N/A


  • OS & Arch: Not platform-specific (model-facing tool contract)
  • Interface: Both UI and CLI affected (Extension Manager is shared)
  • Version: goose crate 1.33.0 (current main, branched at 45d8bf81d)
  • Extensions enabled: Reproducible with any combination of two or more resource-capable extensions
  • Provider & Model: Provider-agnostic; reproduces with any model that uses the Extension Manager's read_resource / list_resources tools

Additional context

Proposed fix

  1. Make ReadResourceParams.extension_name required.
  2. Rewrite the read_resource tool description to direct the model to call list_resources first when ownership is unknown.
  3. Remove the fan-out fallback in read_resource_tool; rely on the existing read_resource() helper's error path.
  4. Fix the list_resources param-name mismatch (extensionextension_name).

Tradeoff considered

If the model has a bare URI from outside (chat paste, memory recall, etc.) it can't call read_resource directly — it has to call list_resources first to find the owning extension. That's one extra round-trip in a rare (?) case, in exchange for retiring the silent probe path in the common case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions