#!/usr/bin/env node /** * Conarium remote entrypoint — Streamable HTTP MCP (claude.ai / mobile / any remote client). * * Security model: * - CONARIUM_MCP_TOKEN (>=24 chars) is REQUIRED; server refuses to boot without it (fail-closed). * - Token is accepted either as capability URL (/t//mcp — claude.ai custom connector UI * has no header field) or as Authorization: Bearer . Comparison is timing-safe. * - Bind 127.0.0.1 by default: TLS termination is a reverse proxy's job (Caddy/Let's Encrypt). * - Same governance/audit pipeline as stdio mode — allowlist, deny, mask, row caps unchanged. * - CONARIUM_MCP_RATE_PER_MIN caps requests per client per minute (0 = off). Public demo * deployments hand the URL to strangers and must set it. * * Session model: canonical SDK pattern — an initialize POST opens a session (own Server+transport), * subsequent requests route by Mcp-Session-Id header; DELETE closes the session. * * A session is bound to the credential that OPENED it. Carrying a valid token is not * enough to speak into an existing session — it must be the SAME token. Without that * binding, anyone holding any valid token could take over a session opened with a * per-user credential by presenting its session id, and every receipt written from * that point on would name the wrong person. The session id travels in a plain header * and lands in proxy logs, so it is routing information, not a secret, and must never * be the only thing standing between two identities. */ import { type IncomingMessage, type ServerResponse } from 'node:http'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { bootDeps } from './server.js'; import { RateLimiter } from './rate_limit.js'; import { loadTokenStore } from './tokens.js'; export declare function currentTokenStore(): ReturnType; /** Session owner = hash of the credential that opened it. The raw token is never stored. */ export declare function ownerKey(supplied: string): Buffer; /** Constant-time comparison — both sides are sha256, lengths are equal. */ export declare function sessionOwnerMatches(owner: Buffer, supplied: string): boolean; /** * Transport + the identity that opened it. We keep the identity WITH the * transport because `buildServer(deps, kisi)` is called once per session: * every request after that runs under that Server's identity and writes * the receipt under that name. */ export interface SessionEntry { transport: StreamableHTTPServerTransport; owner: Buffer; lastActive?: number; } export interface HttpHandlerOpts { now?: () => number; idleMs?: number; maxSessions?: number; } export declare function resolveSessionIdleMs(): number; export declare function resolveMaxSessions(): number; export declare function createHandler(deps: Awaited>, transports: Map, limiter: RateLimiter, opts?: HttpHandlerOpts): (req: IncomingMessage, res: ServerResponse) => Promise; //# sourceMappingURL=http.d.ts.map