mcp-client-core

August 24, 2026 · View on GitHub

Generated: 2026-08-24 / f3642fcda

OVERVIEW

Harness-neutral MCP client lifecycle and OAuth primitives. Consumed by omo-opencode via features/skill-mcp-manager and features/mcp-oauth / cli/mcp-oauth. Private package @oh-my-opencode/mcp-client-core; 30 source files under src/.

KEY FILES

FileRole
skill-mcp-manager/manager.tsSkillMcpManager — per-session client registry, listTools/callTool/readResource/getPrompt, retry loop with OAuth step-up
skill-mcp-manager/connection.tsgetOrCreateClient() / getOrCreateClientWithRetryImpl() — race-safe connection, dispatch to stdio or HTTP
skill-mcp-manager/connection-type.tsConnection-type inference: explicit type field > url presence > command presence
skill-mcp-manager/env-cleaner.tsFilters npm/pnpm/yarn config vars (pnpm breakage) and secret-bearing env vars from stdio server env
skill-mcp-manager/error-redaction.tsRedacts sensitive tokens from error messages (same patterns as env-cleaner)
skill-mcp-manager/stdio-client.tscreateStdioClient()StdioClientTransport, env cleaning, process cleanup registration
skill-mcp-manager/http-client.tscreateHttpClient()StreamableHTTPClientTransport, request init with OAuth headers, URL redaction
skill-mcp-manager/oauth-handler.tsbuildHttpRequestInit(), handleStepUpIfNeeded(), handlePostRequestAuthError() — token refresh, scope merge, 401/403 retry
skill-mcp-manager/cleanup.tsdisconnectSession(), disconnectAll(), forceReconnect(), idle timeout (5 min), SIGTERM/SIGINT handlers
skill-mcp-manager/types.tsSkillMcpClientInfo, ManagedClient, ConnectionType, SkillMcpManagerState
mcp-oauth/provider.tsMcpOAuthProvider — login (DCR + PKCE redirect), refresh, token storage
mcp-oauth/oauth-authorization-flow.tsPKCE verifier/challenge, browser open, 5-min timeout
mcp-oauth/discovery.tsdiscoverOAuthServerMetadata().well-known/oauth-protected-resource + oauth-authorization-server with cache
mcp-oauth/dcr.tsgetOrRegisterClient() — Dynamic Client Registration, fallback to static clientId
mcp-oauth/step-up.tsisStepUpRequired(), mergeScopes(), parseWwwAuthenticate() — 403 scope escalation
mcp-oauth/refresh-mutex.tsPer-server refresh mutex: one in-flight refresh, all waiters share the result
mcp-oauth/resource-indicator.tsgetResourceIndicator() — normalized URL (query/hash/trailing-slash stripped) as OAuth resource indicator
mcp-oauth/schema.tsZod McpOauthSchema (clientId, scopes)
mcp-oauth/storage-index.tsindex.json server-URL → token-file index; atomic rename + chmod writes
mcp-oauth/callback-server.tsfindAvailablePort(), startCallbackServer() for local OAuth callback
mcp-oauth/storage.tsloadToken() / saveToken() — keyed by server URL
config-dir.ts / plugin-identity.ts / logger.tsrealpath-normalized config path resolution; PLUGIN_NAME ("oh-my-openagent"); shared logger
index.tsBarrel: re-exports mcp-oauth/* and skill-mcp-manager/*

NOTES

  • Per-session isolation: client key is ${sessionID}:${skillName}:${serverName}. The same skill in two sessions does not share state.
  • Transports: stdio (local process via StdioClientTransport) and HTTP (remote via StreamableHTTPClientTransport). Connection type inferred from url vs command, or explicit type field.
  • OAuth flow: PKCE + optional DCR. Step-up authentication on 403 merges new scopes and re-authenticates. Refresh mutex prevents concurrent refresh storms.
  • Env hygiene is a security boundary: stdio servers never receive npm/pnpm/yarn config vars or secret-bearing env vars (env-cleaner.ts); errors leaving the manager are token-redacted (error-redaction.ts). Preserve both when touching client construction or error paths.
  • Cleanup: idle clients evicted after 5 minutes. Process signal handlers close all transports on SIGINT/SIGTERM. disconnectAll() is safe across plugin reloads.
  • Consumers: packages/omo-opencode/src/features/skill-mcp-manager/, packages/omo-opencode/src/features/mcp-oauth/, and packages/omo-opencode/src/cli/mcp-oauth/ import this Core package.

Parent: packages/AGENTS.md