feat(mcp): add lowfat-mcp server for Claude Desktop and other MCP clients#8
feat(mcp): add lowfat-mcp server for Claude Desktop and other MCP clients#8swamig wants to merge 1 commit into
Conversation
…ents CLI agents get lowfat's output filtering via the shell hook or shell-init. GUI clients like Claude Desktop don't run a user shell, so they have no place to hook in. This adds a Model Context Protocol server that gives them one: a `run` tool that executes a command and returns its lowfat-condensed output. The server speaks MCP over stdio (newline-delimited JSON-RPC 2.0) and shells out to the `lowfat` binary — the same wrap-the-binary approach used by the shell hook and OpenCode plugin. It lives in its own crate (`lowfat-mcp`) so the main `lowfat` binary stays lean, and depends only on serde_json — no async runtime, no MCP SDK. - `run` tool params: command (required), args, cwd, level (lite/full/ultra) - LOWFAT_BIN overrides the binary path when lowfat isn't on PATH - protocol handlers covered by unit tests - README Setup section documents the Claude Desktop config
|
@swamig Nice PR, thanks! Will check this out. |
zdk
left a comment
There was a problem hiding this comment.
Also, need a rebase to the recent main update.
| cmd.arg(command).args(&cmd_args); | ||
|
|
||
| if let Some(cwd) = args.get("cwd").and_then(Value::as_str) { | ||
| cmd.current_dir(cwd); | ||
| } | ||
| if let Some(level) = args.get("level").and_then(Value::as_str) { | ||
| cmd.env("LOWFAT_LEVEL", level); | ||
| } |
There was a problem hiding this comment.
I think we should handle the run tool to avoid internal lowfat subcommands conflict/collision (with commands in crates/lowfat/src/commands) e.g. cmd.arg("--").arg(command).args(&cmd_args); etc.
| cmd.env("LOWFAT_LEVEL", level); | ||
| } | ||
|
|
||
| let output = match cmd.output() { |
There was a problem hiding this comment.
Could be better if we could set a specific timeout.
There was a problem hiding this comment.
Pull request overview
Adds a new lowfat-mcp binary crate that implements a minimal MCP (JSON-RPC over stdio) server to expose lowfat’s output filtering to GUI MCP clients (e.g., Claude Desktop) that can’t rely on shell hooks.
Changes:
- Introduces
crates/lowfat-mcp, a dependency-light MCP server exposing a singleruntool that shells out to thelowfatbinary. - Registers the new crate in the workspace and lockfile.
- Documents Claude Desktop MCP setup in the README.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds setup instructions for using lowfat-mcp from Claude Desktop / MCP clients. |
| crates/lowfat-mcp/src/main.rs | Implements the stdio JSON-RPC dispatcher, tool schema, and run handler with unit tests. |
| crates/lowfat-mcp/Cargo.toml | Defines the new lowfat-mcp crate and its (workspace) dependency on serde_json. |
| Cargo.toml | Adds crates/lowfat-mcp to the workspace members. |
| Cargo.lock | Records the new lowfat-mcp package entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let id = request.get("id").cloned(); | ||
| let method = request.get("method").and_then(Value::as_str).unwrap_or(""); | ||
| let is_notification = id.is_none(); |
| let cmd_args: Vec<&str> = args | ||
| .get("args") | ||
| .and_then(Value::as_array) | ||
| .map(|arr| arr.iter().filter_map(Value::as_str).collect()) | ||
| .unwrap_or_default(); |
| if let Some(level) = args.get("level").and_then(Value::as_str) { | ||
| cmd.env("LOWFAT_LEVEL", level); | ||
| } |
| let lowfat_bin = std::env::var("LOWFAT_BIN").unwrap_or_else(|_| "lowfat".to_string()); | ||
| let mut cmd = Command::new(&lowfat_bin); | ||
| cmd.arg(command).args(&cmd_args); |
What
Adds
lowfat-mcp, a Model Context Protocol server that exposes lowfat's output filtering to MCP clients such as Claude Desktop.Why
CLI agents (Claude Code, Codex) get lowfat for free via the shell hook or
shell-init. GUI clients like Claude Desktop don't run a user shell, so there's nowhere to hook in. This gives them aruntool that executes a command and returns its lowfat-condensed output — so the token savings reach MCP clients too.How
lowfatbinary — the same wrap-the-binary approach as the shell hook and OpenCode plugin. The binary does all the filtering; the server is a thin bridge.lowfatbinary stays lean. Only dependency isserde_json— no async runtime, no MCP SDK, in keeping with the project's lightweight ethos.runtoolcommandgitargs["status"]cwdlevellite|full|ultraLOWFAT_LEVELLOWFAT_BINoverrides the binary path whenlowfatisn't onPATH.Test plan
cargo build --workspace— cleancargo test -p lowfat-mcp— 7 protocol/handler tests passcargo fmt -p lowfat-mcp -- --check— cleaninitialize→tools/list→tools/call run {git status}returns condensed outputNotes
The main
lowfatbinary andbrew installare unaffected —lowfat-mcpis a separate opt-in binary (cargo build --release -p lowfat-mcp).