2026-08-20 10:04:16 +07:00
---
id : mcp-streamable-http
title : MCP Streamable HTTP Transport
type : documentation
tags :
- mcp
- protocol
- http
- infra
status : published
author : asep
created_at : 2026-08-20
updated_at : 2026-08-20
---
# MCP Streamable HTTP Transport
The MCPedia MCP server is served over **Streamable HTTP** (the MCP 2025-03-26
transport) so remote clients — Claude, a Discord bot, a web frontend — can call its
tools and read its resources without spawning a stdio subprocess.
## Why stateless
The server uses `StreamableHTTPServerTransport` in **stateless mode**
(`sessionIdGenerator: undefined` ):
- One `McpServer` + transport is created **per request** .
- No session affinity, no shared-transport `connect()` race, no session-map memory
leak under burst traffic.
2026-08-21 11:35:27 +07:00
- Re-registering tools and resources per request is negligible for a KB-sized
2026-08-20 10:04:16 +07:00
corpus.
Stateful mode (a `sessionIdGenerator` returning a UUID) would require holding a
transport map keyed by session id and cleaning it up on `onclose` . For this read-mostly
knowledge base, stateless is simpler and equally correct.
## Endpoint
```
POST https://mcp.asepharyana.my.id/mcp
Content-Type: application/json
Accept: application/json, text/event-stream
```
Responses use SSE framing (`event: message` / `data: {...}` ) even for unary results.
Clients must send `Accept: application/json, text/event-stream` or the server returns
406. The MCP `initialize` handshake sets `protocolVersion: "2025-03-26"` .
## CORS
`/mcp` returns permissive CORS headers (`Access-Control-Allow-Origin: *` ) so browser
clients can call it directly. Preflight `OPTIONS` is answered with 204.
## Auth for write tools
2026-08-21 11:35:27 +07:00
Read tools (`search_documents` , `get_document` , `semantic_search` , `hybrid_search` , `list_documents` , `get_related_documents` , `queue_status` ) are open. Write and mutating tools (`create_document` , `update_document` , `delete_document` , `index_document` , `reindex_all` , `restore_revision` ) require the `x-webhook-secret` header matching `WEBHOOK_SECRET` — the same shared secret used by the git-sync webhook. A missing or invalid header returns an authorization error before executing any mutation.