Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/agent-bff/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @forestadmin/agent-bff

> [!IMPORTANT]
> Internal building block of the Forest Gateway. For new deployments, use
> [`@forestadmin/gateway`](https://docs.forestadmin.com/product/embed/gateway-standalone). The
> `forest-bff` command keeps working, deprecated: moving to `forest-gateway` serves the API under
> `/api`.

Standalone REST BFF (Backend-For-Frontend) that lets a trusted third-party UI call a Forest
agent from a browser without learning MCP or JSON:API.

Expand Down
10 changes: 9 additions & 1 deletion packages/agent-bff/src/cli-dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Options:

export const HINT = "Run 'forest-bff --help' for usage.";

export const DEPRECATION_WARNING =
'forest-bff is deprecated: it keeps working, but new deployments should run forest-gateway ' +
'(@forestadmin/gateway). Moving changes the API URL to /api: ' +
'https://docs.forestadmin.com/product/embed/gateway-standalone';

const HELP_FLAGS = new Set(['-h', '--help']);
const VERSION_FLAGS = new Set(['-v', '--version']);

Expand All @@ -49,7 +54,10 @@ export default async function dispatchCli(
const [subcommand, ...rest] = argv;

if (subcommand === undefined) {
return { exitCode: 0, server: await runCli(env, logger) };
const bootLogger = logger ?? createConsoleLogger();
bootLogger('Warn', DEPRECATION_WARNING);

return { exitCode: 0, server: await runCli(env, bootLogger) };
}

if (HELP_FLAGS.has(subcommand)) {
Expand Down
38 changes: 37 additions & 1 deletion packages/agent-bff/test/openapi/openapi-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import { tmpdir } from 'os';
import path from 'path';
import request from 'supertest';

import dispatchCli, { DEFAULT_OUTPUT_FILE, HINT, USAGE } from '../../src/cli-dispatch';
import dispatchCli, {
DEFAULT_OUTPUT_FILE,
DEPRECATION_WARNING,
HINT,
USAGE,
} from '../../src/cli-dispatch';
import { issueBffAccessToken } from '../../src/oauth/bff-token';
import { OPENAPI_PATH } from '../../src/openapi/openapi-routes';
import renderOpenApi from '../../src/openapi/render-openapi';
Expand Down Expand Up @@ -394,6 +399,37 @@ describe('dispatchCli', () => {
await outcome.server?.stop();
}
});

it('should warn once that forest-bff is deprecated in favor of forest-gateway', async () => {
const logger = jest.fn();
const outcome = await dispatchCli([], VALID_ENV, logger);

try {
const deprecations = logger.mock.calls.filter(([, message]) =>
String(message).includes('deprecated'),
);

expect(deprecations).toEqual([['Warn', DEPRECATION_WARNING]]);
expect(DEPRECATION_WARNING).toContain('forest-gateway');
} finally {
await outcome.server?.stop();
}
});
});

describe('when the openapi subcommand runs', () => {
it('should not warn about the deprecation, since it serves nothing', async () => {
const stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
const logger = jest.fn();

try {
await dispatchCli(['openapi'], {}, logger);

expect(logger).not.toHaveBeenCalledWith('Warn', DEPRECATION_WARNING);
} finally {
stdout.mockRestore();
}
});
});

describe.each([
Expand Down
5 changes: 5 additions & 0 deletions packages/mcp-server/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# @forestadmin/mcp-server

> [!IMPORTANT]
> Internal building block of the Forest Gateway. For new deployments, use
> [`@forestadmin/gateway`](https://docs.forestadmin.com/product/embed/gateway-standalone). The
> `forest-mcp-server` command keeps working, deprecated.

Model Context Protocol (MCP) server for Forest Admin with OAuth authentication support.

## Overview
Expand Down
7 changes: 7 additions & 0 deletions packages/mcp-server/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import parseMcpEnv from './mcp-env';
import ForestMCPServer from './server';
import loadFileUploads from './utils/load-file-uploads';

const DEPRECATION_WARNING =
'forest-mcp-server is deprecated: it keeps working, but new deployments should run ' +
'forest-gateway (@forestadmin/gateway): ' +
'https://docs.forestadmin.com/product/embed/gateway-standalone';

async function main() {
console.warn(DEPRECATION_WARNING);

const { options, uploadStorageModule } = parseMcpEnv(process.env);
const fileUploads = await loadFileUploads(uploadStorageModule);

Expand Down
14 changes: 14 additions & 0 deletions packages/mcp-server/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ describe('forest-mcp-server', () => {
expect(Server.mock.results[0].value.run).toHaveBeenCalledWith();
});

it('warns once that it is deprecated in favor of forest-gateway', async () => {
const consoleWarn = jest.spyOn(console, 'warn').mockImplementation();

await startCli({});

const deprecations = consoleWarn.mock.calls.filter(([message]) =>
String(message).includes('deprecated'),
);

expect(deprecations).toHaveLength(1);
expect(deprecations[0][0]).toContain('forest-mcp-server is deprecated');
expect(deprecations[0][0]).toContain('forest-gateway');
});

it("passes fileUploads: false on FOREST_MCP_FILE_UPLOADS='false', module or not", async () => {
const { Server } = await startCli({
FOREST_MCP_FILE_UPLOADS: 'false',
Expand Down
Loading