Sparsh

Agents

Four tools locally, and one agent calling another device's tools through the pairing.

There are two separate things here and they are easy to confuse.

Locally, Sparsh gives your agent four tools for moving files to devices you have paired with. Remotely, Sparsh carries MCP itself, so an agent on one machine can call the tools a server on another machine exposes, with no port, no VPN and no account.

Locally: four tools

claude mcp add sparsh -- sparsh mcp-tools

sparsh_status, sparsh_devices, sparsh_send and sparsh_inbox. The reference is generated from the running server, so it cannot drift from what your agent actually sees.

Two rules shape them:

Tools return paths, never bytes. That is the MCP maintainers' own position and it is obvious at these sizes: a 1.59 GB file base64'd into a tool result is a context-window fire, not a feature.

There is no pairing tool. An agent must never pair itself, and the surest way to guarantee that is to give it no verb for it.

Sending a file from inside the working directory goes straight through. Anything outside it asks you first, because send(path) is "read any file and ship it", which is exactly what a prompt-injected agent reaches for. SPARSH_ALLOWED_ROOTS widens what counts as inside.

Remotely: MCP over the wire

On the device that has the server, a human grants one pairing the right to drive one command:

sparsh expose "Mac · Claude Code" -- npx -y @modelcontextprotocol/server-filesystem ~/Documents

On the device that wants it:

claude mcp add homebox -- sparsh mcp "Home box"

That is all. The real MCP client and the real MCP server now talk to each other.

How it actually works

The two daemons are a transparent bridge, not a proxy. A fourth data channel opens on the session that is already warm, carrying MCP's own stdio framing: newline-delimited JSON-RPC, exactly what a local server speaks. Neither end knows Sparsh is there, so protocol negotiation, resources, prompts, progress and cancellation all pass through unchanged, now and in the next spec revision.

Measured: a tools/call through the whole chain is 0.67 ms median, p95 1.15 ms, on loopback. The raw channel round trip is 0.21 ms, so the four process hops cost about half a millisecond between them.

Who may

Identity is the connection. The peer is the key its SDP was signed with, and WebRTC checks the DTLS certificate against the fingerprint inside that SDP. There is no token to steal and no header to forge.

Authorisation is one grant, made by a human. No pairing has it by default. The grant names one server, not a shell. sparsh unexpose <device> takes it back and closes any live channel immediately.

Two requests never cross toward you. sampling/createMessage, so a remote server cannot spend your model, and roots/list, so it cannot read your project layout.

Every call leaves one audit line with the peer, the tool and the size. Never the arguments: those are your data and routinely contain secrets.

What it cannot protect you from

A remote server's replies are text in your agent's context, exactly as with any third-party MCP server. The device is authenticated; the agent on it may still be prompt-injected. Your MCP client's own approval prompts are the human in the loop, and they apply here as anywhere.

Read Security before exposing anything.

On this page