Any Language
Write tools in Python, TypeScript, Go, Rust, or any language that can speak protobuf over a unix socket.
Any Language
Write tools in Python, TypeScript, Go, Rust, or any language that can speak protobuf over a unix socket.
Hot Reload
Save your file and tools reload instantly — no need to restart Claude Desktop or your MCP host.
Dynamic Tool Lists
Tools can enable or disable themselves at runtime. Show only what’s relevant based on context.
Single Binary
One Go binary. No daemon, no registry, no config files. Just pmcp dev server.py.
protomcp sits between your MCP host (Claude Desktop, etc.) and your tool process. It speaks MCP on one side and a simple protobuf protocol on the other.
MCP Host ←── MCP protocol ──→ protomcp (Go) ←── protobuf/unix socket ──→ tool processYour tool process registers handlers using a decorator or function, and protomcp handles everything else: listing tools, routing calls, hot reload, and dynamic tool list management.
# Installbrew install msilverblatt/tap/protomcp# tools.py (Python)from protomcp import tool, ToolResult
@tool("Add two numbers")def add(a: int, b: int) -> ToolResult: return ToolResult(result=str(a + b))// tools.ts (TypeScript)import { tool, ToolResult } from 'protomcp';import { z } from 'zod';
tool({ description: 'Add two numbers', args: z.object({ a: z.number(), b: z.number() }), handler({ a, b }) { return new ToolResult({ result: String(a + b) }); },});// tools.go (Go)package main
import ( "fmt" "github.com/msilverblatt/protomcp/sdk/go/protomcp")
func main() { protomcp.Tool("add", protomcp.Description("Add two numbers"), protomcp.Args(protomcp.IntArg("a"), protomcp.IntArg("b")), protomcp.Handler(func(ctx protomcp.ToolContext, args map[string]interface{}) protomcp.ToolResult { a := int(args["a"].(float64)) b := int(args["b"].(float64)) return protomcp.Result(fmt.Sprintf("%d", a+b)) }), ) protomcp.Run()}// src/main.rs (Rust)use protomcp::{tool, ToolResult, ArgDef};
#[tokio::main]async fn main() { tool("add") .description("Add two numbers") .arg(ArgDef::int("a")) .arg(ArgDef::int("b")) .handler(|_ctx, args| { let a = args["a"].as_i64().unwrap_or(0); let b = args["b"].as_i64().unwrap_or(0); ToolResult::new(format!("{}", a + b)) }) .register(); protomcp::run().await;}# Pythonpmcp dev tools.py
# TypeScriptpmcp dev tools.ts
# Gopmcp dev tools.go
# Rustpmcp dev src/main.rsThen add the command to your MCP client config. That’s it.
@tool() decorator, ToolResult, tool_managertool(), Zod schemas, toolManagerTool(), functional options, ToolResulttool() builder, ToolResult, ArgDef