mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 21:26:44 +00:00
The least-privilege half of the criterion could not hold as built. provision_mcp.py creates the endpoint owner's workspace through CoreHandler().create_workspace, which makes that account its ADMIN, and 2.3.3 knows only ADMIN and MEMBER - both write table data. There is no read-only workspace role to demote to, so mutating_tools_enabled: false bounded nothing while create_rows, update_rows and delete_rows sat in the served allowlist. The adapter's contract simply omits them: a client calling one is refused with DENY_UNKNOWN_TOOL. Omission is the mechanism, since passthrough.py refuses to load a contract that lists a mutating tool while mutations are off. The other ten stay recorded under upstream_serves so a version bump enabling one shows up as drift rather than as a silently wider surface. The transport was what reverted this twice. Baserow speaks classic HTTP+SSE, where a GET opens the response stream and the stream names a second URL for requests, while the adapter only ever spoke Streamable HTTP. adapter.upstream_transport selects sse.py and defaults to streamable_http, so no existing provider changes. The endpoint key stops being a client credential. Clients present credentials.mcp_bearer to the sidecar; the key reaches the sidecar as ADAPTER_UPSTREAM_PATH_KEY and is spliced in percent-encoded, so it never enters the rendered contract and a key carrying a separator cannot open a path of its own. Deploy is green: the probe reached list_databases over SSE, the served surface matched the contract, and the sidecar proved it reaches only its provider.
Design 🎨
This directory contains contributor guidance for code design and implementation. Its scope is architecture, service wiring, coding principles, exceptions, and the boundaries that shape maintainable changes.