Skip to content

feat(mcp-server): expose workflow tools in Forest MCP server (PRD-49) - #1792

Open
christophebrun-forest wants to merge 6 commits into
mainfrom
feature/prd-49-expose-workflow-tools-in-forest-mcp-server
Open

feat(mcp-server): expose workflow tools in Forest MCP server (PRD-49)#1792
christophebrun-forest wants to merge 6 commits into
mainfrom
feature/prd-49-expose-workflow-tools-in-forest-mcp-server

Conversation

@christophebrun-forest

@christophebrun-forest christophebrun-forest commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

Integration branch for the PRD-49 epic — expose Forest workflow triggering to MCP clients. Adds a report-only (v1) toolset so an LLM can list, trigger, and observe Forest workflows through the MCP server.

The MCP tools call into @forestadmin/forestadmin-client (WorkflowsServiceForestHttpApi), which hits the Forest orchestrator (/api/workflow-orchestrator/mcp-workflows/*) under the MCP session identity (forestServerToken, Forest-Application-Source: MCP).

Included work

Behavior (v1, report-only)

  1. listWorkflows → available MCP-enabled workflows
  2. triggerWorkflow{ runId, runState }
  3. getWorkflowRun → poll runState, currentStep, waitingForHumanInput, terminal result/error

A run parked on a human-gated step reports waitingForHumanInput: true; resuming it via MCP is out of scope here and handled in the follow-up PRD-441 (submitWorkflowInput).

Tests

New/updated unit tests across mcp-server, forestadmin-client, workflow-executor, plus cross-package mocks in agent-testing and agent.

fixes PRD-49

🤖 Generated with Claude Code

Note

Add workflow tools (listWorkflows, triggerWorkflow, getWorkflowRun) to the Forest MCP server

  • Registers three new MCP tools in server.ts: listWorkflows, triggerWorkflow, and getWorkflowRun, enabled by default.
  • Adds a WorkflowsService in forestadmin-client that wraps the three corresponding ForestHttpApi endpoints; each method throws if the transport does not implement the operation.
  • triggerWorkflow maps NotFoundError to a user-facing message directing callers to use listWorkflows, and records an activity log entry (failures are caught and warned, not surfaced to the caller).
  • Exposes workflowsService on ForestAdminClient and threads it through ForestAdminClientWithCache, buildApplicationServices, and the agent's ForestServerClientImpl.
  • Adds TriggerType.Mcp and ServerWorkflowTriggerType.mcp to the workflow-executor type enums.

Macroscope summarized a4d3949.

@linear-code

linear-code Bot commented Jul 30, 2026

Copy link
Copy Markdown

PRD-49

@qltysh

qltysh Bot commented Jul 30, 2026

Copy link
Copy Markdown

3 new issues

Tool Category Rule Count
qlty Structure Function with many parameters (count = 14): constructor 3

Comment thread packages/forestadmin-client/src/types.ts Outdated
christophebrun-forest and others added 4 commits August 3, 2026 14:20
Expose MCP-enabled workflows to LLM clients via a new listWorkflows tool,
calling the Forest server MS3 endpoint (GET /api/workflow-orchestrator/workflows)
over the HTTP contract with the caller's forestServerToken + renderingId.

- forestadmin-client: WorkflowsService + ForestHttpApi.listMcpEnabledWorkflows
- mcp-server: listWorkflows tool, http-client wiring, shared getAuthContext util

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(mcp-server): add triggerWorkflow tool (PRD-738)

Expose the triggerWorkflow MCP tool so an LLM can start a run on a
specific record and get a runId back. Non-blocking by design: the run
continues server-side and status is observed via getWorkflowRun (MS8).

- tool args { workflowId, recordId }; identity from the OAuth auth
  context (forestServerToken + renderingId), wrapped in withActivityLog
  so MCP-triggered runs are audited locally under the caller.
- forestadmin-client: WorkflowsService.triggerMcpWorkflow calls the
  MCP-dedicated start endpoint over HTTP
  (POST /api/workflow-orchestrator/workflows/:workflowId/start), no
  private-api internals imported.
- collectionId is derived server-side from the workflow (MS5), so the
  tool contract stays { workflowId, recordId } — consistent with the
  webhook trigger.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…32) (#1786)

MCP-triggered runs carry triggerType='mcp', but the executor only
recognized manual|webhook, so AvailableStepExecutionSchema.parse
rejected every MCP run at step 0 with a DomainValidationError before
executing. triggerType is informational only (logged in runner.ts, no
logic branches on it), so a run was aborted purely over an unrecognized
logged value.

Add 'mcp' to TriggerType and ServerWorkflowTriggerType so MCP runs map
to a valid AvailableStepExecution and execute.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mcp-server): add getWorkflowRun tool (PRD-740)

Expose the getWorkflowRun polling tool so the LLM can observe a run's
status, closing the discover -> trigger -> poll loop. Report-only in v1:
human-gated runs report waitingForHumanInput but cannot be resumed via
MCP (tracked in PRD-441).

Threads a getMcpWorkflowRun call through forestadmin-client (types, HTTP
api, workflows service) to the MS7 read endpoint, and registers a
read-only getWorkflowRun MCP tool scoped to the caller.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@christophebrun-forest
christophebrun-forest force-pushed the feature/prd-49-expose-workflow-tools-in-forest-mcp-server branch from e87448d to 71eea4a Compare August 3, 2026 12:21
@qltysh

qltysh Bot commented Aug 3, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

⬆️ Merging this pull request will increase total coverage on main by 0.1%.

Modified Files with Diff Coverage (16)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/types/validated/execution.ts100.0%
Coverage rating: A Coverage rating: A
packages/mcp-server/src/utils/activity-logs-creator.ts100.0%
Coverage rating: A Coverage rating: A
packages/mcp-server/src/http-client/index.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/forest-admin-client-with-cache.ts100.0%
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/adapters/server-types.ts100.0%
Coverage rating: F Coverage rating: D
packages/agent-testing/src/forest-admin-client-mock.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/index.ts100.0%
Coverage rating: A Coverage rating: A
packages/mcp-server/src/http-client/mcp-http-client.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/build-application-services.ts100.0%
Coverage rating: A Coverage rating: A
packages/mcp-server/src/server.ts100.0%
Coverage rating: A Coverage rating: A
packages/forestadmin-client/src/permissions/forest-http-api.ts100.0%
New Coverage rating: A
packages/mcp-server/src/tools/get-workflow-run.ts100.0%
New Coverage rating: A
packages/forestadmin-client/src/workflows/index.ts100.0%
New Coverage rating: A
packages/mcp-server/src/tools/list-workflows.ts100.0%
New Coverage rating: A
packages/mcp-server/src/tools/trigger-workflow.ts100.0%
New Coverage rating: A
packages/mcp-server/src/utils/auth-context.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.

@EnkiP

EnkiP commented Aug 4, 2026

Copy link
Copy Markdown
Member

triggerWorkflow: make the pre-check O(1) (re: PRD-831)

The round-trip can't just be dropped — withActivityLog needs the workflow name for the label before the trigger, and there's no label-update path on the activity-log API. But it shouldn't call listMcpWorkflows (unnests every workflow + the multi-MB collections blob, see forestadmin-server#8418) just to resolve one name.

Add a by-id endpoint — the server already has by-id lookups returning the name (getCollectionAndBpmnAwsS3Identifier{ collectionId, name }):

GET /api/workflow-orchestrator/mcp-workflows/:workflowId → { workflowId, name, collectionName, mcpEnabled }

Tool replaces list+find with one indexed fetch. Same behavior/auditing, name kept in the label, pre-check goes from O(all-workflows) to O(1).

WorkflowRunTriggerResult.runId was typed number while getMcpWorkflowRun
expects a string runId, so the trigger result could not be fed back into
the run polling without conversion. The orchestrator's numeric id is now
normalized at the HTTP boundary and the contract uses string end-to-end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lows (PRD-831) (#1805)

perf(mcp-server): trigger workflow by id instead of listing all workflows

triggerWorkflow no longer calls listMcpWorkflows before every trigger just
to resolve the name/collection for the audit label. It now starts the run
directly and reads workflowName/collectionName from the (enriched) start
response, falling back to the workflowId when an older server omits them.

A server 404 (unknown or MCP-disabled workflow) is mapped back to the
existing "is not an MCP-enabled workflow" message so the LLM-facing contract
is unchanged. The audit log is recorded after the run starts and is
best-effort — the run is already ongoing, so a logging hiccup no longer
fails the tool.

fixes PRD-831

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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