Skip to content

feat(mcp): add lowfat-mcp server for Claude Desktop and other MCP clients#8

Open
swamig wants to merge 1 commit into
zdk:mainfrom
swamig:feat/mcp-server
Open

feat(mcp): add lowfat-mcp server for Claude Desktop and other MCP clients#8
swamig wants to merge 1 commit into
zdk:mainfrom
swamig:feat/mcp-server

Conversation

@swamig

@swamig swamig commented Jun 9, 2026

Copy link
Copy Markdown

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 a run tool that executes a command and returns its lowfat-condensed output — so the token savings reach MCP clients too.

How

  • Speaks MCP over stdio (newline-delimited JSON-RPC 2.0).
  • Shells out to the lowfat binary — 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.
  • Lives in its own crate so the main lowfat binary stays lean. Only dependency is serde_json — no async runtime, no MCP SDK, in keeping with the project's lightweight ethos.

run tool

param type notes
command string (required) program to run, e.g. git
args string[] arguments, e.g. ["status"]
cwd string working directory
level lite|full|ultra per-call compression via LOWFAT_LEVEL

LOWFAT_BIN overrides the binary path when lowfat isn't on PATH.

Test plan

  • cargo build --workspace — clean
  • cargo test -p lowfat-mcp — 7 protocol/handler tests pass
  • cargo fmt -p lowfat-mcp -- --check — clean
  • End-to-end stdio smoke test: initializetools/listtools/call run {git status} returns condensed output
  • README Setup section documents the Claude Desktop config

Notes

The main lowfat binary and brew install are unaffected — lowfat-mcp is a separate opt-in binary (cargo build --release -p lowfat-mcp).

…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
@zdk

zdk commented Jun 10, 2026

Copy link
Copy Markdown
Owner

@swamig Nice PR, thanks! Will check this out.

@zdk zdk left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, need a rebase to the recent main update.

Comment on lines +183 to +190
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);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be better if we could set a specific timeout.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 single run tool that shells out to the lowfat binary.
  • 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.

Comment on lines +84 to +86
let id = request.get("id").cloned();
let method = request.get("method").and_then(Value::as_str).unwrap_or("");
let is_notification = id.is_none();
Comment on lines +175 to +179
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();
Comment on lines +188 to +190
if let Some(level) = args.get("level").and_then(Value::as_str) {
cmd.env("LOWFAT_LEVEL", level);
}
Comment on lines +181 to +183
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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants