diff --git a/AGENTS.md b/AGENTS.md index c7376b2..9c59974 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ offloaded to a compute box (`cs run "pnpm test"`) or CI — do not run them loca ## Repo structure - `mcp-server/` — the `opencode-workbench` MCP server + connector (TypeScript). - Tools: `workbench_info`, `inspect_target`, `plan_clone`, `apply_clone`, + Tools: `get_workbench_info`, `inspect_target`, `plan_clone`, `apply_clone`, `verify_clone`, `install_component`, `list_required_credentials`, `run_auth_flow`, `bootstrap_host`. Local + SSH transports. See `mcp-server/README.md` and `docs/architecture/clone-mcp.md`. diff --git a/connector.json b/connector.json index 073f138..7c39335 100644 --- a/connector.json +++ b/connector.json @@ -3,7 +3,7 @@ "name": "opencode-workbench", "title": "OpenCode Workbench", "description": "Clones the OpenCode workbench installation onto Linux machines, locally or over SSH.", - "version": "1.1.4", + "version": "2.0.0", "transport": { "type": "stdio", "command": "npx", diff --git a/context7.json b/context7.json index c27d09b..d5ac9f7 100644 --- a/context7.json +++ b/context7.json @@ -9,7 +9,7 @@ ], "rules": [ "Run locally with `npx -y @simonmak-ascent/opencode-workbench` (Node stdio MCP server; no API key).", - "Drive a clone with the tool order `workbench_info` → `inspect_target` → `plan_clone` → `apply_clone` → `verify_clone`; use `install_component` to install a single component by id, and `bootstrap_host` for a one-call end-to-end provision (platform scan + OpenCode + apply + verify; `help:true` documents parameters).", + "Drive a clone with the tool order `get_workbench_info` → `inspect_target` → `plan_clone` → `apply_clone` → `verify_clone`; use `install_component` to install a single component by id, and `bootstrap_host` for a one-call end-to-end provision (platform scan + OpenCode + apply + verify; `help:true` documents parameters).", "`apply_clone` and `install_component` are consent-gated: without `confirm:true` they return a plan and change nothing.", "Every tool takes a `target` of `{mode: \"local\"}` or `{mode: \"ssh\", host, user, port?, identityFile?}`.", "The connector never reads, transmits or writes secret values; `apply_clone` writes an empty `~/.env.workbench` template (mode 600) listing the `{env:VAR}` names to fill in.", diff --git a/docs/CHANGELOG_WORKBENCH.md b/docs/CHANGELOG_WORKBENCH.md index 8f3091d..843d8b7 100644 --- a/docs/CHANGELOG_WORKBENCH.md +++ b/docs/CHANGELOG_WORKBENCH.md @@ -3,6 +3,19 @@ > All notable changes to the workbench configuration. > Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [2026-10-03] — v2.0.0 + +### Breaking +- Renamed the MCP tool `workbench_info` → `get_workbench_info` for a consistent + `verb_noun` naming pattern (TDQS coherence). Clients that call `workbench_info` + must update. All other tools are unchanged. + +### Changed +- TDQS description pass across all 9 tools: explicit purpose, usage (use/do-not-use), + behavioral transparency, and sibling disambiguation. +- Official MCP Registry: added `mcpName` to `package.json`, `server.json` + description within the 100-char limit, workflow uses `login github-oidc`. + ## [2026-10-03] — VDD-ready, key-resilient profile ### Added diff --git a/docs/architecture/clone-mcp.md b/docs/architecture/clone-mcp.md index a9de543..3798396 100644 --- a/docs/architecture/clone-mcp.md +++ b/docs/architecture/clone-mcp.md @@ -37,7 +37,7 @@ mcp-server/src/ | Tool | Purpose | |------|---------| -| `workbench_info` | Repo, components by tier, optional MCP add-ons. | +| `get_workbench_info` | Repo, components by tier, optional MCP add-ons. | | `inspect_target` | OS/arch/pkg-manager/Node/Docker/OpenCode and the *names* of credentials present. | | `plan_clone` | Diff the target against the profile → steps (with privileged-command previews). | | `apply_clone` | Consent-gated: without `confirm:true` returns the plan; with it, clones + installs. | diff --git a/docs/architecture/opencode-runtime-snapshot.md b/docs/architecture/opencode-runtime-snapshot.md index 6bc3c5f..a0ef6d8 100644 --- a/docs/architecture/opencode-runtime-snapshot.md +++ b/docs/architecture/opencode-runtime-snapshot.md @@ -35,7 +35,7 @@ Notes: ## MCP Tool Surface -The server exposes **9 tools**: `workbench_info`, `inspect_target`, `plan_clone`, +The server exposes **9 tools**: `get_workbench_info`, `inspect_target`, `plan_clone`, `apply_clone`, `verify_clone`, `install_component`, `list_required_credentials`, `run_auth_flow`, `bootstrap_host`. diff --git a/llms.txt b/llms.txt index cac4335..7c5899e 100644 --- a/llms.txt +++ b/llms.txt @@ -15,7 +15,7 @@ ## MCP tools (9) -- `workbench_info` — describe this server: repo, components by tier, optional MCP add-ons +- `get_workbench_info` — describe this server: repo, components by tier, optional MCP add-ons - `inspect_target` — probe a machine: OS, arch, package manager, Node, Docker, OpenCode, home and npm-global paths - `plan_clone` — diff the target against the profile → install / present / manual steps (with command previews) - `apply_clone` — consent-gated: without `confirm:true` returns the plan; with it, clones + installs the profile (idempotent) diff --git a/mcp-server/README.md b/mcp-server/README.md index 6a190f0..184a092 100644 --- a/mcp-server/README.md +++ b/mcp-server/README.md @@ -34,7 +34,7 @@ From a checkout, use the local build instead: | Tool | Purpose | |------|---------| -| `workbench_info` | Repo, components by tier, optional MCP add-ons. | +| `get_workbench_info` | Repo, components by tier, optional MCP add-ons. | | `inspect_target` | OS/arch/pkg-manager/Node/Docker/OpenCode/home/npm paths. | | `plan_clone` | Diff the target against the profile → steps to install / present / manual. | | `apply_clone` | Clone the profile + install missing components + write rendered config. Idempotent. | diff --git a/mcp-server/src/tools.ts b/mcp-server/src/tools.ts index 630d346..43a2e65 100644 --- a/mcp-server/src/tools.ts +++ b/mcp-server/src/tools.ts @@ -199,7 +199,7 @@ function fail(message: string, error: unknown) { export function registerTools(server: McpServer): void { server.registerTool( - "workbench_info", + "get_workbench_info", { title: "Workbench server info", description: @@ -323,10 +323,10 @@ export function registerTools(server: McpServer): void { { title: "Install one Workbench component", description: - "Install a single Workbench component by id (e.g. `node`, `opencode`, `npm-mcps`, `skills`) on a target; `component` must be an id from workbench_info. Idempotent and consent-gated: without `confirm:true` it returns the plan. Use it for one targeted component; use apply_clone for a component subset, or bootstrap_host for a first-time end-to-end provision — do not combine them for the same host and change.", + "Install a single Workbench component by id (e.g. `node`, `opencode`, `npm-mcps`, `skills`) on a target; `component` must be an id from get_workbench_info. Idempotent and consent-gated: without `confirm:true` it returns the plan. Use it for one targeted component; use apply_clone for a component subset, or bootstrap_host for a first-time end-to-end provision — do not combine them for the same host and change.", inputSchema: { target: targetShape, - component: z.string().describe("Component id from workbench_info."), + component: z.string().describe("Component id from get_workbench_info."), workspace: z.string().optional().describe("Target directory for the profile repo."), confirm: z.boolean().optional().describe("Set true to actually install. When absent, the call returns a plan and makes no changes."), }, diff --git a/mcp-server/test/server.test.ts b/mcp-server/test/server.test.ts index e920433..5013bb0 100644 --- a/mcp-server/test/server.test.ts +++ b/mcp-server/test/server.test.ts @@ -22,13 +22,13 @@ describe("opencode-workbench server", () => { expect(names).toEqual([ "apply_clone", "bootstrap_host", + "get_workbench_info", "inspect_target", "install_component", "list_required_credentials", "plan_clone", "run_auth_flow", "verify_clone", - "workbench_info", ]); await client.close(); }); @@ -47,9 +47,9 @@ describe("opencode-workbench server", () => { await client.close(); }); - it("answers workbench_info with components and optional MCPs", async () => { + it("answers get_workbench_info with components and optional MCPs", async () => { const client = await connect(); - const res = await client.callTool({ name: "workbench_info", arguments: {} }); + const res = await client.callTool({ name: "get_workbench_info", arguments: {} }); const info = res.structuredContent as { components: Array<{ id: string; tier: string }>; optionalMcp: string[]; diff --git a/package.json b/package.json index 94e1b69..0ef1973 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@simonmak-ascent/opencode-workbench", "mcpName": "io.github.simonmak-ascent/opencode-workbench", - "version": "1.1.4", + "version": "2.0.0", "description": "MCP server and connector that clones the OpenCode workbench configuration onto Linux machines (locally or over SSH).", "license": "MIT", "type": "module", diff --git a/server.json b/server.json index 614ccd1..ca7ae4b 100644 --- a/server.json +++ b/server.json @@ -2,7 +2,7 @@ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", "name": "io.github.simonmak-ascent/opencode-workbench", "description": "Provision an OpenCode workbench and MCP stack on any Linux box, local or over SSH.", - "version": "1.1.4", + "version": "2.0.0", "repository": { "url": "https://github.com/simonmak-ascent/opencode-workbench", "source": "github" @@ -11,7 +11,7 @@ { "registryType": "npm", "identifier": "@simonmak-ascent/opencode-workbench", - "version": "1.1.4", + "version": "2.0.0", "transport": { "type": "stdio" } } ], diff --git a/vdd/specs/mcp-quality-and-registry/spec.md b/vdd/specs/mcp-quality-and-registry/spec.md index ee00aa9..8afc15a 100644 --- a/vdd/specs/mcp-quality-and-registry/spec.md +++ b/vdd/specs/mcp-quality-and-registry/spec.md @@ -53,6 +53,11 @@ the registries my client reads, so I can discover and invoke it correctly. - Invent quality scores; only report measured values. - Commit registry API keys. +> **Decision (2026-10-03):** the original boundary "never rename tools" was +> superseded. TDQS flagged `workbench_info` as the lone non-`verb_noun` name, so it +> was renamed to `get_workbench_info` as a **breaking change in v2.0.0** (recorded +> in `docs/CHANGELOG_WORKBENCH.md`). + ## Acceptance Criteria ### AC-1: TDQS lint clean [MUST] diff --git a/vdd/specs/mcp-quality-and-registry/tdqs-baseline.md b/vdd/specs/mcp-quality-and-registry/tdqs-baseline.md index 1e25bf6..1fba36b 100644 --- a/vdd/specs/mcp-quality-and-registry/tdqs-baseline.md +++ b/vdd/specs/mcp-quality-and-registry/tdqs-baseline.md @@ -12,7 +12,7 @@ npx -y mcp-tdqs lint --command 'node mcp-server/dist/index.js' \ | Tool | Params | Coverage | Annotations | Output schema | Cost | Warning | |------|--------|----------|-------------|---------------|------|---------| -| workbench_info | 0 | 100% | yes | yes | 0 | — | +| workbench_info (now `get_workbench_info`) | 0 | 100% | yes | yes | 0 | — | | inspect_target | 1 | 100% | yes | yes | 4 | shadow-candidate (vs bootstrap_host) | | plan_clone | 6 | 100% | yes | yes | 4 | shadow-candidate | | apply_clone | 7 | 100% | yes | yes | 4 | shadow-candidate |