fix: stamp server info on graceful subscription results (#1078)
* fix: stamp server info on graceful subscription results * fix: expose subscription server info metadata --------- Co-authored-by: mrcs64 <9069178+mrcs64@users.noreply.github.com>
This commit is contained in:
parent
4e361b715f
commit
cb50ae7890
2 changed files with 94 additions and 26 deletions
|
|
@ -154,7 +154,8 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
McpError::method_not_found::<SubscriptionsListenRequestMethod>(),
|
||||
);
|
||||
};
|
||||
let advertised = requested.supported_by(&self.get_info().capabilities);
|
||||
let server_info = self.get_info();
|
||||
let advertised = requested.supported_by(&server_info.capabilities);
|
||||
let handler_accepted = requested.intersection(&candidate);
|
||||
let accepted = handler_accepted.intersection(&advertised);
|
||||
if accepted != handler_accepted {
|
||||
|
|
@ -168,15 +169,16 @@ impl<H: ServerHandler> Service<RoleServer> for H {
|
|||
"subscription filter reduced to advertised server capabilities"
|
||||
);
|
||||
}
|
||||
let server_implementation = server_info.server_info;
|
||||
let subscription_id = context.id.clone();
|
||||
let subscription =
|
||||
SubscriptionContext::establish(context, requested, accepted).await?;
|
||||
// The 2026-07-28 schema defines a final result for graceful
|
||||
// server teardown; explicit stdio cancellation remains a notification.
|
||||
self.listen(subscription).await.map(|()| {
|
||||
ServerResult::SubscriptionsListenResult(
|
||||
SubscriptionsListenResult::complete(subscription_id),
|
||||
)
|
||||
let mut result = SubscriptionsListenResult::complete(subscription_id);
|
||||
result.meta.set_server_info(server_implementation);
|
||||
ServerResult::SubscriptionsListenResult(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1199,9 +1199,20 @@ pub struct DiscoverResult {
|
|||
pub meta: Option<MetaObject>,
|
||||
}
|
||||
|
||||
impl DiscoverResult {
|
||||
const SERVER_INFO_META_KEY: &str = "io.modelcontextprotocol/serverInfo";
|
||||
const SERVER_INFO_META_KEY: &str = "io.modelcontextprotocol/serverInfo";
|
||||
|
||||
fn server_info_from_meta(meta: &MetaObject) -> Option<Implementation> {
|
||||
meta.get(SERVER_INFO_META_KEY)
|
||||
.and_then(|value| serde_json::from_value(value.clone()).ok())
|
||||
}
|
||||
|
||||
fn set_server_info_on_meta(meta: &mut MetaObject, server_info: Implementation) {
|
||||
let server_info =
|
||||
serde_json::to_value(server_info).expect("Implementation serialization cannot fail");
|
||||
meta.insert(SERVER_INFO_META_KEY.to_owned(), server_info);
|
||||
}
|
||||
|
||||
impl DiscoverResult {
|
||||
/// Create a non-cacheable private discovery result.
|
||||
pub fn new(supported_versions: Vec<ProtocolVersion>, capabilities: ServerCapabilities) -> Self {
|
||||
Self {
|
||||
|
|
@ -1217,21 +1228,12 @@ impl DiscoverResult {
|
|||
|
||||
/// Return the server implementation information stored in result metadata.
|
||||
pub fn server_info(&self) -> Option<Implementation> {
|
||||
self.meta
|
||||
.as_ref()?
|
||||
.0
|
||||
.get(Self::SERVER_INFO_META_KEY)
|
||||
.and_then(|value| serde_json::from_value(value.clone()).ok())
|
||||
server_info_from_meta(self.meta.as_ref()?)
|
||||
}
|
||||
|
||||
/// Store server implementation information in result metadata.
|
||||
pub fn set_server_info(&mut self, server_info: Implementation) {
|
||||
let server_info =
|
||||
serde_json::to_value(server_info).expect("Implementation serialization cannot fail");
|
||||
self.meta
|
||||
.get_or_insert_default()
|
||||
.0
|
||||
.insert(Self::SERVER_INFO_META_KEY.to_owned(), server_info);
|
||||
set_server_info_on_meta(self.meta.get_or_insert_default(), server_info);
|
||||
}
|
||||
|
||||
/// Store server implementation information in result metadata.
|
||||
|
|
@ -2174,6 +2176,16 @@ impl SubscriptionsListenResultMeta {
|
|||
subscription_id.into_json_value(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Return the server implementation information stored in result metadata.
|
||||
pub fn server_info(&self) -> Option<Implementation> {
|
||||
server_info_from_meta(&self.0)
|
||||
}
|
||||
|
||||
/// Store server implementation information in result metadata.
|
||||
pub fn set_server_info(&mut self, server_info: Implementation) {
|
||||
set_server_info_on_meta(&mut self.0, server_info);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SubscriptionsListenResultMeta {
|
||||
|
|
@ -2212,9 +2224,14 @@ impl schemars::JsonSchema for SubscriptionsListenResultMeta {
|
|||
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
let subscription_id = generator.subschema_for::<RequestId>();
|
||||
let server_info = generator.subschema_for::<Implementation>();
|
||||
schemars::json_schema!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"io.modelcontextprotocol/serverInfo": {
|
||||
"description": "Identifies the server software producing the response. Servers SHOULD include this field on every response unless specifically configured not to do so.",
|
||||
"allOf": [server_info],
|
||||
},
|
||||
"io.modelcontextprotocol/subscriptionId": subscription_id,
|
||||
},
|
||||
"required": ["io.modelcontextprotocol/subscriptionId"],
|
||||
|
|
|
|||
Loading…
Reference in a new issue