GET /capabilities¶
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=60
ETag: "3f7314e610ee311b51e46134b6c0f530"
Content-Type: application/json; charset=utf-8
{"capabilities":[]}
Which deployment switches are on, readable before sign-in. A client reads
it to decide whether to select GraphQL fields that exist only while a switch is
on. The rule behind it is
cor:api:020:01.
Request¶
| Path | /capabilities, on the server's base URL (https://srv.hadronmemory.com in production) |
| Methods | GET, and HEAD (answered from the same route with no body). Any other method gets the server's ordinary 404. |
| Authentication | None. A token, cookie or session sent with it is ignored. |
| Input | None. The query string, body and cookies are not read, and nothing is echoed back. |
Response¶
capabilities is an array of token words, one per switch that is on:
| Token | On when | What it adds |
|---|---|---|
node-signing |
The server runs with PASSKEY_SIGNING_ENABLED=true |
Node signing: the signing types (SigningRequest, NodeSignature and their enums), every field that returns one, and ServerInfo.signing |
passkey-registration |
Signing is on and PASSKEY_REGISTRATION_ENABLED=true |
Passkey registration: ServerInfo.passkeyRegistration |
- An off switch is absent, never
false. With nothing on, the answer is{"capabilities":[]}. There is no form that lists a switch as off. passkey-registrationnever appears withoutnode-signing. The server computes registration as signing on and registration on, so turning on registration alone leaves both off, and the answer stays[].- Test for a token, never for the array's length or exact contents. New words may be added.
The words are the same ones hadron_server_info prints on its capabilities:
line (see MCP tools: Server identity). Both are read from one function on the
server, so the two cannot disagree.
Headers¶
| Header | Value | Why |
|---|---|---|
Access-Control-Allow-Origin |
* |
Any origin can read it, without credentials. The route answers before the server's credentialed CORS policy, which only allows the portal's origin. |
Cache-Control |
public, max-age=60 |
Shared caches, the CDN included, may keep it for a minute. |
ETag |
A strong ETag of the body | If-None-Match with it gets 304 Not Modified and no body. |
The answer changes only when the server restarts with different switches, so the body and its ETag stay fixed for the life of the process.
Status codes¶
| Status | When |
|---|---|
200 |
The answer. |
304 |
If-None-Match matched the current ETag. |
404 |
A method other than GET or HEAD. |
429 |
More than 60 requests a minute from one client IP. The body is empty. |
Today the 429 carries no Retry-After and no RateLimit headers. It also
carries no Access-Control-Allow-Origin, so a browser reports it as a CORS
failure, not a 429. Adding both headers to the 429 is an open follow-up
(review note on hadron-server#1930).
Any failed read means every switch is off: a network error, a CORS
failure, a 429, or a body that isn't {"capabilities": [...]}.
Using it to pick GraphQL fields¶
A switch doesn't make a field return null or an error when it is off: it removes the field and its types from the schema. Selecting a removed field fails GraphQL validation, and the whole operation fails with it.
- Read
/capabilitiesonce, when the client starts or the page loads. - Select a switch-gated field only when its token is in the array:
ServerInfo.signingand anything that returns a signing type neednode-signing;ServerInfo.passkeyRegistrationneedspasskey-registration. - If the read fails in any way, select none of them.
There is no GraphQL capabilities field: this endpoint is the discovery path.
The GraphQL reference shows the schema production serves,
so a field behind a switch that is off in production is not listed there.
Related¶
- MCP tools: Server identity: the same tokens on the MCP surface, and the rule to test for a token, never a version.
- GraphQL API: the schema as production serves it.