Is that MCP request actually from your AI agent?
Last week we open-sourced Signet — cryptographic signing for every AI agent tool call.
Someone asked a good question: the agent signs, but does the server verify?
Fair point. v0.1 was one-sided. The agent signed every request, but the server didn't check. Like mailing a signed contract that nobody verifies on the other end. Better than nothing, but the trust chain is broken.
This week we closed the loop.
From one-sided to bilateral
v0.1 Agent signs (one-sided)
→ proves the agent sent the request
v0.2 Compound receipt (request + response bound)
→ proves the request and response are paired
v0.3 Server verification
→ server can verify "this request was signed by a specific agent"
v0.4 Bilateral co-signing
→ agent signs the request, server signs the response, both hold proof
Server verification: 3 lines
Add this to your MCP server handler:
import { verifyRequest } from "@signet-auth/mcp-server";
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const v = verifyRequest(request, {
trustedKeys: ["ed25519:..."],
maxAge: 300,
});
if (!v.ok) return { content: [{ type: "text", text: v.error }], isError: true };
// verified — proceed
console.log(`Request from: ${v.signerName}`);
});
One function. Six checks: signature validity, trusted key list, freshness window (anti-replay), target binding (anti-cross-server), tool name match, params match. ~50μs.
Bilateral co-signing: 3 more lines
After verifying and processing the request, the server signs the response:
import { signResponse } from "@signet-auth/mcp-server";
const bilateral = signResponse(request, response, {
serverKey: process.env.SIGNET_SERVER_KEY,
serverName: "my-server",
});
This produces a BilateralReceipt:
{
"v": 3,
"agent_receipt": {
"v": 1,
"action": { "tool": "create_issue", "params_hash": "sha256:..." },
"signer": { "pubkey": "ed25519:...", "name": "deploy-bot" },
"sig": "ed25519:..."
},
"response": { "content_hash": "sha256:..." },
"server": { "pubkey": "ed25519:...", "name": "github-mcp" },
"ts_response": "...",
"sig": "ed25519:..."
}
Two signatures, two keys, one record. The agent says "I sent this request." The server says "I received this request and returned this response." Both parties hold proof. Neither can deny it.
Why bilateral matters
One-sided signing proves "what the agent did." Bilateral signing proves "what happened between the agent and the server."
The difference:
Scenario: an agent places a purchase order, but the amount is wrong.
One-sided: the agent says "I sent price=100." But the server might have received price=10000. You can't prove what happened in between.
Bilateral: the agent's signature binds the params_hash. The server's signature binds the response content_hash. Any tampering in between breaks one of the signatures. Both parties signed the same facts — when something goes wrong, the signatures tell you who's right.
Python support
from signet_auth import SigningAgent
agent = SigningAgent.create("my-agent", owner="willamhou")
receipt = agent.sign("create_issue", params={"title": "fix bug"})
# Verify a bilateral receipt
from signet_auth import verify_bilateral
result = verify_bilateral(bilateral_receipt_json, agent_pubkey, server_pubkey)
Where this fits in the MCP ecosystem
In the MCP spec discussion (SEP-1763), five independent projects were identified as layers of an enforcement stack:
| Layer | Project | What it does |
|---|---|---|
| Transport integrity | Signet | Agent signs request, server verifies + co-signs |
| Policy enforcement | APS | Authorization checks, policy engine |
| External anchoring | ArkForge | Receipt anchoring to transparency logs |
| Spend control | AgentPay | Budget caps |
| Output verification | veroq | Response content validation |
Signet went from a one-sided signing tool to the transport layer of a bilateral trust protocol. Each layer does its own thing. Together they form a complete agent security stack.
Try it
Claude Code (on the official Anthropic plugin marketplace):
/plugin install signet@claude-plugins-official
Every tool call is signed and audited. Zero config.
MCP server (on the MCP Registry, Glama indexed):
npm install @signet-auth/mcp-server
Agent side:
# TypeScript
npm install @signet-auth/core @signet-auth/mcp
# Python (LangGraph, LlamaIndex, Pydantic AI, Google ADK, OpenAI Agents, Semantic Kernel, smolagents)
pip install signet-auth
GitHub: github.com/Prismer-AI/signet

Top comments (0)