aether_core/mcp/
exposure.rs1use super::{ToolFilter, ToolMatcher};
2use rmcp::model::Tool;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
7#[serde(from = "ToolExposureConfig", into = "ToolExposureConfig")]
8#[schemars(with = "ToolExposureConfig")]
9pub enum ToolExposure {
10 #[default]
11 ModelVisible,
12 Deferred(ToolFilter),
13}
14
15impl ToolExposure {
16 pub fn deferred_all() -> Self {
17 Self::Deferred(ToolFilter::default())
18 }
19
20 pub fn defers_tools(&self) -> bool {
21 matches!(self, Self::Deferred(_))
22 }
23
24 pub fn is_deferred(&self, tool: &Tool) -> bool {
25 matches!(self, Self::Deferred(filter) if filter.allows(&tool.name, tool))
26 }
27}
28
29#[derive(Deserialize, Serialize, JsonSchema)]
30#[serde(untagged, deny_unknown_fields)]
31enum ToolExposureConfig {
32 Enabled(bool),
33 Rules {
34 #[serde(default, skip_serializing_if = "Vec::is_empty")]
35 include: Vec<ToolMatcher>,
36 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 exclude: Vec<ToolMatcher>,
38 },
39}
40
41impl From<ToolExposureConfig> for ToolExposure {
42 fn from(repr: ToolExposureConfig) -> Self {
43 match repr {
44 ToolExposureConfig::Enabled(false) => Self::ModelVisible,
45 ToolExposureConfig::Enabled(true) => Self::deferred_all(),
46 ToolExposureConfig::Rules { include, exclude } => {
47 Self::Deferred(ToolFilter { allow: include, deny: exclude })
48 }
49 }
50 }
51}
52
53impl From<ToolExposure> for ToolExposureConfig {
54 fn from(exposure: ToolExposure) -> Self {
55 match exposure {
56 ToolExposure::ModelVisible => Self::Enabled(false),
57 ToolExposure::Deferred(filter) if filter.is_empty() => Self::Enabled(true),
58 ToolExposure::Deferred(ToolFilter { allow, deny }) => Self::Rules { include: allow, exclude: deny },
59 }
60 }
61}