Skip to main content

sim_mcp_server/
lib.rs

1//! Standalone MCP server entry point for SIM.
2//!
3//! Parses [`CliOptions`], builds a runtime [`Cx`] with the MCP codec and
4//! library installed, and serves the Model Context Protocol over the selected
5//! [`Transport`] (currently stdio).
6
7#![deny(missing_docs)]
8
9mod cli;
10
11use std::io::{BufRead, Write};
12use std::sync::Arc;
13
14use sim_codec_mcp::McpCodecLib;
15use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Error, Result};
16use sim_lib_mcp::stdio::{StdioOptions, mcp_stdio_capability, run_stdio};
17use sim_lib_mcp::{McpRouter, McpSession, install_mcp_lib};
18
19pub use cli::{CliOptions, Transport};
20
21/// Parses options from process arguments and serves on the standard streams.
22pub fn run_from_env() -> Result<()> {
23    run(
24        CliOptions::parse()?,
25        std::io::stdin().lock(),
26        std::io::stdout(),
27        std::io::stderr(),
28    )
29}
30
31/// Serves MCP per `opts` over the given reader, writer, and diagnostics streams.
32///
33/// Only the stdio transport is supported; selecting HTTP returns an error.
34pub fn run<R, W, E>(opts: CliOptions, reader: R, writer: W, diagnostics: E) -> Result<()>
35where
36    R: BufRead,
37    W: Write,
38    E: Write,
39{
40    match &opts.transport {
41        Transport::Stdio => run_stdio_transport(opts, reader, writer, diagnostics),
42        Transport::Http { .. } => Err(Error::Eval(
43            "sim-mcp-server --http is disabled; use --stdio".to_owned(),
44        )),
45    }
46}
47
48fn run_stdio_transport<R, W, E>(
49    opts: CliOptions,
50    reader: R,
51    writer: W,
52    diagnostics: E,
53) -> Result<()>
54where
55    R: BufRead,
56    W: Write,
57    E: Write,
58{
59    let mut cx = runtime_cx()?;
60    let mut session = McpSession::new("stdio", opts.profile);
61    session = session.with_granted_capability(mcp_stdio_capability());
62    for capability in opts.capabilities {
63        session = session.with_granted_capability(capability);
64    }
65    let mut router = McpRouter::new(session);
66    run_stdio(
67        &mut cx,
68        &mut router,
69        reader,
70        writer,
71        diagnostics,
72        StdioOptions {
73            log_stderr: opts.log_stderr,
74        },
75    )?;
76    Ok(())
77}
78
79fn runtime_cx() -> Result<Cx> {
80    let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
81    let codec = McpCodecLib::new(cx.registry_mut().fresh_codec_id());
82    cx.load_lib(&codec)?;
83    install_mcp_lib(&mut cx)?;
84    Ok(cx)
85}
86
87#[cfg(test)]
88mod tests;