Skip to main content

soma_mcp/
lib.rs

1// Render per-item feature-requirement badges when rustdoc runs on nightly with
2// `--cfg docsrs` (docs.rs posture; locally via `cargo xtask doc --docsrs-cfg`).
3// Inert under the stable CI doc gate: stable rustdoc never sets `docsrs`.
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5//! MCP protocol layer — tool dispatch, schemas, prompts, and server handler.
6//!
7//! This module is strictly MCP concerns: the `ServerHandler` impl, tool schemas,
8//! prompt templates, and dispatch shims. Business operations flow through `SomaApplication`.
9
10mod gateway_proxy;
11mod prompts;
12mod protocol_errors;
13mod rmcp_auth;
14pub mod rmcp_server;
15mod schemas;
16mod state;
17mod tools;
18mod trace_resolution;
19#[cfg(feature = "http")]
20mod transport;
21
22pub use rmcp_server::{rmcp_server, SomaRmcpServer};
23pub use state::{McpRouteScope, McpState};
24#[cfg(feature = "http")]
25pub use transport::{allowed_origins, streamable_http_config, streamable_http_service};
26
27pub(crate) const ACTION_DISCRIMINATOR_FIELD: &str = "_soma_action";
28
29#[cfg(test)]
30pub(crate) fn assert_result_has_no_meta(result: &rmcp::model::CallToolResult) {
31    assert!(result.meta.is_none(), "result meta should stay empty");
32    let serialized = serde_json::to_value(result).expect("result should serialize");
33    assert!(
34        serialized.get("_meta").is_none(),
35        "serialized result included _meta: {serialized}"
36    );
37}
38
39#[cfg(any(test, feature = "test-support"))]
40#[doc(hidden)]
41pub use tools::execute_tool_without_peer_for_test;
42
43#[cfg(test)]
44mod testing {
45    use std::sync::Arc;
46
47    use soma_application::{ApplicationPorts, GatewayPort};
48    use soma_config::McpConfig;
49    use soma_domain::AuthorizationMode;
50
51    pub fn loopback_state() -> super::McpState {
52        state(McpConfig::default(), AuthorizationMode::LoopbackDev)
53    }
54
55    pub fn loopback_state_with_gateway(gateway: Arc<dyn GatewayPort>) -> super::McpState {
56        state_with_ports(
57            McpConfig::default(),
58            AuthorizationMode::LoopbackDev,
59            ApplicationPorts::unavailable().with_gateway(gateway),
60        )
61    }
62
63    pub fn bearer_state(token: &str) -> super::McpState {
64        state(
65            McpConfig {
66                api_token: Some(token.to_owned()),
67                ..McpConfig::default()
68            },
69            AuthorizationMode::Mounted,
70        )
71    }
72
73    fn state(config: McpConfig, authorization_mode: AuthorizationMode) -> super::McpState {
74        state_with_ports(config, authorization_mode, ApplicationPorts::unavailable())
75    }
76
77    fn state_with_ports(
78        config: McpConfig,
79        authorization_mode: AuthorizationMode,
80        ports: ApplicationPorts,
81    ) -> super::McpState {
82        let application = soma_test_support::default_application_with_ports(ports);
83        super::McpState::new(application, config, authorization_mode, Default::default())
84    }
85}
86
87#[cfg(test)]
88#[path = "mcp_tests.rs"]
89mod tests;