Files
computer-playbook/roles/web-app-baserow/meta/secrets.yml
kevinveenbirkenbach 0b9fe7861a feat(baserow): front the native MCP endpoint with the adapter
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.
2026-08-29 11:08:49 +02:00

18 lines
627 B
YAML

---
credentials:
secret_key:
description: Django SECRET_KEY for Baserow
algorithm: alphanumeric
validation:
min_length: 50
mcp_bearer:
description: Bearer an MCP client presents to the Baserow adapter sidecar. Distinct from the endpoint key the sidecar presents upstream, because reaching
Baserow says nothing about who called the adapter.
algorithm: alphanumeric
validation: "^[A-Za-z0-9]{32,}$"
length: 48
mcp_endpoint_key:
description: URL-path secret of the MCP endpoint, stored in MCPEndpoint.key (varchar 32)
algorithm: random_hex_16
validation: "^[a-f0-9]{32}$"