Repository navigation
Conversation
* feat(gateway): serve the MCP and the API on one port Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: lint and test the gateway package Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(gateway): build against the workspace agent-bff and mcp-server Exact pins fall behind the workspace on each release, since a private package is skipped by multi-semantic-release, and Yarn then pulls the published versions instead of linking the local ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp-server): export the listener variables parseMcpEnv reads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(gateway): follow the listener variable names agent-bff and mcp-server own A rename on their side now fails the gateway's typecheck, or carries over through the exported name, instead of silently moving the API's public url and port. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(agent-bff): export the openapi --output handling for other CLIs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(gateway): reuse agent-bff's openapi --output handling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(gateway): read one set of env vars, legacy names as aliases (#1980) * feat(gateway): warn that forest-mcp-server and forest-bff are deprecated (#1990) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(mcp-server): accept a service account credential An fgw_ or fbff_ bearer is resolved on the Forest server with service mcp, cached, and turned into a short-lived agent token. The resolve client lives in forestadmin-client so mcp-server imports nothing from agent-bff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp-server): validate tags and log why a credential resolve failed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(forestadmin-client): keep why a gateway key resolve was unreachable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp-server): sign the service account agent token in the shared claims shape Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: sim <sim@local>
…#1985) * feat(agent-bff): declare the api service and surface the plan refusal * fix(agent-bff): log the plan refusal as expected, with its reason * refactor(agent-bff): extract the session access failure mapping --------- Co-authored-by: sim <sim@local>
13 new issues
|
nbouliol
left a comment
There was a problem hiding this comment.
Spec (PRD-1333, PRD-1334, PRD-1337, PRD-1353, PRD-1354, PRD-1372, PRD-1374): conforms, except the MCP discovery documents not answering 503 while the embedded Gateway starts, inline on gateway.ts:30.
Applies to: the PR as a whole
Claude Opus 5.5 (claude-opus-5-5): Should fix: a reader of addGateway cannot learn why the MCP and the API share one /oauth/* route, and no ADR records it.
Code
Customers register clients against <basePath>/oauth/*?service=api, the code never says why <basePath>/api/oauth/token was turned down, and docs/adr holds no Gateway record.
A way out: run /adr on the shared OAuth route and on addGateway superseding mountAiMcpServer, addBff and forest-bff.
Reproduction
- Read
agent.tsandgateway.tsfor why OAuth is shared across services. - Search
docs/adrfor the Gateway, which returns no record.
| @@ -1,9 +1,12 @@ | |||
| /* eslint-disable @typescript-eslint/no-explicit-any */ | |||
| import type { GatewayServices } from './gateway'; | |||
There was a problem hiding this comment.
Claude Opus 5.5 (claude-opus-5-5): This pull request lands in files that keep accumulating debt, so refactor them, or open a ticket naming each file, before the next feature.
Files
packages/agent/src/agent.ts: 894 lines, 12 commits in 90 days, mixes lifecycle, datasource customization and embedded MCP, BFF and Gateway composition.- Split first: lines 366-625 and 739-793, the embedded-service composition, into its own module.
packages/agent-bff/src/build-bff.ts: 653 lines, 22 commits in 90 days, mixes body guards, the OAuth edge, the API-key edge and agent routes.- Split first: lines 305-552, the agent edge, into its own module.
packages/agent-bff/src/openapi/openapi-document.ts: 705 lines, 18 commits in 90 days, mixes the error-response catalog, the route table and document assembly.- Split first: lines 36-268, the error-response catalog, into its own module.
packages/agent-bff/src/openapi/unfolded-paths.ts: 786 lines, 11 commits in 90 days, mixes filter-schema derivation, request bodies and operation registration.- Split first: lines 106-265, the filter-schema derivation, into its own module.
There was a problem hiding this comment.
Out of scope for the R1 release, which only merges already reviewed changes. Ticketed as PRD-1542, one sub-issue and one PR per file: PRD-1543 (agent.ts embedded-service composition), PRD-1544 (build-bff.ts agent edge), PRD-1545 (openapi-document.ts error catalog), PRD-1546 (unfolded-paths.ts filter-schema derivation). Each is a pure move, starting once this PR is merged.
| export { default as GatewayApiKeyResolveError } from './resolve-error'; | ||
| export type { GatewayApiKeyResolveErrorParams } from './resolve-error'; | ||
|
|
||
| const API_KEY_PATTERN = /^(?:fgw|fbff)_([0-9a-f]{16})_([0-9a-f]{64})$/; |
There was a problem hiding this comment.
Claude Opus 5.5 (claude-opus-5-5): Should fix: the next change to the key format or the resolve contract must land twice, or the API and the MCP accept different credentials.
Code
This file copies the key pattern, RESOLVE_PATH and the error mapping that agent-bff/src/api-key/api-key.ts:3 and api-key-client.ts still own.
A way out: keep forestadmin-client as the single home and have agent-bff's api-key-authenticator.ts consume GatewayApiKeyClient with service: 'api'.
Also moves: agent-bff's tests of api-key-client.ts and api-key.ts, and the hashApiKey copy in gateway-api-key-authenticator.ts:76.
Reproduction
- Add a key prefix to
API_KEY_PATTERNin this file only. - Send a key with that prefix to the Gateway MCP, which resolves it.
- Send the same key to the Gateway API, which answers 401.
There was a problem hiding this comment.
Agreed, and already ticketed: PRD-1409 moves agent-bff's resolve onto GatewayApiKeyClient (single key pattern, resolve path and error mapping, public agent-bff exports kept as re-exports). It was left out of #1944 on purpose (decided 2026-09-30) to keep this release scoped; not fixed in this PR.
There was a problem hiding this comment.
Reopened: the two copies still stand at this head, and PRD-1409 tracks their merge outside this pull request.
How it was checked
Predicate: a key format or resolve contract defined in both forestadmin-client and agent-bff/src/api-key.
API_KEY_PATTERN still sits in both gateway-api-key/index.ts:6 and agent-bff/src/api-key/api-key.ts:3, untouched since the review.
PRD-1409 covers exactly this move, so the thread stays open until it lands or a reviewer accepts the deferral.
|
Review follow-up for the PR-level finding (no ADR for the shared OAuth route): recorded in c0f3658, |
|
Closed: How it was checkedPredicate: a reader who cannot learn why the MCP and the API share |

Merges the Forest Gateway R1 train into
main:addGateway()on the agent, the standalone@forestadmin/gatewaypackage (forest-gateway), service account credentials on the Gateway MCP, and the plan refusal surfaced by agent-bff.fixes PRD-1333
fixes PRD-1334
fixes PRD-1337
fixes PRD-1353
fixes PRD-1354
fixes PRD-1372
fixes PRD-1374
What
Every change below was reviewed and approved in its own PR against
feat/gateway-r1:addGateway()as the single gateway entry pointaddGateway()served through the gateway switchfgw_/fbff_) accepted on the MCP?service=apion token exchanges, plan refusal becomes403 plan_feature_missingmainwas merged into the train beforehand (18dac204b, no conflict). The conflicts of #1944 and #1985 with the train were resolved as unions on their branches.Why
feat, minor) and publishes@forestadmin/gatewayfor the first time.?service=apiis ignored by servers that do not validate the query.How to test
CI of each PR on the train. Locally after the train sync, on the #1944 and #1985 merge results:
Real-stack proof of the service account on the MCP: trust bench
gateway-mcp-sa(merge of #1978 + #1944 against #8575): PASS, baseline without #1944 answers 401.Definition of Done
General
Security
https://claude.ai/code/session_0127TaBC6gYXxGAzzFRRfSt9