Skip to content

fix(mcp): multi-agent session, resource routing, and bridge parity#86

Merged
khaliqgant merged 5 commits intomainfrom
multi-session-sub-agent-registration
Mar 15, 2026
Merged

fix(mcp): multi-agent session, resource routing, and bridge parity#86
khaliqgant merged 5 commits intomainfrom
multi-session-sub-agent-registration

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

@khaliqgant khaliqgant commented Mar 14, 2026

Summary

  • Multi-agent routing now supports per-request workspace + as overrides for resources and piggyback, without changing legacy resource URIs.
  • WsBridge lifecycle is preserved across same-workspace agent token rotations (no second WsClient), while cross-workspace changes recreate the bridge.
  • Resource subscription behavior remains on literal relay:// URIs to preserve MCP compatibility.
  • Added routing/bridge/resource parity tests and fixed unknown-agent validation for routed as.

Verification

  • npx vitest run packages/mcp/src/tests/resource-definitions.test.ts
  • npx vitest run packages/mcp/src/tests/multi-agent-bridge.test.ts packages/mcp/src/tests/multi-agent-piggyback.test.ts packages/mcp/src/tests/multi-agent-session.test.ts packages/mcp/src/tests/multi-agent-integration.test.ts packages/mcp/src/tests/server-multi-workspace.test.ts
  • npm test (packages/mcp)
  • npm run lint (packages/mcp)

Open with Devin

@github-actions
Copy link
Copy Markdown

Preview deployed!

Environment URL
API https://pr86-api.relaycast.dev
Health https://pr86-api.relaycast.dev/health
Observer https://pr86-observer.relaycast.dev/observer

This preview shares the staging database and will be cleaned up when the PR is merged or closed.

Run E2E tests

npm run e2e -- https://pr86-api.relaycast.dev --ci

Open observer dashboard

https://pr86-observer.relaycast.dev/observer

@khaliqgant
Copy link
Copy Markdown
Member Author

Basically allows sub agents to communicate independently via relaycast

@khaliqgant khaliqgant merged commit bab2ebe into main Mar 15, 2026
4 checks passed
@khaliqgant khaliqgant deleted the multi-session-sub-agent-registration branch March 15, 2026 09:43
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 11 additional findings in Devin Review.

Open in Devin Review

Comment on lines +71 to +75
try {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Bootstrap timed out after ${timeoutMs}ms`)), timeoutMs),
);
return await Promise.race([doBootstrap(), timeout]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Timer leak in bootstrapOneWorkspace prevents clean event loop drain

When doBootstrap() resolves before the timeout, the setTimeout timer created for the timeout promise at packages/mcp/src/transports.ts:72-74 is never cleared. The timer remains active, holding a ref on the Node.js event loop for up to timeoutMs (default 5 seconds). Since bootstrapWorkspaces runs all workspaces concurrently via Promise.allSettled (packages/mcp/src/transports.ts:96-98), up to N lingering timers can accumulate. When the timers eventually fire, they call reject() on an already-settled promise (a no-op), but until that point they prevent graceful process shutdown and consume memory for the timer reference and its closure.

Suggested change
try {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Bootstrap timed out after ${timeoutMs}ms`)), timeoutMs),
);
return await Promise.race([doBootstrap(), timeout]);
try {
let timer: ReturnType<typeof setTimeout>;
const timeout = new Promise<never>((_, reject) => {
timer = setTimeout(() => reject(new Error(`Bootstrap timed out after ${timeoutMs}ms`)), timeoutMs);
});
const result = await Promise.race([doBootstrap(), timeout]);
clearTimeout(timer!);
return result;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

khaliqgant added a commit that referenced this pull request Mar 15, 2026
When doBootstrap() resolves before the timeout, the setTimeout timer
was never cleared, holding a ref on the event loop and preventing
clean shutdown. Now clears the timer on success.

Addresses Devin review on PR #86.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant