forked from zereight/gitlab-mcp
-
Notifications
You must be signed in to change notification settings - Fork 1
refactor(pipelines): CQRS consolidation - 12 tools → 3 tools #14
Copy link
Copy link
Labels
refactorCode restructuring without behavior changeCode restructuring without behavior change
Description
Summary
Consolidate 12 pipeline tools into 3 CQRS-aligned tools for better MCP client compatibility and cleaner read/write separation.
Current State (12 tools)
| Tool | Type | Description |
|---|---|---|
list_pipelines |
READ | List pipelines with filtering |
get_pipeline |
READ | Get pipeline details |
list_pipeline_jobs |
READ | List jobs in pipeline |
list_pipeline_trigger_jobs |
READ | List bridge/trigger jobs |
get_pipeline_job |
READ | Get single job details |
get_pipeline_job_output |
READ | Get job logs |
create_pipeline |
WRITE | Trigger new pipeline |
retry_pipeline |
WRITE | Retry failed pipeline |
cancel_pipeline |
WRITE | Cancel running pipeline |
play_pipeline_job |
WRITE | Trigger manual job |
retry_pipeline_job |
WRITE | Retry single job |
cancel_pipeline_job |
WRITE | Cancel single job |
Target State (3 tools)
browse_pipelines (Query)
Consolidates all READ operations:
{
action: "list" | "get" | "jobs" | "triggers" | "job" | "logs",
// Common
projectId: string,
// For "list" action
status?: "created" | "waiting_for_resource" | "preparing" | "pending" |
"running" | "success" | "failed" | "canceled" | "skipped" | "manual" | "scheduled",
ref?: string,
sha?: string,
username?: string,
yaml_errors?: boolean,
updated_before?: string,
updated_after?: string,
name?: string,
order_by?: "id" | "status" | "ref" | "updated_at" | "user_id",
sort?: "asc" | "desc",
source?: string,
// For "get", "jobs", "triggers"
pipelineId?: number,
// For "jobs" action
scope?: "created" | "pending" | "running" | "failed" | "success" |
"canceled" | "skipped" | "waiting_for_resource" | "manual",
include_retried?: boolean,
// For "job", "logs"
jobId?: number,
// Pagination
per_page?: number,
page?: number
}Read-only mode: Always allowed
manage_pipeline (Command)
Pipeline-level operations:
{
action: "create" | "retry" | "cancel",
projectId: string,
// For "create"
ref?: string, // Branch or tag
variables?: Array<{
key: string,
value: string,
variable_type?: "env_var" | "file"
}>,
// For "retry" and "cancel"
pipelineId?: number
}Read-only mode: Blocked entirely
manage_pipeline_job (Command)
Job-level operations:
{
action: "play" | "retry" | "cancel",
projectId: string,
jobId: number,
// For "play" action (manual jobs)
job_variables_attributes?: Array<{
key: string,
value: string
}>
}Read-only mode: Blocked entirely
Implementation Tasks
- Create new
browse_pipelineshandler with action dispatch - Create new
manage_pipelinehandler with action dispatch - Create new
manage_pipeline_jobhandler with action dispatch - Update Zod schemas with discriminated union pattern
- Update registry to export new tool names
- Update read-only tools list (only
browse_pipelines) - Remove old handlers after migration
- Update unit tests
- Update integration tests
Schema Pattern
const BrowsePipelinesSchema = z.discriminatedUnion("action", [
z.object({
action: z.literal("list"),
projectId: z.string(),
status: PipelineStatusSchema.optional(),
ref: z.string().optional(),
// ...
}),
z.object({
action: z.literal("get"),
projectId: z.string(),
pipelineId: z.number(),
}),
z.object({
action: z.literal("jobs"),
projectId: z.string(),
pipelineId: z.number(),
scope: JobScopeSchema.optional(),
include_retried: z.boolean().optional(),
}),
z.object({
action: z.literal("triggers"),
projectId: z.string(),
pipelineId: z.number(),
}),
z.object({
action: z.literal("job"),
projectId: z.string(),
jobId: z.number(),
}),
z.object({
action: z.literal("logs"),
projectId: z.string(),
jobId: z.number(),
}),
]);Breaking Changes
| Old Tool | Migration Path |
|---|---|
list_pipelines |
browse_pipelines with action: "list" |
get_pipeline |
browse_pipelines with action: "get" |
list_pipeline_jobs |
browse_pipelines with action: "jobs" |
list_pipeline_trigger_jobs |
browse_pipelines with action: "triggers" |
get_pipeline_job |
browse_pipelines with action: "job" |
get_pipeline_job_output |
browse_pipelines with action: "logs" |
create_pipeline |
manage_pipeline with action: "create" |
retry_pipeline |
manage_pipeline with action: "retry" |
cancel_pipeline |
manage_pipeline with action: "cancel" |
play_pipeline_job |
manage_pipeline_job with action: "play" |
retry_pipeline_job |
manage_pipeline_job with action: "retry" |
cancel_pipeline_job |
manage_pipeline_job with action: "cancel" |
Why 3 Tools Instead of 2?
Pipeline-level and job-level operations have distinct targets:
- Pipeline operations target
pipelineId - Job operations target
jobId
Combining them would create confusing parameter requirements. Keeping them separate maintains clarity while still achieving significant consolidation (12 → 3).
Feature Flag
Existing USE_PIPELINE flag continues to control entire pipelines entity visibility.
Testing Requirements
- Unit tests for discriminated union schema validation
- Test pipeline listing with various filters
- Test job listing and logs retrieval
- Test pipeline create/retry/cancel
- Test manual job play with variables
- Test job retry/cancel
- Test read-only mode blocks command tools
- Integration tests for all operations
Acceptance Criteria
- Total tools reduced from 12 to 3
- All existing functionality preserved
- Clear separation between pipeline and job operations
- Variable passing works for create and play
- Read-only mode correctly gates write operations
- Clear error messages for invalid action/parameter combinations
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
refactorCode restructuring without behavior changeCode restructuring without behavior change