20  MCP

9 operations.

20.0.1 getMcpStream

GET /api/mcp

The server→client stream slot; not offered in this stateless phase (answers 405).

Why it exists. † Report what the assistant surface offers, so a connecting client can discover the available tools before calling any.

The Streamable-HTTP server→client channel. This stateless phase offers no server-initiated stream, so it always answers 405 (or 404 when disabled) and reads nothing — hence public.

Authentication: none

Returns — not readable from the source: the handler returns a value assembled at run time rather than a literal.

Responses

Status Meaning Body
404 The MCP server is disabled.
405 No server-initiated stream is offered.

20.0.2 sendMcpMessage

POST /api/mcp

The remote Model Context Protocol endpoint for external AI clients (e.g. Claude). Speaks JSON-RPC (initialize, list/call tools) and exposes a curated tool surface plus three spec-driven ones (kap_api_list, kap_api_show, kap_api_call) that discover and call any read in this specification; writes stay curated, and each tool runs as the signed-in user under RLS. Every payload it forwards is scrubbed of secret-keyed values (credentials, account keys, tokens) on the way out, because a tool returns whatever shape its handler returns. Off unless MCP_SERVER_ENABLED. See docs/proposals/20260816_remote_mcp_server.md.

Why it exists. † Serve the platform’s read surface to an external AI assistant over the Model Context Protocol, as the signed-in engineer — one identity, the caller’s own permissions, and the same access rules the browser gets.

Model Context Protocol server exposing a curated read surface as tools (see docs/proposals/20260816_remote_mcp_server.md). Accepts JSON-RPC 2.0 messages — initialize, tools/list, tools/call, ping. Disabled unless MCP_SERVER_ENABLED. Auth reuses the Supabase bearer via requireUser; each tool forwards that token to the corresponding backend operation, so it runs as the caller under RLS.

Authentication: SupabaseAuth

Returns — not readable from the source: the handler returns a value assembled at run time rather than a literal.

Responses

Status Meaning Body
200 A JSON-RPC 2.0 response.
202 Accepted — a notification, no reply.
400 Malformed JSON.
401 Missing or invalid bearer token.
404 The MCP server is disabled.

20.0.3 getMcpFindByContentEmbed

GET /api/mcp/embed/find-by-content

Renders a drop zone where the engineer can put a picture and see which of a dataset’s photographs it is (the target of the kap_find_image_by_content MCP UI resource). Gated by a short-lived sealed t token that carries the user’s bearer server-side. Off unless MCP_SERVER_ENABLED.

Renders a self-contained HTML page with a drop zone for one picture, for a host to load in a sandboxed iframe (the target of the kap_find_image_by_content tool’s UI resource when it is called without an image_url). The page posts the picture back to this same URL, which forwards it to searchImagesByContent as the user. Authenticated by a short-lived sealed t token that carries the user’s bearer server-side (never exposed to the page). Framing is allowed on purpose. Off unless MCP_SERVER_ENABLED.

Authentication: none

Parameters

Name In Required Type Notes
t query yes string

Responses

Status Meaning Body
200 The drop-zone HTML page.
400 The embed token is invalid or expired.
404 The MCP server is disabled.

20.0.4 searchImagesByContentEmbed

POST /api/mcp/embed/find-by-content

The drop-zone page’s search call: forwards the posted picture to searchImagesByContent for the token’s dataset, as the user the token was sealed for, and returns that operation’s answer.

Called by the find-by-content embed page. Opens the sealed t token server-side, forwards the body to POST /datasets/{slug}/find-by-content (searchImagesByContent) for the token’s dataset with the user’s bearer, and returns the answer and status as they are. Off unless MCP_SERVER_ENABLED.

Authentication: none

Parameters

Name In Required Type Notes
t query yes string

Request body

Field Type Required
image string yes
max_distance integer, nullable no
limit integer no

Responses

Status Meaning Body
200 searchImagesByContent’s answer.
400 The embed token is invalid or expired, or the body is not a picture.
404 The MCP server is disabled.

20.0.5 getMcpGalleryEmbed

GET /api/mcp/embed/gallery

Renders a dataset’s image gallery as a self-contained HTML page for a host to embed in a sandboxed iframe (the target of the kap_gallery_ui(hosted:true) MCP UI resource). Gated by a short-lived sealed t token that carries the user’s bearer server-side; images are fetched under RLS. Off unless MCP_SERVER_ENABLED.

Why it exists. † Render a gallery of images for an assistant that can display a web page, so photographs appear inline in the conversation rather than as links.

