Saphan StudioDocs
MCP server

The record of the surface itself

Path redaction, the access log, and what conformance actually drives.

Path redaction on the HTTP boundary

HTTP responses pass through a response-boundary choke point that replaces every absolute host root the projection could carry — the workspace root, each stream's worktree, each repo directory — with its workspace-relative form (roots outside the workspace tree become external-repo/<name>). Longest root first, so nesting cannot leak a prefix. The stdio transport is exempt by an explicit transport marker: the local operator keeps real absolute paths, because they are their paths. CLI↔MCP parity in conformance is asserted after applying this same normalization to the CLI side — the redaction is part of the contract, not a test convenience.

The access log

Apache combined format, one line per request, on every transport (stdio logs too, with - as the remote). Three properties matter:

  • Virtual paths. MCP is one POST /mcp on the wire; the log resolves each message to POST /mcp/initialize, POST /mcp/tools-list, POST /mcp/tools/<name> — the tool name is the resource, path-escaped so a hostile method name cannot forge a log line.
  • Honest status. A refusal that the MCP wire wraps in a 200 JSON-RPC envelope still logs as the 4xx its nature earns: notifications 202, parse/argument errors 400, unknown tool/method/slug 404, record-level refusals 409, oversized results 413, execution failures 500. Refusals are visible where an auditor looks.
  • No values. The request-line field carries the path only, never a query string — whatever a client appends there is exactly the kind of value that must not land in an audit file. Control bytes, quotes and backslashes are escaped so one request stays one line.

The log observes and never alters: responses are byte-identical with logging on, off, or absent, pinned by byte-equality tests.

Conformance coverage

Three of the engine's end-to-end conformance scenarios drive this surface on the real binary: the OAuth code flow (discovery → authorize → PKCE exchange → authenticated call), the bearer gate (seven cells: no token, malformed, expired, wrong audience, untrusted issuer, valid token, scope denial — the negative cells signed with the server's real AS key so exactly one claim is defective per cell and signature rejection cannot mask whether a validator ran), and projection parity (the eight CLI-backed tools, HTTP versus CLI, deep-equal after normalization; unknown tool and unknown slug refusals included — the three aggregates project no CLI verb, so they are not cells of that comparison).

On this page