Skip to main content
Glama

mcp-server-circleci

Official
handler.ts5.61 kB
import { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js'; import { listComponentVersionsInputSchema } from './inputSchema.js'; import { getCircleCIClient } from '../../clients/client.js'; import mcpErrorOutput from '../../lib/mcpErrorOutput.js'; type ProjectInfo = { projectID: string; orgID: string; }; export const listComponentVersions: ToolCallback<{ params: typeof listComponentVersionsInputSchema; }> = async (args) => { const { projectSlug, projectID: providedProjectID, orgID: providedOrgID, componentID, environmentID, } = args.params ?? {}; try { // Resolve project and organization information const projectInfoResult = await resolveProjectInfo(projectSlug, providedProjectID, providedOrgID); if (!projectInfoResult.success) { return projectInfoResult.error; } const { projectID, orgID } = projectInfoResult.data; // If environmentID is not provided, list environments if (!environmentID) { return await listEnvironments(orgID); } // If componentID is not provided, list components if (!componentID) { return await listComponents(projectID, orgID); } // If both componentID and environmentID are provided, list component versions return await fetchComponentVersions(componentID, environmentID); } catch (error) { return mcpErrorOutput( `Failed to list component versions: ${error instanceof Error ? error.message : 'Unknown error'}`, ); } }; /** * Resolves project and organization information from the provided parameters */ async function resolveProjectInfo( projectSlug?: string, providedProjectID?: string, providedOrgID?: string, ): Promise<{ success: true; data: ProjectInfo } | { success: false; error: any }> { const circleci = getCircleCIClient(); try { if (providedProjectID && providedOrgID) { // Both IDs provided, use them directly return { success: true, data: { projectID: providedProjectID, orgID: providedOrgID, }, }; } if (projectSlug) { // Use projectSlug to get projectID and orgID const { id: resolvedProjectId, organization_id: resolvedOrgId } = await circleci.projects.getProject({ projectSlug, }); return { success: true, data: { projectID: resolvedProjectId, orgID: resolvedOrgId, }, }; } if (providedProjectID) { // Use projectID to get orgID const { id: resolvedProjectId, organization_id: resolvedOrgId } = await circleci.projects.getProjectByID({ projectID: providedProjectID, }); return { success: true, data: { projectID: resolvedProjectId, orgID: resolvedOrgId, }, }; } return { success: false, error: mcpErrorOutput(`Invalid request. Please specify either a project slug or a project ID.`), }; } catch (error) { const errorMessage = projectSlug ? `Failed to resolve project information for ${projectSlug}. Please verify the project slug is correct.` : `Failed to resolve project information for project ID ${providedProjectID}. Please verify the project ID is correct.`; return { success: false, error: mcpErrorOutput(`${errorMessage} ${error instanceof Error ? error.message : 'Unknown error'}`), }; } } /** * Lists available environments for the organization */ async function listEnvironments(orgID: string) { const circleci = getCircleCIClient(); const environments = await circleci.deploys.fetchEnvironments({ orgID, }); if (environments.items.length === 0) { return { content: [ { type: 'text', text: `No environments found`, }, ], }; } const environmentsList = environments.items .map((env: any, index: number) => `${index + 1}. ${env.name} (ID: ${env.id})`) .join('\n'); return { content: [ { type: 'text', text: `Please provide an environmentID. Available environments:\n\n${environmentsList}\n\n`, }, ], }; } /** * Lists available components for the project */ async function listComponents(projectID: string, orgID: string) { const circleci = getCircleCIClient(); const components = await circleci.deploys.fetchProjectComponents({ projectID, orgID, }); if (components.items.length === 0) { return { content: [ { type: 'text', text: `No components found`, }, ], }; } const componentsList = components.items .map((component: any, index: number) => `${index + 1}. ${component.name} (ID: ${component.id})`) .join('\n'); return { content: [ { type: 'text', text: `Please provide a componentID. Available components:\n\n${componentsList}\n\n`, }, ], }; } /** * Lists component versions for the specified component and environment */ async function fetchComponentVersions(componentID: string, environmentID: string) { const circleci = getCircleCIClient(); const componentVersions = await circleci.deploys.fetchComponentVersions({ componentID, environmentID, }); if (componentVersions.items.length === 0) { return { content: [ { type: 'text', text: `No component versions found`, }, ], }; } return { content: [ { type: 'text', text: `Versions for the component: ${JSON.stringify(componentVersions)}`, }, ], }; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CircleCI-Public/mcp-server-circleci'

If you have feedback or need assistance with the MCP directory API, please join our Discord server