Renders a dataset’s image gallery as a self-contained HTML page for a host to load in a sandboxed iframe (the target of the kap_gallery_ui(hosted:true) mode’s UI resource). Authenticated by a short-lived sealed t token that carries the user’s bearer server-side (never exposed to the client); the images are fetched under RLS. Framing is allowed on purpose. Off unless MCP_SERVER_ENABLED.

Authentication: none

Parameters

Name In Required Type Notes
t query yes string

Responses

Status Meaning Body
200 The gallery HTML page.
400 The embed token is invalid or expired.
404 The MCP server is disabled.
502 The dataset’s images could not be loaded.

20.0.6 getMcpAuthorization

GET /api/mcp/oauth/authorize

OAuth 2.1 authorization (PKCE). Authenticates via the existing Supabase session; when signed in it renders a consent page naming the client (no code issued here), and bounces to /login when not.

Why it exists. † Show the engineer what an assistant is asking to reach and let them approve or refuse it, so access is granted by a person rather than assumed from a session.

Authenticates the user via their existing KAP Supabase session. When signed in, renders a consent page naming the client (no code is issued here); when not signed in, redirects to /login. Public entry point; it performs its own session handling and never 401s. Off unless MCP_SERVER_ENABLED.

Authentication: none

Returns — not readable from the source: the handler returns a value assembled at run time rather than a literal.

Parameters

Name In Required Type Notes
client_id query no string
redirect_uri query no string
state query no string
response_type query no string
code_challenge query no string
code_challenge_method query no string

Responses

Status Meaning Body
200 The consent page (HTML) shown to a signed-in user.
303 Redirect to /login, or back to the client on a protocol error.
400 Invalid client_id or redirect_uri.
404 The MCP server is disabled.

20.0.7 decideMcpAuthorization

POST /api/mcp/oauth/authorize

The consent decision. Only an explicit approval carrying a signed, session-bound consent token issues a code — this is what prevents silent code issuance to an arbitrary registered client. Denial/forgery returns access_denied or 400.

Why it exists. † Record the engineer’s explicit approval and issue the one-time code the assistant exchanges for access — the step that stops a registered client obtaining access silently.

Receives the consent form. On an explicit approval carrying a signed, session-bound consent token, seals the Supabase session into an authorization code and redirects back to the client; on denial or a missing/forged token, redirects back with access_denied (or 400). This step is what prevents silent code issuance to an arbitrary registered client. Off unless MCP_SERVER_ENABLED.

Authentication: none

Returns — not readable from the source: the handler returns a value assembled at run time rather than a literal.

Responses

Status Meaning Body
303 Redirect back to the client with a code or an error. 303 rather than 307, so the consent POST is never replayed onto the client callback.
400 Invalid request or consent token.
404 The MCP server is disabled.

20.0.8 createMcpClient

POST /api/mcp/oauth/register

Dynamic client registration (RFC 7591). The client’s metadata is HMAC-signed into a stateless client_id; redirect_uris must be absolute http(s) URLs. Public clients (PKCE, no secret). Off unless MCP_SERVER_ENABLED.

Why it exists. † Let an assistant register itself as a client without an administrator provisioning it in advance, keeping its details signed into the identifier rather than stored.

Registers a public OAuth client for the MCP connector. The client’s metadata is HMAC-signed into the returned client_id (stateless, no store). Off unless MCP_SERVER_ENABLED.

Authentication: none

Returns — client_id · client_id_issued_at · redirect_uris · token_endpoint_auth_method · grant_types · response_types

Field names as the handler returns them; the source states no types for them.

Request body

Field Type Required
redirect_uris array of string no
client_name string, nullable no

Responses

Status Meaning Body
201 The registered client.
400 Invalid client metadata.
404 The MCP server is disabled.

20.0.9 createMcpToken

POST /api/mcp/oauth/token

Exchanges a PKCE authorization code (or a refresh token) for the user’s Supabase access token, returned as the OAuth access token so the resource server verifies it with the existing requireUser.

Why it exists. † Exchange an approved code for the caller’s own access token, so the assistant acts as the engineer and never holds a credential of its own.

Exchanges an authorization code (PKCE) or a refresh token for the user’s Supabase access token, returned as the OAuth access token so the resource server verifies it with the existing requireUser. Off unless MCP_SERVER_ENABLED.

Authentication: none

Returns — access_token · token_type · expires_in · refresh_token · scope

Field names as the handler returns them; the source states no types for them.

Request body

Field Type Required
grant_type string no
code string no
code_verifier string no
client_id string no
redirect_uri string no
refresh_token string no

Responses

Status Meaning Body
200 The token response (access_token = Supabase JWT).
400 invalid_grant or unsupported_grant_type.
404 The MCP server is disabled.