Skip to content

[Feature]: Replace skill-mcp-manager with mcporter CLI runtime for unified MCP management, auto-install, and daemon support #1797

@code-yeongyu

Description

@code-yeongyu

Prerequisites

  • I will write this issue in English (see our Language Policy)
  • I have searched existing issues and discussions to avoid duplicates
  • This feature request is specific to oh-my-opencode (not OpenCode core)
  • I have read the documentation or asked an AI coding agent with this project's GitHub URL loaded and couldn't find the answer

Problem Description

Background

oh-my-opencode currently has its own MCP client implementation via skill-mcp-manager and claude-code-mcp-loader features. These work well for the current use case (skill-embedded MCPs and Claude Code MCP configs), but they require:

  1. Manual MCP server management — users must configure MCP servers in Claude Code config files (~/.claude.json, .mcp.json) or skill frontmatter/mcp.json files
  2. No unified discovery — MCP servers are scattered across multiple config scopes (user, project, local, skill-embedded) with different loading logic
  3. No auto-install — if an MCP server requires installation (e.g., npx -y @some/mcp-server), users must set it up manually
  4. No CLI generation — users cannot generate standalone CLIs from their MCP servers
  5. No daemon/keep-alive — stdio MCP servers are spawned per-session with idle timeout cleanup, no persistent connection pooling

mcporter (MIT license, npm: [email protected]) is a mature TypeScript runtime, CLI, and code-generation toolkit for MCP that already solves all of these problems:

  • Zero-config discovery — merges ~/.mcporter/mcporter.json, config/mcporter.json, plus imports from Cursor/Claude/Codex/Windsurf/OpenCode/VS Code
  • CLI generationmcporter generate-cli turns any MCP server into a standalone CLI
  • TypeScript codegenmcporter emit-ts generates typed client wrappers
  • OAuth handling — built-in OAuth caching, step-up auth
  • Daemonmcporter daemon start/stop/restart keeps MCP servers warm across sessions
  • Ad-hoc connections--http-url / --stdio flags for trying MCP servers without config
  • Config managementmcporter config add/remove/import/login/logout

Proposed Solution

Phase 1: mcporter as the unified MCP backend

Replace skill-mcp-manager's direct @modelcontextprotocol/sdk usage with mcporter as the underlying MCP client runtime.

Architecture Mapping

Current (skill-mcp-manager) Proposed (mcporter)
SkillMcpManager.getOrCreateClient() → direct Client from @modelcontextprotocol/sdk mcporter.createRuntime() → connection-pooled runtime with auto-discovery
StdioClientTransport / StreamableHTTPClientTransport manual setup mcporter handles stdio/HTTP/SSE transport selection automatically
Manual env expansion via expandEnvVarsInObject() mcporter's ${ENV} placeholder expansion built-in
Custom OAuth via McpOAuthProvider + step-up handling mcporter's built-in OAuth caching + mcporter auth CLI
Idle timeout cleanup (5min default) mcporter daemon with configurable lifecycle: keep-alive/ephemeral
Skill frontmatter mcp: block or mcp.json per skill Skill MCPs auto-registered into mcporter config at skill load time

Key Integration Points

1. Config Unification

mcporter already supports OpenCode config import paths:

opencode.jsonc / opencode.json (project root)
~/.config/opencode/opencode.jsonc / opencode.json (global)

The skill-embedded MCP configs (from mcp.json or YAML frontmatter in SKILL.md) would be dynamically registered into mcporter's runtime at skill load time:

// In opencode-skill-loader, after loading skill MCPs:
for (const [serverName, config] of Object.entries(skill.mcpConfig)) {
  await mcporterRuntime.addServer(serverName, config)
}

2. Tool Compatibility — Full Backward Compatibility

The skill_mcp tool interface remains unchanged:

skill_mcp(mcp_name="sqlite", tool_name="query", arguments='{"sql": "SELECT * FROM users"}')
skill_mcp(mcp_name="memory", resource_name="memory://notes")

Internally, instead of manager.callTool(info, context, name, args) creating a raw MCP SDK client, it delegates to mcporter:

const result = await mcporterRuntime.call(`${serverName}.${toolName}`, args)

3. Claude Code MCP Loader Compatibility

claude-code-mcp-loader reads MCP configs from 4 paths:

  • ~/.claude.json
  • ~/.claude/.mcp.json
  • {cwd}/.mcp.json
  • {cwd}/.claude/.mcp.json

mcporter's config import claude-code already reads these same paths. The loader can be simplified to delegate to mcporter's discovery.

4. Builtin MCPs

Current builtin MCPs (websearch, context7, grep_app) are remote HTTP MCPs. These would be registered as mcporter configs:

{
  "websearch": { "url": "https://...", "headers": { "Authorization": "Bearer ${OPENCODE_WEBSEARCH_KEY}" } },
  "context7": { "url": "https://mcp.context7.com/mcp" },
  "grep_app": { "url": "https://mcp.grep.app/mcp" }
}

Phase 2: Auto-install and MCP Discovery

MCP Auto-Install in Skills

Extend the skill mcp.json or SKILL.md frontmatter to support install directives:

---
name: my-skill
mcp:
  sqlite:
    command: npx
    args: [-y, "@anthropic/mcp-server-sqlite", "--db", "${SKILL_DIR}/data.db"]
    auto_install: true  # mcporter handles installation
---

Or in mcp.json:

{
  "mcpServers": {
    "sqlite": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-server-sqlite"],
      "autoInstall": true
    }
  }
}

