Files
oh-my-opencode/src/features/skill-mcp-manager/AGENTS.md
T
YeonGyu-Kim 1e7a7600a2 docs(agents-md): regenerate hierarchical AGENTS.md knowledge base for v4.1.1
Refresh all AGENTS.md files to reflect codebase state at 5ffbe0e24 (was cd31d2a1a, 197 commits behind).

Key drift corrections across 45 modified + 1 new file:

Root AGENTS.md:
- TS file counts: 1967 -> 2034 in src/ (1337 source + 697 test)
- LOC: 278k -> 292k
- Barrel index.ts: 120 -> 122
- Hook tier composition: 52/59 -> 54/61 (base/with team-mode)
- Tool Guard hooks: 14 -> 16 (add fsync-skip-warning, bash-file-read-guard)
- Add boulder feature, agent-ordering schema, .agents/ directory, v4.1.1 release tag
- Add generated/ directory entry

src/AGENTS.md:
- Subsystem inventory: agents 96->102, hooks 570->581, tools 306->314,
  features 389->400, shared 258->278, cli 150->158, plugin 55->56
- LOC totals refreshed for every subsystem
- Schema files: 32 -> 30

src/hooks/AGENTS.md:
- Tier 2 (Tool Guard): 14 -> 16 hooks, add fsyncSkipWarning row
- Total: 52 base / 59 team-mode -> 54 base / 61 team-mode
- zauc-mocks count: 7 -> 5

src/features/AGENTS.md:
- background-agent: 47 -> 57 files, mention archive fallback
- opencode-skill-loader: 33 -> 30
- tmux-subagent: 34 -> 32

src/plugin/AGENTS.md:
- Tool Guard composer count: 14 -> 16
- Aggregator total: 43 -> 45

src/cli/AGENTS.md:
- Add new boulder subcommand (BoulderState inspector)
- Command count: 6 -> 7

NEW: src/features/boulder-state/AGENTS.md
- Document the new Boulder work tracking feature
- Schema v2 with BoulderState/BoulderWorkState/TaskSessionState
- Lifecycle, storage, integration points with atlas/ralph-loop hooks

All other AGENTS.md files: Generated date 2026-05-08 -> 2026-05-14.
2026-05-14 12:57:46 +09:00

4.4 KiB

src/features/skill-mcp-manager/ — Skill-Embedded MCP Client Lifecycle

Generated: 2026-05-14

OVERVIEW

18 files. Manages tier 3 of the MCP system: skill-embedded MCP servers declared in SKILL.md YAML frontmatter. Per-session client isolation, dual transport (stdio + HTTP), OAuth 2.0 with step-up authentication, idle cleanup.

THREE-TIER MCP CONTEXT

Tier Manager Scope
1. Built-in createBuiltinMcps() (src/mcp/) Global, 3 remote HTTP
2. Claude Code claude-code-mcp-loader (src/features/) From .mcp.json
3. Skill-embedded SkillMcpManager (this module) Per-session, from SKILL.md YAML

CLIENT KEY FORMAT

${sessionID}:${skillName}:${serverName}

Enables: per-session isolation, same skill usable in multiple sessions concurrently, multiple servers per skill.

DUAL TRANSPORT

Type File Backend
stdio stdio-client.ts StdioClientTransport (local process)
http http-client.ts StreamableHTTPClientTransport (remote)

Detection (connection-type.ts): explicit type field → URL presence → command presence. Legacy "sse" mapped to http.

STATE

interface SkillMcpManagerState {
  clients: Map<clientKey, ManagedClient>              // Active connections
  pendingConnections: Map<clientKey, Promise<Client>> // Race prevention
  disconnectedSessions: Map<sessionID, generation>    // Stale connection detection
  authProviders: Map<url, OAuthProvider>              // OAuth state per server
  inFlightConnections: Map<sessionID, count>          // Connection counting
}

KEY FILES

File Purpose
manager.ts SkillMcpManager class — main API (getOrCreateClient, disconnectSession, listTools, callTool, etc.)
types.ts ManagedStdioClient, ManagedHttpClient, SkillMcpManagerState, ConnectionType
connection.ts Client factory with race prevention, retry, env var expansion
connection-type.ts Detect stdio vs http from config (legacy sse → http)
stdio-client.ts Stdio transport factory
http-client.ts HTTP transport factory
cleanup.ts SIGINT/SIGTERM handlers, idle timer (60s interval, 5min TTL)
oauth-handler.ts OAuth token management, refresh, step-up (403 scope escalation)
env-cleaner.ts Filter npm/pnpm/yarn config + 25+ secret patterns (_KEY, _SECRET, _TOKEN)
error-redaction.ts Redact sensitive data from error messages before logging

LIFECYCLE INTEGRATION

Hook: src/plugin/event.ts on session.deleted:

await managers.skillMcpManager.disconnectSession(sessionInfo.id)

LIFECYCLE FLOW

1. session.created      → No action (lazy connection)
2. First MCP tool call  → getOrCreateClient() creates + caches
3. Ongoing use          → lastUsedAt timestamp updated
4. Idle >5min           → cleanup timer removes
5. session.deleted      → disconnectSession() closes session clients
6. Process exit         → disconnectAll() via SIGINT/SIGTERM handlers

RACE CONDITION PREVENTION

  • pendingConnections: Deduplicates concurrent connection attempts for same key
  • inFlightConnections: Per-session counter, prevents premature cleanup during connection setup
  • shutdownGeneration: Counter-based stale connection detection after disconnect

PUBLIC API

class SkillMcpManager {
  constructor(options?: { createOAuthProvider? })
  getOrCreateClient(info, config): Promise<Client>
  disconnectSession(sessionID): Promise<void>
  disconnectAll(): Promise<void>
  listTools/Resources/Prompts(info, context): Promise<...[]>
  callTool(info, context, name, args): Promise<unknown>
  readResource(info, context, uri): Promise<unknown>
  getPrompt(info, context, name, args): Promise<unknown>
  getConnectedServers(): string[]
  isConnected(info): boolean
}

RETRY SEMANTICS

  • getOrCreateClientWithRetry() — 3 attempts with force reconnect on failure
  • withOperationRetry() — OAuth-aware wrapper: step-up on 403, token refresh on 401

SECURITY

  • env-cleaner.ts — strips npm/pnpm config vars (prevents pnpm project isolation issues) and secret patterns before stdio spawn
  • error-redaction.ts — masks tokens/secrets in error messages before logger.log
  • OAuth isolation — auth providers keyed by server URL, tokens never cross servers