run_rollback_pipeline
Execute a rollback pipeline or workflow rerun for a CircleCI project, guiding users through project selection, environment configuration, and version targeting to revert deployments.
Instructions
On success: The rollback ID or a confirmation in case of workflow rerun.
On error: A clear message describing what is missing or what went wrong.
If the selected project does not have a rollback pipeline configured: The tool will provide a clear error message specific to that project and will NOT suggest trying another project.
Important Note:
This tool is designed to work only with the specific project provided by the user.
If a project does not have rollback capability configured, the tool will NOT suggest alternatives or recommend trying other projects.
The assistant should NOT suggest trying different projects when a project lacks rollback configuration.
Each project must have its own rollback pipeline configuration to be eligible for rollback operations.
When a project cannot be rolled back, provide only the configuration guidance for THAT specific project.
If neither option is fully satisfied, prompt the user for the missing information before making the tool call.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| params | No |
Implementation Reference
- The main handler function `runRollbackPipeline` that implements the core logic of the tool. It validates inputs, fetches necessary project data from CircleCI, guides the user through selections if needed, and executes the rollback pipeline or workflow rerun.export const runRollbackPipeline: ToolCallback<{ params: typeof runRollbackPipelineInputSchema; }> = async (args: any) => { const { projectSlug: inputProjectSlug, environment_name, component_name, current_version, target_version, workflow_id, reason, parameters, projectID, rollback_type, } = args.params; // They need to provide the projectID or projectSlug const hasProjectIDOrSlug = inputProjectSlug || projectID; if (!hasProjectIDOrSlug) { return mcpErrorOutput( 'For rollback requests, projectSlug or projectID is required.', ); } let updatedProjectID = projectID; let orgID = undefined; // Init the client and get the base URL const circleci = getCircleCIClient(); // Get project information - we need both projectID and orgID if (inputProjectSlug) { // Use projectSlug to get projectID and orgID try { const { id: projectId, organization_id: orgId } = await circleci.projects.getProject({ projectSlug: inputProjectSlug, }); updatedProjectID = projectId; orgID = orgId; } catch (error) { return mcpErrorOutput( `Failed to get project information for ${inputProjectSlug}. Please verify the project slug is correct. ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } else if (projectID) { // Use projectID directly - we need to get orgID somehow updatedProjectID = projectID; try { // Try to get project info using projectID to get orgID const { organization_id: orgId } = await circleci.projects.getProjectByID({ projectID: projectID, }); orgID = orgId; } catch (error) { return mcpErrorOutput( `Failed to get project information for project ID ${projectID}. Please verify the project ID is correct. ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } if (!updatedProjectID || !orgID) { return mcpErrorOutput( 'Could not get project information. Please verify the projectID or slug is correct.', ); } if (rollback_type === 'PIPELINE') { // // Check if the project has a rollback pipeline defined (only needed for actual rollback) try { const deploySettings = await circleci.deploys.fetchProjectDeploySettings({ projectID: updatedProjectID, }); if (!deploySettings.rollback_pipeline_definition_id) { return { content: [ { type: 'text', text: `No rollback pipeline defined for this project. Would you like to rerun a workflow instead? Call this tool again with rollback_type set to "WORKFLOW_RERUN". Otherwise, you can set up a rollback pipeline using https://circleci.com/docs/deploy/rollback-a-project-using-the-rollback-pipeline/ ` } ] }; } } catch { return mcpErrorOutput( 'Failed to fetch rollback pipeline definition. Please try again later.', ); } } // Get the components for this project, if there is only one we can use the information // If there is a component, we are sure there is a deploy marker const components = await circleci.deploys.fetchProjectComponents({ projectID: updatedProjectID, orgID: orgID, }); if (components?.items.length === 0) { // If there is no components, we can't rollback since there are no deploy markers return mcpErrorOutput( 'No components found for this project. Set up deploy markers to use this tool. See https://circleci.com/docs/deploy/configure-deploy-markers/ for more information.', ); } if (components.items.length > 1 && !component_name) { const componentList = components.items .map((env: any, index: number) => `${index + 1}. ${env.name} (ID: ${env.id})`) .join('\n'); return { content: [ { type: 'text', text: `Multiple components found for this project. Please specify component_name parameter with one of the following:\n\n${componentList}\n\nExample: Call the rollback tool again with component_name set to "${components.items[0].name}"`, }, ], }; } let selectedComponent = components.items[0]; if (component_name) { const matchingComponent = components.items.find((component: any) => component.name === component_name); if (!matchingComponent) { const componentList = components.items .map((component: any, index: number) => `${index + 1}. ${component.name}`) .join('\n'); return mcpErrorOutput( `Component "${component_name}" not found. Available components:\n\n${componentList}` ); } selectedComponent = matchingComponent; } // Fetch the environments for this project const environments = await circleci.deploys.fetchEnvironments({ orgID: orgID, }); if (environments.items.length === 0) { // If there is no components, we can't rollback since there are no deploy markers return mcpErrorOutput( 'No environments found for this project. Set up one using https://circleci.com/docs/deploy/configure-deploy-markers/#manage-environments', ); } // If multiple environments, we need to ask the user to select one if (environments.items.length > 1 && !environment_name) { const environmentList = environments.items .map((env: any, index: number) => `${index + 1}. ${env.name} (ID: ${env.id})`) .join('\n'); return { content: [ { type: 'text', text: `Multiple environments found for this project. Please specify environment_name parameter with one of the following:\n\n${environmentList}\n\nExample: Call the rollback tool again with environment_name set to "${environments.items[0].name}"`, }, ], }; } let selectedEnvironment = environments.items[0]; // If user provided environment_name, find the matching environment if (environment_name) { const matchingEnvironment = environments.items.find((env: any) => env.name === environment_name); if (!matchingEnvironment) { const environmentList = environments.items .map((env: any, index: number) => `${index + 1}. ${env.name}`) .join('\n'); return mcpErrorOutput( `Environment "${environment_name}" not found. Available environments:\n\n${environmentList}` ); } selectedEnvironment = matchingEnvironment; } // Check if this is a new rollback request with required fields const isRollbackRequestComplete = environment_name && component_name && current_version && target_version; // If only projectSlug is provided, fetch and show component versions for selection if (!isRollbackRequestComplete) { // Show which environment and component we're working with let message = ''; // Environment selection message if (environments.items.length === 1) { message += `Found 1 environment: "${selectedEnvironment.name}". Using this environment for rollback.\n`; } else { message += `Using environment: "${selectedEnvironment.name}".\n`; } // Component selection message if (components.items.length === 1) { message += `Found 1 component: "${selectedComponent.name}". Using this component for rollback.\n\n`; } else { message += `Found ${components.items.length} components. Using component: "${selectedComponent.name}".\n\n`; } // Fetch the versions const componentVersions = await circleci.deploys.fetchComponentVersions({ componentID: selectedComponent.id, environmentID: selectedEnvironment.id, workflowID: workflow_id, }); return { content: [ { type: 'text', text: `${message}Select a component version from: ${JSON.stringify(componentVersions)}`, }, ], }; } // Fetch component versions for actual rollback execution const componentVersions = await circleci.deploys.fetchComponentVersions({ componentID: components.items[0].id, environmentID: selectedEnvironment.id, }); const currentVersion = componentVersions.items.find( (component: any) => component.is_live )?.name; const namespace = componentVersions.items.find( (component: any) => component.is_live )?.namespace; if (isRollbackRequestComplete && rollback_type === 'PIPELINE') { // Handle new rollback API const rollbackRequest = { environment_name: selectedEnvironment.name!, component_name: selectedComponent.name!, current_version: currentVersion!, target_version: target_version!, ...(namespace && { namespace }), ...(reason && { reason }), ...(parameters && { parameters }), }; try { const rollbackResponse = await circleci.deploys.runRollbackPipeline({ projectID: updatedProjectID, rollbackRequest, }); return { content: [ { type: 'text', text: `Rollback initiated successfully. ID: ${rollbackResponse.id}, Type: ${rollbackResponse.rollback_type}`, }, ], }; } catch (error) { return mcpErrorOutput( `Failed to initiate rollback: ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } if (isRollbackRequestComplete && rollback_type === 'WORKFLOW_RERUN') { if (!workflow_id) { return mcpErrorOutput( 'The selected version has no associated workflow. Please select a different version.', ); } try { // Handle workflow rerun await circleci.workflows.rerunWorkflow({ workflowId: workflow_id!, fromFailed: false, }); return { content: [ { type: 'text', text: `Workflow rerun initiated successfully.`, }, ], }; } catch (error) { return mcpErrorOutput( `Failed to initiate rollback: ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } return mcpErrorOutput( 'Incomplete rollback request. Please provide environment_name, component_name, current_version, and target_version.', ); };
- Zod input schema defining the parameters for the `run_rollback_pipeline` tool, including project identifiers, rollback type, environment, component, versions, etc.export const runRollbackPipelineInputSchema = z.object({ projectSlug: z.string().describe(projectSlugDescription).optional(), projectID: z.string().uuid().describe('The ID of the CircleCI project (UUID)').optional(), rollback_type: z .enum(['PIPELINE', 'WORKFLOW_RERUN']) .describe('The type of rollback operation to perform') .default('PIPELINE'), workflow_id: z .string() .describe('The ID of the workflow to rerun') .optional(), environment_name: z .string() .describe('The environment name') .optional(), component_name: z .string() .describe('The component name') .optional(), current_version: z .string() .describe('The current version') .optional(), target_version: z .string() .describe('The target version') .optional(), reason: z .string() .describe('The reason for the rollback') .optional(), parameters: z .record(z.any()) .describe('The extra parameters for the rollback pipeline') .optional(), });
- src/tools/runRollbackPipeline/tool.ts:3-67 (registration)Registers the tool definition as `runRollbackPipelineTool` with the exact name 'run_rollback_pipeline', a comprehensive description, and references the input schema.export const runRollbackPipelineTool = { name: 'run_rollback_pipeline' as const, description: ` Run a rollback pipeline for a CircleCI project. This tool guides you through the full rollback process, adapting to the information you provide and prompting for any missing details. **Initial Step:** - First, call the \`listFollowedProjects\` tool to retrieve the list of projects the user follows. - Then, ask the user to select a project by providing either a \`projectID\` or the exact \`projectSlug\` as returned by \`listFollowedProjects\`. **Typical Flow:** 1. **Start:** User initiates a rollback request. 2. **Project Selection:** If a \`projectSlug\` or \`projectID\` is not provided, call \`listFollowedProjects\` and prompt the user to select a project using the exact value returned. 3. **Execute the tool and list the versions.** 4. **Workflow Rerun:** - Inform the user of the fact that no rollback pipeline is defined for this project. - Ask the user if they want to rerun a workflow. - If the user wants to rerun a workflow, execute the tool with rollback_type set to \`WORKFLOW_RERUN\`. Do not propose to choose another project. 6. **Component Selection:** - If the project has multiple components, present up to 20 options for the user to choose from. - If there is only one component, proceed automatically and do not ask the user to select a component. 7. **Environment Selection:** - If the project has multiple environments, present up to 20 options for the user to choose from. - If there is only one environment, proceed automatically and do not ask the user to select an environment. 8. **Version Selection:** - Present the user with available versions to rollback to, based on the selected environment and component. Include the namespace for each version. - Ask for both the current deployed version and the target version to rollback to. 9. **Optional Details:** - If the rollback type is \`PIPELINE\`, prompt the user for an optional reason for the rollback (e.g., "Critical bug fix"). - If the rollback type is \`WORKFLOW_RERUN\`, provide the workflow ID of the selected version to the tool. - provide the namespace for the selected version to the tool. 10. **Confirmation:** - Summarize the rollback request and confirm with the user before submitting. **Parameters:** - Either \`projectSlug\` (e.g., "gh/organization/repository") or \`projectID\` (UUID) must be provided. - \`environment_name\` (optional at first if multiple environments): The target environment (e.g., "production", "staging"). - \`component_name\` (optional at first components): The component to rollback (e.g., "frontend", "backend"). - \`current_version\` (optional at first): The currently deployed version. - \`target_version\` (optional at first): The version to rollback to. - \`reason\` (optional): Reason for the rollback. - \`parameters\` (optional): Additional rollback parameters as key-value pairs. **Behavior:** - If there are more than 20 environments or components, ask the user to refine their selection. - Never attempt to guess or construct project slugs or URLs; always use values provided by the user or from \`listFollowedProjects\`. - Do not prompt for missing parameters until versions have been listed. - Do not call this tool with incomplete parameters. - If the selected project lacks rollback pipeline configuration, provide a definitive error message without suggesting alternative projects. **Returns:** - On success: The rollback ID or a confirmation in case of workflow rerun. - On error: A clear message describing what is missing or what went wrong. - If the selected project does not have a rollback pipeline configured: The tool will provide a clear error message specific to that project and will NOT suggest trying another project. **Important Note:** - This tool is designed to work only with the specific project provided by the user. - If a project does not have rollback capability configured, the tool will NOT suggest alternatives or recommend trying other projects. - The assistant should NOT suggest trying different projects when a project lacks rollback configuration. - Each project must have its own rollback pipeline configuration to be eligible for rollback operations. - When a project cannot be rolled back, provide only the configuration guidance for THAT specific project. If neither option is fully satisfied, prompt the user for the missing information before making the tool call. `, inputSchema: runRollbackPipelineInputSchema, };
- src/circleci-tools.ts:26-72 (registration)Aggregates and registers the `runRollbackPipelineTool` into the main `CCI_TOOLS` array and maps the handler under key 'run_rollback_pipeline' in `CCI_HANDLERS`.import { runRollbackPipelineTool } from './tools/runRollbackPipeline/tool.js'; import { runRollbackPipeline } from './tools/runRollbackPipeline/handler.js'; // Define the tools with their configurations export const CCI_TOOLS = [ getBuildFailureLogsTool, getFlakyTestLogsTool, getLatestPipelineStatusTool, getJobTestResultsTool, configHelperTool, createPromptTemplateTool, recommendPromptTemplateTestsTool, runPipelineTool, listFollowedProjectsTool, runEvaluationTestsTool, rerunWorkflowTool, analyzeDiffTool, runRollbackPipelineTool, ]; // Extract the tool names as a union type type CCIToolName = (typeof CCI_TOOLS)[number]['name']; export type ToolHandler<T extends CCIToolName> = ToolCallback<{ params: Extract<(typeof CCI_TOOLS)[number], { name: T }>['inputSchema']; }>; // Create a type for the tool handlers that directly maps each tool to its appropriate input schema type ToolHandlers = { [K in CCIToolName]: ToolHandler<K>; }; export const CCI_HANDLERS = { get_build_failure_logs: getBuildFailureLogs, find_flaky_tests: getFlakyTestLogs, get_latest_pipeline_status: getLatestPipelineStatus, get_job_test_results: getJobTestResults, config_helper: configHelper, create_prompt_template: createPromptTemplate, recommend_prompt_template_tests: recommendPromptTemplateTests, run_pipeline: runPipeline, list_followed_projects: listFollowedProjects, run_evaluation_tests: runEvaluationTests, rerun_workflow: rerunWorkflow, analyze_diff: analyzeDiff, run_rollback_pipeline: runRollbackPipeline, } satisfies ToolHandlers;