The day my MCP adapter stopped being just plumbing

# ai# mcp# security# showdev
The day my MCP adapter stopped being just plumbingAakash

TL;DR: Remote MCP Adapter started as a usability layer for remote MCP workflows, but recent MCP...

TL;DR: Remote MCP Adapter started as a usability layer for remote MCP workflows, but recent MCP tool-poisoning research made one thing painfully clear: middleware in the path is also part of the security boundary. In v0.3.0, I added tool-definition pinning, drift detection, metadata sanitization, description minimization, and stricter session binding to reduce what unsafe upstream metadata and session misuse can do.

After finishing the core work for Remote MCP Adapter, I did what most of us do after shipping something that finally works: I stepped back and started looking around.

I wanted to see how other people were dealing with the same class of problems. Remote MCP is useful, but once the client and server stop sharing a filesystem, things get ugly fast. Uploads become awkward. Generated files become awkward. Anything involving screenshots, PDFs, artifacts, or session-scoped state becomes awkward. That was the original reason I built the adapter in the first place.

I wrote more about that side of the story in the earlier blog that inspired this work.

Then I ran into a post on DEV: Your MCP server's tool descriptions are an attack surface.

That post, along with the underlying research it points to, forced an uncomfortable realization.

The adapter I had built to make remote MCP usable had already placed itself in the middle of a trust boundary.

And if something sits in the middle of a trust boundary, it does not get to pretend it is just plumbing anymore.

The realization

My adapter was already doing serious work. It was sitting between the client and upstream MCP servers. It was forwarding model-visible tool metadata. It was managing uploads, artifacts, and per-session state. It was translating behavior across boundaries that do not exist in local-only setups.

That is the kind of component people often mentally classify as a thin relay.

It is not.

Once a gateway or adapter sees tool catalogs, schema text, descriptions, session identifiers, uploads, auth context, and returned artifacts, it has already become part of the system's security posture whether the maintainer planned for that or not.

That was the moment the project changed in my head.

Remote MCP Adapter was no longer just a convenience layer for remote file and artifact handling. It had also become a natural enforcement point.

Not a silver bullet. Not an AI firewall. Not some magical solution to MCP security.

But definitely an enforcement point.

What changed in v0.3.0

v0.3.0 is the first release where I treated the adapter like that explicitly.

The goal was not to solve all MCP security problems. That would be dishonest.

The goal was narrower and much more practical:

  • stop blindly relaying model-visible tool metadata
  • detect when tool definitions drift mid-session
  • reduce how much unsafe or unnecessary description text reaches the model
  • tighten the adapter's own session semantics once stateful features and auth are involved
  • document what is implemented and what is still out of scope

That led to five concrete changes.

1) Safer defaults for model-visible tool metadata

The adapter now takes a stricter default stance for tool metadata.

  • core.tool_metadata_sanitization.mode now defaults to sanitize
  • core.tool_definition_pinning.mode now defaults to warn

That default matters.

Before this, users had to think like security engineers up front and opt into the right behavior. Now the adapter starts from a safer position and becomes stricter from there if the environment demands it.

I prefer that tradeoff. A lot of security features die in the field simply because they exist only as options nobody enables.

2) Tool-definition pinning and drift detection

This one addresses what some people are calling the "rug pull" problem.

If a server presents one tool catalog at the start of a session and then later changes tool titles, descriptions, or schemas, that is not a harmless cosmetic update anymore. That is model-visible behavior changing under an already-established trust relationship.

So the adapter can now baseline the first visible tool catalog for a session and compare later catalogs against it.

When a drift is detected, policy decides what happens next:

  • warn
  • block
  • invalidate the session entirely

This is not meant to be clever. It is meant to be boring and reliable.

If the thing the model sees has changed, that change should not pass through silently.

3) Metadata sanitization before forwarding tool schemas

Tool poisoning is not only about the top-level tool description.

That is one of the most important takeaways from the recent research. Once tool metadata enters the model context, any model-visible text can become an instruction surface: titles, descriptions, schema text, annotation titles, nested descriptions, and other fields that look harmless when treated like normal software metadata.

So v0.3.0 adds model-visible metadata sanitization for:

  • tool titles
  • tool descriptions
  • annotation titles
  • schema text

In stricter mode, the adapter can block tools with dirty metadata instead of forwarding them at all.

This is the right place to be conservative. If the middleware is already on the path, it should at least stop acting like every upstream schema is innocent by default.

4) Tool description minimization and stripping

There is now a unified tool_description_policy that applies to both top-level tool descriptions and nested schema descriptions.

It supports three modes:

  • preserve
  • truncate
  • strip

This one is especially useful for paranoid or tightly controlled environments.

Sometimes the right answer is not "try to detect every clever poisoning trick in free-form description text."

Sometimes the right answer is: why is this much prose reaching the model at all?

That is what this policy is for.

If an environment does not need rich description text, it should be allowed to minimize or remove it completely.

5) Stricter session binding when adapter auth is enabled

This one is less flashy, but it matters.

Once the adapter stores uploads, artifacts, cancellation state, or other per-session data, session integrity stops being just an MCP transport concern. It becomes part of the product's own security model.

So when adapter auth is enabled, sessions are now bound to the authenticated context that established them.

That means a reused Mcp-Session-Id cannot simply be picked up under a different authenticated context.

If the adapter is going to own state, then it also has to own the consequences of that state being misused.

Why I did not want to oversell this

It would be very easy to market all of this as:

"Remote MCP Adapter now protects you from MCP poisoning."

That would be lazy and false.

What v0.3.0 does is much more specific.

It gives the adapter enough awareness and policy surface to stop being a blind forwarder of model-visible tool metadata and state.

That helps.

It does not magically solve:

  • first-seen poisoning that looks semantically legitimate
  • every novel encoding trick
  • every schema-level manipulation pattern
  • every exfiltration path through allowed downstream tools
  • every bad trust decision made elsewhere in the stack

Those limits matter, and pretending otherwise would make the release less trustworthy, not more.

Evidence and implementation trail

I did not want this release to be just a changelog dressed up as a security post, so I wrote and linked the supporting material as well.

The implementation and evidence trail for this work lives here:

Credit where it is due

This release did not come out of nowhere.

The immediate push came from reading Your MCP server's tool descriptions are an attack surface, along with the research and guidance around MCP tool poisoning and schema manipulation.

That post is worth reading, and so is the work behind it.

If you are exploring the security side of MCP seriously, do check out Pipelock as well. It takes a more security-focused posture as a dedicated control point, and it is useful to see how others are approaching the same family of problems.


If you are running remote MCP setups in a team or organization and have seen poisoning, schema weirdness, or mid-session tool drift in the wild, I would genuinely like to hear about it. Real attack samples and ugly edge cases are far more useful than clean toy examples when deciding what to harden next.