From a6c49eae2eb4e876acddbc85d8737ec8db15ba6f Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 6 Jul 2026 15:02:07 +0200 Subject: [PATCH 1/5] docs(mcp-server): document basePath option and host OAuth collision The embedded MCP server registers its OAuth and .well-known routes at the host root, which shadows a host app's own OAuth routes. Document the new mountAiMcpServer({ basePath }) option that scopes every MCP route under a prefix, with a warning on the collision and its resolution. Co-Authored-By: Claude Opus 4.8 (1M context) --- product/embed/mcp-server.mdx | 12 ++++++++++++ reference/agent-api/nodejs.mdx | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx index 54169f6..7a38572 100644 --- a/product/embed/mcp-server.mdx +++ b/product/embed/mcp-server.mdx @@ -84,6 +84,18 @@ Your Forest MCP Server URL will be `{your-agent-url}/mcp` Note that each Environment has its own Back-end URL, and therefore its own Forest MCP Server URL. + + When mounted, the MCP server registers its OAuth and `.well-known` routes at your back-end's root, including `/oauth/authorize`, `/oauth/token` and `/.well-known/*`. **If your back-end already serves its own OAuth or `.well-known` routes, they will be shadowed and break.** + + Pass a `basePath` to move every MCP route under a dedicated prefix so both coexist: + + ```text + const agent = createAgent(options).addDataSource(/* ... */).mountAiMcpServer({ basePath: '/ai' }); + ``` + + Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. + + # Available tools The Forest MCP server exposes the following capabilities: diff --git a/reference/agent-api/nodejs.mdx b/reference/agent-api/nodejs.mdx index b9c12dd..57d9b7c 100644 --- a/reference/agent-api/nodejs.mdx +++ b/reference/agent-api/nodejs.mdx @@ -250,6 +250,7 @@ Enable a Model Context Protocol (MCP) server on the agent, allowing AI assistant ```typescript agent.mountAiMcpServer(options?: { enabledTools?: ToolName[]; + basePath?: string; }): Agent; ``` @@ -258,6 +259,7 @@ agent.mountAiMcpServer(options?: { | Option | Type | Description | |--------|------|-------------| | `enabledTools` | `ToolName[]` | Restrict which MCP tools are exposed. Defaults to all tools. | +| `basePath` | `string` | Path prefix under which all MCP routes are mounted (e.g. `'/ai'`). Defaults to the host root. | **Available tool names:** `'describeCollection'`, `'list'`, `'listRelated'`, `'create'`, `'update'`, `'delete'`, `'associate'`, `'dissociate'`, `'getActionForm'`, `'executeAction'` @@ -269,14 +271,41 @@ agent.mountAiMcpServer({ }); ``` -The MCP server exposes HTTP endpoints for OAuth and protocol communication: +By default, the MCP server registers its endpoints at the host root: | Endpoint | Purpose | |----------|---------| | `POST /mcp` | Main MCP protocol endpoint (Bearer token required) | | `POST /oauth/authorize` | OAuth authorization | | `POST /oauth/token` | Token exchange | -| `GET /.well-known/oauth-protected-resource/mcp` | OAuth discovery | +| `GET /.well-known/oauth-authorization-server` | Authorization server metadata | +| `GET /.well-known/oauth-protected-resource/mcp` | Protected resource metadata | + + +When mounted inside an existing application, the MCP server takes over the `/oauth/authorize`, `/oauth/token` and `/.well-known/*` routes at the host root. **If your application already serves its own OAuth or `.well-known` routes, they will be shadowed and break.** Set `basePath` to move every MCP route under a dedicated prefix so the two coexist. + + +**Scoping under a prefix:** + +```typescript +agent.mountAiMcpServer({ basePath: '/ai' }); +``` + +With `basePath: '/ai'`, every route moves under the prefix, leaving your application's own routes untouched: + +| Endpoint | Purpose | +|----------|---------| +| `POST /ai/mcp` | Main MCP protocol endpoint | +| `POST /ai/oauth/authorize` | OAuth authorization | +| `POST /ai/oauth/token` | Token exchange | +| `GET /.well-known/oauth-authorization-server/ai` | Authorization server metadata | +| `GET /.well-known/oauth-protected-resource/ai/mcp` | Protected resource metadata | + +MCP clients discover these endpoints automatically from the metadata, so no client-side configuration is needed. + + +The prefix applies to **all** routes, including the protocol endpoint — so `basePath: '/mcp'` yields `/mcp/mcp`. Use a distinct prefix such as `/ai` to avoid the repetition. + You can also configure enabled tools via the `FOREST_MCP_ENABLED_TOOLS` environment variable (comma-separated tool names), or set the server port with `MCP_SERVER_PORT` (default: `3931`). From 28cc49e1f1bf63e3467b1575d9f6379e7f03aaa8 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 6 Jul 2026 15:14:22 +0200 Subject: [PATCH 2/5] docs(mcp-server): correct how basePath handles .well-known routes The prior wording implied basePath moves the .well-known routes under the prefix. Per OAuth discovery (RFC 8414/9728) those metadata documents stay at the host root and are only prefix-suffixed (e.g. /.well-known/oauth-authorization-server/ai), which is what avoids the collision with a host app's own root .well-known routes. Co-Authored-By: Claude Opus 4.8 (1M context) --- product/embed/mcp-server.mdx | 4 ++-- reference/agent-api/nodejs.mdx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx index 7a38572..1e02dba 100644 --- a/product/embed/mcp-server.mdx +++ b/product/embed/mcp-server.mdx @@ -85,9 +85,9 @@ Your Forest MCP Server URL will be `{your-agent-url}/mcp` - When mounted, the MCP server registers its OAuth and `.well-known` routes at your back-end's root, including `/oauth/authorize`, `/oauth/token` and `/.well-known/*`. **If your back-end already serves its own OAuth or `.well-known` routes, they will be shadowed and break.** + When mounted, the MCP server registers its OAuth and `.well-known` routes at your back-end's root, including `/oauth/authorize`, `/oauth/token`, `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource/mcp`. **If your back-end already serves its own OAuth or matching `.well-known` routes, they will be shadowed and break.** - Pass a `basePath` to move every MCP route under a dedicated prefix so both coexist: + Pass a `basePath` to scope the MCP routes under a dedicated prefix so both coexist. The OAuth and protocol routes move under the prefix; the `.well-known` discovery documents stay at the root (as OAuth discovery requires) but are served at prefix-suffixed paths such as `/.well-known/oauth-authorization-server/ai`, so they no longer collide with your own root `.well-known` routes: ```text const agent = createAgent(options).addDataSource(/* ... */).mountAiMcpServer({ basePath: '/ai' }); diff --git a/reference/agent-api/nodejs.mdx b/reference/agent-api/nodejs.mdx index 57d9b7c..6754416 100644 --- a/reference/agent-api/nodejs.mdx +++ b/reference/agent-api/nodejs.mdx @@ -282,7 +282,7 @@ By default, the MCP server registers its endpoints at the host root: | `GET /.well-known/oauth-protected-resource/mcp` | Protected resource metadata | -When mounted inside an existing application, the MCP server takes over the `/oauth/authorize`, `/oauth/token` and `/.well-known/*` routes at the host root. **If your application already serves its own OAuth or `.well-known` routes, they will be shadowed and break.** Set `basePath` to move every MCP route under a dedicated prefix so the two coexist. +When mounted inside an existing application, the MCP server takes over the `/oauth/authorize`, `/oauth/token`, `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource/mcp` routes at the host root. **If your application already serves its own OAuth or matching `.well-known` routes, they will be shadowed and break.** Set `basePath` to scope the MCP routes under a dedicated prefix so the two coexist. **Scoping under a prefix:** @@ -291,15 +291,15 @@ When mounted inside an existing application, the MCP server takes over the `/oau agent.mountAiMcpServer({ basePath: '/ai' }); ``` -With `basePath: '/ai'`, every route moves under the prefix, leaving your application's own routes untouched: +With `basePath: '/ai'`, the OAuth and protocol routes move under the prefix. The `.well-known` discovery documents stay at the host root (as required by OAuth discovery, RFC 8414/9728) but are served at prefix-suffixed paths, so they no longer collide with your application's own root `.well-known` routes: | Endpoint | Purpose | |----------|---------| | `POST /ai/mcp` | Main MCP protocol endpoint | | `POST /ai/oauth/authorize` | OAuth authorization | | `POST /ai/oauth/token` | Token exchange | -| `GET /.well-known/oauth-authorization-server/ai` | Authorization server metadata | -| `GET /.well-known/oauth-protected-resource/ai/mcp` | Protected resource metadata | +| `GET /.well-known/oauth-authorization-server/ai` | Authorization server metadata (root, prefix-suffixed) | +| `GET /.well-known/oauth-protected-resource/ai/mcp` | Protected resource metadata (root, prefix-suffixed) | MCP clients discover these endpoints automatically from the metadata, so no client-side configuration is needed. From 68461910500368fda78e228d51510d0b8ba2bf8b Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 6 Jul 2026 15:35:01 +0200 Subject: [PATCH 3/5] docs(mcp-server): note basePath requires the agent at the domain root OAuth discovery must be served at the origin root, so the code now rejects a basePath when the agent's base URL has a path. Document that constraint. Co-Authored-By: Claude Opus 4.8 (1M context) --- product/embed/mcp-server.mdx | 2 +- reference/agent-api/nodejs.mdx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx index 1e02dba..62791cb 100644 --- a/product/embed/mcp-server.mdx +++ b/product/embed/mcp-server.mdx @@ -93,7 +93,7 @@ Your Forest MCP Server URL will be `{your-agent-url}/mcp` const agent = createAgent(options).addDataSource(/* ... */).mountAiMcpServer({ basePath: '/ai' }); ``` - Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. + Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. Because OAuth discovery must stay at the origin root, `basePath` requires your agent to be served at the domain root (it throws at startup if the agent URL already includes a path). # Available tools diff --git a/reference/agent-api/nodejs.mdx b/reference/agent-api/nodejs.mdx index 6754416..da5fb36 100644 --- a/reference/agent-api/nodejs.mdx +++ b/reference/agent-api/nodejs.mdx @@ -307,6 +307,10 @@ MCP clients discover these endpoints automatically from the metadata, so no clie The prefix applies to **all** routes, including the protocol endpoint — so `basePath: '/mcp'` yields `/mcp/mcp`. Use a distinct prefix such as `/ai` to avoid the repetition. + +Because the `.well-known` discovery documents must stay at the origin root, `basePath` requires the agent to be served at the **domain root**. If your agent's URL already includes a path (e.g. `https://host/api`), setting `basePath` throws at startup. + + You can also configure enabled tools via the `FOREST_MCP_ENABLED_TOOLS` environment variable (comma-separated tool names), or set the server port with `MCP_SERVER_PORT` (default: `3931`). --- From 40fd79fc3cc056d32c8dbaa9503769b1fbb950f2 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 6 Jul 2026 15:48:14 +0200 Subject: [PATCH 4/5] docs(mcp-server): note the basePath prefix-doubling on the product page Document the /mcp/mcp repetition (prefix applies to the protocol endpoint too) on the embed page, and tighten the basePath param description now that .well-known routes are not moved under the prefix. Co-Authored-By: Claude Opus 4.8 (1M context) --- product/embed/mcp-server.mdx | 2 ++ reference/agent-api/nodejs.mdx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx index 62791cb..e6fddba 100644 --- a/product/embed/mcp-server.mdx +++ b/product/embed/mcp-server.mdx @@ -94,6 +94,8 @@ Your Forest MCP Server URL will be `{your-agent-url}/mcp` ``` Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. Because OAuth discovery must stay at the origin root, `basePath` requires your agent to be served at the domain root (it throws at startup if the agent URL already includes a path). + + The prefix applies to every route, including the protocol endpoint — so `basePath: '/mcp'` would make the endpoint `/mcp/mcp`. Prefer a distinct prefix such as `/ai` to avoid the repetition. # Available tools diff --git a/reference/agent-api/nodejs.mdx b/reference/agent-api/nodejs.mdx index da5fb36..746c47c 100644 --- a/reference/agent-api/nodejs.mdx +++ b/reference/agent-api/nodejs.mdx @@ -259,7 +259,7 @@ agent.mountAiMcpServer(options?: { | Option | Type | Description | |--------|------|-------------| | `enabledTools` | `ToolName[]` | Restrict which MCP tools are exposed. Defaults to all tools. | -| `basePath` | `string` | Path prefix under which all MCP routes are mounted (e.g. `'/ai'`). Defaults to the host root. | +| `basePath` | `string` | Path prefix under which the MCP OAuth and protocol routes are mounted (e.g. `'/ai'`). Defaults to the host root. | **Available tool names:** `'describeCollection'`, `'list'`, `'listRelated'`, `'create'`, `'update'`, `'delete'`, `'associate'`, `'dissociate'`, `'getActionForm'`, `'executeAction'` From 7750b432e9655898efb997f84a8f3e6ad2ed3883 Mon Sep 17 00:00:00 2001 From: alban bertolini Date: Mon, 6 Jul 2026 16:03:04 +0200 Subject: [PATCH 5/5] docs(mcp-server): sharpen default-mode blast radius and basePath caveats - State that default mode claims the entire /oauth/* and /.well-known/* namespaces (captured-but-unserved routes 404/405 instead of falling through). - Mark the authorization endpoint as GET, POST (browser redirect flow). - Note that root /.well-known/* must still reach the agent behind a proxy. - Clarify the basePath param description (discovery stays at origin root). Co-Authored-By: Claude Opus 4.8 (1M context) --- product/embed/mcp-server.mdx | 6 +++--- reference/agent-api/nodejs.mdx | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/product/embed/mcp-server.mdx b/product/embed/mcp-server.mdx index e6fddba..960056c 100644 --- a/product/embed/mcp-server.mdx +++ b/product/embed/mcp-server.mdx @@ -85,15 +85,15 @@ Your Forest MCP Server URL will be `{your-agent-url}/mcp` - When mounted, the MCP server registers its OAuth and `.well-known` routes at your back-end's root, including `/oauth/authorize`, `/oauth/token`, `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource/mcp`. **If your back-end already serves its own OAuth or matching `.well-known` routes, they will be shadowed and break.** + When mounted, the MCP server intercepts the **entire** `/oauth/*` and `/.well-known/*` namespaces plus `/mcp` at your back-end's root. Any request in those namespaces is captured by the MCP server — if it doesn't serve that exact route (or your back-end already does), the request gets a 404/405 **instead of reaching your back-end**. So your own `/oauth/callback` or `/.well-known/apple-app-site-association` would break, not just OAuth. - Pass a `basePath` to scope the MCP routes under a dedicated prefix so both coexist. The OAuth and protocol routes move under the prefix; the `.well-known` discovery documents stay at the root (as OAuth discovery requires) but are served at prefix-suffixed paths such as `/.well-known/oauth-authorization-server/ai`, so they no longer collide with your own root `.well-known` routes: + Pass a `basePath` to narrow the MCP server to a dedicated prefix so your routes are left untouched. The OAuth and protocol routes move under the prefix; the `.well-known` discovery documents stay at the root (as OAuth discovery requires) but are served at prefix-suffixed paths such as `/.well-known/oauth-authorization-server/ai`, narrowing the `.well-known` claim to just those two paths: ```text const agent = createAgent(options).addDataSource(/* ... */).mountAiMcpServer({ basePath: '/ai' }); ``` - Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. Because OAuth discovery must stay at the origin root, `basePath` requires your agent to be served at the domain root (it throws at startup if the agent URL already includes a path). + Your Forest MCP Server URL then becomes `{your-agent-url}/ai/mcp`. Because OAuth discovery must stay at the origin root, `basePath` requires your agent to be served at the domain root (it throws at startup if the agent URL already includes a path), and root `/.well-known/*` requests must still reach the agent. The prefix applies to every route, including the protocol endpoint — so `basePath: '/mcp'` would make the endpoint `/mcp/mcp`. Prefer a distinct prefix such as `/ai` to avoid the repetition. diff --git a/reference/agent-api/nodejs.mdx b/reference/agent-api/nodejs.mdx index 746c47c..140cf6d 100644 --- a/reference/agent-api/nodejs.mdx +++ b/reference/agent-api/nodejs.mdx @@ -259,7 +259,7 @@ agent.mountAiMcpServer(options?: { | Option | Type | Description | |--------|------|-------------| | `enabledTools` | `ToolName[]` | Restrict which MCP tools are exposed. Defaults to all tools. | -| `basePath` | `string` | Path prefix under which the MCP OAuth and protocol routes are mounted (e.g. `'/ai'`). Defaults to the host root. | +| `basePath` | `string` | Path prefix for the MCP OAuth and protocol routes (e.g. `'/ai'`); the `.well-known` discovery documents stay at the origin root (prefix-suffixed). Requires the agent at the domain root. Defaults to the host root. | **Available tool names:** `'describeCollection'`, `'list'`, `'listRelated'`, `'create'`, `'update'`, `'delete'`, `'associate'`, `'dissociate'`, `'getActionForm'`, `'executeAction'` @@ -276,13 +276,13 @@ By default, the MCP server registers its endpoints at the host root: | Endpoint | Purpose | |----------|---------| | `POST /mcp` | Main MCP protocol endpoint (Bearer token required) | -| `POST /oauth/authorize` | OAuth authorization | +| `GET`, `POST /oauth/authorize` | OAuth authorization | | `POST /oauth/token` | Token exchange | | `GET /.well-known/oauth-authorization-server` | Authorization server metadata | | `GET /.well-known/oauth-protected-resource/mcp` | Protected resource metadata | -When mounted inside an existing application, the MCP server takes over the `/oauth/authorize`, `/oauth/token`, `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource/mcp` routes at the host root. **If your application already serves its own OAuth or matching `.well-known` routes, they will be shadowed and break.** Set `basePath` to scope the MCP routes under a dedicated prefix so the two coexist. +When mounted inside an existing application, the MCP server intercepts the **entire** `/oauth/*` and `/.well-known/*` namespaces plus `/mcp` at the host root. Any request in those namespaces is captured by the MCP server — if it doesn't serve that exact route (or your app already does), the request gets a 404/405 **instead of reaching your app**. For example, your own `/oauth/callback` or `/.well-known/apple-app-site-association` would break, not just OAuth. Set `basePath` to narrow the MCP server to a dedicated prefix (and just two suffixed `.well-known` paths) so your routes are left untouched. **Scoping under a prefix:** @@ -296,7 +296,7 @@ With `basePath: '/ai'`, the OAuth and protocol routes move under the prefix. The | Endpoint | Purpose | |----------|---------| | `POST /ai/mcp` | Main MCP protocol endpoint | -| `POST /ai/oauth/authorize` | OAuth authorization | +| `GET`, `POST /ai/oauth/authorize` | OAuth authorization | | `POST /ai/oauth/token` | Token exchange | | `GET /.well-known/oauth-authorization-server/ai` | Authorization server metadata (root, prefix-suffixed) | | `GET /.well-known/oauth-protected-resource/ai/mcp` | Protected resource metadata (root, prefix-suffixed) | @@ -308,7 +308,7 @@ The prefix applies to **all** routes, including the protocol endpoint — so `ba -Because the `.well-known` discovery documents must stay at the origin root, `basePath` requires the agent to be served at the **domain root**. If your agent's URL already includes a path (e.g. `https://host/api`), setting `basePath` throws at startup. +Because the `.well-known` discovery documents must stay at the origin root, `basePath` requires the agent to be served at the **domain root**. If your agent's URL already includes a path (e.g. `https://host/api`), setting `basePath` throws at startup. And root `/.well-known/*` requests must still reach the agent — a reverse proxy that forwards only `//*` will break discovery. You can also configure enabled tools via the `FOREST_MCP_ENABLED_TOOLS` environment variable (comma-separated tool names), or set the server port with `MCP_SERVER_PORT` (default: `3931`).