feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability#6927
feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability#6927
Conversation
WIP: Depends on rmcp PR #643 being merged and released. This change updates the MCP client to advertise support for the io.modelcontextprotocol/ui extension during capability negotiation, as required by the MCP Apps specification. The client now advertises: { "capabilities": { "extensions": { "io.modelcontextprotocol/ui": { "mimeTypes": ["text/html;profile=mcp-app"] } } } } Blocked by: - modelcontextprotocol/rust-sdk#643 Related: - https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx
|
note: Depending on timing, we might be able to leverage conditional declaration based off platform detection: #6931 |
Introduces a GoosePlatform enum to distinguish between GooseCli and GooseDesktop environments.
This allows the MCP client to conditionally advertise capabilities based on the active
platform.
Changes:
- Core: Added GoosePlatform enum to crates/goose/src/agents/agent.rs and included it in
AgentConfig.
- MCP Integration: Updated GooseClient to include platform info. Now, the client
advertises its client name as "goose-desktop" while using Goose Desktop and "goose-cli"
for Goose Cli. Leave params.capabilities.extension part for
block#6927.
- Plumbing: Updated ExtensionManager, McpClient, and Agent constructors across the codebase
to propagate the platform type.
- Defaults:
- goose-acp and goose-cli default to GoosePlatform::GooseCli.
- AgentManager (used by the desktop execution flow) defaults to
GoosePlatform::GooseDesktop.
- Testing: Updated scenario runners and integration tests to explicitly pass a platform
variant (typically GooseCli).
Signed-off-by: Jazzcort <jason101011113@gmail.com>
Introduces a GoosePlatform enum to distinguish between GooseCli and GooseDesktop environments.
This allows the MCP client to conditionally advertise capabilities based on the active
platform.
Changes:
- Core: Added GoosePlatform enum to crates/goose/src/agents/agent.rs and included it in
AgentConfig.
- MCP Integration: Updated GooseClient to include platform info. Now, the client
advertises its client name as "goose-desktop" while using Goose Desktop and "goose-cli"
for Goose Cli. Leave params.capabilities.extension part for block#6927
- Plumbing: Updated ExtensionManager, McpClient, and Agent constructors across the codebase
to propagate the platform type.
- Defaults:
- goose-acp and goose-cli default to GoosePlatform::GooseCli.
- AgentManager (used by the desktop execution flow) defaults to
GoosePlatform::GooseDesktop.
- Testing: Updated scenario runners and integration tests to explicitly pass a platform
variant (typically GooseCli).
Signed-off-by: Jazzcort <jason101011113@gmail.com>
…vertisement Upgrades rmcp to 0.15.0 which adds the 'extensions' field on ClientCapabilities, enabling goose to advertise io.modelcontextprotocol/ui support during MCP initialize. Breaking changes addressed: - Implementation: added description field - ServerCapabilities: added extensions field - Tool: added execution field - SamplingMessage.content: Content → SamplingContent<SamplingMessageContent> - SamplingMessage: added meta field (handled by constructor) - CreateElicitationRequestParams: struct → enum (FormElicitationParams/UrlElicitationParams)
- Resolve Cargo.lock conflicts by regenerating lockfile - Accept deletion of skills_extension.rs (replaced by summon_extension.rs on main) - Add missing 'description' field to Implementation structs in summon_extension.rs and tom_extension.rs - Add missing 'extensions' field to ServerCapabilities structs in summon_extension.rs and tom_extension.rs
There was a problem hiding this comment.
Pull request overview
This PR upgrades the MCP SDK dependency (rmcp) from version 0.14.0 to 0.15.0 and adds support for advertising the MCP Apps UI extension capability during client capability negotiation, as specified in the MCP Apps specification.
Changes:
- Upgraded rmcp dependency from 0.14.0 to 0.15.0 in Cargo.toml
- Updated GooseClient to advertise the
io.modelcontextprotocol/uiextension capability with support fortext/html;profile=mcp-appMIME type - Addressed rmcp 0.15.0 breaking changes across all affected files: added
descriptionfield to Implementation structs, addedextensionsfield to ServerCapabilities, addedexecutionfield to Tool constructs, updated SamplingMessage API usage, and adapted CreateElicitationRequestParams enum handling
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Cargo.toml | Upgraded rmcp dependency from 0.14.0 to 0.15.0 |
| Cargo.lock | Updated dependency lock file with new rmcp version and transitive dependencies |
| crates/goose/src/agents/mcp_client.rs | Added MCP Apps UI extension capability advertisement, updated SamplingMessage and CreateElicitationRequestParams usage, added test coverage |
| crates/goose/src/agents/tom_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/todo_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/summon_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/extension_manager_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/extension_manager.rs | Added execution field when constructing Tool instances |
| crates/goose/src/agents/code_execution_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/chatrecall_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose/src/agents/apps_extension.rs | Added description and extensions fields for rmcp 0.15.0 compatibility |
| crates/goose-mcp/src/tutorial/mod.rs | Added description field to Implementation for rmcp 0.15.0 compatibility |
| crates/goose-mcp/src/memory/mod.rs | Added description field to Implementation for rmcp 0.15.0 compatibility |
| crates/goose-mcp/src/developer/rmcp_developer.rs | Added description field to Implementation for rmcp 0.15.0 compatibility |
| crates/goose-mcp/src/computercontroller/mod.rs | Added description field to Implementation for rmcp 0.15.0 compatibility |
| crates/goose-mcp/src/autovisualiser/mod.rs | Added description field to Implementation for rmcp 0.15.0 compatibility |
The PR added MCP Apps UI extension capability advertisement in the
client's initialize request, but the recorded replay files still had
the old initialize message without the extensions field. This caused
all 4 replay tests to fail because the playback comparison found a
mismatch and closed the connection.
Updated all 4 replay files to include:
extensions: { io.modelcontextprotocol/ui: { mimeTypes: [text/html;profile=mcp-app] } }
in the capabilities of the initialize STDIN line.
The rmcp 0.15.0 upgrade added an execution field to Tool that references ToolExecution and TaskSupport types. These were missing from the OpenAPI schema definitions, causing @hey-api/openapi-ts to fail with a missing $ref pointer error.
| match msg.content.first().and_then(|c| c.as_text()) { | ||
| Some(text) => base.with_text(&text.text), | ||
| None => base.with_content(msg.content.clone().into()), | ||
| None => base, | ||
| } |
There was a problem hiding this comment.
create_message drops non-text sampling message content (and even text beyond the first part), producing provider messages with empty content when the incoming MCP message contains images/resources; this is a behavioral regression from the previous with_content(msg.content.clone().into()) path and can lead to invalid/empty prompts being sent to providers. Convert each SamplingMessageContent item into MessageContent (text/image/resource) and add it to the base message (or at least preserve the first non-text part via a placeholder) instead of returning base unchanged.
| derive_utoipa!(ToolAnnotations as ToolAnnotationsSchema); | ||
| derive_utoipa!(ToolExecution as ToolExecutionSchema); | ||
| derive_utoipa!(TaskSupport as TaskSupportSchema); |
There was a problem hiding this comment.
The schemars→utoipa conversion used by derive_utoipa! currently ignores JSON Schema enum values, so rmcp enums like TaskSupport degrade into meaningless oneOf entries of plain string (as seen in the generated OpenAPI), which in turn makes the generated TypeScript type just string. Extend the converter (e.g., in convert_typed_schema/convert_json_object_to_utoipa) to preserve enum (and collapse redundant oneOf) so the OpenAPI accurately constrains allowed values.
| "oneOf": [ | ||
| { | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "type": "string" | ||
| } | ||
| ] |
There was a problem hiding this comment.
TaskSupport is emitted as oneOf with three identical { "type": "string" } schemas, which loses the underlying enum/variant information and provides no validation constraints to clients. Regenerate this schema after fixing the schemars→OpenAPI conversion to preserve enum values (or, if it really is unconstrained, simplify it to a single type: string).
| "oneOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "string" | |
| } | |
| ] | |
| "type": "string" |
| @@ -1,4 +1,4 @@ | |||
| STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"sampling":{},"elicitation":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} | |||
| STDIN: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{"elicitation":{},"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}},"sampling":{}},"clientInfo":{"name":"goose","version":"0.0.0"}}} | |||
There was a problem hiding this comment.
leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers (in Python 3).
* origin/main: (107 commits) feat: Allow overriding default bat themes using environment variables (#7140) Make the system prompt smaller (#6991) Pre release script (#7145) Spelling (#7137) feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability (#6927) fix: ensure assistant messages with tool_calls include content field (#7076) fix(canonical): handle gcp_vertex_ai model mapping correctly (#6836) Group dependencies in root Cargo.toml (#6948) refactor: updated elevenLabs API module and `remove button` UX (#6781) fix: we were missing content from langfuse traces (#7135) docs: update username in authors.yml (#7132) fix extension selector syncing issues (#7133) fix(acp): per-session Agent for model isolation and load_session restore (#7115) fix(claude-code): defensive coding improvements for model switching (#7131) feat(claude-code): dynamic model listing and mid-session model switching (#7120) Inline worklet source (#7128) [docs] One shot prompting is dead - Blog Post (#7113) fix: correct spelling of Debbie O'Brien's name in authors.yml (#7127) docs: GCP Vertex AI org policy filtering & update OnboardingProviderSetup component (#7125) feat: replace subagent and skills with unified summon extension (#6964) ... # Conflicts: # Cargo.lock # Cargo.toml
* upstream/main: (109 commits) [docs] Skills Marketplace UI Improvements (block#7158) More no-window flags (block#7122) feat: Allow overriding default bat themes using environment variables (block#7140) Make the system prompt smaller (block#6991) Pre release script (block#7145) Spelling (block#7137) feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability (block#6927) fix: ensure assistant messages with tool_calls include content field (block#7076) fix(canonical): handle gcp_vertex_ai model mapping correctly (block#6836) Group dependencies in root Cargo.toml (block#6948) refactor: updated elevenLabs API module and `remove button` UX (block#6781) fix: we were missing content from langfuse traces (block#7135) docs: update username in authors.yml (block#7132) fix extension selector syncing issues (block#7133) fix(acp): per-session Agent for model isolation and load_session restore (block#7115) fix(claude-code): defensive coding improvements for model switching (block#7131) feat(claude-code): dynamic model listing and mid-session model switching (block#7120) Inline worklet source (block#7128) [docs] One shot prompting is dead - Blog Post (block#7113) fix: correct spelling of Debbie O'Brien's name in authors.yml (block#7127) ...
* origin/main: (33 commits) fix: replace panic with proper error handling in get_tokenizer (#7175) Lifei/smoke test for developer (#7174) fix text editor view broken (#7167) docs: White label guide (#6857) Add PATH detection back to developer extension (#7161) docs: pin version in ci/cd (#7168) Desktop: - No Custom Headers field for custom OpenAI-compatible providers (#6681) feat: edit model and extensions of a recipe from GUI (#6804) feat: MCP support for agentic CLI providers (#6972) docs: keyring fallback to secrets.yaml (#7165) feat: load provider/model specified inside the recipe config (#6884) fix ask-ai bot hitting tool call limits (#7162) fix flatpak icon (#7154) [docs] Skills Marketplace UI Improvements (#7158) More no-window flags (#7122) feat: Allow overriding default bat themes using environment variables (#7140) Make the system prompt smaller (#6991) Pre release script (#7145) Spelling (#7137) feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability (#6927) ...
Summary
This PR updates the MCP client to advertise support for the
io.modelcontextprotocol/uiextension during capability negotiation, as required by the MCP Apps specification.Changes
extensionsfield onClientCapabilitiesExtensionCapabilitiesfromrmcp::modelGooseClient::get_info()to build and advertise the UI extension capabilityImplementation: newdescriptionfieldServerCapabilities: newextensionsfieldTool: newexecutionfieldSamplingMessage.content:Content→SamplingContent<SamplingMessageContent>CreateElicitationRequestParams: struct → enum (FormElicitationParams/UrlElicitationParams)Capability Advertised
{ "capabilities": { "extensions": { "io.modelcontextprotocol/ui": { "mimeTypes": ["text/html;profile=mcp-app"] } } } }Verification
cargo build— compiles cleanlycargo fmt— no formatting issues./scripts/clippy-lint.sh— all baseline checks passcargo test -p goose --lib— 532 passed (4 pre-existing snapshot failures unrelated)cargo test -p goose-mcp --lib— 182 passedRelated