Skip to main content

agentic_memory_mcp/protocol/
negotiation.rs

1//! MCP capability negotiation during initialization.
2
3use crate::types::{
4    ClientCapabilities, InitializeParams, InitializeResult, McpError, McpResult, MemoryMode,
5    MCP_VERSION,
6};
7
8/// Stored client capabilities after negotiation.
9#[derive(Debug, Clone)]
10pub struct NegotiatedCapabilities {
11    /// The client's declared capabilities.
12    pub client: ClientCapabilities,
13    /// Whether the handshake is complete.
14    pub initialized: bool,
15    /// Memory saving mode.
16    pub mode: MemoryMode,
17}
18
19impl Default for NegotiatedCapabilities {
20    fn default() -> Self {
21        Self {
22            client: ClientCapabilities::default(),
23            initialized: false,
24            mode: MemoryMode::Smart,
25        }
26    }
27}
28
29impl NegotiatedCapabilities {
30    /// Create with a specific memory mode.
31    pub fn with_mode(mode: MemoryMode) -> Self {
32        Self {
33            mode,
34            ..Default::default()
35        }
36    }
37
38    /// Process an initialize request and return the result.
39    pub fn negotiate(&mut self, params: InitializeParams) -> McpResult<InitializeResult> {
40        // Verify protocol version compatibility
41        if params.protocol_version != MCP_VERSION {
42            tracing::warn!(
43                "Client requested protocol version {}, server supports {}. Proceeding with server version.",
44                params.protocol_version,
45                MCP_VERSION
46            );
47        }
48
49        self.client = params.capabilities;
50
51        tracing::info!(
52            "Initialized with client: {} v{}",
53            params.client_info.name,
54            params.client_info.version
55        );
56
57        Ok(InitializeResult::with_mode(self.mode))
58    }
59
60    /// Mark the handshake as complete (after receiving `initialized` notification).
61    pub fn mark_initialized(&mut self) -> McpResult<()> {
62        self.initialized = true;
63        tracing::info!("MCP handshake complete");
64        Ok(())
65    }
66
67    /// Check that the handshake is complete before processing requests.
68    pub fn ensure_initialized(&self) -> McpResult<()> {
69        if !self.initialized {
70            return Err(McpError::InvalidRequest(
71                "Server not yet initialized. Send 'initialize' first.".to_string(),
72            ));
73        }
74        Ok(())
75    }
76}