Skip to content

refactor: move MCP lifecycle out of AgentLoop - #5343

Merged
chengyongru merged 6 commits into
HKUDS:mainfrom
chengyongru:codex/extract-mcp-provider-runtime
Aug 12, 2026
Merged

refactor: move MCP lifecycle out of AgentLoop#5343
chengyongru merged 6 commits into
HKUDS:mainfrom
chengyongru:codex/extract-mcp-provider-runtime

Conversation

@chengyongru

@chengyongru chengyongru commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add an application-owned MCPProvider that owns merged configuration, connections, status, reload/reconnect, tool registration, and shutdown
  • inject one shared ToolRegistry into an MCP-agnostic AgentLoop, with provider composition at the gateway, CLI, API, and SDK entry points
  • replace the WebUI bus control message with an explicit reload callback while preserving readiness deadlines, reload timeouts, and restart fallback behavior
  • unregister dynamic tools during reload/shutdown, roll back partially connected batches on timeout or cancellation, and finish closing every connection before propagating cancellation

Design

This moves lifecycle ownership out of the agent loop instead of only wrapping its existing MCP fields. AgentLoop now consumes tools and focuses on turns; application composition roots own infrastructure readiness and cleanup. This keeps the same provider instance and registry visible to every supported entry point without weak references or runtime-control events.

Validation

  • uv run --no-sync basedpyright — 0 errors
  • uv run --no-sync ruff check nanobot tests — passed
  • relevant Python suites — 517 passed, 1 skipped
  • bun run test -- src/tests/settings-apps-oauth.test.tsx — 10 passed
  • bun run build — passed
  • browser smoke test — direct MCP reload, persisted failure status, reconnect retry, and zero console errors

Closes #4858

Supersedes #4875.

@chengyongru chengyongru added priority: p2 Normal backlog: minor bug, enhancement, docs, cleanup, edge case, or unvalidated proposal. refactor test webui labels Aug 11, 2026
@chengyongru
chengyongru merged commit 19997d2 into HKUDS:main Aug 12, 2026
6 checks passed
@chengyongru
chengyongru deleted the codex/extract-mcp-provider-runtime branch August 12, 2026 09:51
fuutott added a commit to fuutott/nanobot that referenced this pull request Aug 14, 2026
…actor, exec/security hardening

Absorbed from HKUDS/nanobot (b3b0517..221e8a4):
- feat(mcp) HKUDS#5316: native browser OAuth for remote MCP servers (mcp_oauth.py +
  webui/mcp_oauth_api.py; auth: "oauth" marker; MCP SDK OAuthClientProvider).
- refactor HKUDS#5343: move MCP lifecycle out of AgentLoop into an MCPProvider;
  from_config now takes a caller-owned tool_registry; close_mcp -> aclose.
- Security: exec.allowPatterns shell-chain bypass fix, exec path-guard hardening
  (double-slash / redirection / named-user home), Docker privilege-drop
  hardening, stop leaking API keys into subprocess env, web credential-URL
  redaction (keep creds out of logs / Jina reader / SW caches).
- WebUI: tabbed pane workbench (HKUDS#5322), MCP management dialog, PWA support,
  native folder picker, settings split by domain (HKUDS#5323), session drag polish.
- Providers: DeepSeek V4 Pro Responses; gemini tool-history across model switch.
- Session: history stored outside workspace, symlink-migration rejection,
  storage relocation.

Local customisations — MCP OAuth now COEXISTS with upstream's native flow
(upstream is browser-only; our fork keeps the headless path for containers):
- schema.py: unified auth field to `OAuthConfig | Literal["oauth"] | None`
  ("oauth" -> upstream browser flow; OAuthConfig object -> our headless
  device_code/client_credentials).
- mcp.py: re-applied _resolve_oauth_token bearer injection inside upstream's new
  open_single_server, selected by auth-type; upstream's oauth_auth httpx.Auth
  handles the "oauth" marker. request_headers now also feeds streamableHttp.
- loop.py: _oauth_refresh_loop reads self.tools_config.mcp_servers (post-HKUDS#5343
  self._mcp_servers is gone), gated to isinstance(cfg.auth, OAuthConfig); kept
  our from_config subagent factory + tool_registry param together.
- Dropped orphaned fork reload_single_server (its module-level deps were removed
  by HKUDS#5343); the refresh loop now refreshes tokens on disk and the live session
  picks them up on next reconnect (reactive, matching upstream). Removed its
  two fork tests; fixed test_oauth_refresh_task to use tools_config.
- docker-compose.yml: kept SYS_ADMIN + unconfined apparmor/seccomp for the
  bubblewrap sandbox (upstream's no-new-privileges model breaks bwrap; we run
  as nanobottie via direct USER, not upstream's entrypoint drop).
- conftest.py: kept fork plugin-path setup alongside upstream's session
  isolation fixture. strip_history / web exclusive-timeout / utf-8-sig / mcp_auth
  CLI / plugin channels all preserved.

Verified: ruff clean; host sweep ~4270 passed. One expected Windows-only
failure (test_equivalent_workspace_paths_share_one_store: WinError 1314 on an
unguarded symlink() in a new upstream test — passes on Linux).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
okwillbe pushed a commit to okwillbe/nanobot that referenced this pull request Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p2 Normal backlog: minor bug, enhancement, docs, cleanup, edge case, or unvalidated proposal. refactor test webui

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor dynamic tool provider lifecycle out of AgentLoop

1 participant