1e7a7600a2
Refresh all AGENTS.md files to reflect codebase state at5ffbe0e24(wascd31d2a1a, 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.
4.4 KiB
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 failurewithOperationRetry()— 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