use aion_mcp::tasks::resolve::{TaskProjection, TaskResolveError};
use aion_mcp::tools::service::{
ToolCall, ToolCatalog, ToolFailure, ToolOutcome, ToolService, ToolTaskDecision,
};
use serde_json::json;
use crate::{CallerIdentity, ServerState};
use super::catalog::aion_tool_catalog;
use super::instructions::instructions;
use super::task_ref;
use super::tools::{authoring, control, describe, history, list, start, transcript};
pub struct AionToolService {
state: ServerState,
catalog: ToolCatalog,
instructions: String,
}
impl AionToolService {
pub fn new(state: ServerState) -> Result<Self, crate::ServerError> {
let catalog = aion_tool_catalog().map_err(|error| crate::ServerError::Config {
message: format!("the MCP tool catalog is invalid: {error}"),
})?;
Ok(Self {
state,
catalog,
instructions: instructions(),
})
}
}
#[async_trait::async_trait]
impl ToolService for AionToolService {
type Caller = CallerIdentity;
fn catalog(&self) -> &ToolCatalog {
&self.catalog
}
fn instructions(&self) -> &str {
&self.instructions
}
fn task_decision(&self, call: &ToolCall) -> ToolTaskDecision {
if start::awaits_completion(call) {
ToolTaskDecision::Task
} else {
ToolTaskDecision::Inline
}
}
async fn call(
&self,
caller: &Self::Caller,
call: ToolCall,
) -> Result<ToolOutcome, ToolFailure> {
match call.name.as_str() {
"describe_run" => describe::describe_run(&self.state, caller, &call).await,
"read_transcript" => transcript::read_transcript(&self.state, caller, &call).await,
"read_history" => history::read_history(&self.state, caller, &call).await,
"list_runs" => list::list_runs(&self.state, caller, &call).await,
"query" => control::query(&self.state, caller, &call).await,
"start_run" => start::start_run(&self.state, caller, &call).await,
"signal" => control::signal(&self.state, caller, &call).await,
"cancel" => control::cancel(&self.state, caller, &call).await,
"list_documents" => authoring::list_documents(&self.state, caller, &call).await,
"read_document" => authoring::read_document(&self.state, caller, &call).await,
"check_document" => authoring::check_document(&self.state, caller, &call).await,
"save_document" => authoring::save_document(&self.state, caller, &call).await,
"deploy_document" => authoring::deploy_document(&self.state, caller, &call).await,
other => Err(ToolFailure::new(
format!("`{other}` is not a tool this server implements"),
json!({ "code": "unknown_tool", "tool": other }),
)),
}
}
fn task_handle(&self, call: &ToolCall, outcome: &ToolOutcome) -> Option<String> {
task_ref::task_handle(call, outcome)
}
async fn resolve_task(
&self,
caller: &Self::Caller,
task_id: &str,
) -> Result<TaskProjection, TaskResolveError> {
task_ref::resolve_task(&self.state, caller, task_id).await
}
}