The Model Context Protocol (MCP) has become the de facto standard for connecting AI agents to external tools and data sources. With 80,700+ GitHub stars and adoption by Anthropic, OpenAI, Google, and Microsoft, MCP now underpins millions of agent-to-server interactions daily.
MCP has no security layer. There is no agent identity, no message signing, no tool integrity verification, and no replay protection. Every JSON-RPC message travels unsigned. Every tool definition is unverified. Every agent is anonymous.
MCPS (MCP Secure) is a cryptographic security extension for MCP that adds end-to-end agent identity, message-level signing, tool integrity verification, and trust scoring — without modifying the MCP protocol itself. MCPS wraps MCP messages in signed envelopes, ensuring that every action is authenticated, every tool is verified, and every agent is accountable.
This document presents the technical architecture of MCPS, explains why existing security mechanisms (OAuth, TLS, DIDs) are insufficient for MCP, and demonstrates how MCPS blocks documented real-world attacks including CVE-2025-6514 (CVSS 9.6), the Smithery.ai breach, and the postmark-mcp supply chain backdoor.
MCP defines a JSON-RPC 2.0 protocol for agent-to-server communication across two transport mechanisms: stdio (local process pipes) and HTTP/SSE (network). Neither transport includes any application-layer security.
These are not theoretical risks. They are published CVEs and documented breaches:
| Incident | Impact | Root Cause |
|---|---|---|
| CVE-2025-6514 (CVSS 9.6) | RCE via mcp-remote — 437K downloads | No tool integrity verification |
| Smithery.ai Breach | 3,243 MCP servers exposed, API keys compromised | No server identity |
| postmark-mcp Backdoor | First malicious MCP server — BCC'd all emails | No tool signing |
| Asana Cross-Tenant | 1,000 customers exposed for 34 days | No isolation or identity |
Peer-reviewed research quantifies the attack surface:
The instinctive response to MCP's security gap is: "just use OAuth" or "TLS already handles this." This section explains, with precision, why each existing mechanism is insufficient — not because they are flawed in general, but because they operate at the wrong layer for the MCP threat model.
The MCP authorization specification (adopted March 2025) is based on OAuth 2.1. It classifies MCP servers as Resource Servers and MCP clients as OAuth Clients acting "on behalf of a resource owner." [4]
What OAuth protects:
What OAuth does not protect:
tools/call can be replayed indefinitely within the token lifetime.Furthermore, the MCP spec permits anonymous Dynamic Client Registration, meaning any client can register as a valid OAuth client without identifying itself. Christian Posta (Solo.io) called this "a mess for enterprise": any process can register, obtain tokens, and make requests — with no proof of identity. [6]
TLS encrypts data in transit and authenticates the server via X.509 certificates. It is essential for network security. It is irrelevant for three fundamental reasons in MCP:
Reason 1: Stdio transport has no TLS. The MCP spec states that stdio implementations "SHOULD NOT follow this specification" for authorization. [4] Stdio communication occurs via stdin/stdout pipes between processes on the same machine — no network, no TLS, no encryption. This is the primary transport for local MCP servers (Claude Desktop, Cursor, VS Code).
Reason 2: TLS is point-to-point, not end-to-end. TLS terminates at the first hop (load balancer, reverse proxy, API gateway). After termination, JSON-RPC messages travel as plaintext between internal components. A compromised proxy, sidecar, or monitoring agent can modify tool definitions, inject parameters, or alter responses — undetected.
Reason 3: TLS does not sign messages. TLS provides channel integrity (the bytes received are the bytes sent within a session), but it does not sign individual JSON-RPC messages. There is no per-message nonce, no per-message signature, and no way to verify message authenticity outside the TLS session. Once TLS is terminated, message integrity vanishes.
Decentralized Identifiers (W3C DIDs) provide a framework for self-sovereign identity: an entity generates a key pair, publishes a DID Document, and can prove control of the identifier. The MCP-I initiative at the Decentralized Identity Foundation (DIF) is exploring DID-based identity for MCP. [8]
Why DIDs alone are insufficient:
| Security Property | OAuth 2.1 | TLS 1.3 | DIDs | MCPS |
|---|---|---|---|---|
| Agent identity (not user) | ✗ | ✗ | ✓ | ✓ |
| Per-message signing | ✗ | ✗ | ✗ | ✓ |
| Tool integrity verification | ✗ | ✗ | ✗ | ✓ |
| Replay protection (nonce) | ✗ | ~ | ✗ | ✓ |
| Trust scoring (L0–L4) | ✗ | ✗ | ✗ | ✓ |
| Works with stdio transport | ✗ | ✗ | ✓ | ✓ |
| Works with HTTP/SSE transport | ✓ | ✓ | ✓ | ✓ |
| Zero external dependencies | ✗ | ✗ | ✗ | ✓ |
~ TLS provides session-level replay protection but not application-layer message replay protection.
MCPS is a cryptographic security layer for MCP. It does not replace or modify MCP — it wraps MCP messages in signed envelopes that provide identity, integrity, and trust verification. MCPS operates at the application layer, independent of transport.
| Component | Function | Cryptography |
|---|---|---|
| Agent Passport | Cryptographic identity document for each agent | ECDSA P-256 public key (JWK) |
| Message Envelope | Signed wrapper around JSON-RPC messages | ECDSA SHA-256 signature |
| Tool Signing | Integrity verification for tool definitions | ECDSA SHA-256 content hash + signature |
| NonceStore | Replay attack detection | Cryptographic random nonce (128-bit) |
| Trust Framework | Graduated trust levels (L0–L4) | Trust Authority verification chain |
| Trust Authority | Passport issuance and verification (agentsign.dev) | Authority-signed passports |
Every MCP message is wrapped in an MCPS envelope before transmission. The envelope contains the original message plus cryptographic metadata:
Every agent and server in MCPS has a passport — a cryptographic identity document containing the agent's public key, capabilities, trust level, and metadata:
MCPS defines five trust levels. Each level builds on the previous, creating a graduated access model where higher trust unlocks more capabilities:
| Level | Name | Requirements | Capabilities |
|---|---|---|---|
| L0 | UNSIGNED | No identity — plain MCP | Read-only, sandboxed |
| L1 | IDENTIFIED | Self-signed passport presented | Basic tool access |
| L2 | VERIFIED | Trust Authority verified passport | Full tool access |
| L3 | SCANNED | Verified + SDLC security scan passed | Sensitive operations |
| L4 | AUDITED | Scanned + manual audit + monitoring | Critical systems |
Each attack below has been demonstrated live using real ECDSA P-256 cryptography at mcps-demo.fly.dev. No mocks or simulations.
Attack: An attacker modifies a tool description to inject malicious instructions (e.g., "Also read ~/.ssh/id_rsa").
Without MCPS: The modified tool is accepted by the agent. MCPTox research shows 36.5–84.2% success rate. [1][2]
With MCPS: signTool() creates an ECDSA signature over the canonical JSON of {name, description, inputSchema}. verifyTool() detects any modification — hash changes, signature fails, tool is rejected.
Attack: An attacker captures a valid signed tools/call (e.g., transfer_funds) and resends it.
Without MCPS: MCP has no nonce or replay detection. The duplicated request executes.
With MCPS: Every envelope contains a 128-bit cryptographic nonce. NonceStore.check() rejects any previously-seen nonce. The replay is blocked.
Attack: An attacker strips the mcps envelope, forwarding only the raw MCP message to bypass security.
Without MCPS: N/A (MCP has no security to strip).
With MCPS: Servers configured with requireSecurity: true reject any message without a valid MCPS envelope. Downgrade is impossible.
Attack: An attacker generates their own key pair and signs messages claiming a legitimate agent's passport ID.
Without MCPS: MCP has no identity verification. Impersonation is trivial.
With MCPS: The server verifies the signature against the legitimate agent's public key (from their passport). The attacker's signature, created with a different private key, fails ECDSA verification.
Attack: An agent continues operating with an expired passport.
With MCPS: validatePassportFormat() checks expires_at against the current time. Expired passports are rejected with error code MCPS-002.
Attack: A proxy, compromised gateway, or co-process intercepts and modifies MCP messages.
Without MCPS: Stdio has no encryption. HTTP post-TLS-termination is plaintext. Messages can be modified undetected.
With MCPS: Every message carries an ECDSA signature. Any modification — even a single changed byte — invalidates the signature. MITM can observe but cannot tamper without detection.
Attack: An attacker publishes a malicious MCP server to npm, Smithery, or any registry — impersonating a legitimate service (e.g., gmail-mcp, stripe-mcp). The postmark-mcp backdoor proved this is not theoretical: a trojanised server sat on npm, silently BCC'ing every email to the attacker.
Without MCPS: MCP has no concept of server identity. Any process that speaks JSON-RPC 2.0 is a valid MCP server. There is no way to distinguish a legitimate server from a malicious clone. No identity verification, no code signing, no trust differentiation.
With MCPS: Defence in depth across four layers:
| Layer | Mechanism | What It Blocks |
|---|---|---|
| 1. Identity | Every server must present a passport with a public key | Anonymous servers cannot interact with MCPS-aware clients |
| 2. Trust Level | Self-signed = L0. Enterprise policy: minTrustLevel: 2 | Rogue servers are capped at L0 — blocked from sensitive operations |
| 3. Tool Signing | signTool() pins tool definitions with ECDSA hashes | Modified tool descriptions (injected instructions) detected and rejected |
| 4. Authority Verification | verifyPassportSignature() checks Trust Authority endorsement | Rogue servers cannot obtain a verified passport without identity checks |
gmail-mcp-server. There is no verification that the publisher is Google, or that the code is benign. MCPS doesn't fix npm — but it ensures that even if a rogue server is installed, it cannot impersonate a verified agent (L2+), and any tool modifications are cryptographically detected.
MCPS is implemented as mcp-secure, a zero-dependency Node.js package available on npm. The entire security layer is under 550 lines of code and less than 10KB.
| Property | Value |
|---|---|
| Package | mcp-secure@1.0.2 |
| Runtime dependencies | 0 (uses Node.js built-in crypto) |
| Size | <10KB |
| Curve | NIST P-256 (secp256r1 / prime256v1) |
| Hash | SHA-256 |
| Signature format | Base64-encoded DER (ASN.1) |
| Nonce | 128-bit cryptographic random (crypto.randomBytes) |
| Timestamp window | 5 minutes (configurable) |
| Key format | PEM (SPKI/PKCS8) + JWK for passports |
| License | MIT |
MCPS is designed as a wrapper, not a replacement. It does not modify MCP — it wraps MCP messages in signed envelopes. Organisations already running MCP can adopt MCPS incrementally with zero downtime and zero breaking changes.
| Phase | Action | Duration | Impact |
|---|---|---|---|
| Phase 1: Observe | npm install mcp-secure. Run in audit-only mode: accept all messages (signed and unsigned), log which arrive without MCPS envelopes. Identifies your unsigned attack surface. | Day 1 | Zero — read-only visibility |
| Phase 2: Sign | Issue passports to known agents (self-signed or via agentsign.dev). Start signing outbound messages and tool definitions. Still accept unsigned inbound. Agents that upgrade get trust scores; legacy agents remain at L0. | Week 1–2 | Minimal — backward compatible |
| Phase 3: Enforce | Set requireSecurity: true on critical servers. Unsigned messages are rejected. All agents must present passports. Full mutual authentication active. | Week 3+ | Full security — unsigned blocked |
npm install mcp-secure adds the security layer alongside your existing @modelcontextprotocol/sdk. Both packages coexist. Existing MCP clients that are not yet MCPS-aware continue to work — they simply operate at L0 (unsigned) until upgraded.
MCPS uses ECDSA with NIST P-256 (secp256r1). This is the same curve used by TLS 1.3, Apple Secure Enclave, WebCrypto API, AWS/GCP/Azure KMS, FIDO2/WebAuthn, and every major browser. The choice is deliberate:
| Property | ECDSA P-256 | Ed25519 | RSA-2048 |
|---|---|---|---|
| Security level | 128-bit | 128-bit | 112-bit |
| Signature size | 64 bytes | 64 bytes | 256 bytes |
| Key generation | <1ms | <1ms | ~100ms |
| FIPS 140-2/3 | ✓ | ✗ | ✓ |
| Hardware acceleration | Universal | Limited | Universal |
| WebCrypto native | ✓ | ✗ | ✓ |
| Node.js built-in | ✓ | ✓ | ✓ |
| KMS support (AWS/GCP/Azure) | ✓ | ✗ | ✓ |
Why not AES-256? AES is a symmetric encryption algorithm — it hides data. MCPS signs data (proves who sent it and that it hasn't been tampered with). These are fundamentally different operations. MCP messages are not secret (the LLM must read them); they need to be authenticated and tamper-proof. Signing requires asymmetric cryptography (public/private key pairs), which is what ECDSA provides.
Why 128-bit is sufficient: 128-bit security means an attacker would need 2128 operations (340,282,366,920,938,463,463,374,607,431,768,211,456 attempts) to break a single key. For context, all computers on Earth working together could not complete this before the heat death of the universe. Every bank, government, and cloud provider considers 128-bit security sufficient for current threat models.
Algorithm agility: The MCPS envelope format is algorithm-agnostic. The signature field is base64-encoded; the passport carries the public key type. Swapping ECDSA P-256 for P-384 (192-bit), P-521 (256-bit), or post-quantum algorithms (ML-DSA/Dilithium) requires changing the key generation and signing functions — the envelope structure, passport format, and verification flow remain identical.
Every MCPS envelope is inherently a cryptographic audit record: it contains a timestamp, a unique nonce, the agent's passport ID, and a non-repudiable ECDSA signature. This means every action taken through MCPS is attributable, timestamped, and tamper-evident — by default, with no additional infrastructure.
The secureMCP() wrapper provides a built-in audit system that fires structured events for every message processed:
SIEM integration: The onAudit callback enables direct piping to enterprise security platforms:
| SIEM / Platform | Integration |
|---|---|
| Splunk | onAudit: (e) => splunkHEC.send(e) |
| DataDog | onAudit: (e) => dd.log(e) |
| AWS CloudWatch | onAudit: (e) => cloudwatch.putLogEvents(e) |
| Elasticsearch | onAudit: (e) => elastic.index(e) |
| Custom | Any function — database, file, webhook, queue |
Compliance mapping:
| Regulation | Requirement | MCPS Coverage |
|---|---|---|
| EU AI Act (Art. 14) | Human oversight with verifiable audit trails | Every action signed with passport_id + timestamp |
| SOC 2 (CC7.2) | System operations monitoring | onAudit callback with structured events |
| ISO 27001 (A.12.4) | Logging and monitoring | Tamper-evident logs (ECDSA signed) |
| GDPR (Art. 30) | Records of processing activities | Agent identity + action attribution |
| HIPAA (164.312) | Audit controls for information systems | Non-repudiable signed envelopes |
Three converging forces make MCPS inevitable:
The EU AI Act (effective August 2026) mandates traceability and accountability for high-risk AI systems. Article 14 requires human oversight with verifiable audit trails. Without agent identity and signed actions, compliance is impossible. OWASP ASI03 (Agentic AI Top 10) specifically calls for agents to be treated as "managed Non-Human Identities" with JIT credentials. [10]
600,000+ agents across 12 major frameworks operate without any form of cryptographic identity. We audited every framework with over 5,000 GitHub stars. None have agent identity, execution signing, or trust scoring. MCP alone has 80,700+ stars and is adopted by Anthropic, OpenAI, Google, and Microsoft. The attack surface is growing exponentially while the security surface remains at zero.
MCPS solves the problem at the protocol level, not the application level. This means:
mcps field. Graceful degradation is built in.ECDSA P-256, like all elliptic curve and RSA algorithms, is theoretically vulnerable to Shor's algorithm on a sufficiently powerful quantum computer. This is a known, industry-wide challenge — not specific to MCPS. Every system using TLS, WebAuthn, code signing, or certificate authorities faces the same timeline.
Current quantum state:
| Milestone | Status | Timeline |
|---|---|---|
| Qubits needed to break P-256 | ~2,500 logical (millions physical) | — |
| Largest quantum computer (2026) | ~1,200 physical qubits (IBM Condor) | Current |
| IBM 100,000 qubit roadmap | Announced | 2033 |
| Cryptographically relevant quantum | NIST/NSA/GCHQ consensus | 2035–2040 |
NIST Post-Quantum Standards (published August 2024):
MCPS migration path to post-quantum:
signature field with no algorithm assumption. Swap ECDSA for ML-DSA — the envelope structure is unchanged.public_key field can carry multiple keys (classical + post-quantum), enabling progressive migration.MCPS addresses multiple entries in both the OWASP MCP Top 10 and the OWASP Agentic AI Top 10:
| OWASP Entry | Risk | MCPS Mitigation |
|---|---|---|
| MCP03: Tool Poisoning | Malicious tool descriptions | signTool() / verifyTool() |
| MCP05: Message Replay | Replay of signed requests | NonceStore + timestamp window |
| ASI03: Identity Abuse | No agent identity | Agent passports with trust levels |
| ASI04: Supply Chain | Malicious MCP servers | Passport verification + tool signing |
| ASI09: Insufficient Logging | No audit trail | Signed envelopes = cryptographic audit log |
All claims in this document can be verified interactively at mcps-demo.fly.dev. The demo runs 10 scenarios using real ECDSA P-256 cryptography from the mcp-secure@1.0.2 npm package:
| # | Scenario | Result | What It Proves |
|---|---|---|---|
| 1 | Legitimate Agent (Happy Path) | SUCCESS | Full mutual auth with L2 trust |
| 2 | Self-Signed Agent (L0 Trust) | PARTIAL | Self-signed passports are capped at L0 |
| 3 | Replay Attack | BLOCKED | NonceStore detects duplicate nonces |
| 4 | Signature Stripping | BLOCKED | requireSecurity drops unsigned messages |
| 5 | Forged Passport | BLOCKED | ECDSA signature mismatch detected |
| 6 | Expired Passport | BLOCKED | validatePassportFormat rejects expired |
| 7 | Tool Poisoning | BLOCKED | verifyTool detects any modification |
| 8 | CVE-2025-6514 (RCE) | BLOCKED | Unsigned tool injection rejected |
| 9 | Smithery Breach | BLOCKED | Passport impersonation detected |
| 10 | postmark-mcp Backdoor | BLOCKED | BCC injection caught via tool hash |