1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// SPDX-License-Identifier: Apache-2.0
//! The MCP tool catalog: the definitions of every registered tool.
//!
//! The tools themselves live in the MCP server layer, which registers its
//! catalog here (`server::registry::register_tool_catalog`, called by the CLI
//! at start-up and by every MCP server construction). Engine code that only
//! needs the definitions — manifests, overhead measurement, discovery cards,
//! docs — reads them through this module instead of building the registry.
//!
//! Without a registration (library use that never starts a server) the
//! catalog is empty. It describes and counts tools; it never decides whether a
//! call is allowed — tool admission, policy and role gates do not read it.
//! Engine unit tests see it empty as well; the tests that measure the real
//! catalog register it and live with the server (`server/catalog_tests.rs`).
use std::sync::OnceLock;
use rmcp::model::Tool;
/// The registered catalog entry points.
#[derive(Clone, Copy)]
pub struct ToolCatalog {
/// The official public surface: sorted, annotated definitions of every
/// publicly advertised tool (what `tools/list` may offer).
pub tool_defs: fn() -> Vec<Tool>,
/// Every registered tool, including local compatibility substrate and
/// internal host hooks that stay callable but are never advertised.
pub registered_tool_defs: fn() -> Vec<Tool>,
}
static CATALOG: OnceLock<ToolCatalog> = OnceLock::new();
/// Register the tool catalog. The first registration wins.
pub fn register_tool_catalog(catalog: ToolCatalog) {
let _ = CATALOG.set(catalog);
}
/// Whether a catalog has been registered.
#[must_use]
pub fn is_registered() -> bool {
catalog().is_some()
}
fn catalog() -> Option<&'static ToolCatalog> {
CATALOG.get()
}
/// Definitions of the publicly advertised tools; empty when unregistered.
#[must_use]
pub fn tool_defs() -> Vec<Tool> {
catalog().map_or_else(Vec::new, |c| (c.tool_defs)())
}
/// Definitions of every registered tool; empty when unregistered.
#[must_use]
pub fn registered_tool_defs() -> Vec<Tool> {
catalog().map_or_else(Vec::new, |c| (c.registered_tool_defs)())
}
/// Number of official MCP tools (the public surface).
#[must_use]
pub fn tool_count() -> usize {
tool_defs().len()
}
/// Sorted names of every registered tool.
#[must_use]
pub fn registered_tool_names() -> Vec<String> {
let mut names: Vec<String> = registered_tool_defs()
.into_iter()
.map(|t| t.name.to_string())
.collect();
names.sort_unstable();
names
}