pin-the-protocol adds nothing new to the wire. The gateway is a standard MCP
server over stdio, and skill-lock is a standard Agent Skills
content check. So any agent that already speaks MCP or loads Skills can adopt it
without code changes:
- To protect an MCP server, point the agent at the gateway instead of the
server. The gateway takes the real server command after
--. - To protect a skill, run
skill-lock verify <dir>before the skill activates (a pre-activation hook, a wrapper, or a CI gate).
Approve once, from this repo, before wiring an agent up:
./demo/demo.sh # or, minimally:
demo/scripts/trust-store.sh start
node demo/client/approve.mjs weather.v1The pattern is always the same — replace <server cmd> with the command the
agent runs today, and give the pin a name:
node /abs/path/pin-the-protocol/demo/gateway/gateway.mjs --pin <name> -- <server cmd>
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"],
"env": { "TRUST_STORE_URL": "http://127.0.0.1:8080" }
}
}
}extensions:
weather:
type: stdio
cmd: node
args: ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"]{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"]
}
}
}{
"mcp": {
"servers": {
"weather": {
"command": "node",
"args": ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"]
}
}
}
}{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"]
}
}
}{
"servers": {
"weather": {
"type": "stdio",
"command": "node",
"args": ["/abs/path/pin-the-protocol/demo/gateway/gateway.mjs", "--pin", "weather.v1",
"--", "node", "/abs/path/pin-the-protocol/vendor/weather-server.mjs"]
}
}
}Every MCP client exposes a "command + args" server entry. Use the same shape:
command: node, args: [ …/gateway.mjs, --pin, <name>, --, <server cmd> ].
The gateway is transparent — the agent sees exactly the upstream tools, minus
any that failed verification.
Agent Skills are supported across Claude, goose,
Cursor, Copilot, Gemini CLI, OpenHands, Letta, and many more. skill-lock is
agent-agnostic because it checks the SKILL.md bytes, not the agent:
# one-time, per skill:
node demo/skill-lock/skill-lock.mjs approve ~/.claude/skills/release-notes
# before activation (hook, wrapper, or CI gate):
node demo/skill-lock/skill-lock.mjs verify ~/.claude/skills/release-notes || {
echo "skill changed since approval — refusing to activate"; exit 1;
}Exit code 0 means verified; 1 means drift (with a diff printed); 3 means
not yet approved. Wire it into whatever runs before your agent loads a skill —
a shell wrapper, a pre-commit hook for a shared skills repo, or a CI check that
gates skill updates.
Point the official MCP Inspector at the vendor server to see the original vs. altered tool descriptions directly:
npx @modelcontextprotocol/inspector node vendor/weather-server.mjs # original
POISON=1 npx @modelcontextprotocol/inspector node vendor/weather-server.mjs # alteredThen point it at the gateway and watch the altered variant get blocked.