feat(mcp): upgrade rmcp to 0.15.0 and advertise MCP Apps UI extension capability (#6927)

This commit is contained in:
Andrew Harvard
2026-02-11 09:34:04 -05:00
committed by GitHub
parent 0e7294835c
commit 544bc1bc4f
24 changed files with 382 additions and 76 deletions
Generated
+224 -34
View File
@@ -524,9 +524,9 @@ dependencies = [
[[package]]
name = "aws-smithy-async"
version = "1.2.11"
version = "1.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52eec3db979d18cb807fc1070961cc51d87d069abe9ab57917769687368a8c6c"
checksum = "3cba48474f1d6807384d06fec085b909f5807e16653c5af5c45dfe89539f0b70"
dependencies = [
"futures-util",
"pin-project-lite",
@@ -693,9 +693,9 @@ dependencies = [
[[package]]
name = "aws-smithy-xml"
version = "0.60.13"
version = "0.60.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57"
checksum = "b53543b4b86ed43f051644f704a98c7291b3618b67adf057ee77a366fa52fcaa"
dependencies = [
"xmlparser",
]
@@ -1568,7 +1568,7 @@ dependencies = [
"candle-kernels",
"candle-metal-kernels",
"candle-ug",
"cudarc 0.19.1",
"cudarc 0.19.2",
"float8 0.6.1",
"gemm 0.19.0",
"half",
@@ -2295,9 +2295,9 @@ dependencies = [
[[package]]
name = "cudarc"
version = "0.19.1"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60d4882b3e023670c25b8a3e1ac97349070f8e5400807c091b70e0bdad6e9b93"
checksum = "aed81f178e780f3d5d354d12b4c5c5a484c4a9c329ecd037ac57f2a0e0648397"
dependencies = [
"float8 0.7.0",
"half",
@@ -2869,9 +2869,9 @@ dependencies = [
[[package]]
name = "deranged"
version = "0.5.5"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
dependencies = [
"powerfmt",
]
@@ -3491,7 +3491,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719a903cc23e4a89e87962c2a80fdb45cdaad0983a89bd150bb57b4c8571a7d5"
dependencies = [
"cudarc 0.19.1",
"cudarc 0.19.2",
"half",
"num-traits",
"rand 0.9.2",
@@ -4075,6 +4075,19 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
"wasip3",
]
[[package]]
name = "gif"
version = "0.13.3"
@@ -4176,7 +4189,7 @@ dependencies = [
"rand 0.8.5",
"regex",
"reqwest 0.12.28",
"rmcp 0.14.0",
"rmcp 0.15.0",
"rubato",
"schemars 1.2.1",
"serde",
@@ -4234,7 +4247,7 @@ dependencies = [
"goose-test-support",
"http-body-util",
"regex",
"rmcp 0.14.0",
"rmcp 0.15.0",
"sacp",
"serde",
"serde_json",
@@ -4277,7 +4290,7 @@ dependencies = [
"open",
"rand 0.8.5",
"regex",
"rmcp 0.14.0",
"rmcp 0.15.0",
"rustyline",
"serde",
"serde_json",
@@ -4318,7 +4331,7 @@ dependencies = [
"rayon",
"regex",
"reqwest 0.12.28",
"rmcp 0.14.0",
"rmcp 0.15.0",
"schemars 1.2.1",
"serde",
"serde_json",
@@ -4368,7 +4381,7 @@ dependencies = [
"once_cell",
"rand 0.9.2",
"reqwest 0.12.28",
"rmcp 0.14.0",
"rmcp 0.15.0",
"rustls 0.23.36",
"serde",
"serde_json",
@@ -4405,7 +4418,7 @@ name = "goose-test-support"
version = "1.23.0"
dependencies = [
"axum 0.7.9",
"rmcp 0.14.0",
"rmcp 0.15.0",
"serde_json",
"tokio",
]
@@ -4985,6 +4998,12 @@ dependencies = [
"zerovec",
]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -5458,9 +5477,9 @@ dependencies = [
[[package]]
name = "lazy-regex"
version = "3.5.1"
version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5c13b6857ade4c8ee05c3c3dc97d2ab5415d691213825b90d3211c425c1f907"
checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496"
dependencies = [
"lazy-regex-proc_macros",
"once_cell",
@@ -5469,9 +5488,9 @@ dependencies = [
[[package]]
name = "lazy-regex-proc_macros"
version = "3.5.1"
version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a95c68db5d41694cea563c86a4ba4dc02141c16ef64814108cb23def4d5438"
checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358"
dependencies = [
"proc-macro2",
"quote",
@@ -5488,6 +5507,12 @@ dependencies = [
"spin",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lebe"
version = "0.5.3"
@@ -5496,9 +5521,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
name = "libc"
version = "0.2.180"
version = "0.2.181"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
[[package]]
name = "libdbus-sys"
@@ -7333,9 +7358,9 @@ dependencies = [
[[package]]
name = "process-wrap"
version = "9.0.1"
version = "9.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd1395947e69c07400ef4d43db0051d6f773c21f647ad8b97382fc01f0204c60"
checksum = "5811c133381ea59d7dd6ca37419b434bb2e3089a2a59c1e4b26a86fa79426e23"
dependencies = [
"futures",
"indexmap 2.13.0",
@@ -7981,6 +8006,33 @@ name = "rmcp"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a621b37a548ff6ab6292d57841eb25785a7f146d89391a19c9f199414bd13da"
dependencies = [
"async-trait",
"base64 0.22.1",
"chrono",
"futures",
"http 1.4.0",
"pastey",
"pin-project-lite",
"process-wrap",
"reqwest 0.12.28",
"rmcp-macros 0.14.0",
"schemars 1.2.1",
"serde",
"serde_json",
"sse-stream",
"thiserror 2.0.18",
"tokio",
"tokio-stream",
"tokio-util",
"tracing",
]
[[package]]
name = "rmcp"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bef41ebc9ebed2c1b1d90203e9d1756091e8a00bbc3107676151f39868ca0ee"
dependencies = [
"async-trait",
"axum 0.8.8",
@@ -7997,7 +8049,7 @@ dependencies = [
"process-wrap",
"rand 0.9.2",
"reqwest 0.12.28",
"rmcp-macros 0.14.0",
"rmcp-macros 0.15.0",
"schemars 1.2.1",
"serde",
"serde_json",
@@ -8038,6 +8090,19 @@ dependencies = [
"syn 2.0.114",
]
[[package]]
name = "rmcp-macros"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e88ad84b8b6237a934534a62b379a5be6388915663c0cc598ceb9b3292bbbfe"
dependencies = [
"darling 0.23.0",
"proc-macro2",
"quote",
"serde_json",
"syn 2.0.114",
]
[[package]]
name = "roff"
version = "0.2.2"
@@ -9989,12 +10054,12 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.24.0"
version = "3.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
dependencies = [
"fastrand",
"getrandom 0.3.4",
"getrandom 0.4.1",
"once_cell",
"rustix 1.1.3",
"windows-sys 0.61.2",
@@ -10448,9 +10513,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.11+spec-1.1.0"
version = "0.9.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
dependencies = [
"indexmap 2.13.0",
"serde_core",
@@ -10472,9 +10537,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.0.6+spec-1.1.0"
version = "1.0.7+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
dependencies = [
"winnow",
]
@@ -10895,9 +10960,9 @@ checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908"
[[package]]
name = "typed-path"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3015e6ce46d5ad8751e4a772543a30c7511468070e98e64e20165f8f81155b64"
checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
[[package]]
name = "typeid"
@@ -11303,6 +11368,15 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasite"
version = "0.1.0"
@@ -11368,6 +11442,28 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap 2.13.0",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasm-streams"
version = "0.4.2"
@@ -11391,6 +11487,18 @@ dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.10.0",
"hashbrown 0.15.5",
"indexmap 2.13.0",
"semver",
]
[[package]]
name = "web-sys"
version = "0.3.85"
@@ -12119,6 +12227,88 @@ name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap 2.13.0",
"prettyplease",
"syn 2.0.114",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn 2.0.114",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.10.0",
"indexmap 2.13.0",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap 2.13.0",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "writeable"
+1 -1
View File
@@ -15,7 +15,7 @@ uninlined_format_args = "allow"
string_slice = "warn"
[workspace.dependencies]
rmcp = { version = "0.14.0", features = ["schemars", "auth"] }
rmcp = { version = "0.15.0", features = ["schemars", "auth"] }
anyhow = "1.0"
async-stream = "0.3"
async-trait = "0.1"
@@ -417,6 +417,7 @@ impl ServerHandler for AutoVisualiserRouter {
name: "goose-autovisualiser".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
description: None,
icons: None,
website_url: None,
},
@@ -1301,6 +1301,7 @@ impl ServerHandler for ComputerControllerServer {
name: "goose-computercontroller".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
description: None,
icons: None,
website_url: None,
},
@@ -427,6 +427,7 @@ impl ServerHandler for DeveloperServer {
name: "goose-developer".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
description: None,
icons: None,
website_url: None,
},
+1
View File
@@ -549,6 +549,7 @@ impl ServerHandler for MemoryServer {
name: "goose-memory".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
description: None,
icons: None,
website_url: None,
},
+1
View File
@@ -114,6 +114,7 @@ impl ServerHandler for TutorialServer {
name: "goose-tutorial".to_string(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: None,
description: None,
icons: None,
website_url: None,
},
+5 -1
View File
@@ -12,7 +12,7 @@ use goose::session::{Session, SessionInsights, SessionType, SystemInfo};
use rmcp::model::{
Annotations, Content, EmbeddedResource, Icon, ImageContent, JsonObject, RawAudioContent,
RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ResourceContents, Role,
TextContent, Tool, ToolAnnotations,
TaskSupport, TextContent, Tool, ToolAnnotations, ToolExecution,
};
use utoipa::{OpenApi, ToSchema};
@@ -319,6 +319,8 @@ derive_utoipa!(RawEmbeddedResource as RawEmbeddedResourceSchema);
derive_utoipa!(RawResource as RawResourceSchema);
derive_utoipa!(Tool as ToolSchema);
derive_utoipa!(ToolAnnotations as ToolAnnotationsSchema);
derive_utoipa!(ToolExecution as ToolExecutionSchema);
derive_utoipa!(TaskSupport as TaskSupportSchema);
derive_utoipa!(Annotations as AnnotationsSchema);
derive_utoipa!(ResourceContents as ResourceContentsSchema);
derive_utoipa!(JsonObject as JsonObjectSchema);
@@ -497,6 +499,8 @@ derive_utoipa!(Icon as IconSchema);
RecipeManifest,
ToolSchema,
ToolAnnotationsSchema,
ToolExecutionSchema,
TaskSupportSchema,
ToolInfo,
PermissionLevel,
Permission,
@@ -131,11 +131,13 @@ impl AppsManagerClient {
experimental: None,
tasks: None,
logging: None,
extensions: None,
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
title: Some("Apps Manager".to_string()),
version: "1.0.0".to_string(),
description: None,
icons: None,
website_url: None,
},
@@ -43,11 +43,12 @@ impl ChatRecallClient {
let info = InitializeResult {
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ServerCapabilities {
tasks: None,
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
tasks: None,
resources: None,
extensions: None,
prompts: None,
completions: None,
experimental: None,
@@ -55,6 +56,7 @@ impl ChatRecallClient {
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
description: None,
title: Some("Chat Recall".to_string()),
version: "1.0.0".to_string(),
icons: None,
@@ -56,11 +56,12 @@ impl CodeExecutionClient {
let info = InitializeResult {
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ServerCapabilities {
tasks: None,
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
tasks: None,
resources: None,
extensions: None,
prompts: None,
completions: None,
experimental: None,
@@ -68,6 +69,7 @@ impl CodeExecutionClient {
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
description: None,
title: Some("Code Mode".to_string()),
version: "1.0.0".to_string(),
icons: None,
@@ -925,6 +925,7 @@ impl ExtensionManager {
input_schema: tool.input_schema,
annotations: tool.annotations,
output_schema: tool.output_schema,
execution: tool.execution,
icons: tool.icons,
title: tool.title,
meta: Some(rmcp::model::Meta(meta_map)),
@@ -85,11 +85,12 @@ impl ExtensionManagerClient {
let info = InitializeResult {
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ServerCapabilities {
tasks: None,
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
tasks: None,
resources: None,
extensions: None,
prompts: None,
completions: None,
experimental: None,
@@ -97,6 +98,7 @@ impl ExtensionManagerClient {
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
description: None,
title: Some(EXTENSION_NAME.to_string()),
version: "1.0.0".to_string(),
icons: None,
+74 -31
View File
@@ -2,8 +2,8 @@ use crate::action_required_manager::ActionRequiredManager;
use crate::agents::types::SharedProvider;
use crate::session_context::{SESSION_ID_HEADER, WORKING_DIR_HEADER};
use rmcp::model::{
Content, CreateElicitationRequestParams, CreateElicitationResult, ElicitationAction, ErrorCode,
Extensions, JsonObject, Meta,
CreateElicitationRequestParams, CreateElicitationResult, ElicitationAction, ErrorCode,
ExtensionCapabilities, Extensions, JsonObject, Meta, SamplingMessageContent,
};
/// MCP client implementation for Goose
use rmcp::{
@@ -223,9 +223,9 @@ impl ClientHandler for GooseClient {
Role::Assistant => crate::conversation::message::Message::assistant(),
};
match msg.content.as_text() {
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,
}
})
.collect();
@@ -255,29 +255,26 @@ impl ClientHandler for GooseClient {
Ok(CreateMessageResult {
model: usage.model,
stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.to_string()),
message: SamplingMessage {
role: Role::Assistant,
// TODO(alexhancock): MCP sampling currently only supports one content on each SamplingMessage
// https://modelcontextprotocol.io/specification/draft/client/sampling#messages
// This doesn't mesh well with goose's approach which has Vec<MessageContent>
// There is a proposal to MCP which is agreed to go in the next version to have SamplingMessages support multiple content parts
// https://github.com/modelcontextprotocol/modelcontextprotocol/pull/198
// Until that is formalized, we can take the first message content from the provider and use it
content: if let Some(content) = response.content.first() {
message: SamplingMessage::new(
Role::Assistant,
if let Some(content) = response.content.first() {
match content {
crate::conversation::message::MessageContent::Text(text) => {
Content::text(&text.text)
SamplingMessageContent::text(&text.text)
}
crate::conversation::message::MessageContent::Image(img) => {
Content::image(&img.data, &img.mime_type)
SamplingMessageContent::Image(rmcp::model::RawImageContent {
data: img.data.clone(),
mime_type: img.mime_type.clone(),
meta: None,
})
}
// TODO(alexhancock) - Content::Audio? goose's messages don't currently have it
_ => Content::text(""),
_ => SamplingMessageContent::text(""),
}
} else {
Content::text("")
SamplingMessageContent::text("")
},
},
),
})
}
@@ -286,20 +283,28 @@ impl ClientHandler for GooseClient {
request: CreateElicitationRequestParams,
_context: RequestContext<RoleClient>,
) -> Result<CreateElicitationResult, ErrorData> {
let schema_value = serde_json::to_value(&request.requested_schema).map_err(|e| {
ErrorData::new(
ErrorCode::INTERNAL_ERROR,
format!("Failed to serialize elicitation schema: {}", e),
None,
)
})?;
let (message, schema_value) = match &request {
CreateElicitationRequestParams::FormElicitationParams {
message,
requested_schema,
..
} => {
let schema_value = serde_json::to_value(requested_schema).map_err(|e| {
ErrorData::new(
ErrorCode::INTERNAL_ERROR,
format!("Failed to serialize elicitation schema: {}", e),
None,
)
})?;
(message.clone(), schema_value)
}
CreateElicitationRequestParams::UrlElicitationParams { message, url, .. } => {
(message.clone(), serde_json::json!({ "url": url }))
}
};
ActionRequiredManager::global()
.request_and_wait(
request.message.clone(),
schema_value,
Duration::from_secs(300),
)
.request_and_wait(message, schema_value, Duration::from_secs(300))
.await
.map(|user_data| CreateElicitationResult {
action: ElicitationAction::Accept,
@@ -315,10 +320,25 @@ impl ClientHandler for GooseClient {
}
fn get_info(&self) -> ClientInfo {
// Build MCP Apps UI extension capability
// See: https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx
let mut ui_extension_settings = JsonObject::new();
ui_extension_settings.insert(
"mimeTypes".to_string(),
serde_json::json!(["text/html;profile=mcp-app"]),
);
let mut extensions = ExtensionCapabilities::new();
extensions.insert(
"io.modelcontextprotocol/ui".to_string(),
ui_extension_settings,
);
ClientInfo {
meta: None,
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ClientCapabilities::builder()
.enable_extensions_with(extensions)
.enable_sampling()
.enable_elicitation()
.build(),
@@ -328,6 +348,7 @@ impl ClientHandler for GooseClient {
.unwrap_or(env!("CARGO_PKG_VERSION").to_owned()),
icons: None,
title: None,
description: None,
website_url: None,
},
}
@@ -945,4 +966,26 @@ mod tests {
assert_eq!(&mcp_meta.0, expected_meta.as_object().unwrap());
}
#[test]
fn test_client_info_advertises_mcp_apps_ui_extension() {
let client = new_client();
let info = ClientHandler::get_info(&client);
// Verify the client advertises the MCP Apps UI extension capability
let extensions = info
.capabilities
.extensions
.expect("capabilities should have extensions");
let ui_ext = extensions
.get("io.modelcontextprotocol/ui")
.expect("should have io.modelcontextprotocol/ui extension");
let mime_types = ui_ext
.get("mimeTypes")
.expect("ui extension should have mimeTypes");
assert_eq!(mime_types, &json!(["text/html;profile=mcp-app"]));
}
}
@@ -260,11 +260,13 @@ impl SummonClient {
completions: None,
experimental: None,
logging: None,
extensions: None,
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
title: Some("Summon".to_string()),
version: "1.0.0".to_string(),
description: None,
icons: None,
website_url: None,
},
+3 -1
View File
@@ -30,11 +30,12 @@ impl TodoClient {
let info = InitializeResult {
protocol_version: ProtocolVersion::V_2025_03_26,
capabilities: ServerCapabilities {
tasks: None,
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
tasks: None,
resources: None,
extensions: None,
prompts: None,
completions: None,
experimental: None,
@@ -42,6 +43,7 @@ impl TodoClient {
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
description: None,
title: Some("Todo".to_string()),
version: "1.0.0".to_string(),
icons: None,
+2
View File
@@ -30,11 +30,13 @@ impl TomClient {
completions: None,
experimental: None,
logging: None,
extensions: None,
},
server_info: Implementation {
name: EXTENSION_NAME.to_string(),
title: Some("Top Of Mind".to_string()),
version: "1.0.0".to_string(),
description: None,
icons: None,
website_url: None,
},
@@ -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"}}}
STDERR: time=2025-12-11T17:58:47.636-05:00 level=INFO msg="starting server" version=0.24.1 host="" dynamicToolsets=false readOnly=false lockdownEnabled=false
STDERR: GitHub MCP Server running on stdio
STDERR: time=2025-12-11T17:58:47.640-05:00 level=INFO msg="server run start"
@@ -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"}}}
STDERR: Starting default (STDIO) server...
STDOUT: {"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true},"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},"logging":{},"completions":{}},"serverInfo":{"name":"mcp-servers/everything","title":"Everything Reference Server","version":"2.0.0"},"instructions":"# Everything Server Server Instructions\n\nAudience: These instructions are written for an LLM or autonomous agent integrating with the Everything MCP Server.\nFollow them to use, extend, and troubleshoot the server safely and effectively.\n\n## Cross-Feature Relationships\n\n- Use `get-roots-list` to see client workspace roots before file operations\n- `gzip-file-as-resource` creates session-scoped resources accessible only during the current session\n- Enable `toggle-simulated-logging` before debugging to see server log messages\n- Enable `toggle-subscriber-updates` to receive periodic resource update notifications\n\n## Constraints & Limitations\n\n- `gzip-file-as-resource`: Max fetch size controlled by `GZIP_MAX_FETCH_SIZE` (default 10MB), timeout by `GZIP_MAX_FETCH_TIME_MILLIS` (default 30s), allowed domains by `GZIP_ALLOWED_DOMAINS`\n- Session resources are ephemeral and lost when the session ends\n- Sampling requests (`trigger-sampling-request`) require client sampling capability\n- Elicitation requests (`trigger-elicitation-request`) require client elicitation capability\n\n## Operational Patterns\n\n- For long operations, use `trigger-long-running-operation` which sends progress notifications\n- Prefer reading resources before calling mutating tools\n- Check `get-roots-list` output to understand the client's workspace context\n\n## Easter Egg\n\nIf asked about server instructions, respond with \"🎉 Server instructions are working! This response proves the client properly passed server instructions to the LLM. This demonstrates MCP's instructions feature in action.\"\n"},"jsonrpc":"2.0","id":0}
STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"}
@@ -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"}}}
STDERR:
STDERR:
STDERR:
@@ -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"}}}
STDOUT: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"mcp-fetch","version":"1.25.0"}}}
STDIN: {"jsonrpc":"2.0","method":"notifications/initialized"}
STDIN: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"agent-session-id":"test-session-id","progressToken":0},"name":"fetch","arguments":{"url":"https://example.com"}}}
+38
View File
@@ -6755,6 +6755,19 @@
"inlineMessage"
]
},
"TaskSupport": {
"oneOf": [
{
"type": "string"
},
{
"type": "string"
},
{
"type": "string"
}
]
},
"TelemetryEventRequest": {
"type": "object",
"required": [
@@ -6899,6 +6912,16 @@
"description": {
"type": "string"
},
"execution": {
"anyOf": [
{
"$ref": "#/components/schemas/ToolExecution"
},
{
"type": "object"
}
]
},
"icons": {
"type": "array",
"items": {
@@ -6964,6 +6987,21 @@
}
}
},
"ToolExecution": {
"type": "object",
"properties": {
"taskSupport": {
"anyOf": [
{
"$ref": "#/components/schemas/TaskSupport"
},
{
"type": "object"
}
]
}
}
},
"ToolInfo": {
"type": "object",
"description": "Information about the tool used for building prompts",
File diff suppressed because one or more lines are too long
+11
View File
@@ -1148,6 +1148,8 @@ export type SystemNotificationContent = {
export type SystemNotificationType = 'thinkingMessage' | 'inlineMessage';
export type TaskSupport = string;
export type TelemetryEventRequest = {
event_name: string;
properties?: {
@@ -1198,6 +1200,9 @@ export type Tool = {
[key: string]: unknown;
};
description?: string;
execution?: ToolExecution | {
[key: string]: unknown;
};
icons?: Array<Icon>;
inputSchema: {
[key: string]: unknown;
@@ -1224,6 +1229,12 @@ export type ToolConfirmationRequest = {
toolName: string;
};
export type ToolExecution = {
taskSupport?: TaskSupport | {
[key: string]: unknown;
};
};
/**
* Information about the tool used for building prompts
*/