mod mcp;
mod tools;
use std::io::{BufRead, Write};
use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::Parser;
use scema_agent::Agent;
use scema_tools::Workspace;
use crate::mcp::McpServer;
use crate::tools::Tools;
#[derive(Parser)]
#[command(
name = "scema-mcp",
version,
about = "Scematica Omni over the Model Context Protocol (stdio)"
)]
struct Cli {
#[arg(long, default_value = ".scema")]
root: PathBuf,
#[arg(long = "allow")]
allow: Vec<PathBuf>,
#[arg(long)]
allow_decide: bool,
#[arg(long)]
dqstar: Option<String>,
}
fn main() -> Result<()> {
let cli = Cli::parse();
let roots: Vec<PathBuf> = if cli.allow.is_empty() {
vec![std::env::current_dir()?]
} else {
cli.allow.clone()
};
let workspace = Workspace::new(&roots).context("resolving --allow roots")?;
eprintln!("scema-mcp {} — {}", env!("CARGO_PKG_VERSION"), scema_agent::RUNTIME);
for r in workspace.root_labels() {
eprintln!(" allow {r}");
}
eprintln!(" state {}", cli.root.display());
eprintln!(
" omni_decide {}",
if cli.allow_decide { "advertised" } else { "not advertised (--allow-decide)" }
);
let server = McpServer::new(Tools {
agent: Agent::new(cli.root.clone(), cli.dqstar.clone()),
workspace,
root: cli.root,
allow_decide: cli.allow_decide,
});
let stdin = std::io::stdin();
let mut stdout = std::io::stdout();
for line in stdin.lock().lines() {
let line = line.context("reading stdin")?;
if let Some(reply) = server.handle_line(&line) {
stdout.write_all(reply.as_bytes())?;
stdout.write_all(b"\n")?;
stdout.flush()?;
}
}
Ok(())
}