Skip to content

Surface HTTP MCP bearer header for opencode on --foreground (part of #1120)#1141

Open
RhysSullivan wants to merge 1 commit into
mainfrom
fix/1120-opencode-mcp-bearer
Open

Surface HTTP MCP bearer header for opencode on --foreground (part of #1120)#1141
RhysSullivan wants to merge 1 commit into
mainfrom
fix/1120-opencode-mcp-bearer

Conversation

@RhysSullivan

Copy link
Copy Markdown
Owner

Part of #1120 (4 of 4). Independent of the other three.

Problem

The local /mcp endpoint is bearer-gated and exposes no OAuth discovery, so an external client that auto-detects OAuth (opencode) just chokes on a plain 401 with no way to find the token.

Fix

The --foreground ready output now prints the exact Authorization: Bearer header plus a copy-pasteable opencode.json block that pins oauth: false, so the client sends the header instead of probing for an authorization server.

Tests

Adds an e2e scenario (http-mcp-bearer) asserting /mcp works with the bearer header and 401s without it (lint 0/0, typecheck 41/41).

…round

The local /mcp endpoint is bearer-gated and exposes no OAuth discovery,
so an external client that auto-detects OAuth (opencode) just chokes on a
plain 401 with no way to find the token.

The --foreground ready output now prints the exact Authorization: Bearer
header plus a copy-pasteable opencode.json block that pins `oauth: false`
so the client sends the header instead of probing for an authorization
server.

Adds an e2e scenario (http-mcp-bearer) asserting /mcp works with the
bearer header and 401s without it.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 33edb90 Commit Preview URL

Branch Preview URL
Jun 26 2026, 05:39 AM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud 33edb90 Jun 26 2026, 05:40 AM

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare preview

Console https://executor-preview-pr-1141.executor-e2e.workers.dev
MCP https://executor-preview-pr-1141.executor-e2e.workers.dev/mcp
Deployed commit 33edb90

Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes.

@pkg-pr-new

pkg-pr-new Bot commented Jun 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@1141

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@1141

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@1141

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@1141

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@1141

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@1141

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@1141

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@1141

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@1141

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@1141

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@1141

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@1141

executor

npm i https://pkg.pr.new/executor@1141

commit: 33edb90

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown

Greptile Summary

This PR extends the --foreground startup output to surface the bearer token as a copy-pasteable Authorization header and a complete opencode.json snippet (with oauth: false), solving the discovery problem for clients that probe for OAuth on a plain 401. It also adds a new e2e/local/http-mcp-bearer scenario that confirms the HTTP MCP endpoint accepts the bearer and rejects unauthenticated connections.

  • apps/cli/src/main.ts: two new console.log lines after the existing MCP URL print, emitting the bearer header and a JSON.stringify'd opencode config block.
  • e2e/local/http-mcp-bearer.test.ts: new local e2e scenario that boots a real server, connects an MCP client over HTTP with and without the bearer, and asserts on the outcome; a code comment incorrectly claims the test also verifies the terminal output contains the opencode config block, but that assertion is absent from the body.

Confidence Score: 4/5

The change is safe to merge: it adds informational console output and a companion e2e test with no changes to the auth logic itself.

The functional change (printing the bearer header and opencode config at startup) is straightforward and correct. The e2e test exercises the right behaviors but its header comment misstates what it asserts, and both files contain prohibited em-dashes. These are minor quality issues, not regressions.

Both changed files have em-dash violations; e2e/local/http-mcp-bearer.test.ts additionally has a misleading comment about an assertion that does not exist.

Important Files Changed

Filename Overview
apps/cli/src/main.ts Adds bearer token and opencode.json block to --foreground console output; functionally correct but one code comment contains a prohibited em-dash.
e2e/local/http-mcp-bearer.test.ts New e2e scenario covering HTTP MCP bearer gating; correctly uses the local test infrastructure, but the header comment claims a terminal-output assertion that the test body does not implement, and contains a prohibited em-dash.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as executor web --foreground
    participant Console as Terminal Output
    participant Client as opencode / HTTP MCP client
    participant MCP as /mcp endpoint

    CLI->>Console: "Executor is ready."
    CLI->>Console: "Open: http://127.0.0.1:<port>/?_token=<token>"
    CLI->>Console: "MCP: http://127.0.0.1:<port>/mcp"
    CLI->>Console: "Header: Authorization: Bearer <token>"
    CLI->>Console: "opencode.json: {..., oauth: false}"

    Client->>MCP: POST /mcp (no Authorization header)
    MCP-->>Client: "401 Bearer realm=executor"

    Client->>MCP: POST /mcp (Authorization: Bearer token)
    MCP-->>Client: 200 + tools list
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as executor web --foreground
    participant Console as Terminal Output
    participant Client as opencode / HTTP MCP client
    participant MCP as /mcp endpoint

    CLI->>Console: "Executor is ready."
    CLI->>Console: "Open: http://127.0.0.1:<port>/?_token=<token>"
    CLI->>Console: "MCP: http://127.0.0.1:<port>/mcp"
    CLI->>Console: "Header: Authorization: Bearer <token>"
    CLI->>Console: "opencode.json: {..., oauth: false}"

    Client->>MCP: POST /mcp (no Authorization header)
    MCP-->>Client: "401 Bearer realm=executor"

    Client->>MCP: POST /mcp (Authorization: Bearer token)
    MCP-->>Client: 200 + tools list
Loading

Reviews (1): Last reviewed commit: "Fix #1120: surface the HTTP MCP bearer h..." | Re-trigger Greptile

Comment thread apps/cli/src/main.ts
// to discover the token (there is no OAuth server on the local app, so a
// client that tries OAuth auto-detection just errors). Surface the exact
// header — and a ready opencode block that pins `oauth: false` so it sends
// the header instead of probing for an authorization server.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Em-dash in code comment. AGENTS.md explicitly prohibits the character anywhere, including code comments: "Never use em-dashes anywhere: prose, docs, code comments, commit messages, or PRs. Use commas, colons, parentheses, or separate sentences instead." The same violation appears in e2e/local/http-mcp-bearer.test.ts line 1 (// Local-only — REPRO + guard). Replace both with a comma, colon, or parenthetical.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +1 to +14
// Local-only — REPRO + guard for "I've been running executor as stdio as get
// errors trying http one in opencode". The local app's HTTP `/mcp` endpoint is
// bearer-gated (hardened so loopback is not a free pass) and serves NO OAuth
// discovery. An external agent like opencode, pointed at the URL, tries MCP
// OAuth auto-detection, gets a plain `401 Bearer realm="executor"` with no
// resource-metadata to discover an authorization server from, and errors out.
//
// The HTTP transport itself is fine — it works the moment the bearer is supplied
// (opencode's remote MCP supports `headers` + `oauth: false`). This scenario
// proves exactly that: tools list over HTTP WITH the bearer, and the gate 401s
// WITHOUT it. It also asserts the `--foreground` ready output now prints a
// ready-to-paste opencode config (URL + bearer header + `oauth: false`) so a
// user does not have to reverse-engineer the gate.
import { expect } from "@effect/vitest";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Test comment overstates coverage. Line 13 says "It also asserts the --foreground ready output now prints a ready-to-paste opencode config (URL + bearer header + oauth: false)". The actual test body never checks the terminal snapshot for this output, so the assertion described in the comment does not exist. Per e2e/AGENTS.md, the test source is the review artifact; a reader should be able to trust comments as a spec. The withLocalServer helper does expose the full terminal text in snapshot, so the check is addable, but as written the comment is misleading.

Context Used: e2e/AGENTS.md (source)

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