From ae45894848459912b35f54aaaf98d12c8557e837 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 24 Jun 2026 16:19:51 -0500 Subject: [PATCH 1/4] fix(opencode): hide MCP access token prefix --- packages/opencode/src/cli/cmd/mcp.ts | 2 +- packages/opencode/test/cli/mcp-debug.test.ts | 47 ++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/opencode/test/cli/mcp-debug.test.ts diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts index 06cb77bce135..7e249096a7be 100644 --- a/packages/opencode/src/cli/cmd/mcp.ts +++ b/packages/opencode/src/cli/cmd/mcp.ts @@ -719,7 +719,7 @@ export const McpDebugCommand = effectCmd({ prompts.log.info(`Auth status: ${getAuthStatusIcon(authStatus)} ${getAuthStatusText(authStatus)}`) if (entry?.tokens) { - prompts.log.info(` Access token: ${entry.tokens.accessToken.substring(0, 20)}...`) + prompts.log.info(` Access token: present`) if (entry.tokens.expiresAt) { const expiresDate = new Date(entry.tokens.expiresAt * 1000) const isExpired = entry.tokens.expiresAt < Date.now() / 1000 diff --git a/packages/opencode/test/cli/mcp-debug.test.ts b/packages/opencode/test/cli/mcp-debug.test.ts new file mode 100644 index 000000000000..7d8dbfbbd710 --- /dev/null +++ b/packages/opencode/test/cli/mcp-debug.test.ts @@ -0,0 +1,47 @@ +import { describe, expect } from "bun:test" +import { Effect } from "effect" +import fs from "fs/promises" +import path from "path" +import { cliIt } from "../lib/cli-process" + +describe("opencode mcp debug", () => { + cliIt.concurrent( + "does not disclose access token bytes", + ({ home, llm, opencode }) => + Effect.gen(function* () { + const data = path.join(home, ".local", "share", "opencode") + yield* Effect.promise(() => fs.mkdir(data, { recursive: true })) + yield* Effect.promise(() => + Bun.write( + path.join(data, "mcp-auth.json"), + JSON.stringify({ + github: { + tokens: { + accessToken: "secret-access-token-prefix-and-remainder", + refreshToken: "refresh-token", + expiresAt: 4_102_444_800, + }, + clientInfo: { clientId: "test-client" }, + }, + }), + ), + ) + + const result = yield* opencode.spawn(["mcp", "debug", "github"], { + env: { + OPENCODE_CONFIG_CONTENT: JSON.stringify({ + mcp: { github: { type: "remote", url: llm.url } }, + }), + }, + }) + opencode.expectExit(result, 0) + + const output = result.stdout + result.stderr + expect(output).toContain("Access token: present") + expect(output).not.toContain("secret-access-token-prefix") + expect(output).toContain("Refresh token: present") + expect(output).toContain("Client ID: test-client") + }), + 60_000, + ) +}) From 47546436a0f05ecdb42a6dbc1a7b01d8b74d28ee Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 24 Jun 2026 16:56:02 -0500 Subject: [PATCH 2/4] test(opencode): cover MCP token expiry diagnostic --- packages/opencode/test/cli/mcp-debug.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/test/cli/mcp-debug.test.ts b/packages/opencode/test/cli/mcp-debug.test.ts index 7d8dbfbbd710..6f2f6b43f716 100644 --- a/packages/opencode/test/cli/mcp-debug.test.ts +++ b/packages/opencode/test/cli/mcp-debug.test.ts @@ -39,6 +39,7 @@ describe("opencode mcp debug", () => { const output = result.stdout + result.stderr expect(output).toContain("Access token: present") expect(output).not.toContain("secret-access-token-prefix") + expect(output).toContain("Expires: 2100-01-01T00:00:00.000Z") expect(output).toContain("Refresh token: present") expect(output).toContain("Client ID: test-client") }), From 28bdc894b9c85329f933c883593612a392d165a4 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 24 Jun 2026 17:13:32 -0500 Subject: [PATCH 3/4] fix(opencode): mask MCP access token output --- packages/opencode/src/cli/cmd/mcp.ts | 2 +- packages/opencode/test/cli/mcp-debug.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts index 7e249096a7be..921561cf0570 100644 --- a/packages/opencode/src/cli/cmd/mcp.ts +++ b/packages/opencode/src/cli/cmd/mcp.ts @@ -719,7 +719,7 @@ export const McpDebugCommand = effectCmd({ prompts.log.info(`Auth status: ${getAuthStatusIcon(authStatus)} ${getAuthStatusText(authStatus)}`) if (entry?.tokens) { - prompts.log.info(` Access token: present`) + prompts.log.info(` Access token: ••••`) if (entry.tokens.expiresAt) { const expiresDate = new Date(entry.tokens.expiresAt * 1000) const isExpired = entry.tokens.expiresAt < Date.now() / 1000 diff --git a/packages/opencode/test/cli/mcp-debug.test.ts b/packages/opencode/test/cli/mcp-debug.test.ts index 6f2f6b43f716..6d58285d4bfb 100644 --- a/packages/opencode/test/cli/mcp-debug.test.ts +++ b/packages/opencode/test/cli/mcp-debug.test.ts @@ -37,7 +37,7 @@ describe("opencode mcp debug", () => { opencode.expectExit(result, 0) const output = result.stdout + result.stderr - expect(output).toContain("Access token: present") + expect(output).toContain("Access token: ••••") expect(output).not.toContain("secret-access-token-prefix") expect(output).toContain("Expires: 2100-01-01T00:00:00.000Z") expect(output).toContain("Refresh token: present") From c5324e0cd476d2ef371d948a478c1a2256c22965 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 24 Jun 2026 17:15:51 -0500 Subject: [PATCH 4/4] fix(opencode): censor MCP access token output --- packages/opencode/src/cli/cmd/mcp.ts | 4 +- packages/opencode/test/cli/mcp-debug.test.ts | 48 -------------------- 2 files changed, 3 insertions(+), 49 deletions(-) delete mode 100644 packages/opencode/test/cli/mcp-debug.test.ts diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts index 921561cf0570..47caff0f5ec3 100644 --- a/packages/opencode/src/cli/cmd/mcp.ts +++ b/packages/opencode/src/cli/cmd/mcp.ts @@ -719,7 +719,9 @@ export const McpDebugCommand = effectCmd({ prompts.log.info(`Auth status: ${getAuthStatusIcon(authStatus)} ${getAuthStatusText(authStatus)}`) if (entry?.tokens) { - prompts.log.info(` Access token: ••••`) + prompts.log.info( + ` Access token: ${entry.tokens.accessToken.length > 8 ? `${entry.tokens.accessToken.slice(0, 4)}***${entry.tokens.accessToken.slice(-4)}` : "***"}`, + ) if (entry.tokens.expiresAt) { const expiresDate = new Date(entry.tokens.expiresAt * 1000) const isExpired = entry.tokens.expiresAt < Date.now() / 1000 diff --git a/packages/opencode/test/cli/mcp-debug.test.ts b/packages/opencode/test/cli/mcp-debug.test.ts deleted file mode 100644 index 6d58285d4bfb..000000000000 --- a/packages/opencode/test/cli/mcp-debug.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect } from "bun:test" -import { Effect } from "effect" -import fs from "fs/promises" -import path from "path" -import { cliIt } from "../lib/cli-process" - -describe("opencode mcp debug", () => { - cliIt.concurrent( - "does not disclose access token bytes", - ({ home, llm, opencode }) => - Effect.gen(function* () { - const data = path.join(home, ".local", "share", "opencode") - yield* Effect.promise(() => fs.mkdir(data, { recursive: true })) - yield* Effect.promise(() => - Bun.write( - path.join(data, "mcp-auth.json"), - JSON.stringify({ - github: { - tokens: { - accessToken: "secret-access-token-prefix-and-remainder", - refreshToken: "refresh-token", - expiresAt: 4_102_444_800, - }, - clientInfo: { clientId: "test-client" }, - }, - }), - ), - ) - - const result = yield* opencode.spawn(["mcp", "debug", "github"], { - env: { - OPENCODE_CONFIG_CONTENT: JSON.stringify({ - mcp: { github: { type: "remote", url: llm.url } }, - }), - }, - }) - opencode.expectExit(result, 0) - - const output = result.stdout + result.stderr - expect(output).toContain("Access token: ••••") - expect(output).not.toContain("secret-access-token-prefix") - expect(output).toContain("Expires: 2100-01-01T00:00:00.000Z") - expect(output).toContain("Refresh token: present") - expect(output).toContain("Client ID: test-client") - }), - 60_000, - ) -})