Skip to main content

boost/
tool.rs

1//! The `Tool` trait — every MCP tool exposed by Boost implements this.
2//!
3//! Tools own their input schema (for client-side validation in the AI agent),
4//! their name, and an async handler that receives the parsed JSON arguments and
5//! the shared `Context` (Application + DB pool).
6
7use async_trait::async_trait;
8use serde_json::Value;
9use std::sync::Arc;
10
11use anvil_core::Application;
12use anvil_core::Container;
13
14use crate::protocol::CallToolResult;
15
16/// Per-server shared state passed into every tool invocation.
17pub struct Context {
18    pub container: Container,
19    pub routes: Vec<anvil_core::RouteInfo>,
20    pub project_root: std::path::PathBuf,
21    pub log_buffer: Arc<crate::log_capture::LogBuffer>,
22}
23
24impl Context {
25    pub fn from_app(app: &Application, log_buffer: Arc<crate::log_capture::LogBuffer>) -> Self {
26        Self {
27            container: app.container.clone(),
28            routes: app.routes().to_vec(),
29            project_root: std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
30            log_buffer,
31        }
32    }
33}
34
35#[async_trait]
36pub trait Tool: Send + Sync + 'static {
37    fn name(&self) -> &'static str;
38    fn description(&self) -> &'static str;
39
40    /// JSON Schema for the tool's `arguments` object.
41    fn input_schema(&self) -> Value {
42        serde_json::json!({ "type": "object", "properties": {} })
43    }
44
45    async fn call(&self, ctx: &Context, args: Value) -> CallToolResult;
46}