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
- Validation. Host and Origin against an allowlist (DNS-rebinding
protection, required by the transport spec);
POSTonly,GETandDELETEanswer405; JSON content type or415. - Credential extraction. The
Authorizationheader is parsed only far enough to recover the organisation UUID for cache keying, then forwarded unchanged. - Dispatch. A fresh server instance per request, built by a factory. Nothing carries over.
- 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.
- Shaping. The response is reduced before serialisation. See Response shaping.
- 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
| Limit | Value |
|---|---|
| Upstream calls per tool | 12 |
| Upstream timeout | 45 s |
| Response buffer guard | 3 MB |
vdb_request default cap | 256 KB |
raw detail refusal | above 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.