soma_gateway/gateway/manager/
mcp_scoped_routes.rs1use 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;