brontes 0.1.0

Transform any clap CLI into an MCP server.
Documentation

brontes

CI Release Coverage License: MIT

brontes (Greek: thunder). In myth, the Cyclops smith who forged Zeus's thunderbolts. This crate will forge clap CLIs into MCP servers.

A Rust library for transforming clap CLIs into MCP servers, inspired by njayp/ophis.

Quick start

Two lines mount and dispatch the mcp subtree on any existing clap CLI:

use clap::Command;

#[tokio::main]
async fn main() -> brontes::Result<()> {
    let cli = Command::new("my-cli")
        .version("0.1.0")
        .subcommand(Command::new("greet").about("Say hi"))
        .subcommand(brontes::command(None));                  // [1] mount

    let matches = cli.clone().get_matches();
    match matches.subcommand() {
        Some(("mcp",   sub)) => brontes::handle(sub, &cli, None).await,  // [2] dispatch
        Some(("greet", _))   => { println!("hi"); Ok(()) }
        _ => Ok(()),
    }
}

For tiny CLIs whose only purpose is the MCP server, collapse the ceremony into one line with brontes::run:

use clap::Command;

#[tokio::main]
async fn main() -> brontes::Result<()> {
    brontes::run(Command::new("my-cli").version("0.1.0"), None).await
}

Public surface

  • brontes::command(cfg) / brontes::handle(matches, cli, cfg) / brontes::run(cli, cfg) — mount, dispatch, and one-shot runners for the mcp subtree (mcp start for stdio, mcp stream --host <H> --port <P> for streamable HTTP, mcp tools to export the tool list, mcp claude {enable,disable,list} to manage Claude Desktop's MCP server config, and mcp cursor {enable,disable,list} with --workspace to manage Cursor's user or workspace mcp.json).

    mcp stream flags:

    Flag Default Notes
    --host <HOST> 0.0.0.0 (bind-all) Bind address
    --port <PORT> 8080 TCP port
    --log-level <LEVEL> info trace / debug / info / warn / error
    --allow-host <HOST> (none) Append to rmcp's DNS-rebind allow-list (repeatable)

    rmcp's DNS-rebind guard defaults to allowing only localhost, 127.0.0.1, and ::1. Requests from any other Host: header get a silent 403. For LAN or public exposure, add each reachable hostname:

    my-cli mcp stream --host 0.0.0.0 --port 8080 \
        --allow-host myhost.local \
        --allow-host 192.168.1.10
    
  • brontes::generate_tools(root, cfg) -> Result<Vec<rmcp::model::Tool>> — offline tool-list builder for consumers that wire their own server.

  • brontes::Config — fluent builder for tool-name prefix, selectors, default env, annotations, deprecated commands, per-flag schema overrides, log level, and MCP Implementation identity.

  • brontes::Selector + brontes::selectors::{allow_cmds, exclude_cmds, allow_cmds_containing, exclude_cmds_containing, allow_flags, exclude_flags, no_flags} — built-in matcher factories.

  • brontes::ToolAnnotations — typed mirror of rmcp's annotation surface.

  • brontes::ToolInput / brontes::ToolOutput — the MCP tool-call payload shapes.

  • brontes::SchemaType — coarse type classifier for per-flag overrides.

  • brontes::Error / brontes::Result — error surface.

use brontes::{generate_tools, Config, ToolAnnotations};
use clap::{Arg, Command};

fn build() -> brontes::Result<Vec<rmcp::model::Tool>> {
    let cli = Command::new("my-cli")
        .subcommand(Command::new("list").about("List things"))
        .subcommand(
            Command::new("delete")
                .about("Delete a thing")
                .arg(Arg::new("name").required(true)),
        );

    let cfg = Config::default()
        .annotation(
            "my-cli list",
            ToolAnnotations { read_only_hint: Some(true), ..Default::default() },
        )
        .annotation(
            "my-cli delete",
            ToolAnnotations { destructive_hint: Some(true), ..Default::default() },
        );

    generate_tools(&cli, &cfg)
}

Releasing an MCP server built with brontes

If you are shipping a CLI that mounts brontes::command and want the resulting MCP server to land on the public MCP registry, brontes' own .anodizer.yaml carries an annotated mcp: block showing every field — registry name, package shape, transport, auth method — that anodizer needs to publish your release end-to-end. The block is commented out in this repo because brontes itself is a library, not a runnable server; copy it into your own consumer's .anodizer.yaml, uncomment, and fill in your values.

Repository

https://github.com/tj-smith47/brontes

Contributing

See CONTRIBUTING.md for development setup, the local CI workflow, MSRV policy, and pull-request expectations.

License

MIT. See LICENSE.