agentic-workflow-mcp 0.1.0

MCP server for AgenticWorkflow — universal LLM access to workflow orchestration
Documentation
use serde_json::json;

use crate::types::{ToolDefinition, ToolResult};
use super::registry::EngineState;

pub fn definitions() -> Vec<ToolDefinition> {
    vec![
        ToolDefinition {
            name: "workflow_fsm_create".to_string(),
            description: "Create a finite state machine with states and transitions".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "name": { "type": "string", "description": "FSM name" },
                    "states": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": { "type": "string" },
                                "is_terminal": { "type": "boolean" }
                            }
                        },
                        "description": "List of states"
                    },
                    "transitions": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "from": { "type": "string" },
                                "to": { "type": "string" },
                                "event": { "type": "string" }
                            }
                        },
                        "description": "List of transitions"
                    },
                    "initial_state": { "type": "string", "description": "Starting state name" }
                },
                "required": ["name", "states", "transitions", "initial_state"]
            }),
        },
        ToolDefinition {
            name: "workflow_fsm_transition".to_string(),
            description: "Trigger a state transition by sending an event".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "fsm_id": { "type": "string", "description": "FSM ID" },
                    "event": { "type": "string", "description": "Event to trigger" }
                },
                "required": ["fsm_id", "event"]
            }),
        },
        ToolDefinition {
            name: "workflow_fsm_state".to_string(),
            description: "Get the current state of a finite state machine".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "fsm_id": { "type": "string", "description": "FSM ID" }
                },
                "required": ["fsm_id"]
            }),
        },
        ToolDefinition {
            name: "workflow_fsm_valid_next".to_string(),
            description: "List valid next transitions from the current state".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "fsm_id": { "type": "string", "description": "FSM ID" }
                },
                "required": ["fsm_id"]
            }),
        },
        ToolDefinition {
            name: "workflow_fsm_history".to_string(),
            description: "Get the transition history of a finite state machine".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "fsm_id": { "type": "string", "description": "FSM ID" }
                },
                "required": ["fsm_id"]
            }),
        },
        ToolDefinition {
            name: "workflow_fsm_diagram".to_string(),
            description: "Generate a Mermaid state diagram for an FSM".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "fsm_id": { "type": "string", "description": "FSM ID" }
                },
                "required": ["fsm_id"]
            }),
        },
    ]
}

pub fn dispatch(
    name: &str,
    params: serde_json::Value,
    state: &mut EngineState,
) -> Result<ToolResult, (i32, String)> {
    match name {
        "workflow_fsm_create" => {
            let fsm_name = params["name"].as_str().unwrap_or("fsm");
            let initial = params["initial_state"].as_str().unwrap_or("");
            let states: Vec<agentic_workflow::types::State> = params["states"]
                .as_array()
                .map(|arr| arr.iter().map(|s| agentic_workflow::types::State {
                    name: s["name"].as_str().unwrap_or("").to_string(),
                    description: s["description"].as_str().map(String::from),
                    entry_action: None,
                    exit_action: None,
                    is_terminal: s["is_terminal"].as_bool().unwrap_or(false),
                }).collect())
                .unwrap_or_default();
            let transitions: Vec<agentic_workflow::types::Transition> = params["transitions"]
                .as_array()
                .map(|arr| arr.iter().map(|t| agentic_workflow::types::Transition {
                    from: t["from"].as_str().unwrap_or("").to_string(),
                    to: t["to"].as_str().unwrap_or("").to_string(),
                    event: t["event"].as_str().unwrap_or("").to_string(),
                    guard: None,
                    action: None,
                }).collect())
                .unwrap_or_default();
            match state.fsm.create_fsm(fsm_name, states, transitions, initial) {
                Ok(fid) => Ok(ToolResult::text(json!({
                    "fsm_id": fid,
                    "status": "created"
                }).to_string())),
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        "workflow_fsm_transition" => {
            let fid = params["fsm_id"].as_str().unwrap_or("");
            let event = params["event"].as_str().unwrap_or("");
            match state.fsm.transition(fid, event) {
                Ok(new_state) => Ok(ToolResult::text(json!({
                    "fsm_id": fid,
                    "new_state": new_state
                }).to_string())),
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        "workflow_fsm_state" => {
            let fid = params["fsm_id"].as_str().unwrap_or("");
            match state.fsm.current_state(fid) {
                Ok(s) => Ok(ToolResult::text(json!({
                    "fsm_id": fid,
                    "current_state": s
                }).to_string())),
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        "workflow_fsm_valid_next" => {
            let fid = params["fsm_id"].as_str().unwrap_or("");
            match state.fsm.valid_next(fid) {
                Ok(transitions) => {
                    let items: Vec<_> = transitions.iter().map(|t| json!({
                        "event": t.event,
                        "to": t.to
                    })).collect();
                    Ok(ToolResult::text(json!({
                        "fsm_id": fid,
                        "valid_transitions": items
                    }).to_string()))
                }
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        "workflow_fsm_history" => {
            let fid = params["fsm_id"].as_str().unwrap_or("");
            match state.fsm.get_history(fid) {
                Ok(records) => {
                    let items: Vec<_> = records.iter().map(|r| json!({
                        "from": r.from_state,
                        "to": r.to_state,
                        "event": r.event,
                        "timestamp": r.timestamp.to_rfc3339()
                    })).collect();
                    Ok(ToolResult::text(json!({
                        "fsm_id": fid,
                        "history": items
                    }).to_string()))
                }
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        "workflow_fsm_diagram" => {
            let fid = params["fsm_id"].as_str().unwrap_or("");
            match state.fsm.diagram(fid) {
                Ok(diagram) => Ok(ToolResult::text(diagram)),
                Err(e) => Ok(ToolResult::error(format!("{}", e))),
            }
        }
        _ => Ok(ToolResult::error(format!("Unknown FSM tool: {}", name))),
    }
}