Skip to content

feat(generator): direct tools cover every non-deprecated operation OAuth can call - #269

Open
mattzcarey wants to merge 1 commit into
feat/insufficient-scope-challengefrom
feat/direct-tools-oauth-coverage
Open

mattzcarey wants to merge 1 commit into
feat/insufficient-scope-challengefrom
feat/direct-tools-oauth-coverage

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Fourth of five stacked PRs, on #268.

?codemode=false followed the cf CLI's selection, which drops operations an MCP connection should have: GA endpoints tagged sdk-only (cron triggers, Workers account settings, assets upload) and everything marked x-fern-ignore. Direct tools now include every non-deprecated operation an OAuth connection can call: 2,903 → 3,125 tools.

Which operations OAuth can call. Forge has no OAuth marker, but OAuth scopes share API token permission names. An operation is in when any permission in its x-api-token-group has an OAuth scope (scripts/generator/oauth.ts).

Operations Why
Included hidden, sdk-only, x-fern-ignore an OAuth connection can call them
Included no x-api-token-group (e.g. GET /accounts) nothing rules them out
Excluded Billing, API Tokens, Account API Tokens, OAuth Client, SSO Connector permissions no OAuth scope exists
Excluded assets_jwt, pages_upload_token security need a special token
Excluded deprecated they duplicate their replacements' names. Code Mode still reaches them.
  • Stale labels: some Forge labels don't match the scope names (Browser Rendering Read → Browser Run Read, Artifacts Edit → Artifacts Write, Zone Zone Read → Zone Read, …). PERMISSION_ALIASES maps them. spec.json and each tool's permissions carry the canonical names, so fix(api): explain why Cloudflare refused a request #267's explanations and feat(auth): ask for a missing OAuth scope with a 403 insufficient_scope challenge #268's challenges find the scope.
  • Names: a collision keeps the cf command's name and gives the others a readable path-based name. A hash is only a last resort, and none is needed today. 45 names are longer than 64 characters.
  • Overlays: scripts/generator/overlays/mcp.overlay.json is an OpenAPI Overlay 1.0 of targeted fixes to Forge's document, applied before generation by a small applier (overlay.ts; no new dependency). A target that matches nothing fails the build, so a fix that Forge has absorbed gets removed rather than left stale. It starts with two schema bugs that real responses exposed:
    • iam_account_settings.abuse_contact_email → nullable (GET /accounts returns null)
    • iam_organization.id → plain string (GET /user returns "0", not a 32-character ID)

Note

Codex refuses any server with more than 2,048 tools (#262). ?codemode=false was already over that limit with the cf selection. Code Mode is unaffected.

Forge findings, including the label table: https://gist.github.com/mattzcarey/52b3e08c64a5b4101a3a02f24387665b

…uth can call; Forge fixes as overlays

The cf CLI's selection dropped GA operations tagged sdk-only (cron triggers,
Workers account settings, assets upload) and everything x-fern-ignore.
Direct tools now include every non-deprecated operation an OAuth connection
can call: OAuth scopes share permission names, with an alias table for
Forge's stale labels. spec.json and tool entries carry the canonical names,
so refusal explanations and scope challenges find the scope. Deprecated operations stay out: they duplicate their
replacements' names and Code Mode still reaches them. Name collisions keep
the cf command's name and give the others a readable path-based name.

scripts/generator/overlays holds an OpenAPI Overlay 1.0 of targeted fixes to
Forge's document, applied before generation; a stale target fails the build.
It starts with two schema bugs real responses exposed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant