diff --git a/packages/twenty-server/src/engine/api/mcp/utils/build-mcp-server-instructions.util.ts b/packages/twenty-server/src/engine/api/mcp/utils/build-mcp-server-instructions.util.ts index c85ba4aabf..ddf6dee1b3 100644 --- a/packages/twenty-server/src/engine/api/mcp/utils/build-mcp-server-instructions.util.ts +++ b/packages/twenty-server/src/engine/api/mcp/utils/build-mcp-server-instructions.util.ts @@ -24,7 +24,7 @@ export const buildMcpServerInstructions = ( ``, `Non-CRUD tools — use learn_tools for schemas:`, ` ACTION: http_request | send_email | draft_email | navigate_app | code_interpreter | search_help_center`, - ` WORKFLOW: create_complete_workflow | create/update/delete_workflow_version_step | activate/deactivate_workflow_version`, + ` WORKFLOW: list_workflows | create_complete_workflow | create/update/delete_workflow_version_step | activate/deactivate_workflow_version | list_workflow_runs | get_workflow_run | get_workflow_current_version`, ` METADATA: get/create/update/delete_object_metadata | get/create/update/delete_field_metadata`, ` Both GET tools return system items as compact summaries by default — keep that default for listing/inspecting; only set includeFullSystemObjects / includeFullSystemFields=true when you specifically need a system item's full configuration`, ` VIEW: get_views | get_view_query_parameters | create/update/delete_view | manage view fields, filters, sorts`, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts index dc068e06ba..69dccd6817 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/skill-metadata/create-standard-flat-skill-metadata.util.ts @@ -68,6 +68,10 @@ LOGIC_FUNCTION steps execute logic functions provided by installed applications. { "stepType": "LOGIC_FUNCTION", "workflowVersionId": "", "defaultSettings": { "input": { "logicFunctionId": "" } } } 3. Or when using \`create_complete_workflow\`, include a step with type "LOGIC_FUNCTION" and settings.input.logicFunctionId. +## Listing Workflows + +To discover existing workflows in the workspace, use \`list_workflows\`. Use this before modifying a workflow when the user refers to it by name rather than id — resolve the \`id\` here first, then call \`get_workflow_current_version\` with it. + ## Troubleshooting Workflow Runs When a user reports a failing or misbehaving workflow, diagnose it with two read-only tools: diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts index 7d828c7c87..8e38cec735 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-tools/services/workflow-tool.workspace-service.ts @@ -27,6 +27,7 @@ import { createGetWorkflowCurrentVersionTool } from 'src/modules/workflow/workfl import { createGetWorkflowRunTool } from 'src/modules/workflow/workflow-tools/tools/get-workflow-run.tool'; import { createListLogicFunctionToolsTool } from 'src/modules/workflow/workflow-tools/tools/list-logic-function-tools.tool'; import { createListWorkflowRunsTool } from 'src/modules/workflow/workflow-tools/tools/list-workflow-runs.tool'; +import { createListWorkflowsTool } from 'src/modules/workflow/workflow-tools/tools/list-workflows.tool'; import { createUpdateAgentTool } from 'src/modules/workflow/workflow-tools/tools/update-agent.tool'; import { createUpdateLogicFunctionSourceTool } from 'src/modules/workflow/workflow-tools/tools/update-logic-function-source.tool'; import { createUpdateWorkflowVersionPositionsTool } from 'src/modules/workflow/workflow-tools/tools/update-workflow-version-positions.tool'; @@ -134,6 +135,10 @@ export class WorkflowToolWorkspaceService { this.deps, contextWithPermissions, ); + const listWorkflows = createListWorkflowsTool( + this.deps, + contextWithPermissions, + ); const updateLogicFunctionSource = createUpdateLogicFunctionSourceTool( this.deps, context, @@ -159,6 +164,7 @@ export class WorkflowToolWorkspaceService { [deactivateWorkflowVersion.name]: deactivateWorkflowVersion, [computeStepOutputSchema.name]: computeStepOutputSchema, [getWorkflowCurrentVersion.name]: getWorkflowCurrentVersion, + [listWorkflows.name]: listWorkflows, [getWorkflowRun.name]: getWorkflowRun, [listWorkflowRuns.name]: listWorkflowRuns, [updateLogicFunctionSource.name]: updateLogicFunctionSource, diff --git a/packages/twenty-server/src/modules/workflow/workflow-tools/tools/list-workflows.tool.ts b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/list-workflows.tool.ts new file mode 100644 index 0000000000..e9814c393b --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/workflow-tools/tools/list-workflows.tool.ts @@ -0,0 +1,92 @@ +import { z } from 'zod'; + +import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; +import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; +import { + WorkflowStatus, + type WorkflowWorkspaceEntity, +} from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; +import { + type WorkflowToolContext, + type WorkflowToolDependencies, +} from 'src/modules/workflow/workflow-tools/types/workflow-tool-dependencies.type'; + +type ListWorkflowsToolContext = WorkflowToolContext & { + rolePermissionConfig: RolePermissionConfig; +}; + +const listWorkflowsSchema = z.object({ + status: z + .nativeEnum(WorkflowStatus) + .optional() + .describe('Filter by status (DRAFT, ACTIVE, DEACTIVATED)'), + limit: z.number().int().min(1).max(100).optional().default(50), + offset: z.number().int().min(0).optional().default(0), +}); + +type ListWorkflowsInput = z.infer; + +export const createListWorkflowsTool = ( + deps: Pick, + context: ListWorkflowsToolContext, +) => ({ + name: 'list_workflows' as const, + description: + 'List all workflows in the workspace. Supports filtering by status and pagination.', + inputSchema: listWorkflowsSchema, + execute: async (parameters: ListWorkflowsInput) => { + try { + const authContext = buildSystemAuthContext(context.workspaceId); + + return await deps.globalWorkspaceOrmManager.executeInWorkspaceContext( + async () => { + const workflowRepository = + await deps.globalWorkspaceOrmManager.getRepository( + context.workspaceId, + 'workflow', + context.rolePermissionConfig, + ); + + const queryBuilder = + workflowRepository.createQueryBuilder('workflow'); + + if (parameters.status) { + queryBuilder.where(':status = ANY(workflow.statuses)', { + status: parameters.status, + }); + } + + queryBuilder + .orderBy('workflow.createdAt', 'DESC') + .take(parameters.limit) + .skip(parameters.offset); + + const [workflows, totalCount] = await queryBuilder.getManyAndCount(); + + return { + success: true, + workflows: workflows.map((workflow) => ({ + id: workflow.id, + name: workflow.name, + statuses: workflow.statuses, + lastPublishedVersionId: workflow.lastPublishedVersionId, + createdAt: workflow.createdAt, + updatedAt: workflow.updatedAt, + })), + totalCount, + }; + }, + authContext, + ); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + + return { + success: false, + error: errorMessage, + message: `Failed to list workflows: ${errorMessage}`, + }; + } + }, +});