feat(mcp): dir= on madt_api_call — the escape hatch can't escape the launch scope #87

Closed
opened 2026-07-15 14:39:33 +00:00 by hexajon · 1 comment
hexajon commented 2026-07-15 14:39:33 +00:00 (Migrated from codeberg.org)

Problem

madt_api_call is the escape hatch, but it cannot escape the MCP server's launch scope. Its input struct is method/endpoint/body/raw/jq/template/paginate only (internal/mcp/tools_api.go:20) and it resolves credentials via config.GetCredentials(ctx) against the server's launch environment (env vars → the launch checkout's git config → global). There is no dir=, unlike the git-plane tools (madt_commit, madt_finish, madt_worktrees, …).

Concrete case (2026-07-15): I was in an unauthed scratch checkout of madtea and needed one read against Codeberg - GET /user/gpg_keys as the identity configured in a correctly-authed local clone of madtea.

  • madt_api_callnot configured - run 'madtea auth login' first. Dead end on the MCP surface.
  • Only working path: shell out to the CLI from inside the authed clone (cd <authed-clone> && madtea api /user/gpg_keys) - exactly what the server instructions tell agents NOT to do, and what the CLI-steering hook (ADR 0009) blocks in stricter setups.

The same dead end then forced the whole follow-up (issue search, view, comment) through the CLI too — one missing param turned an MCP session into a shell session.

Why owner_repo= can never substitute here

The passthrough hits endpoints with no repo scope at all (/user/gpg_keys, /user/keys, /orgs/..., /admin/...). dir= on madt_api_call is purely a credential/forge-resolution selector — "call forge X as the identity configured in clone Y" — not a repo scoper. That also makes it a clean data point for the #62 matrix: a remote-API tool whose correct scope is dir=, not RepoScope.

Ask

Add dir= to madt_api_call: resolve base URL + token from that clone's credential scope (the ADR 0025 config.GetConfigForDir machinery the git plane already uses), falling back to today's launch-scope resolution when omitted.

Notes:

  • No tree-write surface is involved, so the foreign-primary refusal does not apply — dir= here reads config only. Document that distinction on the param.
  • The CLI sibling (madtea api) already gets this for free by being run from the target dir; MCP parity is the whole point.

Acceptance

  • madt_api_call dir=/path/to/clone endpoint=/user/gpg_keys succeeds from a session whose launch checkout is unauthed or bound to a different forge, using the clone's forge + token.
  • Omitted dir= behaves exactly as today.
  • Param doc states dir= is credential/forge resolution, not repo scoping, and does not imply any local-tree access.

Refs #59 (typed API tools dir= targeting — this is the passthrough sibling; see also the 2026-07-15 comment there), #62 (DirScope matrix: classify api_call as dir=-scoped).

## Problem `madt_api_call` is the escape hatch, but it cannot escape the MCP server's launch scope. Its input struct is method/endpoint/body/raw/jq/template/paginate only (internal/mcp/tools_api.go:20) and it resolves credentials via `config.GetCredentials(ctx)` against the server's launch environment (env vars → the launch checkout's git config → global). There is no `dir=`, unlike the git-plane tools (`madt_commit`, `madt_finish`, `madt_worktrees`, …). Concrete case (2026-07-15): I was in an **unauthed scratch checkout** of madtea and needed one read against Codeberg - `GET /user/gpg_keys` as the identity configured in a correctly-authed local clone of madtea. - `madt_api_call` → `not configured - run 'madtea auth login' first`. Dead end on the MCP surface. - Only working path: shell out to the CLI from inside the authed clone (`cd <authed-clone> && madtea api /user/gpg_keys`) - exactly what the server instructions tell agents NOT to do, and what the CLI-steering hook (ADR 0009) blocks in stricter setups. The same dead end then forced the whole follow-up (issue search, view, comment) through the CLI too — one missing param turned an MCP session into a shell session. ## Why `owner_repo=` can never substitute here The passthrough hits endpoints with **no repo scope at all** (`/user/gpg_keys`, `/user/keys`, `/orgs/...`, `/admin/...`). `dir=` on `madt_api_call` is purely a **credential/forge-resolution selector** — "call forge X as the identity configured in clone Y" — not a repo scoper. That also makes it a clean data point for the #62 matrix: a remote-API tool whose correct scope is `dir=`, not `RepoScope`. ## Ask Add `dir=` to `madt_api_call`: resolve base URL + token from that clone's credential scope (the ADR 0025 `config.GetConfigForDir` machinery the git plane already uses), falling back to today's launch-scope resolution when omitted. Notes: - No tree-write surface is involved, so the foreign-primary refusal does not apply — `dir=` here reads config only. Document that distinction on the param. - The CLI sibling (`madtea api`) already gets this for free by being run from the target dir; MCP parity is the whole point. ## Acceptance - `madt_api_call dir=/path/to/clone endpoint=/user/gpg_keys` succeeds from a session whose launch checkout is unauthed or bound to a different forge, using the clone's forge + token. - Omitted `dir=` behaves exactly as today. - Param doc states dir= is credential/forge resolution, not repo scoping, and does not imply any local-tree access. Refs #59 (typed API tools dir= targeting — this is the passthrough sibling; see also the 2026-07-15 comment there), #62 (DirScope matrix: classify api_call as dir=-scoped).
hexajon commented 2026-07-15 14:46:53 +00:00 (Migrated from codeberg.org)

Won't-do — inverted by maintainer ruling the same day (2026-07-15): an agent must be PREVENTED from crossing outside the launch pwd and using auth tokens it finds in other checkouts, so dir=-as-credential-selector on the passthrough is an anti-goal, not a feature. The underlying need (unauthed session can't reach the forge) is now tracked by the sanctioned remedies instead: #88 (loud connect-time warning) and #89 (in-MCP OAuth login for the launch scope). The boundary this ruling defines is enforced via #90.

Won't-do — inverted by maintainer ruling the same day (2026-07-15): an agent must be PREVENTED from crossing outside the launch pwd and using auth tokens it finds in other checkouts, so dir=-as-credential-selector on the passthrough is an anti-goal, not a feature. The underlying need (unauthed session can't reach the forge) is now tracked by the sanctioned remedies instead: #88 (loud connect-time warning) and #89 (in-MCP OAuth login for the launch scope). The boundary this ruling defines is enforced via #90.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#87
No description provided.