Skip to main content

systemprompt_models/mcp/
client_profile.rs

1//! Negotiated MCP client identity used to shape tool results per client.
2//!
3//! [`ClientProfile`] captures the protocol version, implementation name and
4//! negotiated extension keys a client declared when it initialised. The
5//! response builder consults it to decide which wire pieces the client can
6//! accept (embedded UI resources, `structuredContent`, custom `_meta`); an
7//! absent or unparseable declaration yields [`ClientProfile::unknown`], which
8//! downgrades the result to the plain-text shape every conforming client
9//! accepts.
10//!
11//! Copyright (c) systemprompt.io — Business Source License 1.1.
12//! See <https://systemprompt.io> for licensing details.
13
14use rmcp::model::{InitializeRequestParams, ProtocolVersion};
15use std::collections::BTreeSet;
16
17use super::capabilities::McpExtensionId;
18
19#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct ClientProfile {
21    pub protocol_version: Option<ProtocolVersion>,
22    pub client_name: Option<String>,
23    pub extensions: BTreeSet<String>,
24}
25
26impl ClientProfile {
27    #[must_use]
28    pub fn unknown() -> Self {
29        Self::default()
30    }
31
32    #[must_use]
33    pub fn from_initialize_params(params: &InitializeRequestParams) -> Self {
34        Self {
35            protocol_version: Some(params.protocol_version.clone()),
36            client_name: Some(params.client_info.name.clone()),
37            extensions: params
38                .capabilities
39                .extensions
40                .as_ref()
41                .map(|exts| exts.keys().cloned().collect())
42                .unwrap_or_default(),
43        }
44    }
45
46    #[must_use]
47    pub fn supports_ui(&self) -> bool {
48        self.extensions.contains(McpExtensionId::McpAppsUi.as_str())
49    }
50
51    #[must_use]
52    pub fn supports_structured_content(&self) -> bool {
53        self.protocol_version
54            .as_ref()
55            .is_some_and(|v| *v >= ProtocolVersion::V_2025_06_18)
56    }
57}