P0.9.1 — ν MCP Bridge — Verification
Step 5 of the 5-step chain. Test evidence and build evidence for the ν MCP Bridge.
Build evidence
Command: npm run build (from worktree, using main checkout’s node_modules)
Result: PASS — zero new TypeScript errors.
Pre-existing error (unchanged from main, not introduced by this task):
src/domains/proof/merkle.ts(47,28): error TS2307: Cannot find module
'merkletreejs' or its corresponding type declarations.
This is a pre-existing @types gap for merkletreejs (no @types/merkletreejs package).
skipLibCheck: true in tsconfig.json prevents it from failing the compile — but the
diagnostic still shows. Not introduced by this PR. Confirmed identical on main
before this branch.
One deliberate type cast added in mcp-bridge.ts:
return new StreamableHTTPClientTransport(new URL(url)) as unknown as Transport;
Required because StreamableHTTPClientTransport.sessionId is typed as
string | undefined while the Transport interface (under exactOptionalPropertyTypes:
true) expects exactly string. The cast is safe — the runtime behaviour is identical.
Test evidence
Command: node --experimental-vm-modules node_modules/jest/bin/jest.js --no-coverage
Run from: .worktrees/claude/p0-9-1-nu-mcp-bridge/ with node_modules resolved from
E:/AMS/ (worktrees share the main checkout’s node_modules).
mcp-bridge test suite results
Test Suites: 1 passed, 1 total (mcp-bridge.test.ts)
Tests: 24 passed, 24 total
Time: 5.597 s
| Test group | Tests | Status |
|---|---|---|
connectToServer |
5 | PASS |
callTool roundtrip |
3 | PASS |
timeout via COLIBRI_MCP_TIMEOUT |
2 | PASS |
retry on transient errors |
2 | PASS |
non-retryable errors |
2 | PASS |
max retries exhausted |
2 | PASS |
close() |
2 | PASS |
exported constants |
4 | PASS |
McpBridgeError |
2 | PASS |
Full suite results
Test Suites: 21 passed, 21 total
Tests: 934 passed, 934 total
Snapshots: 0 total
Time: 20.511 s
Pre-task baseline (main at 21e199cb): 835+ tests across 20 suites.
Post-task: 934 tests across 21 suites.
New tests added: 24 (mcp-bridge.test.ts).
Regressions: 0.
Acceptance criteria verification
| Criterion | Test | Status |
|---|---|---|
McpBridge wraps outbound MCP client calls |
connectToServer › returns a bridge with a Client instance |
PASS |
connectToServer(url) creates client, returns connected bridge |
connectToServer › returns a bridge with the correct url property + Client instance test |
PASS |
callTool(bridge, name, args) calls remote tool, returns result |
callTool roundtrip › calls the echo tool and returns the correct content (InMemory server) |
PASS |
Timeout: 30s default via COLIBRI_MCP_TIMEOUT |
timeout via COLIBRI_MCP_TIMEOUT › DEFAULT_TIMEOUT_MS is 30000 + env override test |
PASS |
| Retry: 3 attempts with exponential backoff | retry on transient errors › retries on McpError InternalError and succeeds on 3rd attempt + backoff delays test |
PASS |
| Test: mock MCP server → verify roundtrip tool call | callTool roundtrip group (uses InMemoryTransport.createLinkedPair() + McpServer) |
PASS |
Key implementation notes
SDK transport type cast
StreamableHTTPClientTransport from @modelcontextprotocol/sdk declares
sessionId?: string | undefined which is incompatible with Transport’s sessionId: string
under exactOptionalPropertyTypes: true. The cast as unknown as Transport is the correct
escape hatch. This is a known SDK type gap, not a Colibri issue.
McpServer tool error wrapping
The MCP SDK’s McpServer wraps tool handler throws into { isError: true, content: [...] }
responses — NOT into McpError exceptions on the client side. Only UrlElicitationRequired
propagates as an actual protocol error. This means:
- Application-level tool errors (tool handler throws) →
{ isError: true }result, no retry - Transport/network-level errors (McpError from protocol layer, AbortError, TypeError) → retry
The retry tests use a makeFakeBridge() helper that bypasses the SDK’s error wrapping
to inject McpError exceptions directly, correctly simulating transport-level failures.
__setSleep injection
The production _sleep function is module-level and injectable via __setSleep().
This allows retry tests to run instantly (no real 1-3s delays) while still asserting
the correct delay values are computed.
Library-only
No new MCP tool surface was registered in src/server.ts. The bridge exports:
McpBridge(interface)connectToServer(function)callTool(function)McpBridgeError(class)- Constants:
MCP_TIMEOUT_ENV_KEY,DEFAULT_TIMEOUT_MS,DEFAULT_MAX_ATTEMPTS,BACKOFF_BASE_MS
These are available for future consumers (δ Model Router, etc.) via the ν barrel.
Pre-existing flakes
The startup › subprocess smoke test is intermittently flaky (pre-existing, noted by all
Wave F sub-agents). It did not affect this test run.
Files created / modified
| Path | Change |
|---|---|
src/domains/integrations/mcp-bridge.ts |
New: bridge implementation (291 lines) |
src/__tests__/domains/integrations/mcp-bridge.test.ts |
New: 24 tests |
src/config.ts |
Modified: added COLIBRI_MCP_TIMEOUT to Zod schema |
src/domains/integrations/index.ts |
Modified: added export * from './mcp-bridge.js' |
docs/audits/p0-9-1-nu-mcp-bridge-audit.md |
New: Step 1 |
docs/contracts/p0-9-1-nu-mcp-bridge-contract.md |
New: Step 2 |
docs/packets/p0-9-1-nu-mcp-bridge-packet.md |
New: Step 3 |
docs/verification/p0-9-1-nu-mcp-bridge-verification.md |
New: Step 5 (this file) |