diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1d7c1..789df3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,20 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.1.0] - 2026-10-29 + +This release supports OpenCode 1.x only and was tested with OpenCode 1.19.3. OpenCode 2.x servers are not supported in 3.x; support is planned for 4.0. + ### Added -- Bearer-token authentication with `OPENCODE_SERVER_TOKEN`. +- Bearer-token authentication with `OPENCODE_SERVER_TOKEN`. When set, it replaces Basic auth; `OPENCODE_OPENCHAMBER_PASSWORD` takes precedence over it. - OpenChamber sign-in with `OPENCODE_OPENCHAMBER_PASSWORD` (and optional `OPENCODE_OPENCHAMBER_URL`): exchanges the UI password for a client token, keeps it in memory, and renews it once on 401. Applies to API requests, event streams and the health probe. Each process gets a distinct client identifier by default (override with `OPENCODE_OPENCHAMBER_CLIENT_ID`), so independent MCP instances on the same host do not replace each other's token. ### Fixed -- Event streams (`opencode_events_poll`) preserved the `OPENCODE_BASE_URL` path prefix (e.g. OpenChamber's `/api` proxy) instead of resolving against the origin alone. +- Event streams (`opencode_events_poll`) now keep the `OPENCODE_BASE_URL` path prefix (e.g. OpenChamber's `/api` proxy). Previously they resolved against the origin and dropped it. - The smoke-test runner now forwards `OPENCODE_SERVER_TOKEN`, `OPENCODE_OPENCHAMBER_PASSWORD`, `OPENCODE_OPENCHAMBER_URL` and `OPENCODE_OPENCHAMBER_CLIENT_ID` to the smoke child. - A refused OpenChamber sign-in is no longer retried on every tool call, where it could reach OpenChamber's failure limit and lock out the UI. A rejected password is reported until restart. A rate limit waits for `Retry-After`. Other refusals wait 60 seconds. Network errors and 5xx responses are still retried. The same applies when OpenChamber accepts the password but issues no client token. ### Security -- Raise the minimum versions of `@modelcontextprotocol/core` and `@modelcontextprotocol/server` to 2.4.0 and of `zod` to 4.6.6. These address the published high-severity advisories GHSA-jm63-cq47-j5jp, GHSA-46jr-4wx8-v453, GHSA-f897-62hf-6gxq and GHSA-mrhx-c7xc-m3w5, and the medium-severity GHSA-rvq5-wwqv-78pq. `core` follows the exact version that `server` 2.4.0 pins. Development dependencies are updated too; `npm audit` reports no advisories. +- Raise the minimum versions of `@modelcontextprotocol/core` and `@modelcontextprotocol/server` to 2.4.0 and of `zod` to 4.6.6. These address the published high-severity advisories GHSA-jm63-cq47-j5jp, GHSA-46jr-4wx8-v453, GHSA-f897-62hf-6gxq and GHSA-mrhx-c7xc-m3w5, and the medium-severity GHSA-rvq5-wwqv-78pq. `core` follows the exact version that `server` 2.4.0 pins. opencode-mcp uses stdio only, so the HTTP-transport advisories did not affect it; the new floors keep installs clear of them. Development dependencies are updated too; `npm audit` reports no advisories. ### Documentation diff --git a/README.md b/README.md index abc6309..711851c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ opencode-mcp connects Claude, Cursor, VS Code, and other MCP clients to OpenCode's headless API. Ask questions, implement features, monitor background work, respond to questions and permissions, and review changes across projects. -> Version 3.0.0 requires **Node.js 22 or newer**. Upgrading from 2.x? See the [migration notes](CHANGELOG.md#300---2026-09-16). +> Version 3.x requires **Node.js 22 or newer** and works with **OpenCode 1.x** (tested with 1.18.31 and 1.19.3). Support for OpenCode 2.x is planned for 4.0. Upgrading from 2.x? See the [migration notes](CHANGELOG.md#300---2026-09-16). ## Quick Start diff --git a/docs/examples.md b/docs/examples.md index 492c1bd..2d1a488 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -1,6 +1,6 @@ # Usage Examples -These examples describe version 3.0.0. Replace provider/model placeholders with IDs discovered from `opencode_setup` and `opencode_provider_models`. All `directory` values refer to absolute paths on the OpenCode server. +These examples describe version 3.1.0. Replace provider/model placeholders with IDs discovered from `opencode_setup` and `opencode_provider_models`. All `directory` values refer to absolute paths on the OpenCode server. ## Quick Question and Follow-Up diff --git a/docs/getting-started.md b/docs/getting-started.md index ca060a1..f9402d0 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -6,7 +6,7 @@ - [OpenCode](https://opencode.ai/docs/) installed and a provider configured for model calls. - An MCP client capable of launching a stdio server. -These instructions cover version 3.0.0. Review the [migration notes](../CHANGELOG.md#300---2026-09-16) when upgrading from 2.x. +These instructions cover version 3.1.0. Review the [migration notes](../CHANGELOG.md#300---2026-09-16) when upgrading from 2.x. ## 1. Start OpenCode diff --git a/docs/releasing.md b/docs/releasing.md index 5ec140f..161e899 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -13,7 +13,7 @@ The runner creates a temporary Git project and a session owned by that test run. No model calls run by default. Tools outside these fixture checks appear as **SKIP**, with a reason; a successful smoke run does not claim coverage of those capabilities. Any unexpected tool error, failed fixture assertion, or failed session cleanup makes the command exit nonzero. Response bodies and server diagnostics are not printed because they can contain credentials or private configuration. -The runner uses a local server because the disposable project must be on the same filesystem as OpenCode. It rejects remote URLs instead of interpreting a local temporary path on another machine. Authentication uses the normal `OPENCODE_SERVER_USERNAME` and `OPENCODE_SERVER_PASSWORD` environment variables, forwarded to the MCP child; keep secrets out of command arguments. `OPENCODE_AUTO_SERVE` is always disabled for this test. +The runner uses a local server because the disposable project must be on the same filesystem as OpenCode. It rejects remote URLs instead of interpreting a local temporary path on another machine. Authentication uses `OPENCODE_SERVER_USERNAME`/`OPENCODE_SERVER_PASSWORD`, `OPENCODE_SERVER_TOKEN`, or `OPENCODE_OPENCHAMBER_PASSWORD` (with optional `OPENCODE_OPENCHAMBER_URL`/`OPENCODE_OPENCHAMBER_CLIENT_ID`), forwarded to the MCP child; keep secrets out of command arguments. `OPENCODE_AUTO_SERVE` is always disabled for this test. ### Optional inference checks diff --git a/package-lock.json b/package-lock.json index 3adcc4f..ac3ab11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "opencode-mcp", - "version": "3.0.0", + "version": "3.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opencode-mcp", - "version": "3.0.0", + "version": "3.1.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/core": "^2.4.0", diff --git a/package.json b/package.json index 90b560a..61fdb18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-mcp", - "version": "3.0.0", + "version": "3.1.0", "description": "MCP server for OpenCode coding workflows, durable async jobs, project resources, and explicit user input", "type": "module", "main": "dist/index.js", diff --git a/src/app.ts b/src/app.ts index 3480ab7..26c8a1e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -22,7 +22,7 @@ import { registerPrompts } from "./prompts.js"; /** Build registrations without connecting or performing network/filesystem I/O. */ export function createServer(client: OpenCodeClient, jobs: JobService, profile: ToolProfile = "full") { - const server = new McpServer({ name: "opencode-mcp", version: "3.0.0", + const server = new McpServer({ name: "opencode-mcp", version: "3.1.0", description: "Delegate coding work to OpenCode with durable jobs, explicit input, and project-scoped tools." }, { capabilities: { extensions: { [TASKS_EXTENSION]: {} } }, cacheHints: { "tools/list": { ttlMs: 60000, cacheScope: "private" }, "prompts/list": { ttlMs: 60000, cacheScope: "private" }, diff --git a/src/auth.ts b/src/auth.ts index c8fd6da..6392fb6 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -46,10 +46,10 @@ export class AuthProvider { * Identifies this MCP instance to OpenChamber. Stable for the lifetime of * the provider (and thus reused for every renewal), but unique per * instance so a second independent MCP instance on the same host cannot - * replace this one's client record: OpenChamber v2.4.0 revokes the - * previous client record whenever a login reuses a `dedupeKey` (see - * https://github.com/openchamber/openchamber/blob/v2.4.0/packages/web/ - * server/lib/client-auth/remote-clients.js#L188-L200), so a key derived + * replace this one's client record: OpenChamber (1.12 and later) revokes + * the previous client record whenever a login reuses a `dedupeKey` (see + * https://github.com/openchamber/openchamber/blob/v1.24.2/packages/web/ + * server/lib/client-auth/remote-clients.js), so a key derived * only from `hostname()` let a second MCP process silently invalidate the * first one's cached token. Override with `OPENCODE_OPENCHAMBER_CLIENT_ID` * when two instances must intentionally share one client record, e.g. diff --git a/src/index.ts b/src/index.ts index 57ba949..7324b13 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,6 +32,6 @@ async function main() { legacy: "serve", transport: new TaskTransport(new StdioServerTransport(), jobs), onerror: error => console.error("MCP transport error:", error.message), }); - console.error(`opencode-mcp v3.0.0 started (profile: ${profile})`); + console.error(`opencode-mcp v3.1.0 started (profile: ${profile})`); } main().catch(error => { console.error("Fatal error starting opencode-mcp:", error); process.exitCode = 1; }); diff --git a/tests/stdio-integration.test.ts b/tests/stdio-integration.test.ts index 1a1d5a6..c3657d0 100644 --- a/tests/stdio-integration.test.ts +++ b/tests/stdio-integration.test.ts @@ -34,7 +34,7 @@ describe("MCP process lifecycle", () => { await new Promise((resolve, reject) => { child!.stderr!.on("data", (chunk) => { log += chunk; - if (log.includes("opencode-mcp v3.0.0 started (")) resolve(); + if (log.includes("opencode-mcp v3.1.0 started (")) resolve(); }); child!.once("error", reject); child!.once("exit", () => reject(new Error(`Premature exit: ${log}`)));