TL;DR: rust-faf-mcp migrates from hand-rolled JSON-RPC to the rmcp SDK. main.rs drops from 253 lines to ~20. Three new tools land: faf_compress, faf_discover, faf_tokens. Tests go from 49 to 91 across 5 files.

Why rmcp

v0.1.0 shipped with a hand-rolled JSON-RPC stdio loop. It worked — 49 tests proved it. But it meant maintaining transport, schema generation, and protocol compliance manually. The rmcp crate (v1.1) provides all of that via #[tool_router] and ServerHandler.

The migration deletes 230+ lines and replaces them with derive macros:

#[tool(tool_box)]
impl FafServer {
    #[tool(description = "Create or enhance a project.faf file")]
    async fn faf_init(
        &self,
        params: Parameters<PathParams>,
    ) -> Result<String, String> {
        let args = params_to_value(&params.0);
        value_to_string_result(tools::faf_init(&args))
    }
}

Parameter structs get schemars::JsonSchema for automatic schema generation. main.rs becomes ~20 lines:

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let server = server::FafServer;
    let transport = stdio();
    server.serve(transport).await.unwrap();
}

Three New Tools

ToolWhat
faf_compressCompress .faf for token-limited contexts — minimal, standard, or full
faf_discoverWalk up the directory tree to find the nearest project.faf
faf_tokensEstimate token count at each compression level

All three are powered by faf-rust-sdk v1.3 — the same SDK that drives the Axum middleware. compress(), find_faf_file(), and estimate_tokens() do the real work. The MCP server adapts them to JSON-RPC.

Architecture

src/
├── main.rs      # ~20 lines — tokio entry, rmcp stdio transport
├── server.rs    # FafServer: #[tool_router], ServerHandler, resources
└── tools.rs     # Business logic — all 8 tools, pure functions

Tools return serde_json::Value. The server adapts them to Result<String, String> for rmcp's IntoCallToolResult. Business logic stays testable. Protocol concerns stay in the server layer.

91 Tests

FileTestsCoverage
mcp_protocol.rs9Init handshake, tools/list, resources, schema validation
tools_functional.rs25All 8 tools — happy path, error paths, language detection
tier1_security.rs12Path traversal, null bytes, shell injection, oversized input
tier2_engine.rs35Corrupt YAML, sync, pipelines, dual manifests, legacy filenames
tier3_edge_cases.rs10Unicode, CJK, score boundaries, GitHub URL parsing

Every test spawns the compiled binary as a subprocess and communicates via stdin/stdout JSON-RPC. No mocks. The server under test is the server you install.

Install

cargo install rust-faf-mcp
brew install Wolfe-Jam/faf/rust-faf-mcp

Configure for Claude Code:

claude mcp add faf rust-faf-mcp

Or any MCP client (WARP, Cursor, Zed, Claude Desktop):

{
  "mcpServers": {
    "faf": {
      "command": "rust-faf-mcp"
    }
  }
}

GitHub

Source and release notes.

rust-faf-mcp

crates.io

Install the latest version.

rust-faf-mcp

The Numbers

  • v0.2.0 — Released March 7, 2026
  • 91/91 — Tests passing (was 49)
  • 8 tools — Was 5
  • 4.3 MB — Stripped binary
  • ~20 linesmain.rs (was 253)