Protocol support
You do not need this to connect. It is here for anyone writing a client, or
staring at a -32602 and wanting to know what the server expects.
Revisions served
| Revision | Status |
|---|---|
| 2026-07-28 | Current. Stateless, per-request metadata. |
| 2025-11-25 and earlier | Served through the SDK’s stateless legacy path. |
Both work with no configuration on your side.
Most clients still default to the legacy era. The official client SDK’s
versionNegotiation.mode defaults to 'legacy', so an out-of-the-box client
opens at 2025-11-25, which is why the server answers both. Serving only
the current revision would lock out most clients in the field for no benefit.
Opt in with { versionNegotiation: { mode: 'auto' } } or pin
{ mode: { pin: '2026-07-28' } }.
The endpoint
POST https://mcp.vulnetix.com/mcp
POST only. GET and DELETE return 405, because revision 2026-07-28 removed the
standalone event stream and session teardown, so there is nothing for either to
do.
Required headers
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: vulnetix_vuln
Authorization: ApiKey <orgId>:<hex>
Mcp-Method and Mcp-Name mirror body fields into headers so intermediaries can
route and rate-limit without parsing the body. The server validates that they
match the body, and a mismatch is 400 with JSON-RPC -32020. That prevents a
load balancer routing on one value while the server executes another.
The _meta envelope
Every request carries version, client identity and capabilities in params._meta:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "vulnetix_vuln",
"arguments": { "identifier": "CVE-2021-44228" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "my-client", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
_meta returns -32602
(Invalid _meta envelope), not the -32022 you might expect. That trips
people writing a client by hand. The error names the missing key, so read it
before assuming the version is the problem.Error codes
| Code | HTTP | Meaning |
|---|---|---|
-32602 | 400 | Invalid _meta envelope: a key is missing or malformed |
-32020 | 400 | Header/body mismatch on Mcp-Name or Mcp-Method |
-32022 | 400 | Unsupported protocol version, with data.supported |
-32601 | 404 | Unknown method |
-32600 | 405 | Wrong HTTP method |
Tool failures are not in this table. A tool that cannot answer returns a
normal result with isError: true. That is the MCP contract, and it is why a
rate limit does not surface as a transport error. See
Errors.
Capabilities
server/discover advertises tools, prompts and resources, with cache hints
on the list operations.
The Tasks extension (io.modelcontextprotocol/tasks) is not advertised.
Tasks require durable status across polls, which is server-side state, which this
server does not have. Every tool answers within one exchange instead.
OAuth discovery
The server publishes RFC 9728 Protected Resource Metadata:
GET https://mcp.vulnetix.com/.well-known/oauth-protected-resource
{
"resource": "https://mcp.vulnetix.com/mcp",
"authorization_servers": [],
"bearer_methods_supported": ["header"],
"resource_name": "Vulnetix VDB"
}
authorization_servers is empty because authentication today is the API key,
not an OAuth flow. It is published anyway so that adding an authorization server
later is additive: every client already configured keeps working, with no
reconfiguration.
Verifying by hand
Verify your setup has copy-pasteable curl for each layer.