Gadoes is wiring Mike up to outside legal sources

The fork is laying the plumbing for Mike's assistant to pull from external legal databases on demand, not just whatever's loaded at startup.

integrationinfrastructure

Gadoes is building on MCP - the Model Context Protocol, an emerging standard that lets AI assistants talk to outside tools and data sources through a common interface. The new code is the connective tissue: it spins up these source connections only when needed, queues requests so nothing stampedes, retries gracefully when a source flakes, and shuts down cleanly. If a source keeps failing, it gets quietly dropped from what the assistant can reach, and the assistant is told so rather than hallucinating around the gap.

The team also built an in-memory stand-in so this can all be tested without spinning up real source servers - the kind of scaffolding that pays off across every later feature that plugs into it.

So what If you care whether a legal AI can reach into your firm's own systems - case law subscriptions, document stores, matter databases - this is the layer that decides whether that ever feels reliable.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

6 commits from Gadoes/dispumike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
735c9261 Chunk 1: MCP Host Plumbing (fix test suite) Gadoes 2026-05-02 ↗ GitHub
commit body
- Fixed StdioClientTransport mock to use class constructor (arrow fn can't be used with `new`)
- Fixed callTool() to catch spawn errors and return structured source_unavailable error
- Fixed afterEach to use resetAllMocks() instead of clearAllMocks() to prevent mockImplementationOnce queue leakage between tests
- Fixed dispose() test to clear mockClose call count before the assertion

All 10 Chunk 1 tests pass.

Acceptance criteria:
[x] listTools() returns at least one tool from a running MCP server
[x] No spawn occurs on second warm call within idle TTL
[x] Child process exit triggers reconnect within 1s (fake timers)
[x] 3 consecutive spawn failures → permanently_failed state
[x] dispose() kills all spawned processes (spy verification)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8af29ffc Chunk 1: MCP host plumbing - McpClientManager lazy-spawn singleton Gadoes 2026-05-02 ↗ GitHub
commit body
- Added spike-mcp-host.ts POC: validates StdioClientTransport + server-filesystem stdio server (14 tools, listTools + callTool both pass)
- Implemented McpClientManager singleton with lazy-spawn, 15-min idle TTL, per-server request queue (max 10), auto-reconnect with exponential backoff, permanently_failed state after 3 failures, and dispose() for SIGTERM/SIGINT cleanup
- Added types.ts with McpServerConfig, McpToolDefinition, McpServerState, McpCallResult, McpHealthResult
- Installed @modelcontextprotocol/server-filesystem, vitest, @vitest/coverage-v8
- All 10 Vitest tests pass (cold-start, warm reuse, idle disposal, reconnect, permanently_failed, queue throttle, dispose, health check)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
da93e2e5 Chunk 2: Mock MCP Server for Tests Gadoes 2026-05-02 ↗ GitHub
commit body
- Created backend/src/__mocks__/mockMcpServer.ts - in-process MCP server
  using @modelcontextprotocol/sdk's InMemoryTransport + Server
- Pre-defined tool set: search_cases, retrieve_case
- respondWith(toolName, response) for scripted responses
- createMockMcpServer() returns started server + connected McpClientManager
- 5 unit tests: scripted responses, listTools, respondWith overrides,
  default responses, unknown tool error

Acceptance criteria:
[x] createMockMcpServer() usable in any Vitest test file without spawning child processes
[x] Returns deterministic responses per respondWith() config

Tests: 15 pass (10 Chunk 1 + 5 Chunk 2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
f4c51b40 Merge Chunk 2: Mock MCP Server for Tests Gadoes 2026-05-02 ↗ GitHub
4f4fdc5d Chunk 3: Tool Registration in Agent Loop Gadoes 2026-05-02 ↗ GitHub
commit body
- Added isMcpTool(), parseMcpToolName(), mcpToolToOpenAI() helpers in chatTools.ts
- Extended runToolCalls() with optional mcpManager param; detects mcp__ prefix
  and dispatches to McpClientManager.callTool()
- Emits mcp_tool_call_start SSE event per MCP tool call
- Extended runLLMStream() with mcpServerTools, openCircuitSources, mcpManager params
- MCP tools appended to activeTools after existing TOOLS and WORKFLOW_TOOLS
- Open-circuit sources excluded from activeTools; unavailability note appended
  to system prompt (spec Section 2.7)
- Active MCP source names and tools listed in system prompt

Acceptance criteria:
[x] LLM emits MCP tool call by prefixed name (mcp__{server}__{tool})
[x] runToolCalls() dispatches to McpClientManager
[x] Tool result returned in { role: "tool", tool_call_id, content } format
[x] mcp_tool_call_start SSE event emitted with correct fields
[x] Open-circuit source tools absent from activeTools

Tests: 24 pass (10+5+9)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3091a892 Merge Chunk 3: Tool Registration in Agent Loop Gadoes 2026-05-02 ↗ GitHub

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-26.md from inside the repo you want the changes in.

⬇ Download capture-thread-26.md