Files
upstash--context7/docs/clients
Fahreddin Özcan 07580f10af feat(plugins): add Context7 plugin for OpenCode (#3008)
* feat(plugins): add Context7 plugin for OpenCode

Adds @upstash/context7-opencode, an OpenCode plugin that registers the
hosted Context7 MCP server, the context7-mcp skill, a docs-researcher
subagent, and the /context7-docs command through the config hook.

* docs(opencode): keep ctx7 setup as the primary install path

* refactor(opencode): drop the component toggles and tighten the option boundary

The skill/agent/command toggles were speculative: OpenCode dedupes skills by
name, so running ctx7 setup alongside the plugin is already safe, and a user
who wants a component gone can define it themselves, which the plugin never
overwrites. Removing them collapses resolveOptions into resolveApiKey and
deletes the duplicated defaulting between option parsing and config assembly.

Also assert the MCP endpoints as literals. The tests compared against the same
constants they exercised, so a wrong URL would have passed.

* refactor(opencode): drop tests and collapse the plugin into one file

config.ts existed to give the tests a seam. With the tests gone the split was
indirection with no consumer, so the constants, the config assembly, and the
plugin entry now live in src/index.ts and nothing but the default export is
public. Passing skillsDir through an ApplyInput object also stops being
necessary once it is a module constant.

* fix(opencode): run the MCP server over stdio and drop the slash command

Verified against a real OpenCode 1.18.11 session: the remote transport does
not work. OpenCode opens the optional GET SSE stream, mcp.context7.com answers
405, and OpenCode marks the server failed and registers no tools, so the model
never sees resolve-library-id and falls back to inventing bash calls. A control
project with a plain remote mcp block and no plugin fails the same way, so this
is not plugin-specific. Running the server over stdio connects and the model
calls the tools.

The bundled skill and the agent prompt also referenced the bare tool names.
OpenCode prefixes MCP tools with the server name, so they are now
context7_resolve-library-id and context7_query-docs.

Also removes the /context7-docs command. The skill already triggers on its own
and the subagent covers focused lookups.

* refactor(opencode): use the remote MCP server and drop the subagent

The plugin now adds two things: the hosted MCP server over the remote
transport, and the context7-mcp skill.

Known limitation: OpenCode opens the optional GET SSE stream on the endpoint
and mcp.context7.com answers 405, so OpenCode marks the server failed and
registers no tools. Reproduced on 1.18.11 and 1.18.16, and with a plain remote
mcp block and no plugin, so it is not plugin-specific. It resolves once
mcp.context7.com answers GET /mcp with a 200 SSE stream instead of 405.

* refactor(opencode): ship the canonical skill verbatim and drop the phantom peer dep

The bundled skill had been edited to hard-code OpenCode's context7_ tool
prefix. That divergence was unnecessary and counterproductive:

- It was fixing a misdiagnosis. The model only invented shell commands when
  the MCP server had failed to connect and no context7 tools existed at all.
  With the tools present, claude-haiku-4-5 calls context7_resolve-library-id
  correctly from the bare-name canonical skill.
- It was defeated where it mattered. OpenCode dedupes skills by name and scans
  ~/.claude/skills first, so on any machine that ran ctx7 setup the bundled
  copy is shadowed by the canonical one anyway.
- It was the only client copy to diverge in content. claude, copilot, codex
  and cursor all ship skills/context7-mcp/SKILL.md verbatim, and there is no
  tooling to keep copies in sync.

Also removes peerDependencies on @opencode-ai/plugin. The package is a
type-only import that the build erases, so the published dist has zero
references to it, and peerDependenciesMeta.optional made the declaration inert
anyway. The devDependency is what typechecking actually needs.

* refactor(opencode): strip commentary and inline the plugin function

Keeps only the two comments that stop someone breaking the plugin: why the
skills cast is needed, and why nothing but the default export may be exported.

Inlining the server function into the default export drops the Context7Plugin
binding and the Plugin type import, since satisfies PluginModule already types
the callback. 85 lines down to 56.

* docs(opencode): use the prefixed tool names consistently in the README
2026-08-18 15:20:43 +03:00
..
2026-03-11 22:45:51 -07:00