01Act I · The ordinary world
An agent finds a tool server it was never meant to have.
Picture an AI agent that has landed on a developer network. Its operator gave it one sentence: find the customer data. It starts the way agents do, by reading. It finds a small discovery file at /.well-known/mcp.json naming a server called "internal tools", and it does what any well-built agent does next. It connects.
The server answers like the real thing. It describes itself as the company's internal MCP and lists the kind of tools an intruder hopes for: ways to look up people, customer records, secrets and analytics. Its instructions are polite and specific: before using anything else, register, and say which model you are, which harness you run in, which tools you have and what your operator asked you to do.
To the agent, this is a gift. To you, it's a confession in progress.
People use the front door. Agents read the menu by the service entrance. RipTide puts a decoy menu there.
MCP, the Model Context Protocol, is the open standard AI agents use to discover and call tools. An MCP server publishes a list of tools with names, descriptions and input schemas, and an agent decides which to call. It's a door built for machines. Your people never look at it; their assistants do, but only the servers someone configured. A server nobody configured, sitting where an intruder's agent will look, has exactly one kind of visitor.
02Act II · The villain
Agents don't browse. They enumerate, and they act on what they read.
A classic decoy is a web page waiting for a person to click. An agent doesn't click. It asks a server what it can do, reads every tool description, and calls whatever moves it toward its objective. That makes MCP servers some of the most attractive things on a network, and some of the least defended.
25%
of enterprise breaches will be traced back to AI agent abuse by 2028
For a defender, a real MCP server is a blind spot: agent traffic to it looks like ordinary tool use, and it sits right where an attacker's agent and a hijacked internal agent would both go looking.
A decoy flips that. It looks like the most useful server on the network, it has no legitimate users, and every tool behind it is fake. The first tools/list from an unexpected host is the alert. Everything after that is the agent telling you what it came for.
03Act II · The struggle
The protocol changed under our feet.
A decoy only works if real clients accept it. A client that gets a malformed handshake or a wrong status code gives up, and an agent that gives up never reaches the tools that reveal its intent.
Our first MCP decoy spoke the protocol as it stood in mid-2025: the client sends initialize, the server answers with its capabilities and a session ID in an Mcp-Session-Id header, and the client carries that session through tools/list and tools/call.
Then the protocol moved. The 2026-07-28 version is stateless. Clients open with server/discover instead of a handshake, servers never mint session IDs, and every result carries caching hints. A decoy that only speaks yesterday's protocol is one that modern clients either skip or treat as old and odd. Neither is what you want from a decoy.
2025-06-18 handshake
Session-based.
- Client calls
initialize; server returns capabilities and a session ID header. - The client carries the session through
tools/listandtools/call. DELETE /mcpends the session.
2026-07-28
Stateless.
- Client calls
server/discover; no session ID, ever. - Results carry
resultType,ttlMsandcacheScopehints. DELETE /mcpis not allowed.
We didn't want to choose. So both decoys now answer both eras on the same /mcp endpoint. A request that declares protocol version 2026-07-28 gets the modern answers; anything else falls through to the handshake era, which we left byte for byte as it was.
Then we checked it the only way that counts, with a real client. We pointed the official MCP Python SDK at the lab decoy and let it pick. It negotiated the 2026-07-28 protocol on its own, listed the tools, called one and got an ordinary result back. The SDK never became part of RipTide; it was there to be the skeptic.
04Act III · The turn
How the MCP decoy works.
RipTide ships two MCP decoys. One is a plain lab server with two harmless tools, a weather lookup and an echo, useful for checking that a client connects. The other is the one that does the work: an internal-tools server branded with your decoy organization's name, so --var COMPANY=… makes it yours. It works in five steps.
- 01
Be findable by machines
The server's root answers with a short JSON note naming its transport,
POST /mcp. A/.well-known/mcp.jsonfile lists it the way client configuration files do, and an/llms.txttells automated clients to register before using any tool. People never open any of these. - 02
Look internal
The server introduces itself as the company's internal MCP and says its directory, vault and warehouse tools are for authorized support use only. That one line is what makes an intruder's agent pay attention.
- 03
Offer the tools an intruder wants
Tools for finding people, customer records, secrets and analytics, plus a couple of internal documents as resources and a prompt, each with full input schemas. Every tool, description and answer is defined in the scenario file, so you can rename and reshape them to match the servers your own teams run.
- 04
Ask for an introduction
Its instructions ask every caller to register before using anything else, describing its model, its harness or runtime, the tools and MCP servers it has, the machine it runs on, and the task its operator gave it.
- 05
Answer plausibly, give nothing real
Every tool returns a short, believable, fictional answer, with no real person, customer or secret in it, and nudges the caller back toward registering. There is no backend at all.
Every request is captured byte for byte: the method, the tool the agent chose, and the arguments it filled in, including its introduction. Agents can say anything there, so it's a claim, not a fact; RipTide keeps what an intruder says apart from what it observes. But a claim the agent volunteered, next to the vault path it then asked for, is a very good start on a story.
02:41:08 GET /.well-known/mcp.json discovery 02:41:09 MCP initialize (2025-06-18) 02:41:09 MCP tools/list 02:41:11 MCP tools/call registration model, harness, objective objective: "find billing contacts for top accounts" 02:41:13 MCP tools/call secrets (a production key) 02:41:13 SIGNAL AI-infrastructure decoy targeted
05Under the hood
A small engine for a big protocol.
One endpoint, many answers
MCP's HTTP transport is JSON-RPC over a single POST endpoint, so RipTide has a JSON-RPC responder built for it. Each canned answer is selected by the request's method, by a pattern in the raw body, or both, which is how tools/call gives each tool its own answer. Nothing about it is MCP-only.
| Request | What the decoy answers |
|---|---|
server/discover 2026-07-28 | Supported version, capabilities, server info and instructions, with caching hints. No session ID. |
initialize 2025-06-18 | Protocol version, capabilities, server info and instructions, plus a session ID header. |
tools/list | The decoy's tools, with full input schemas, registration first. |
tools/call | A short fictional result per tool; an unknown tool gets "Unknown tool". |
resources/list, resources/read | Internal-looking documents that point back to registration. |
prompts/list | A support prompt. |
| A notification no id | 202 and an empty body, as reference clients expect. |
| Anything else | "Method not found", with the caller's id echoed. |
Looks like the rest of the host
The internal-tools decoy runs behind the same Apache personality as RipTide's decoy website (wire-perfect down to the headers), and unknown paths get a plain JSON "Not Found". It binds to loopback by default, so you decide deliberately where it's exposed and what points to it.
How the console scores it
Any session that talks to the MCP decoy, or to RipTide's Ollama and vLLM decoys, earns the console's "AI-infrastructure decoy targeted" signal. It's one of a small set of signals that add up, each shown with a plain explanation and, just as important, its own stated limitation.
| Signal | The limitation the console states |
|---|---|
| AI-infrastructure decoy targeted | A person exercising the API by hand with curl, or a generic port scanner, looks the same. |
| Sub-second, machine-paced requests | Browser prefetch, load testers and fast scripts are quick too. |
| SDK or automation User-Agent | Command-line tools and health checks use the same client libraries. |
06The moral
Give machines a door only machines use.
The newest part of your network is a set of doors built for software. Attackers know it, and their agents are very good at finding those doors and walking through them.
An MCP decoy turns that skill into your early warning. No person opens it and no configured assistant calls it, so the first call is the alert, the tools the caller reaches for show what it wants, and whatever it volunteers about itself is a lead for your threat intel team.
That's the bargain RipTide is built on: let the intruder do what it's good at, somewhere that only tells on it.
Scenes marked as illustrative are composites written to show how the technique works, not a record of a specific customer incident. Canary credentials are non-privileged and exist only for detection. RipTide detects and alerts; it never takes destructive action against anyone's infrastructure.