1#![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
21pub 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
31pub 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;