Skip to content

Latest commit

 

History

History
163 lines (129 loc) · 5.77 KB

File metadata and controls

163 lines (129 loc) · 5.77 KB

MCP Implementation Summary

What Was Implemented

1. Complete MCP Support

Configuration Parsing

  • ✅ Support for two .mcp.json formats:
    • Direct format (Claude Code standard): {"server-name": {...}}
    • Wrapped format (backward compatible): {"mcpServers": {"server-name": {...}}}
  • ✅ Support for inline mcpServers in plugin.json
  • ✅ Automatic merging of .mcp.json and plugin.json MCP servers

Variable Substitution

  • ${CLAUDE_PLUGIN_ROOT} → Plugin cache directory path
  • ${PLUGIN_NAME} → Plugin name
  • ${PLUGIN_VERSION} → Plugin version
  • ✅ Applied to: command, args, url, env values

MCP Server Types Supported

  • stdio: Local process execution (e.g., bun run server.ts)
  • http: HTTP/HTTPS endpoints
  • sse: Server-Sent Events
  • websocket: WebSocket connections
  • headers: HTTP headers for authentication

Plugin File Copying

  • ✅ ALL plugin files are copied to cache (not just skills/commands/agents)
  • ✅ MCP server source files (.ts, .js, .py, etc.)
  • ✅ Dependency files (package.json, requirements.txt, etc.)
  • ✅ Configuration files (.npmrc, .env.example, etc.)
  • ✅ Lock files (bun.lock, package-lock.json, etc.)

Installation Flow

  1. Plugin files copied to cache directory
  2. .mcp.json parsed and variables substituted
  3. MCP servers registered with plugin name prefix (e.g., discord.discord)
  4. Configuration written to ~/.config/opencode/.mcp.json

Uninstallation Flow

  1. Plugin cache directory removed
  2. Symlinks removed (skills, commands, agents)
  3. MCP servers with plugin prefix removed from .mcp.json

2. Bug Fixes

  • ✅ Fixed copyPluginToCache to copy ALL files, not just specific directories
  • ✅ Fixed copyDir to use proper recursive copy instead of os.Rename
  • ✅ Fixed ReadPluginJSON to return nil instead of error when file doesn't exist
  • ✅ Fixed marketplace name not being set during plugin installation
  • ✅ Fixed plugin removal not working when marketplace name is empty

3. Testing

Unit Tests

  • ✅ MCP config parsing (both formats)
  • ✅ Variable substitution
  • ✅ MCP server installation/uninstallation
  • ✅ Plugin prefix handling

Integration Tests

  • ✅ Full plugin installation with MCP servers
  • ✅ Real plugin testing (playwright, github, discord)

4. Real-World Verification

# Install Discord plugin (stdio MCP server with source code)
$ opencode-plugin plugin install discord
✓ Successfully installed plugin: discord@0.0.4
  From marketplace: anthropics/claude-plugins-official
  Cache: ~/.opencode-plugin-cli/cache/.../discord/0.0.4
  Skills: 2, Commands: 0, Agents: 0
  MCP Servers: 1

# Verify MCP config
$ opencode-plugin mcp show discord.discord
MCP Server: discord.discord
Type: stdio
Command: bun
Arguments:
  - run
  - --cwd
  - /Users/.../cache/.../discord/0.0.4  # Variable substituted!
  - --shell=bun
  - --silent
  - start

# Verify all files copied
$ ls cache/.../discord/0.0.4/
.claude-plugin/  .mcp.json  .npmrc  ACCESS.md  bun.lock  
LICENSE  package.json  README.md  server.ts  skills/

# Install GitHub plugin (HTTP MCP server)
$ opencode-plugin plugin install github
✓ Successfully installed plugin: github@latest
  MCP Servers: 1

$ opencode-plugin mcp show github.github
MCP Server: github.github
Type: http
URL: https://api.githubcopilot.com/mcp/
Headers:
  Authorization=Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}

# Install Playwright plugin (stdio MCP server, npm package)
$ opencode-plugin plugin install playwright
✓ Successfully installed plugin: playwright@latest
  MCP Servers: 1

# List all MCP servers
$ opencode-plugin mcp list
Installed MCP Servers:
NAME                   TYPE   COMMAND/URL
discord.discord        stdio  bun
github.github          http   https://api.githubcopilot.com/mcp/
playwright.playwright  stdio  npx

# Uninstall removes MCP servers automatically
$ opencode-plugin plugin remove discord
✓ Removed cache: .../discord/0.0.4
✓ Successfully removed plugin: discord (2 symlinks removed)

$ opencode-plugin mcp list
NAME                   TYPE   COMMAND/URL
github.github          http   https://api.githubcopilot.com/mcp/
playwright.playwright  stdio  npx

Files Modified/Created

Core Implementation

  • internal/mcp/manager.go - MCP configuration manager
  • internal/mcp/manager_test.go - Comprehensive unit tests
  • internal/plugin/installer.go - Updated to copy all plugin files
  • internal/marketplace/manager.go - Fixed to return marketplace name
  • cmd/mcp/mcp.go - CLI commands for MCP management

Documentation

  • docs/MCP.md - Complete MCP documentation
  • README.md - Updated with MCP features
  • test/e2e/mcp_integration_test.go - Integration tests
  • test/e2e/real_plugin_test.go - Real plugin tests

Key Design Decisions

  1. Copy ALL plugin files: Instead of only copying skills/, commands/, agents/, the installer now copies everything (except .git). This ensures MCP server source code and dependencies are available.

  2. Plugin name prefix: MCP servers are prefixed with plugin name (e.g., discord.discord) to avoid conflicts between plugins with same server names.

  3. Variable substitution at install time: Variables are replaced when installing, not at runtime, for better performance.

  4. Support both MCP config formats: The system accepts both the direct format (Claude Code standard) and wrapped format for backward compatibility.

  5. Optional plugin.json: MCP-only plugins can have just .mcp.json without plugin.json.

Limitations & Future Work

  • MCP servers are not validated for executable permissions
  • No MCP server health checking
  • No MCP server dependency management (user must install bun, node, etc.)
  • Could add opencode-plugin mcp validate command
  • Could add MCP server logs viewing