Skip to content
This repository was archived by the owner on Oct 27, 2026. It is now read-only.

Commit a7c96cd

Browse files
committed
feat(omp): resolve room-scoped MCP servers at native startup
Source-Base: ae28e96 Source-Head: 8b47f8e Upstream-PR: band-ai#899
1 parent 91981f4 commit a7c96cd

7 files changed

Lines changed: 1526 additions & 28 deletions

File tree

‎docs/acp.md‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,50 @@ negotiate RPC protocol v2 to preserve structured text/image tool results.
349349
enable those receipts without rewriting user settings. Missing or failed
350350
receipts fail startup rather than allowing a model to answer without its
351351
required tools. The enclosing turn timeout still bounds startup.
352+
- **Per-connection MCP servers.** Pass the constructor callable
353+
`resolve_mcp_servers`, an async `(workspace: str) -> Mapping[str, OmpMcpServer]`,
354+
when external servers (or their credentials) can change while the adapter runs.
355+
It is called once for each new room process, with the room's claimed workspace,
356+
before the overlay or process exists; the same result feeds both the overlay and
357+
the startup receipt check. Its result is the room's complete **external** server
358+
set: it replaces every external entry in `mcp_servers` (an empty mapping means
359+
none), and an exception fails that startup with no fallback to them. A `band`
360+
entry in `mcp_servers` is the SDK's own Band endpoint, not an external server: it
361+
is kept beside the resolved set, so Band tools still route through it with
362+
`inject_band_tools=False`. The resolver itself may not return `band`, because OMP
363+
would mint that server's tools under Band tool names. A reused room process never
364+
calls it again; a retired room (cancellation, failure, or cleanup) resolves afresh
365+
on its next start. The callable is runtime-only and never part of
366+
`OmpAdapterConfig`.
367+
- **Room retirement.** `on_cleanup` starts one retirement per room, and overlapping
368+
`on_cleanup` and `cleanup_all` calls join it. The room's active turn is the
369+
current `on_message` call, not the task that made it. A cancellation already
370+
requested when that call starts is delivered at its first step, before anything
371+
is resolved or launched; one its caller had already received and handled does
372+
not stop it. Retirement marks the active turn retired, so nothing it resolves
373+
afterwards can start a process. While the turn is still running, retirement
374+
becomes the cause of its end: it disarms the turn deadline if that has not fired,
375+
so the deadline cannot cancel the turn's settlement again, and cancels the turn
376+
once, or joins a cancellation it is already handling. A turn whose deadline has
377+
fired, or that is already handling its own outcome, keeps its timeout or other
378+
result and its failure report. A fired deadline counts as that cancellation even
379+
if the resolver consumed it with `uncancel()`: cleanup joins it rather than
380+
cancelling again, and a server set the resolver returns afterwards is refused, so
381+
the turn ends with `TimeoutError` and nothing is launched. A turn that has already
382+
finished is never
383+
cancelled, so its caller's later work is untouched. Retirement then waits for
384+
that call's own finalization (not for the rest of its caller's work), and only
385+
then closes the process and releases the workspace. A turn may request cleanup of
386+
its own room, for example from its resolver: that call returns at once, the turn
387+
is not cancelled again but its unfired deadline is disarmed all the same, it stops
388+
before launching, and teardown follows its settlement. Cancelling a cleanup
389+
call stops only that caller's wait. Until the retirement ends, turns already
390+
waiting for the room and turns that arrive during it are cancelled rather than
391+
starting a new process. A later turn starts normally. A room whose native close
392+
fails keeps its process handle, overlay and exclusive workspace claim until a
393+
later close succeeds: `on_cleanup` raises the failure, `cleanup_all` and the
394+
room's next turn retry the close first, and the retiring process never receives
395+
new work.
352396
- **Permissions.** `approval_mode="yolo"` bypasses native approval checks without
353397
changing Band platform permissions. Otherwise `resolve_permission` receives
354398
`OmpPermissionRequest(room_id, session_id, title, options)` and returns an

0 commit comments

Comments
 (0)