Repository navigation
Conversation
Move the MCP server from the OpenCode 1.x HTTP API to the 2.x `/api/*`
surface (tested against opencode 2.1.2).
- client: use @opencode-ai/sdk/v2/client, unwrap {data, location, cursor}
envelopes, derive SSE event names from the JSON `type`
- server-manager: probe GET /api/info with Basic auth, detect 1.x servers
and 401s, spawn `opencode serve` with a generated password for auto-serve
- tools/jobs: new session, prompt-inbox, forms, interrupt and model routes;
completion is read from the idle marker closing the turn
- remove tools without a 2.x equivalent (TUI, share/unshare, todo, init,
lsp/formatter/log, tool_*, find_symbol, instance_dispose): 87 -> 67 tools
- drop prompt-level structured output (`format`)
- fix: idle marker of the current turn, form option values, OAuth default
methodID, split startup lines, required command `text`, stable job scope
- port tests and docs to v2; add 4.0.0 changelog; fix smoke script
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks a lot @norandom! This is the direction the project needs, and it fixes #31. I'd like it to land first as the base for 4.0.0, with my #29 following on top.
Tests, docs check and a smoke run against OpenCode 2.2.0 all pass. A few things to fix before merging:
agentis dropped: 2.x prompts don't accept it, so usePOST /api/session/{id}/agentinstead (jobs.ts:392,workflow.ts:81,message.ts:124,203).- A job never finishes once its turn passes 100 messages. Page through with
cursor(jobs.ts:148,workflow.ts:101). - Send
delivery: "queue". The defaultsteermerges a second prompt into the running turn. - Cut the turn at the idle marker, not at the next user message (
jobs.ts:179). opencode_ask/opencode_replyreturn partial answers on a/waittimeout and swallow errors (workflow.ts:86-97).- Read pending inputs from
/api/session/{id}/formand/permission, not the location-scoped lists (jobs.ts:123).
Optional, and I'm happy to take these as follow-ups: directory scoping for session lists and events_poll, form answer types, the Windows spawn (shell on win32), and recording the server process right after spawn().
I'm resolving the conflicts with main on your branch now with a merge commit, so no force-push.
Brings in 3.1.0 (OpenChamber sign-in, OPENCODE_SERVER_TOKEN, sign-in cooldown, dependency floors) on top of the OpenCode 2.x port. Auth integration: - The v2 SDK client, the /api/event stream and the /api/info probe all go through AuthProvider (OpenChamber > bearer token > Basic). - isServerRunning/ensureServer take an explicit Authorization header. - Auto-serve: startup and reconnect call adoptServer(url, password), which switches to the spawned server's generated Basic password. - Job-store scope hashes the configured credentials (plus token and OpenChamber inputs), never the generated password. - OpenChamber tests now model OpenChamber 2.x passthrough at the origin.
- startServer takes the username, pins OPENCODE_SERVER_USERNAME in the child env and probes /api/info with it, so a custom username no longer fails the health check (ensureServer passes opts.username). - Move the startup ensureServer + adoptServer step into OpenCodeClient.connect() so it is covered by tests; index.ts calls it and keeps the configured URL in the job scope for existing servers. - Tests: username routing in the fake opencode, connect() auth/adoption.
|
Resolved the conflicts with main (3.1.0) in a merge commit on your branch, no force-push. Pull before you push again.
611 tests pass. The review items above are still yours, and I'm happy to help with any of them. |
…rns, wait timeouts, per-session inputs
- prompts: select the agent at session creation or via POST /api/session/{id}/agent
(2.x prompts silently drop an agent field) and send delivery:"queue" so a prompt
dispatched while a turn runs executes as its own turn instead of steering it
- observation: page session messages with the cursor envelope (getWithCursor), so a
job still finishes when its turn spans more than one page; cut the observed turn
at its idle marker instead of the next user message, so a steered follow-up no
longer truncates it and the merged turn's marker completes the original job
- opencode_ask/opencode_reply: a wait-endpoint deadline expiry is now reported as a
flagged timedOut partial answer (TIMEOUT note plus resumable session) and wait
failures surface instead of being swallowed as partial state
- pending inputs: read GET /api/session/{id}/form and /api/session/{id}/permission
instead of the location-scoped lists, which miss sessions in other directories
- request shapes verified against a live opencode 2.2.5 server (its /openapi.json
and the model-free smoke run); tests updated and extended, 618 passing
|
All six review items are addressed in 6bb8c73 (pushed on top of your merge — no force-push). While implementing them I stood up a local opencode 2.2.5 server and verified every request shape against its live endpoints and
Two notes from the live-server digging, no code change needed:
Tests: 618 passing (up from 611). Fixtures moved to the per-session input routes, cursor envelopes and The optional items (directory scoping for session lists and |
…nup crash - The direct-run guard compared import.meta.url against pathToFileURL(resolve(argv[1])); on Windows the two spellings diverge through drive junctions/substituted drives (ESM resolves module URLs to the real path), so the script exited 0 without running any checks. Compare real filesystem paths instead, case-insensitively on win32. Verified: `node scripts/mcp-smoke-test.mjs` now runs end-to-end against a live opencode 2.2.5 server (23/23 model-free checks). - Disposable-fixture cleanup crashed a passing run with an unhandled EBUSY. Root cause on Windows: the OpenCode server keeps a project-watcher handle on every directory the run touched, which blocks recursive deletion until that process exits (POSIX unlink is unaffected). Deletion now retries through transient handle lag (fs.rm maxRetries), and a persistent holder produces a warning naming the path instead of a crash; the exit code stays tied to the smoke results. Verified the fixture deletes cleanly the moment the server exits. - Tests: fixture lifecycle coverage in smoke-runner.test.ts; suite 619 passing.
|
Follow-up in f1741c4: the two Windows smoke-script flakes I flagged earlier are fixed after all.
Suite is at 619 passing (added fixture-lifecycle coverage); |
|
I think this should help, let me know if it's not sufficient please. |
Summary
Ports the MCP server from the OpenCode 1.x HTTP API to the 2.x
/api/*surface and bumps to 4.0.0. Tested against opencode 2.1.2.@opencode-ai/sdk/v2/client(^1.19.3), unwraps{data, location, cursor}envelopes, derives SSE event names from the JSONtypeon the single/api/eventstream.GET /api/infowith Basic auth, rejects 1.x servers with an upgrade message, reports 401s explicitly, and for auto-serve spawnsopencode servewith a generated private password.opencode_tui_*,session_share/unshare/todo/init,lsp_status,formatter_status,log,tool_ids/list,find_symbol,instance_dispose. Prompt-level structured output (format) is gone.opencode_message_send; finished older turns still reported as completed; form option labels mapped to values; OAuth authorize defaultsmethodID; startup line split across stdout reads;textalways sent for slash commands; job-store scope no longer includes the generated auto-serve password; emptyOPENCODE_SERVER_USERNAMEfalls back toopencode.docs/tools.md, 4.0.0 changelog and the smoke script are updated.Test plan
npm test: 585 passed, 2 skipped (17 files)npm run docs:checknode scripts/mcp-smoke-test.mjsagainst a live opencode 2.1.2 server (no model calls)/api/eventstream, 401 handling, auto-serve startup--inferencesmoke test and real prompts through the job path/api/experimental/*routes.Notes for reviewers
opencode, so a customOPENCODE_SERVER_USERNAMEwill get 401s.unknownwhen observed, and cancelling it does not remove the queued item (reported during test porting, not verified live).🤖 Generated with Claude Code