feat(mcp-server): restrict oauth clients to an allowlist of domains - #1797
Conversation
Dynamic Client Registration lets any OAuth client obtain tokens once a legitimate user signs in; zero-trust customers need to cap which client applications can carry that delegation. Matching uses registered redirect URI domains because self-declared metadata is spoofable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 new issue
|
|
Coverage Impact This PR will not change total coverage. Modified Files with Diff Coverage (5)
🤖 Increase coverage with AI coding...🚦 See full report on Qlty Cloud » 🛟 Help
|
A non-http(s) scheme dispatches the callback to whatever local app registered it, so its hostname says nothing about delivery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude Fable 5 (claude-fable-5): On the qlty High total complexity (count = 56) structure issue — pushing back on addressing it in this PR. The flagged total is file-level complexity on |
Restore the readme's original formatting so the diff carries only the new section and env row, shorten the option doc comment, and pin deep subdomain matching plus verbatim parser pass-through with tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A set-but-garbage env value parsed to "not configured" and silently disabled the allowlist, while malformed entries (scheme, port, blanks, unicode) silently denied or allowed the wrong clients. Entries are now trimmed, punycode-normalized and validated at startup; a configured value with no usable domains fails the boot instead of failing open. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An '@' in an entry made URL parse the lead as userinfo and normalize to the wrong hostname, authorizing an unintended domain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WHATWG URL treats a backslash as a path separator, silently truncating the entry to a broader domain than the administrator supplied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
URL.hostname preserves a terminal dot, which no redirect URI hostname carries, so the entry could never match anything. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# @forestadmin/mcp-server [1.21.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/mcp-server@1.20.3...@forestadmin/mcp-server@1.21.0) (2026-08-06) ### Features * **mcp-server:** restrict oauth clients to an allowlist of domains ([#1797](#1797)) ([ebaeb17](ebaeb17))
# @forestadmin/agent [1.92.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.91.6...@forestadmin/agent@1.92.0) (2026-08-06) ### Features * **mcp-server:** restrict oauth clients to an allowlist of domains ([#1797](#1797)) ([ebaeb17](ebaeb17)) ### Dependencies * **@forestadmin/mcp-server:** upgraded to 1.21.0

Description
Adds an
allowedOAuthClientsoption to the MCP server so administrators can restrict which OAuth client applications may connect. DCR means any client can register and — once a legitimate user signs in — obtain tokens; zero-trust customers asked to cap that to approved clients only (e.g. Dust).agent.mountAiMcpServer({ allowedOAuthClients: ['dust.tt'] })andFOREST_MCP_ALLOWED_OAUTH_CLIENTS(standalone CLI) — both entry points, mirroringtokenTtl/enabledTools.ForestOAuthProvider.clientsStore.getClient(), the single choke point the MCP SDK's authorize and token handlers resolve clients through — covering authorization, code exchange, and refresh with one check and no extra HTTP round trip.client_name/client_uriare ignored.invalid_client(4xx, never a 500, never a redirect to the unvalidated URI) with a targetederror_descriptionthat names no allowed domain; the rejection is logged with client id + URIs for support.Testing
fixes PRD-861
🤖 Generated with Claude Code
Note
Restrict MCP server OAuth clients to an allowlist of domains
allowedOAuthClientsoption toForestMCPServerandForestOAuthProviderthat accepts a list of domains; when set, OAuth clients whose redirect URIs do not match an allowed domain (or subdomain) are rejected with a 400invalid_clienterror.FOREST_MCP_ALLOWED_OAUTH_CLIENTSenvironment variable (comma-separated) in both the standalone CLI (cli.ts) and the example agent (agent.ts).ForestMCPServerwith an explicitly emptyallowedOAuthClientsarray now throws, preventing silent rejection of all clients.Changes since #1797 opened
normalizeDomainListfunction to reject domain entries containing '@', '?', or '#' characters in addition to the existing rejections for '/', ':', and whitespace, preventing incorrect hostname parsing when these URL delimiter characters are present [ad46ed3]normalizeDomainListfunction within themcp-serverpackage [6344645]normalizeDomainListfunction to strip trailing root dots from FQDN-style domain entries and added test coverage [691b6d7]Macroscope summarized 6ff0797.