Expose a plain function to Claude, Cursor, or any MCP client — in four lines, with zero dependencies.
Part of the Pipe in 30 Lines series: RAG without a vector DB · Self-healing code · Parallel LLM calls
Building an MCP server usually means picking an SDK, wiring up JSON-RPC plumbing, and shipping a runtime with dependencies. Pipe is the first language with built-in MCP — ai_tool
registers a function, mcp_server
mcp_serve_stdio
start the server.
fn greet name
"Hello, " ++ name ++ "! Pipe speaks MCP natively."
ai_tool "greet" "Greet a person by name" {name: "Person's name"} greet
mcp_server "Pipe Greeting Server" "1.0.0"
mcp_serve_stdio
Point Claude Desktop (or Cursor, or any MCP client) at it:
{
"mcpServers": {
"pipe-greet": {
"command": "/path/to/pipe",
"args": ["examples/blog_mcp_server.pipe"]
}
}
}
What happens here:
turns any Pipe function into a schema'd tool — name, description, and an argument map are all it needs.ai_tool
start the server and serve the tool over stdio.mcp_server
+mcp_serve_stdio
- The same binary that serves MCP can also consume it:
mcp_use_stdio
connects to any MCP server off npm/uvx, so your LLM gets GitHub, filesystem, or database tools in the same pipeline.
There's no SDK, no package.json
, no build step. A single ~7 MB binary is both server and client — the tool you expose to Claude is the same language you write your pipeline in. That's the whole idea behind the MCP Cell: when MCP is a language primitive, the sandbox can wrap the server, the client, and the tools.
Run it yourself: pipe examples/blog_mcp_server.pipe
(it starts a stdio server — hit it with initialize
, tools/list
, then tools/call
with {"name":"greet","arguments":{"name":"Harry"}}
).
Eine normale Funktion für Claude, Cursor oder jeden MCP-Client bereitstellen — in vier Zeilen, mit null Abhängigkeiten.
Teil der Serie Pipe in 30 Lines: RAG ohne Vektor-DB · Selbstheilender Code · Parallele LLM-Calls
Einen MCP-Server zu bauen heißt sonst: SDK auswählen, JSON-RPC-Verkabelung, und eine Runtime mit Dependencies ausliefern. Pipe ist die erste Sprache mit eingebautem MCP — ai_tool
registriert eine Funktion, mcp_server
mcp_serve_stdio
starten den Server.
fn greet name
"Hello, " ++ name ++ "! Pipe speaks MCP natively."
ai_tool "greet" "Greet a person by name" {name: "Person's name"} greet
mcp_server "Pipe Greeting Server" "1.0.0"
mcp_serve_stdio
Claude Desktop (oder Cursor, oder jeder MCP-Client) zeigt darauf:
{
"mcpServers": {
"pipe-greet": {
"command": "/path/to/pipe",
"args": ["examples/blog_mcp_server.pipe"]
}
}
}
Was hier passiert:
macht aus jeder Pipe-Funktion ein Tool mit Schema — Name, Beschreibung und Argument-Map reichen.ai_tool
starten den Server und servieren das Tool über stdio.mcp_server
+mcp_serve_stdio
- Dieselbe Binary, die MCP serviert, kann es auch konsumieren:
mcp_use_stdio
verbindet sich mit jedem MCP-Server von npm/uvx — dein LLM bekommt GitHub-, Dateisystem- oder Datenbank-Tools in derselben Pipeline.
Kein SDK, kein package.json
, kein Build-Schritt. Eine einzelne ~7-MB-Binary ist Server und Client — das Tool, das du Claude gibst, ist dieselbe Sprache, in der du deine Pipeline schreibst. Genau das ist die Idee hinter der MCP-Zelle: Wenn MCP ein Sprach-Primitiv ist, kann die Sandbox Server, Client und Tools gemeinsam umschließen.
Selbst ausprobieren: pipe examples/blog_mcp_server.pipe
(startet einen stdio-Server — teste mit initialize
, tools/list
, dann tools/call
mit {"name":"greet","arguments":{"name":"Harry"}}
).