Skip to main content

soma_gateway/gateway/manager/
mcp_scoped_routes.rs

1use serde_json::Value;
2
3use crate::gateway::protected_routes::ProtectedRouteScope;
4
5use super::{
6    mcp_routes::{GatewayPromptRoute, GatewayResourceRoute, GatewayToolRoute},
7    GatewayManager, GatewayManagerError,
8};
9
10impl GatewayManager {
11    pub async fn tool_routes_for_subject_and_scope(
12        &self,
13        subject: Option<&str>,
14        scope: Option<&ProtectedRouteScope>,
15    ) -> Result<Vec<GatewayToolRoute>, GatewayManagerError> {
16        Ok(self
17            .tool_routes_for_subject(subject)
18            .await?
19            .into_iter()
20            .filter(|route| route_allowed(scope, &route.upstream))
21            .collect())
22    }
23
24    pub async fn call_mcp_tool_for_subject_and_scope(
25        &self,
26        name: &str,
27        params: Value,
28        subject: Option<&str>,
29        scope: Option<&ProtectedRouteScope>,
30    ) -> Result<Option<Value>, GatewayManagerError> {
31        let allowed = self
32            .tool_routes_for_subject_and_scope(subject, scope)
33            .await?
34            .into_iter()
35            .any(|route| route.name == name);
36        if !allowed {
37            return Ok(None);
38        }
39        self.call_mcp_tool_for_subject(name, params, subject).await
40    }
41
42    pub async fn resource_routes_for_subject_and_scope(
43        &self,
44        subject: Option<&str>,
45        scope: Option<&ProtectedRouteScope>,
46    ) -> Result<Vec<GatewayResourceRoute>, GatewayManagerError> {
47        Ok(self
48            .resource_routes_for_subject(subject)
49            .await?
50            .into_iter()
51            .filter(|route| route_allowed(scope, &route.upstream))
52            .collect())
53    }
54
55    pub async fn read_mcp_resource_for_subject_and_scope(
56        &self,
57        uri: &str,
58        subject: Option<&str>,
59        scope: Option<&ProtectedRouteScope>,
60    ) -> Result<Option<Value>, GatewayManagerError> {
61        let allowed = self
62            .resource_routes_for_subject_and_scope(subject, scope)
63            .await?
64            .into_iter()
65            .any(|route| route.uri == uri);
66        if !allowed {
67            return Ok(None);
68        }
69        self.read_mcp_resource_for_subject(uri, subject).await
70    }
71
72    pub async fn prompt_routes_for_subject_and_scope(
73        &self,
74        subject: Option<&str>,
75        scope: Option<&ProtectedRouteScope>,
76    ) -> Result<Vec<GatewayPromptRoute>, GatewayManagerError> {
77        Ok(self
78            .prompt_routes_for_subject(subject)
79            .await?
80            .into_iter()
81            .filter(|route| route_allowed(scope, &route.upstream))
82            .collect())
83    }
84
85    pub async fn get_mcp_prompt_for_subject_and_scope(
86        &self,
87        name: &str,
88        arguments: Option<serde_json::Map<String, Value>>,
89        subject: Option<&str>,
90        scope: Option<&ProtectedRouteScope>,
91    ) -> Result<Option<Value>, GatewayManagerError> {
92        let allowed = self
93            .prompt_routes_for_subject_and_scope(subject, scope)
94            .await?
95            .into_iter()
96            .any(|route| route.name == name);
97        if !allowed {
98            return Ok(None);
99        }
100        self.get_mcp_prompt_for_subject(name, arguments, subject)
101            .await
102    }
103}
104
105fn route_allowed(scope: Option<&ProtectedRouteScope>, upstream: &str) -> bool {
106    match scope {
107        None => true,
108        Some(scope) => scope.upstreams.iter().any(|allowed| allowed == upstream),
109    }
110}
111
112#[cfg(test)]
113#[path = "mcp_scoped_routes_tests.rs"]
114mod tests;