Architecture

Your agent
    POST /mcp   Authorization: ApiKey <orgUUID>:<hex>
  
Cloudflare Worker  (mcp.vulnetix.com)   no storage of any kind
  ├─ validation      Host/Origin, method, content type
  ├─ tools           31, several composing multiple upstream calls
  ├─ prompts         33, generated from the Pix skill library
  ├─ shaping         response reduction before anything reaches you
  └─ inference       AI Gateway, Pro and above, always optional
                           
                           
  Vulnetix VDB API     Cloudflare AI Gateway

Stateless because the protocol is

MCP revision 2026-07-28 made a change that matters here: it removed protocol-level sessions. No initialize handshake, no session id, no resumable streams, and servers may not initiate requests. Every request carries its own version, client identity and capabilities.

So the server holds nothing between requests. This is not an optimisation. There is nothing left to hold.

What that removes for you:

  • No session to expire. A credential rotation takes effect on the next request, with no reconnection dance.
  • No state to leak between tenants. There is no shared object where one organisation’s data could reach another.
  • No cold-start penalty for you. Every request is served by whichever edge location is nearest, with no affinity requirement.
  • No version drift. Nothing runs on your machine, so there is nothing to keep current.

No bindings

The Worker has no Durable Objects, KV, D1, R2 or queues, by design.

Durable per-organisation state (triage decisions, VEX statements, scan history) lives in the Vulnetix API, where it already did before this server existed. Duplicating it here would create a second source of truth to reconcile.

Response caching uses Cloudflare’s edge cache, keyed per principal. Two organisations never share a cache entry, because plan tier changes which fields come back and sharing could leak a paid field to a caller who did not pay for it, or withhold one from a caller who did.

Inference reaches AI Gateway over ordinary HTTPS rather than a binding, which is what lets the server stay binding-free while still having a model available.

Request path

  1. Validation. Host and Origin against an allowlist (DNS-rebinding protection, required by the transport spec); POST only, GET and DELETE answer 405; JSON content type or 415.
  2. Credential extraction. The Authorization header is parsed only far enough to recover the organisation UUID for cache keying, then forwarded unchanged.
  3. Dispatch. A fresh server instance per request, built by a factory. Nothing carries over.
  4. Upstream. Bounded: at most 12 calls per tool, a 45-second timeout, a size guard before buffering, one retry on network errors and never on a rate limit.
  5. Shaping. The response is reduced before serialisation. See Response shaping.
  6. Optional inference. Only if configured, only Pro and above, only ever additive.

Composition and partial failure

Some tools call several upstreams at once. vulnetix_threat_feed calls five and vulnetix_detection_rules up to three. They are issued concurrently, and a leg that fails degrades its own section instead of failing the tool:

"_meta": { "vulnetix/degraded": ["vendor-trends"] }

A five-way digest that fails whole because one upstream was slow would be useless, and silently dropping the section would be worse.

Limits you might hit

LimitValue
Upstream calls per tool12
Upstream timeout45 s
Response buffer guard3 MB
vdb_request default cap256 KB
raw detail refusalabove 512 KB

45 seconds is a generous timeout, but the API runs on AWS behind a CDN while the Worker runs at the edge, and a cold search against a large index can exceed 20 seconds. We found that out by having it fail.

Where the code is

Open source at github.com/Vulnetix/mcp-server, including the conformance suite, the differential tests that hold the shaping layer to the plugin’s original filters, and the smoke test that exercises every tool against the live API.