When auto_install: true, the skill loader invokes mcporter config add <name> --stdio "<command>" to persist it, and mcporter's runtime handles the first-run installation.

MCP Discovery from mcporter

Add a new tool or extend skill_mcp to discover MCP servers that mcporter knows about but aren't skill-embedded:

skill_mcp(mcp_name="__discover__")
# Returns all available MCP servers from mcporter's merged config

This gives agents access to MCPs configured via Cursor, Claude Desktop, Codex, etc. without any oh-my-opencode-specific setup.


Phase 3: Advanced Features

CLI Generation for Custom Tools

Agents can use mcporter's CLI generation to create project-specific tool CLIs:

mcporter generate-cli --server my-project-mcp --compile ./tools/my-cli

This could be exposed as a skill or command:

/mcporter-generate --server <name> --output <path>

Daemon Integration

For long-running agents (sisyphus, hephaestus), mcporter daemon keeps MCP servers warm:

  • Agent starts → mcporter daemon start (if not running)
  • Agent uses MCP tools → connection reuse via daemon
  • Agent ends → daemon stays alive for next agent

Playwright-Style HTTP MCP Servers

mcporter already supports HTTP MCP servers. A Playwright MCP server running locally (e.g., @anthropic/mcp-server-playwright) can be configured as:

{
  "playwright": {
    "command": "npx",
    "args": ["-y", "@anthropic/mcp-server-playwright"],
    "lifecycle": "keep-alive"
  }
}

The daemon keeps the Playwright server (and its browser instance) alive across multiple tool calls.


Detailed Implementation Plan

Files to Modify

File Change
src/features/skill-mcp-manager/manager.ts Replace raw SDK client creation with mcporter runtime
src/features/skill-mcp-manager/connection.ts Delegate to mcporter's connection management
src/features/skill-mcp-manager/stdio-client.ts Remove (mcporter handles stdio)
src/features/skill-mcp-manager/http-client.ts Remove (mcporter handles HTTP)
src/features/skill-mcp-manager/oauth-handler.ts Remove (mcporter handles OAuth)
src/features/skill-mcp-manager/cleanup.ts Simplify — mcporter handles cleanup via daemon
src/features/skill-mcp-manager/env-cleaner.ts Remove (mcporter handles env expansion)
src/features/opencode-skill-loader/skill-mcp-config.ts Add auto-install directive parsing
src/features/claude-code-mcp-loader/loader.ts Optionally delegate to mcporter import
src/mcp/index.ts Register builtins via mcporter config
src/tools/skill-mcp/tools.ts Add __discover__ mode for MCP discovery
package.json Add mcporter as dependency

New Files

File Purpose
src/features/mcporter-runtime/index.ts mcporter runtime initialization and config management
src/features/mcporter-runtime/skill-bridge.ts Bridge between skill MCP configs and mcporter
src/features/mcporter-runtime/discovery.ts MCP discovery from mcporter's merged configs

Migration Path

  1. Add mcporter as dependencybun add mcporter
  2. Create mcporter-runtime wrapper — Wraps mcporter's createRuntime() with oh-my-opencode's session management
  3. Refactor SkillMcpManager — Delegate to mcporter runtime instead of raw SDK
  4. Backward-compatible — All existing skill_mcp calls work unchanged
  5. Add discovery — New __discover__ mode in skill_mcp tool
  6. Add auto-install — Parse autoInstall in skill MCP configs
  7. Daemon integration — Optional, for long-running agent sessions

Config Compatibility

Current skill MCP config (no change needed):

mcp:
  my-server:
    command: npx
    args: [-y, some-mcp-server]
    env:
      API_KEY: ${MY_API_KEY}

Current mcp.json (no change needed):

{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["-y", "some-mcp-server"]
    }
  }
}

Both formats are already compatible with mcporter's config schema (ClaudeCodeMcpServer type matches mcporter's entry schema exactly — command, args, env, url, headers, type, oauth).


Feasibility Assessment

Why This Works

  1. Config format compatibility — oh-my-opencode's ClaudeCodeMcpServer type and mcporter's entry schema are nearly identical (both support command/args/env for stdio, url/headers for HTTP, type field for explicit transport)
  2. mcporter already imports OpenCode configs — The pathsForImport('opencode', rootDir) function in mcporter reads opencode.jsonc/opencode.json from project root and ~/.config/opencode/
  3. MIT license — No licensing issues
  4. Active maintenance[email protected], actively developed by steipete
  5. Programmatic APIcreateRuntime() and createServerProxy() are designed for embedding

Potential Risks

  1. Dependency weight — mcporter adds a dependency, but replaces @modelcontextprotocol/sdk direct usage
  2. Breaking changes — mcporter is pre-1.0; pin version and test thoroughly
  3. Daemon lifecycle — Need to handle daemon startup/shutdown gracefully in oh-my-opencode's process lifecycle

Alternatives Considered

No response

Doctor Output (Optional)

Additional Context

Related existing code:

  • src/features/skill-mcp-manager/ — Current MCP client management (12 files)
  • src/features/claude-code-mcp-loader/ — Claude Code MCP config loading (5 files)
  • src/features/mcp-oauth/ — MCP OAuth handling (8 files)
  • src/tools/skill-mcp/ — skill_mcp tool (5 files)
  • src/mcp/ — Builtin MCP definitions (6 files)

mcporter source: https://github.com/steipete/mcporter

Feature Type

New Tool

Contribution

  • I'm willing to submit a PR for this feature
  • I can help with testing
  • I can help with documentation

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions