isb_server/server/mcp/
downscope.rs1use std::sync::Arc;
5
6use serde_json::Value;
7
8use super::{Caller, Endpoint, Request, Response, Tool};
9
10impl Caller {
11 pub fn downscope(&self) -> Option<&crate::org::OrgId> {
13 self.principal().and_then(|p| p.downscoped.as_ref())
14 }
15
16 pub fn downscoped_to(self, org: &crate::org::OrgId) -> Caller {
21 match self {
22 Caller::Superadmin(s) => Caller::User {
23 principal: Arc::new(s.principal.downscoped_to(org)),
24 },
25 Caller::User { principal } => Caller::User {
26 principal: if principal.platform_admin {
27 Arc::new(principal.downscoped_to(org))
28 } else {
29 principal
30 },
31 },
32 c => c,
33 }
34 }
35}
36
37impl Endpoint {
38 pub(super) fn listed_tools(
41 &self,
42 caller: &Caller,
43 scope: Option<&crate::org::OrgId>,
44 ) -> Vec<Value> {
45 let hide = |t: &Tool| {
46 self.hooks
47 .listed
48 .as_ref()
49 .is_some_and(|l| !l(caller, &t.name, scope))
50 };
51 let all = self.registry.tools().iter();
52 all.filter(|t| self.policy.allows(&t.name) && !hide(t))
53 .map(Tool::describe)
54 .collect()
55 }
56
57 pub(super) fn authenticate_in(
60 &self,
61 req: &Request,
62 scope: Option<&crate::org::OrgId>,
63 ) -> std::result::Result<Caller, Response> {
64 let caller = self.authenticate(req)?;
65 Ok(match scope {
66 Some(org) => caller.downscoped_to(org),
67 None => caller,
68 })
69 }
70}