feat(mcp): DingDuff connector support — OAuth redirect discovery and chat case retrieval - #331
Open
duncanmcqueen wants to merge 1 commit into
Open
Conversation
Contributor
Author
|
Being a lawyer a bit here (and did accept it), but the CLA says this:
|
… chat case retrieval DingDuff's MCP server 302s its well-known OAuth metadata to a path-scoped issuer, which the MCP SDK's own discovery cannot follow. - guardedFetch now follows redirects hop by hop: each 3xx target is re-validated against the SSRF guard (HTTPS-only, private-IP and metadata-host blocks, DNS-pinned dispatcher), credentials are stripped on cross-origin hops, and redirected POSTs become GETs per the fetch spec. Redirects are never auto-followed by undici (redirect: manual on every hop). - discoverOAuthServerState + the OAuthClientProvider.discoveryState hook hand the SDK pre-discovered metadata, so OAuth connectors whose well-known documents live behind a redirect can complete the flow. - Chat: when DingDuff MCP tools are present on a turn, the built-in CourtListener tools are withheld and the system prompt directs case retrieval, case reading, and document lookup at the DingDuff tools, so the two case-law sources are never mixed in one turn. Rebased onto main. The DingDuff research-tool gating now feeds main's `conversationTools` list (added since this branch was opened for the ask_inputs opt-out) rather than declaring a second `baseTools`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
duncanmcqueen
force-pushed
the
dingduff-mcp-support
branch
from
August 21, 2026 11:29
48f9886 to
6907b93
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for DingDuff as a user MCP connector, so the assistant can use DingDuff tools for case retrieval, case reading, and case-specific document lookup directly from chat.
Two changes make this work:
1. OAuth discovery behind redirects (
backend/src/lib/mcp/client.ts,oauth.ts)DingDuff's server 302s its well-known OAuth metadata to a path-scoped issuer, and the MCP SDK's own discovery does not follow redirects, so the OAuth flow could not complete.
guardedFetchnow follows redirects hop by hop instead of refusing them outright: every 3xx target is re-validated against the existing SSRF guard (HTTPS-only, private-IP/metadata-host blocks, DNS-pinned dispatcher), credentials are stripped on cross-origin hops (per the fetch spec), and redirected POSTs are converted to GET with the body dropped. Undici still never auto-follows (redirect: "manual"on every hop), so no redirect can smuggle egress past the guard.discoverOAuthServerStateplus the SDK'sOAuthClientProvider.discoveryStatehook hand the SDK pre-discovered metadata, so connectors whose well-known documents live behind a redirect complete the flow.2. Chat integration (
backend/src/lib/chat/streaming.ts)When DingDuff MCP tools are present on a turn, the built-in CourtListener tools are withheld and the system prompt directs case retrieval at the DingDuff tools, so the two case-law sources are never mixed within a single turn.
Tests
client.ssrf.test.ts: redirect following with per-hop re-validation, refusal to follow a redirect to a blocked address, credential stripping on cross-origin redirects, and POST→GET conversion.tsc --noEmitclean.Rebased onto current main
Re-verified that all three pieces are still needed — none has landed upstream in the meantime:
guardedFetchstill setsredirect: "manual"with no hop-following,oauth.tshas nodiscoveryState/discoverOAuthServerState, andstreaming.tshas no DingDuff handling.One conflict needed resolving beyond the textual merge.
mainhas since introducedincludeAskInputs/conversationTools, which declares its ownbaseTools; this branch declared a second one. The DingDuff contribution here is really theresearchToolsgate, and main's line already consumes that, so the duplicate declaration is dropped and the gate feeds main'sconversationToolslist.Notes