feat(discovery): AI Catalog / Server Card auto-discovery (SEP-2127) — CLI + Desktop#1
Draft
tadasant wants to merge 2 commits into
Draft
feat(discovery): AI Catalog / Server Card auto-discovery (SEP-2127) — CLI + Desktop#1tadasant wants to merge 2 commits into
tadasant wants to merge 2 commits into
Conversation
Experimental background "sidecar" that observes the domains a Goose session touches, probes them for an AI Catalog (/.well-known/ai-catalog.json) and the Server Cards / Skills bundles they reference, and surfaces a non-intrusive one-click install nudge — without ever blocking the agent loop. Installing a discovered MCP server (running auth if the card requires it) makes it active in the SAME session. Core (crates/goose/src/discovery): - DiscoveryService sidecar with three modes (Off / Light-touch / Full) read from the `discovery_mode` config key. Light captures only fetch/search/browse tool calls; Full captures every domain in any tool call's arguments. - Server Card + AI Catalog + Skills bundle types; resolver abstraction with a hand-authored fixture layer (no domain serves a real catalog yet). - server_card_to_extension maps a card to an ExtensionConfig::StreamableHttp, injecting the card's auth header (e.g. `Authorization: Bearer <token>`). - Agent observes each tool call (non-blocking) via discovery.observe_tool_call. goose-server (crates/goose-server/src/routes/discovery.rs): - /discovery/pending, /discovery/install, /discovery/dismiss, /discovery/mode. install adds the extension to the live agent session and returns the now- callable tools. A flat DiscoveryCard DTO decouples the UI from internal types. CLI (crates/goose-cli/src/session): - Inline terminal nudge rendered between turns, with a y/N install prompt and a post-install confirmation listing the new tools. Desktop (ui/desktop): - DiscoveryNudge rendered between the transcript and the prompt input: server card (Install) + Skills bundle (View) entries, auth-token entry for cards that require it, and an "active in this session" confirmation with the new tools. - DiscoverySettingsSection: Off / Light-touch / Full selector in Chat settings. Fixtures: - modelcontextprotocol.io -> a minimal REAL, auth-less card for the live MCP server at https://modelcontextprotocol.io/mcp (search_model_context_protocol), plus a Skills bundle. Installing actually connects and the tool actually works. - github.com -> mocked GitHub MCP server card (api.githubcopilot.com/mcp/, Authorization header) to drive the auth-entry install flow. Co-Authored-By: Claude Opus 4.8 <[email protected]>
…y CI - cargo fmt across the discovery feature files (goose, goose-server, goose-cli) - Box the Server variant of DiscoveryKind to fix clippy::large_enum_variant (ServerCard is much larger than SkillsBundle) Co-Authored-By: Claude Opus 4.8 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AI Catalog / Server Card auto-discovery (SEP-2127) — CLI + Desktop
Experimental, opt-in feature: a background "sidecar" watches the domains a Goose session touches, probes them for an AI Catalog (
GET https://<domain>/.well-known/ai-catalog.json) and the Server Cards / Skills bundles it references, and surfaces a non-intrusive, one-click install nudge — without ever blocking the agent loop. Installing a discovered MCP server (running its auth flow if the card requires one) makes it active in the same session, immediately callable.Implements the SEP-2127 "Server Cards" / AI Catalog discovery concept on both surfaces: the Goose CLI and the Goose Desktop app.
Demo videos (Desktop)
Rendered from the real
DiscoveryNudge/DiscoverySettingsSectioncomponents with the production dark theme (captured headlessly; the container has no GUI/GTK for full Electron). The chat transcript around the nudge is a scripted re-enactment; the nudge, its install/auth flow, and the settings selector are the real components. The fully-live, end-to-end proof is the CLI run below.① Full flow — prompt → response → discovery → install → calling the new tool (~44s):
▶ https://storage.googleapis.com/remote-filesystem-tadas/screenshots/goose-discovery/goose-discovery-flow.mp4
A single session: you ask a question → Goose runs a
fetchtool call that touchesmodelcontextprotocol.io→ the sidecar surfaces its Server Card → one click installs it → a follow-up prompt immediately calls the newsearch_model_context_protocol · docs-servertool and gets the real Elicitation doc back.② Component walkthrough — install, auth-entry, and the settings selector (~47s):
▶ https://storage.googleapis.com/remote-filesystem-tadas/screenshots/goose-discovery/goose-discovery-demo.mp4
How it works
Discovery modes (
discovery_modeconfig key)Exposed in both the CLI config and the Desktop Settings → Chat pane.
Surfaces
crates/goose/src/discovery/(DiscoveryService, Server Card / AI Catalog / Skills types, resolver + fixture layer, card→extension mapping with auth-header injection).Agentcallsobserve_tool_callper tool call.crates/goose-server/src/routes/discovery.rs:/discovery/pending,/discovery/install,/discovery/dismiss,/discovery/mode.installadds the extension to the live agent session and returns the now-callable tools.crates/goose-cli/src/session/: inline terminal nudge between turns with ay/Ninstall prompt and a post-install confirmation listing new tools.ui/desktop/src/components/discovery/DiscoveryNudge.tsx(rendered between the transcript and the prompt input) +settings/discovery/DiscoverySettingsSection.tsx.Fixtures (clearly labeled
fixture = true)No public domain serves a real
/.well-known/ai-catalog.jsonyet, so the cards the sidecar would fetch are hand-authored incrates/goose/src/discovery/fixtures.rs:modelcontextprotocol.io→ a minimal but REAL, auth-less Server Card for the live MCP server athttps://modelcontextprotocol.io/mcp. The endpoint and itssearch_model_context_protocoltool are real — installing actually connects and the tool actually works (this is the headline demo). Plus a Skills bundle.github.com/api.githubcopilot.com→ a mocked GitHub MCP Server card (https://api.githubcopilot.com/mcp/,Authorizationheader auth) used to drive the auth-entry install flow.Demo instructions (macOS)
All commands assume an inference provider. The screenshots/transcripts below used OpenRouter with a cheap tool-calling model. Set your own key — do not commit it:
CLI
Desktop
Verification
Desktop UI — screenshots of the real components
These are the real
DiscoveryNudge/DiscoverySettingsSectionReact components, rendered with the production Tailwind theme (the exact dark-mode token palette injected by the app'sapplyThemeTokens) and representative fixture data, captured headlessly.mcp_docsis now active in this session" + the now-callablesearch_model_context_protocoltool:github_mcpis now active in this session" +search_repositories, create_issue, get_pull_request:Desktop UI — component tests
vitest runover the discovery components — 4/4 passed: nudge renders the auth-less card + installs it (asserts install POST body + "active in this session" + tools); renders the GitHub auth card, reveals the token field on Install, sends the entered secret on Connect; renders nothing when there are no discoveries; settings readsdiscovery_modeand upserts on change.CLI — proven live, end-to-end (this is the headline)
Run live in a container against the real
modelcontextprotocol.io/mcpendpoint with OpenRouteropenai/gpt-4o-mini.shellcurltool call → domain captured → MCP SERVER DISCOVERED nudge →Yes→✓ installed docs-server is now active in this session→ thensearch_model_context_protocolreturns the real doc:web_scrape(fetch-like) tool call drives the same discover → install →search_model_context_protocolpath. (A non-fetchshellcall in light mode is correctly ignored — covered by a unit test.)Core — Rust unit tests
cargo test -p goose discovery::— 7/7 passed, including:github_fixture_requires_auth— the GitHub card requires auth, conversion without a secret errors, and with a secret injectsAuthorization: Bearer <token>into theStreamableHttpconfig.fixture_resolver_returns_mcp_server_and_skills— auth-less MCP card + Skills bundle, endpointhttps://modelcontextprotocol.io/mcp.light_mode_ignores_non_fetch_tools— mode gating.Compilation
cargo check -p goose-server(discovery route + wiring) — clean.goose-clibuilt and ran live (the CLI transcripts above are the proof).CI status
All code-attributable checks are green on this branch:
cargo fmt --check) — passcargo clippy -D warnings) — passThree integration jobs remain red — Compaction Tests, Smoke Tests, and goose server HTTP integration tests. These are not caused by this PR: each one makes a live LLM provider call and fails with
401 Unauthorized — x-api-key header is requiredbecause fork PRs don't have theANTHROPIC_API_KEYsecret. They exercise no discovery code and fail identically for any fork PR; they go green when run with provider secrets (upstream / on merge). The discovery feature's own behavior is fully covered by the greenBuild and Test Rust Project(Rust unit tests) andTest and Lint Electron Desktop App(vitest) jobs.Caveats / notes
fixture = trueand rendered with a "demo fixture" badge so demo content is never confused with a live, authenticated discovery./.well-known/ai-catalog.jsonyet. The resolver is structured so a real HTTP resolver drops in behind the same interface.github_fixture_requires_authunit test). The auth-less MCP-docs path is the fully-live, end-to-end proof.mcp_docs) are illustrative; the shipped Rust fixture names the extensiondocs-server(see the CLI transcript). Same flow, cosmetic naming only.🤖 Generated with Claude Code