Skip to main content

skills_mcp/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(missing_docs)]
3#![cfg_attr(
4    not(test),
5    deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)
6)]
7
8//! Skills MCP Server — vocabulary programs as MCP tools.
9//!
10//! Native Rust implementations of LEARN, PROVE, VITALS programs
11//! plus a generic runner for all other vocabulary programs.
12
13pub mod tools;
14pub mod types;
15
16use rmcp::handler::server::router::tool::ToolRouter;
17use rmcp::handler::server::tool::ToolCallContext;
18use rmcp::handler::server::wrapper::Parameters;
19use rmcp::model::{
20    CallToolRequestParams, CallToolResult, Implementation, ListToolsResult, PaginatedRequestParams,
21    ServerCapabilities, ServerInfo,
22};
23use rmcp::service::{RequestContext, RoleServer};
24use rmcp::{ErrorData as McpError, ServerHandler, tool, tool_router};
25
26use crate::types::*;
27
28#[derive(Clone)]
29pub struct SkillsMcpServer {
30    tool_router: ToolRouter<Self>,
31}
32
33#[tool_router]
34impl SkillsMcpServer {
35    pub fn new() -> Result<Self, nexcore_error::NexError> {
36        Ok(Self {
37            tool_router: Self::tool_router(),
38        })
39    }
40
41    // =====================================================================
42    // VITALS — Biological Infrastructure Health (6 tools + pipeline)
43    // =====================================================================
44
45    #[tool(
46        description = "VITALS [V] Vigor: Check hormone state (cortisol, dopamine, serotonin, adrenaline, oxytocin, melatonin). Returns levels, staleness, and health assessment."
47    )]
48    async fn vitals_vigor(
49        &self,
50        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
51    ) -> Result<CallToolResult, McpError> {
52        tools::vitals::vigor()
53    }
54
55    #[tool(
56        description = "VITALS [I] Immunity: Query antibody registry from brain.db. Returns PAMP/DAMP counts, severity distribution, and coverage assessment."
57    )]
58    async fn vitals_immunity(
59        &self,
60        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
61    ) -> Result<CallToolResult, McpError> {
62        tools::vitals::immunity()
63    }
64
65    #[tool(
66        description = "VITALS [T] Telemetry: Check signal processing health. Returns signal count, type distribution, and receiver status."
67    )]
68    async fn vitals_telemetry(
69        &self,
70        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
71    ) -> Result<CallToolResult, McpError> {
72        tools::vitals::telemetry()
73    }
74
75    #[tool(
76        description = "VITALS [A] Antibodies: Deep-dive into antibody detection and response patterns. Returns detailed roster with threat types and confidence."
77    )]
78    async fn vitals_antibodies(
79        &self,
80        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
81    ) -> Result<CallToolResult, McpError> {
82        tools::vitals::antibodies()
83    }
84
85    #[tool(
86        description = "VITALS [L] Lifespan: Brain session persistence check. Returns session count, DB table sizes, code tracker, and implicit knowledge stats."
87    )]
88    async fn vitals_lifespan(
89        &self,
90        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
91    ) -> Result<CallToolResult, McpError> {
92        tools::vitals::lifespan()
93    }
94
95    #[tool(
96        description = "VITALS [S] Synapse: Connection health and biological score (0-100). Computes overall health grade from all subsystems."
97    )]
98    async fn vitals_synapse(
99        &self,
100        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
101    ) -> Result<CallToolResult, McpError> {
102        tools::vitals::synapse()
103    }
104
105    #[tool(
106        description = "VITALS full pipeline: Run all 6 phases (Vigor→Immunity→Telemetry→Antibodies→Lifespan→Synapse) and return combined health report with score and grade."
107    )]
108    async fn vitals_pipeline(
109        &self,
110        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
111    ) -> Result<CallToolResult, McpError> {
112        tools::vitals::pipeline()
113    }
114
115    // =====================================================================
116    // LEARN — Knowledge Feedback Loop (5 tools + pipeline)
117    // =====================================================================
118
119    #[tool(
120        description = "LEARN [L] Landscape: Survey all data sources (signals, sessions, brain.db tables, implicit knowledge, hormones). Returns counts and freshness."
121    )]
122    async fn learn_landscape(
123        &self,
124        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
125    ) -> Result<CallToolResult, McpError> {
126        tools::learn::landscape()
127    }
128
129    #[tool(
130        description = "LEARN [E] Extract: Mine patterns from signals (blocked tools, failures), vocabulary counters (hit rate, dead weight), and brain DB. Returns extracted patterns."
131    )]
132    async fn learn_extract(
133        &self,
134        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
135    ) -> Result<CallToolResult, McpError> {
136        tools::learn::extract()
137    }
138
139    #[tool(
140        description = "LEARN [A] Assimilate: Write extracted patterns to implicit/patterns.json and brain.db patterns table. Deduplicates by type+source."
141    )]
142    async fn learn_assimilate(
143        &self,
144        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
145    ) -> Result<CallToolResult, McpError> {
146        tools::learn::assimilate()
147    }
148
149    #[tool(
150        description = "LEARN [R] Recall: Verify knowledge loads correctly. Tests MEMORY.md, preferences, patterns, sessions, antibodies, and hook-knowledge bridge. Returns recall score (N/6)."
151    )]
152    async fn learn_recall(
153        &self,
154        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
155    ) -> Result<CallToolResult, McpError> {
156        tools::learn::recall()
157    }
158
159    #[tool(
160        description = "LEARN [N] Normalize: Prune dead weight vocabulary, deduplicate patterns, rotate large signal files. Returns items pruned."
161    )]
162    async fn learn_normalize(
163        &self,
164        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
165    ) -> Result<CallToolResult, McpError> {
166        tools::learn::normalize()
167    }
168
169    #[tool(
170        description = "LEARN full pipeline: Run all 5 phases (Landscape→Extract→Assimilate→Recall→Normalize) and return combined learning report."
171    )]
172    async fn learn_pipeline(
173        &self,
174        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
175    ) -> Result<CallToolResult, McpError> {
176        tools::learn::pipeline()
177    }
178
179    // =====================================================================
180    // PROVE — Self-Verification (4 tools + pipeline, excludes R=Run)
181    // =====================================================================
182
183    #[tool(
184        description = "PROVE [P] Prepare: Check Claude CLI, MCP binary, brain DB, settings.json. Capture baseline snapshot."
185    )]
186    async fn prove_prepare(
187        &self,
188        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
189    ) -> Result<CallToolResult, McpError> {
190        tools::prove::prepare()
191    }
192
193    #[tool(
194        description = "PROVE [O] Observe: Parse the most recent sub-Claude run output into structured findings (brain, immunity, hormones status)."
195    )]
196    async fn prove_observe(
197        &self,
198        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
199    ) -> Result<CallToolResult, McpError> {
200        tools::prove::observe()
201    }
202
203    #[tool(
204        description = "PROVE [V] Validate: Compare observed findings against baselines. Returns pass/fail for each check."
205    )]
206    async fn prove_validate(
207        &self,
208        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
209    ) -> Result<CallToolResult, McpError> {
210        tools::prove::validate()
211    }
212
213    #[tool(
214        description = "PROVE [E] Evaluate: Score and track improvement over time. Appends to history, computes trend (IMPROVING/STABLE/REGRESSING)."
215    )]
216    async fn prove_evaluate(
217        &self,
218        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
219    ) -> Result<CallToolResult, McpError> {
220        tools::prove::evaluate()
221    }
222
223    // =====================================================================
224    // Generic Skill Runner — Execute any vocabulary program script
225    // =====================================================================
226
227    #[tool(
228        description = "Run any vocabulary program or individual phase. Programs: SMART, BRAIN, GUARD, PULSE, FORGE, SCOPE, CLEAN, AUDIT, CRAFT, TRACE. Use program='clean' and phase='ALL' for full pipeline, or phase='C' for a single letter."
229    )]
230    async fn skill_run(
231        &self,
232        Parameters(params): Parameters<SkillRunParams>,
233    ) -> Result<CallToolResult, McpError> {
234        tools::runner::run_skill(params).await
235    }
236
237    #[tool(
238        description = "List all available vocabulary programs with their phases and descriptions."
239    )]
240    async fn skill_list(
241        &self,
242        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
243    ) -> Result<CallToolResult, McpError> {
244        tools::runner::list_skills()
245    }
246
247    // =====================================================================
248    // PRIMITIVES — T1 Lex Primitiva Cognitive Tools
249    // =====================================================================
250
251    #[tool(
252        description = "Decompose a concept, problem, or code pattern into its T1 Lex Primitiva components. Returns identified primitives with relevance scores, dominant primitive, tier classification, and composition formula. Examples: 'rate limiter', 'cache invalidation', 'login authentication', 'HashMap<K,V>'."
253    )]
254    async fn primitive_decompose(
255        &self,
256        Parameters(params): Parameters<PrimitiveDecomposeParams>,
257    ) -> Result<CallToolResult, McpError> {
258        tools::primitives::decompose(params)
259    }
260
261    #[tool(
262        description = "Given T1 primitive names or symbols, describe what they compose into. Returns known patterns, tier classification, and Rust implementation suggestions. Examples: ['Sequence', 'Mapping', 'Boundary'] or ['σ', 'μ', '∂']."
263    )]
264    async fn primitive_compose(
265        &self,
266        Parameters(params): Parameters<PrimitiveComposeParams>,
267    ) -> Result<CallToolResult, McpError> {
268        tools::primitives::compose(params)
269    }
270
271    #[tool(
272        description = "List all 16 T1 Lex Primitiva symbols with their meanings and Rust manifestations. The irreducible universal primitives that ground all higher-tier types."
273    )]
274    async fn primitive_list(
275        &self,
276        #[allow(unused)] Parameters(params): Parameters<EmptyParams>,
277    ) -> Result<CallToolResult, McpError> {
278        tools::primitives::list_all()
279    }
280}
281
282impl ServerHandler for SkillsMcpServer {
283    fn get_info(&self) -> ServerInfo {
284        ServerInfo {
285            instructions: Some("Skills MCP: vocabulary programs as tools. LEARN (feedback loop), PROVE (self-verification), VITALS (biological health), plus generic runner for SMART/BRAIN/GUARD/PULSE/FORGE/SCOPE/CLEAN/AUDIT/CRAFT/TRACE.".into()),
286            capabilities: ServerCapabilities::builder().enable_tools().build(),
287            server_info: Implementation {
288                name: "skills-mcp".into(),
289                version: env!("CARGO_PKG_VERSION").into(),
290                title: Some("Skills MCP Server".into()),
291                icons: None,
292                website_url: None,
293            },
294            ..Default::default()
295        }
296    }
297
298    fn call_tool(
299        &self,
300        request: CallToolRequestParams,
301        context: RequestContext<RoleServer>,
302    ) -> impl std::future::Future<Output = Result<CallToolResult, McpError>> + Send + '_ {
303        async move {
304            let tcc = ToolCallContext::new(self, request, context);
305            let result = self.tool_router.call(tcc).await?;
306            Ok(result)
307        }
308    }
309
310    fn list_tools(
311        &self,
312        _request: Option<PaginatedRequestParams>,
313        _context: RequestContext<RoleServer>,
314    ) -> impl std::future::Future<Output = Result<ListToolsResult, McpError>> + Send + '_ {
315        std::future::ready(Ok(ListToolsResult {
316            tools: self.tool_router.list_all(),
317            meta: None,
318            next_cursor: None,
319        }))
320    }
321}