MCP — MDDB API
Model Context Protocol 2026-07-28 and 2025-11-25 served side by side — Streamable HTTP transport, tools, resources, prompts, completion, logging, discovery
List MCP API keys #
GET /v1/mcp/keys
Lists the registered MCP API keys. No key material is returned: each
entry carries a fingerprint (four bytes of SHA-256, hex) that also
identifies the key in the server log, while keyPrefix holds only the
mcp_ scheme marker.
Requires admin authentication.
Authorization: BearerAuth
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Key list | object (application/json) |
403 |
Admin permission required | |
503 |
MCP API key store not initialized |
Create MCP API key #
POST /v1/mcp/keys
Creates a named API key for MCP clients. The full key is returned once, in this response only — the listing exposes a fingerprint rather than key material, so it cannot be recovered afterwards.
Requires admin authentication.
Authorization: BearerAuth
Request body #
Required.
Content type application/json: object
| Property | Type | Description |
|---|---|---|
name (required) |
string |
Label identifying what the key is for. |
expiresAt |
integer (int64) |
Unix timestamp; omit or 0 for a key that never expires. |
toolsets |
array of string |
MCP toolsets the key may list and call (MCP-003, v2.18.8); omit for every toolset the server exposes. A call outside them is answered with JSON-RPC -32601. An unknown name is a 400. |
{
"expiresAt": 0,
"name": "claude-desktop",
"toolsets": [
"search",
"code"
]
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Key created (plaintext returned once) | object (application/json) |
400 |
Invalid request body, key name or toolset | |
403 |
Admin permission required | |
503 |
MCP API key store not initialized |
Delete MCP API key #
DELETE /v1/mcp/keys
Permanently removes a key, identified by its full value. The MCP auth cache is invalidated, so the key stops working immediately.
Requires admin authentication.
Authorization: BearerAuth
Request body #
Required.
Content type application/json: MCPAPIKeyRef
{
"key": "mcp_4f3c2a1b8e7d6c5b4a39281706f5e4d3"
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Key deleted | object (application/json) |
400 |
Invalid request body | |
403 |
Admin permission required | |
404 |
No such key | |
503 |
MCP API key store not initialized |
Disable MCP API key #
POST /v1/mcp/keys/disable
Marks a key disabled without deleting it, so it stops authenticating but stays visible in the listing.
Requires admin authentication.
Authorization: BearerAuth
Request body #
Required.
Content type application/json: MCPAPIKeyRef
{
"key": "mcp_4f3c2a1b8e7d6c5b4a39281706f5e4d3"
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Key disabled | object (application/json) |
400 |
Invalid request body | |
403 |
Admin permission required | |
404 |
No such key | |
503 |
MCP API key store not initialized |
(v2.18.1+) OAuth protected-resource metadata, RFC 9728 (MCP listener) #
GET /.well-known/oauth-protected-resource
Served on the MCP listener when MDDB_MCP_OAUTH_ENABLED=true (#322).
Authorization: none
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Resource metadata | application/json |
404 |
OAuth is off (MDDB_MCP_OAUTH_ENABLED is not true): the path is not served | ErrorResponse (application/json) |
200 example (application/json)
{
"authorization_servers": [
"https://mcp.example.com"
],
"bearer_methods_supported": [
"header"
],
"resource": "https://mcp.example.com/mcp"
}
(v2.18.1+) OAuth authorization-server metadata, RFC 8414 (MCP listener) #
GET /.well-known/oauth-authorization-server
Authorization: none
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Server metadata | application/json |
404 |
OAuth is off (MDDB_MCP_OAUTH_ENABLED is not true): the path is not served | ErrorResponse (application/json) |
200 example (application/json)
{
"authorization_endpoint": "https://mcp.example.com/oauth/authorize",
"code_challenge_methods_supported": [
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"issuer": "https://mcp.example.com",
"registration_endpoint": "https://mcp.example.com/oauth/register",
"response_types_supported": [
"code"
],
"token_endpoint": "https://mcp.example.com/oauth/token",
"token_endpoint_auth_methods_supported": [
"none"
]
}
(v2.18.1+) Dynamic client registration, RFC 7591 (MCP listener) #
POST /oauth/register
Authorization: none
Request body #
Required.
Content type application/json: object
| Property | Type | Description |
|---|---|---|
redirect_uris (required) |
array of string |
Each must be in MDDB_MCP_OAUTH_REDIRECT_URIS or an http loopback URI. |
client_name |
string |
At most 200 characters. |
{
"client_name": "string",
"redirect_uris": [
"string"
]
}
Responses #
| Status | Description | Body |
|---|---|---|
201 |
Registered; client_id is the sealed registration, nothing is stored | |
400 |
invalid_client_metadata or invalid_redirect_uri |
(v2.18.1+) Authorization endpoint — consent page (MCP listener) #
GET /oauth/authorize
Authorization code with PKCE (S256 only). Renders a page asking for an MCP API key; POSTing it redirects to redirect_uri with code, state and iss.
Authorization: none
Parameters #
| Name | In | Type | Description |
|---|---|---|---|
response_type (required) |
query | string |
One of "code". |
client_id (required) |
query | string |
|
redirect_uri (required) |
query | string |
|
code_challenge (required) |
query | string |
|
code_challenge_method (required) |
query | string |
One of "S256". |
state |
query | string |
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Consent page (text/html) | |
302 |
Redirect to the client with an error | |
400 |
Unknown client or redirect URI |
(v2.18.1+) Token endpoint (MCP listener) #
POST /oauth/token
Authorization: none
Request body #
Required.
Content type application/x-www-form-urlencoded: object
| Property | Type | Description |
|---|---|---|
grant_type (required) |
string |
One of "authorization_code", "refresh_token". |
client_id (required) |
string |
|
code |
string |
|
redirect_uri |
string |
|
code_verifier |
string |
|
refresh_token |
string |
{
"client_id": "string",
"code": "string",
"code_verifier": "string",
"grant_type": "authorization_code",
"redirect_uri": "string",
"refresh_token": "string"
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Tokens. The access token stands for the MCP API key entered on the consent page. | application/json |
400 |
invalid_grant or unsupported_grant_type | |
401 |
invalid_client |
200 example (application/json)
{
"access_token": "mddb_oat_...",
"expires_in": 3600,
"refresh_token": "mddb_ort_...",
"token_type": "Bearer"
}
MCP SSE stream for server-initiated messages (handshake clients) #
GET /mcp
Open an SSE stream for receiving server-initiated messages (notifications, progress). Requires MCP-Session-Id header from a previous initialize call. Belongs to 2025-11-25 only: 2026-07-28 removed the standalone stream in favour of subscriptions/listen, which answers on the POST that opened it.
Authorization: BearerAuth or APIKeyAuth or none
Parameters #
| Name | In | Type | Description |
|---|---|---|---|
MCP-Session-Id (required) |
header | string |
Responses #
| Status | Description | Body |
|---|---|---|
200 |
SSE event stream | string (text/event-stream) |
400 |
No MCP-Session-Id, or MCP-Protocol-Version names a revision this server does not serve | ErrorResponse (application/json) |
401 |
The MCP listener wants credentials: MDDB_MCP_API_KEY_ENABLED=true and no key (JSON-RPC -32001), OAuth on and no valid access token (JSON-RPC -32001 and a WWW-Authenticate header naming the resource metadata), or MDDB_AUTH_ENABLED=true guarding the listener ({"error": ...}). | oneOf JSONRPCError | ErrorResponse (application/json) |
403 |
The MCP API key is unknown or disabled (JSON-RPC -32001). | JSONRPCError (application/json) |
429 |
Over the MCP listener's rate limit (JSON-RPC -32429); retry after Retry-After seconds. | JSONRPCError (application/json) |
MCP Streamable HTTP endpoint (2026-07-28 + 2025-11-25) #
POST /mcp
Streamable HTTP transport for both MCP revisions. Which one serves a request is
decided per request: one carrying io.modelcontextprotocol/protocolVersion in
params._meta is served statelessly under 2026-07-28, one without it under
2025-11-25.
Stateless (2026-07-28): server/discover, tools/list, tools/call, resources/list, resources/templates/list, resources/read, prompts/list, prompts/get, completion/complete, subscriptions/listen. Requires the MCP-Protocol-Version, Mcp-Method and (where a name or URI is addressed) Mcp-Name headers, which must match the body — a disagreement is 400 with JSON-RPC error -32020. No session is minted. An unimplemented method is 404 with a JSON-RPC -32601 body.
Handshake (2025-11-25): initialize, tools/list, tools/call, resources/list, resources/templates/list, resources/read, prompts/list, prompts/get, completion/complete, logging/setLevel, ping, with session management via the MCP-Session-Id header.
Notifications (no id) return 202 Accepted. Available on MCP port (default 9000). See docs/MCP-REVISIONS.md.
Authorization: BearerAuth or APIKeyAuth or none
Parameters #
| Name | In | Type | Description |
|---|---|---|---|
MCP-Session-Id |
header | string |
Session identifier (assigned by the server at initialize). Handshake clients only; ignored, and never echoed, for a stateless request. |
MCP-Protocol-Version |
header | string |
The revision this request is written in. Required for 2026-07-28, where it must equal params._meta['io.modelcontextprotocol/protocolVersion']; optional for 2025-11-25. |
Mcp-Method |
header | string |
Mirrors the body's method. Required on every 2026-07-28 request so an intermediary can route without parsing the body. |
Mcp-Name |
header | string |
Mirrors params.name (tools/call, prompts/get) or params.uri (resources/read). Required on those methods for 2026-07-28. A value outside plain ASCII is carried as =?base64? |
Request body #
Required.
Content type application/json: object
| Property | Type | Description |
|---|---|---|
jsonrpc |
string |
|
id |
integer |
|
method |
string |
|
params |
object |
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/list"
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
JSON-RPC response | object (application/json) |
202 |
Notification accepted (no response body) | |
400 |
Malformed or unservable request. The JSON-RPC body names which: -32020 (headers disagree with the body), -32022 (revision not served, with data.supported listing what is), or -32602 (a required _meta field is missing). | object (application/json) |
404 |
Method not implemented, with a JSON-RPC -32601 body. The body is what distinguishes this from a 404 at a URL hosting no MCP endpoint. | object (application/json) |
Terminate MCP session #
DELETE /mcp
Close an active MCP Streamable HTTP session.
Authorization: BearerAuth or APIKeyAuth or none
Parameters #
| Name | In | Type | Description |
|---|---|---|---|
MCP-Session-Id (required) |
header | string |
Responses #
| Status | Description | Body |
|---|---|---|
204 |
Session terminated | |
400 |
MCP-Protocol-Version names a revision this server does not serve | ErrorResponse (application/json) |
401 |
The MCP listener wants credentials: MDDB_MCP_API_KEY_ENABLED=true and no key (JSON-RPC -32001), OAuth on and no valid access token (JSON-RPC -32001 and a WWW-Authenticate header naming the resource metadata), or MDDB_AUTH_ENABLED=true guarding the listener ({"error": ...}). | oneOf JSONRPCError | ErrorResponse (application/json) |
403 |
The MCP API key is unknown or disabled (JSON-RPC -32001). | JSONRPCError (application/json) |
429 |
Over the MCP listener's rate limit (JSON-RPC -32429); retry after Retry-After seconds. | JSONRPCError (application/json) |