Skip to content

feat(mcp-server): claim only the mcp discovery documents under .well-known - #1969

Merged
Tonours merged 3 commits into
mainfrom
hp/gateway-mcp-bff/t-0035-impl-prd-1473-wellknown-root
Oct 6, 2026
Merged

Tonours merged 3 commits into
mainfrom
hp/gateway-mcp-bff/t-0035-impl-prd-1473-wellknown-root

Conversation

@Tonours

@Tonours Tonours commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

The started MCP now claims only its two discovery documents under /.well-known/, so a host app keeps its ACME challenges and security.txt. refs PRD-1473

What

  • Root basePath: the MCP claims /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource/mcp, nothing else under /.well-known/.
  • Prefixed basePath: same rule. Paths under /.well-known/oauth-protected-resource/<prefix>/ other than .../mcp no longer go to the MCP.
  • Observable changes: an unclaimed /.well-known/* path now reaches the host instead of the MCP's 405. Gateway switch without a host next: 404 JSON instead of 405; the standalone forest-mcp-server CLI is unchanged. The bare /.well-known/oauth-protected-resource and openid-configuration fall to the host; the MCP never served them. Double-slash paths on the two documents (.../oauth-authorization-server//, .../oauth-protected-resource/mcp//) answered 200 on main and now fall to the host.
  • MCP_PATHS (public export) changes content: semver-minor.

Why

  • At the root basePath, buildMcpPaths('') returned the /.well-known/ directory, so acme-challenge/<token> and security.txt hit the MCP's allowedMethods(['POST']) and answered 405. Let's Encrypt renewals broke for any host serving the agent at the root while the MCP was up.

How

  • One formula for both modes: oauth-authorization-server${prefix} and oauth-protected-resource${prefix}/mcp, matched by exact pathname (one trailing slash tolerated, nothing after). /oauth/ and /mcp keep their segment-boundary match.
  • No change to the OAuth provider, the server's route mounting, or the PRD-1334 stub windows (feat(agent): serve addGateway() through the gateway switch #1967), which claim nothing under /.well-known/.

Verification

  • Tests: path matrix at root and /ai, gateway-switch rows on '', /ai, /a/b, started getHttpCallback (GET, HEAD, OPTIONS), agent integration on 8 frameworks including Koa. 43 mcp-server and 16 agent tests fail on main, pass here. Suites: mcp-server 1558/1558, agent 1742/1742. eslint and tsc clean.
Check Result
Unit + integration tests (mcp-server, agent) ✅
Independent review: GO WITH NOTES, notes fixed in 3b43886ed ✅
Real-stack e2e on 3b43886ed: PASS, full matrix. 296 responses carry the loaded build's marker, the recompile diff proves which build served them, 88/88 regression lines identical, A/B diff confined to .well-known. Not measured: a base URL with a path and a trailing slash at the root basePath (review F3) ✅
CI on 30ffa70af (main merged in, PR diff unchanged): 29 pass, 3 skipped. Reruns covered a GitHub runner outage and a datasource-mongo test that also flakes on main ✅

Definition of Done

General

  • Write an explicit title for the Pull Request, following Conventional Commits specification
  • Test manually the implemented changes
  • Validate the code quality (indentation, syntax, style, simplicity, readability)

Security

  • Consider the security impact of the changes made

@linear-code

linear-code Bot commented Oct 5, 2026

Copy link
Copy Markdown

PRD-1473

@qltysh

qltysh Bot commented Oct 5, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (1)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/mcp-server/src/mcp-paths.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@nbouliol nbouliol left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Spec (PRD-1473): conforms to all five acceptance criteria.

Applies to: the Forest documentation, product/embed/mcp-server and reference/agent-api/nodejs
Claude Opus 5.5 (claude-opus-5-5): Should fix: once this ships, integrators read that a root-mounted MCP still breaks their own /.well-known/* routes, which stops being true.

Code

Both pages say the mounted MCP intercepts all of /.well-known/*, but mcp-paths.ts:29 now claims only the two discovery documents.

A way out: scope both mountAiMcpServer warnings to /oauth/* and /mcp in a docs change released alongside.

Reproduction
  1. Mount the MCP at the root basePath with this PR.
  2. Request /.well-known/security.txt on the agent and see the host answer it.
  3. Read the mountAiMcpServer warning, which says that request breaks.

@Tonours

Tonours commented Oct 6, 2026

Copy link
Copy Markdown
Member Author

Confirmed, thanks. Both warnings are stale once this ships:

  • product/embed/mcp-server.mdx:115
  • reference/agent-api/nodejs.mdx:316

At the root basePath the MCP now claims /oauth/*, /mcp, and just two .well-known documents: /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource/mcp. The rest of /.well-known/* reaches the host. /oauth/callback still breaks without a basePath.

The fix lives in the docs repo, outside this PR's scope. I've flagged it so a docs change ships alongside this release.

@Tonours

Tonours commented Oct 6, 2026

Copy link
Copy Markdown
Member Author

@nbouliol the PR for the docs is here https://github.com/ForestAdmin/docs/pull/51

@nbouliol

nbouliol commented Oct 6, 2026

Copy link
Copy Markdown
Member

Closed: ForestAdmin/docs#51 scopes both root-mount warnings to /oauth/*, /mcp and the two discovery documents, so merge it with this release.

How it was checked

Predicate: a docs sentence says a root-mounted MCP blocks a .well-known path other than the two discovery documents.
Every .well-known mention in ForestAdmin/docs at 2faf81f68 was read, and none still satisfies it.
No regression test pins this, because docs prose has no test harness.

@nbouliol nbouliol left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved after /verify-fixes run 1969-20261006121628-nbouliol-verify: 1 findings of 1969-20261006082101-nbouliol closed or accepted, none reopened.

@Tonours
Tonours merged commit fb8f000 into main Oct 6, 2026
53 of 61 checks passed
@Tonours
Tonours deleted the hp/gateway-mcp-bff/t-0035-impl-prd-1473-wellknown-root branch October 6, 2026 12:22
forest-bot added a commit that referenced this pull request Oct 6, 2026
# @forestadmin/mcp-server [1.27.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/mcp-server@1.26.0...@forestadmin/mcp-server@1.27.0) (2026-10-06)

### Features

* **mcp-server:** claim only the mcp discovery documents under .well-known ([#1969](#1969)) ([fb8f000](fb8f000))
forest-bot added a commit that referenced this pull request Oct 6, 2026
# @forestadmin/agent [1.106.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent@1.105.6...@forestadmin/agent@1.106.0) (2026-10-06)

### Features

* **mcp-server:** claim only the mcp discovery documents under .well-known ([#1969](#1969)) ([fb8f000](fb8f000))

### Dependencies

* **@forestadmin/mcp-server:** upgraded to 1.27.0
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.

2 participants