Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
7851749
feat(mcp-server): add listWorkflows tool (PRD-736) (#1771)
christophebrun-forest Jul 24, 2026
2884a04
feat(mcp-server): add triggerWorkflow tool (PRD-738) (#1777)
christophebrun-forest Jul 27, 2026
104b719
fix(workflow-executor): accept triggerType='mcp' in run mapper (PRD-8…
christophebrun-forest Jul 28, 2026
71eea4a
feat(mcp-server): add getWorkflowRun tool (PRD-740) (#1785)
christophebrun-forest Jul 29, 2026
1f4b2c3
fix(forestadmin-client): normalize workflow run id to a string
christophebrun-forest Aug 5, 2026
a4d3949
perf(mcp-server): trigger workflow by id instead of listing all workf…
christophebrun-forest Aug 6, 2026
de2872b
feat(mcp-server): expose the full hydrated workflow run in getWorkflo…
christophebrun-forest Aug 10, 2026
2255f13
test(mcp-server): align mock ForestServerClient default run with Hydr…
christophebrun-forest Aug 10, 2026
0ecd716
feat(mcp-server): make triggerWorkflow audit fail-closed via O(1) wor…
christophebrun-forest Aug 11, 2026
1e988e2
fix(mcp-server): reject empty workflow args and add polling guidance …
christophebrun-forest Aug 11, 2026
29a4cf1
fix(mcp-server): fail closed on null activity-log id and annotate tri…
christophebrun-forest Aug 11, 2026
7f60f45
fix(forestadmin-client): append workflowsService at the end of the cl…
christophebrun-forest Aug 11, 2026
1c30c76
fix(mcp-server): reject workflows without a collection at trigger tim…
christophebrun-forest Aug 12, 2026
bbc329e
docs(forestadmin-client): drop the O(1) claim from the mcp workflow l…
christophebrun-forest Aug 12, 2026
5027916
test(forestadmin-client): surface 409 conflict detail through ServerU…
christophebrun-forest Aug 12, 2026
4aa57c6
fix(mcp-server): mark triggerWorkflow as destructive in tool annotati…
christophebrun-forest Aug 12, 2026
bdc8208
fix(mcp-server): scope the fail-closed audit guard to write actions (…
christophebrun-forest Aug 17, 2026
ecb3125
fix(mcp-server): label the MCP-side trigger audit row via MCP (PRD-49)
christophebrun-forest Aug 17, 2026
0cdbcce
refactor(forestadmin-client): drop workflowName/collectionName from t…
christophebrun-forest Aug 17, 2026
1ce50dc
docs(forestadmin-client): hedge the hydrated-run customer-data claim …
christophebrun-forest Aug 17, 2026
ade72f8
refactor(forestadmin-client): factor the workflow transport guards (P…
christophebrun-forest Aug 17, 2026
d8ceca4
test(mcp-server): pin auth-context extraction directly (PRD-49)
christophebrun-forest Aug 17, 2026
0a9f2e2
docs(mcp-server): tighten review-fix comments (PRD-49)
christophebrun-forest Aug 17, 2026
e97b498
fix(mcp-server): arbitrate a rejected audit log by action type (PRD-49)
christophebrun-forest Aug 18, 2026
7052c54
fix(mcp-server): stop a missing lookup route from looping the assista…
christophebrun-forest Aug 18, 2026
790b913
Merge remote-tracking branch 'origin/main' into feature/prd-49-expose…
christophebrun-forest Aug 18, 2026
9ec10b7
fix(mcp-server): hide untriggerable workflows from listWorkflows (PRD…
christophebrun-forest Aug 18, 2026
80b6b78
fix(forestadmin-client): stamp the MCP source header on the MCP-only …
christophebrun-forest Aug 18, 2026
2be4504
fix(mcp-server): bound recordId to the server column width (PRD-49)
christophebrun-forest Aug 18, 2026
a3b04ef
refactor(mcp-server): address the review nits (PRD-49)
christophebrun-forest Aug 18, 2026
23b878b
test(mcp-server): cover the skipped status update on a missing token …
christophebrun-forest Aug 18, 2026
18c954b
fix(mcp-server): propagate an authorization refusal on the read path …
christophebrun-forest Aug 19, 2026
4318495
fix(forestadmin-client): project the workflow listing and each step c…
christophebrun-forest Aug 19, 2026
1337700
fix(mcp-server): keep transport detail out of the model's context (PR…
christophebrun-forest Aug 19, 2026
1f6decf
test(mcp-server): pin that the three workflow tools are registered (P…
christophebrun-forest Aug 19, 2026
8d834c4
fix(mcp-server): align the collectionName guard with triggerWorkflow …
christophebrun-forest Aug 19, 2026
b0aac65
docs(mcp-server): correct the notes the workflow tools invalidated (P…
christophebrun-forest Aug 19, 2026
edf9721
fix(mcp-server): classify workflow transport failures before a model …
christophebrun-forest Aug 19, 2026
122cf3a
fix(forestadmin-client): project the mcp workflow by-id lookup respon…
christophebrun-forest Aug 19, 2026
caa542c
docs(mcp-server): correct the rationale on the skipped status update …
christophebrun-forest Aug 19, 2026
31976ed
fix(mcp-server): tell the two MCP trigger audit rows apart (PRD-49)
christophebrun-forest Aug 20, 2026
701f523
fix(mcp-server): tell the polling tools when a refusal will repeat (P…
christophebrun-forest Aug 20, 2026
1627c04
docs(mcp-server): list the three workflow tools in the README (PRD-49)
christophebrun-forest Aug 20, 2026
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
29 changes: 29 additions & 0 deletions packages/agent-testing/src/forest-admin-client-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
export default class ForestAdminClientMock implements ForestAdminClient {
readonly chartHandler: ChartHandlerInterface;
readonly contextVariablesInstantiator: ContextVariablesInstantiatorInterface = {
buildContextVariables: () => ({} as any), // TODO: return actual context variables

Check warning on line 47 in packages/agent-testing/src/forest-admin-client-mock.ts

View workflow job for this annotation

GitHub Actions / Linting & Testing (agent-testing)

Unexpected any. Specify a different type
};

readonly modelCustomizationService: ModelCustomizationService;
Expand All @@ -62,8 +62,37 @@
updateActivityLogStatus: () => Promise.resolve(),
};

readonly workflowsService: ForestAdminClient['workflowsService'] = {
listMcpEnabledWorkflows: () => Promise.resolve([]),
getMcpWorkflowById: () =>
Promise.resolve({
workflowId: 'wf-1',
name: 'Refund order',
collectionName: 'orders',
mcpEnabled: true,
}),
triggerMcpWorkflow: () => Promise.resolve({ runId: '1', runState: 'loading' }),
getMcpWorkflowRun: () =>
Promise.resolve({
id: 1,
userId: 1,
renderingId: 1,
collectionId: 'orders',
workflowId: 'wf-1',
bpmnVersion: '1',
selectedRecordId: '1',
runState: 'loading',
engine: 'orchestrator',
triggerType: 'mcp',
lockedAt: null,
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2024-01-01T00:00:00.000Z',
workflowHistory: [],
}),
};

readonly permissionService: any;

Check warning on line 94 in packages/agent-testing/src/forest-admin-client-mock.ts

View workflow job for this annotation

GitHub Actions / Linting & Testing (agent-testing)

Unexpected any. Specify a different type
readonly authService: any;

Check warning on line 95 in packages/agent-testing/src/forest-admin-client-mock.ts

View workflow job for this annotation

GitHub Actions / Linting & Testing (agent-testing)

Unexpected any. Specify a different type

constructor() {
this.permissionService = {
Expand Down
66 changes: 66 additions & 0 deletions packages/agent-testing/test/forest-admin-client-mock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import ForestAdminClientMock from '../src/forest-admin-client-mock';

describe('ForestAdminClientMock', () => {
describe('workflowsService', () => {
it('should resolve an empty list of MCP-enabled workflows', async () => {
const client = new ForestAdminClientMock();

await expect(
client.workflowsService.listMcpEnabledWorkflows({
forestServerToken: 'token',
renderingId: '1',
}),
).resolves.toEqual([]);
});

it('should resolve an mcp-enabled workflow when fetching one by id', async () => {
const client = new ForestAdminClientMock();

await expect(
client.workflowsService.getMcpWorkflowById({
forestServerToken: 'token',
renderingId: '1',
workflowId: 'wf-1',
}),
).resolves.toEqual(
expect.objectContaining({
workflowId: 'wf-1',
mcpEnabled: true,
}),
);
});

it('should resolve a loading run when triggering a workflow', async () => {
const client = new ForestAdminClientMock();

await expect(
client.workflowsService.triggerMcpWorkflow({
forestServerToken: 'token',
renderingId: '1',
workflowId: 'wf-1',
recordId: '42',
}),
).resolves.toEqual({ runId: '1', runState: 'loading' });
});

it('should resolve a loading hydrated run when fetching a workflow run', async () => {
const client = new ForestAdminClientMock();

await expect(
client.workflowsService.getMcpWorkflowRun({
forestServerToken: 'token',
renderingId: '1',
runId: '1',
}),
).resolves.toEqual(
expect.objectContaining({
id: 1,
runState: 'loading',
engine: 'orchestrator',
triggerType: 'mcp',
workflowHistory: [],
}),
);
});
});
});
1 change: 1 addition & 0 deletions packages/agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ export default class Agent<S extends TSchema = TSchema> extends FrameworkMounter
const forestServerClient = new ForestServerClientImpl(
this.options.forestAdminClient.schemaService,
this.options.forestAdminClient.activityLogsService,
this.options.forestAdminClient.workflowsService,
this.options.forestServerUrl,
);

Expand Down
6 changes: 6 additions & 0 deletions packages/agent/test/__factories__/forest-admin-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ const forestAdminClientFactory = ForestAdminClientFactory.define(() => ({
createMcpActivityLog: jest.fn(),
updateActivityLogStatus: jest.fn(),
},
workflowsService: {
listMcpEnabledWorkflows: jest.fn(),
getMcpWorkflowById: jest.fn(),
triggerMcpWorkflow: jest.fn(),
getMcpWorkflowRun: jest.fn(),
},
subscribeToServerEvents: jest.fn(),
close: jest.fn(),
onRefreshCustomizations: jest.fn(),
Expand Down
3 changes: 3 additions & 0 deletions packages/forestadmin-client/src/build-application-services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import UserPermissionService from './permissions/user-permission';
import SchemaService from './schema';
import ContextVariablesInstantiator from './utils/context-variables-instantiator';
import defaultLogger from './utils/default-logger';
import WorkflowsService from './workflows';

export default function buildApplicationServices(
forestAdminServerInterface: ForestAdminServerInterface,
Expand All @@ -31,6 +32,7 @@ export default function buildApplicationServices(
renderingPermission: RenderingPermissionService;
schema: SchemaService;
activityLogs: ActivityLogsService;
workflows: WorkflowsService;
contextVariables: ContextVariablesInstantiator;
ipWhitelist: IpWhiteListService;
permission: PermissionService;
Expand Down Expand Up @@ -89,6 +91,7 @@ export default function buildApplicationServices(
ipWhitelist: new IpWhiteListService(forestAdminServerInterface, optionsWithDefaults),
schema: new SchemaService(forestAdminServerInterface, optionsWithDefaults),
activityLogs: new ActivityLogsService(forestAdminServerInterface, optionsWithDefaults),
workflows: new WorkflowsService(forestAdminServerInterface, optionsWithDefaults),
auth: forestAdminServerInterface.makeAuthService(optionsWithDefaults),
modelCustomizationService: new ModelCustomizationFromApiService(
forestAdminServerInterface,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
PermissionService,
} from './types';
import type ContextVariablesInstantiator from './utils/context-variables-instantiator';
import type WorkflowsService from './workflows';

import verifyAndExtractApproval from './permissions/verify-approval';

Expand All @@ -37,6 +38,7 @@ export default class ForestAdminClientWithCache implements ForestAdminClient {
public readonly mcpServerConfigService: McpServerConfigService,
protected readonly eventsSubscription: BaseEventsSubscriptionService,
protected readonly eventsHandler: RefreshEventsHandlerService,
public readonly workflowsService: WorkflowsService,
) {}

verifySignedActionParameters<TSignedParameters>(signedParameters: string): TSignedParameters {
Expand Down
21 changes: 21 additions & 0 deletions packages/forestadmin-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,26 @@ export {
ActivityLogType,
CreateActivityLogParams,
UpdateActivityLogStatusParams,
McpWorkflow,
McpWorkflowLookup,
ListMcpWorkflowsParams,
GetMcpWorkflowByIdParams,
TriggerMcpWorkflowParams,
GetMcpWorkflowRunParams,
WorkflowRunState,
WorkflowRunEngine,
WorkflowRunTriggerType,
WorkflowStepType,
WorkflowTaskType,
WorkflowStepOutgoing,
WorkflowStepDefinition,
WorkflowHistoryStepContext,
WorkflowHistoryStep,
HydratedWorkflowRun,
WorkflowRunTriggerResult,
// Service interfaces for MCP
ActivityLogsServiceInterface,
WorkflowsServiceInterface,
SchemaServiceInterface,
} from './types';
export { IpWhitelistConfiguration } from './ip-whitelist/types';
Expand Down Expand Up @@ -66,6 +84,7 @@ export default function createForestAdminClient(
ipWhitelist,
schema,
activityLogs,
workflows,
auth,
modelCustomizationService,
mcpServerConfigService,
Expand All @@ -87,6 +106,7 @@ export default function createForestAdminClient(
mcpServerConfigService,
eventsSubscription,
eventsHandler,
workflows,
);
}

Expand All @@ -105,6 +125,7 @@ export { default as ServerUtils } from './utils/server';
// export is necessary for the agent-generator package
export { default as SchemaService, SchemaServiceOptions } from './schema';
export { default as ActivityLogsService, ActivityLogsOptions } from './activity-logs';
export { default as WorkflowsService, WorkflowsServiceOptions } from './workflows';

export * from './auth/errors';
export * from './utils/errors';
Loading
Loading