forked from zereight/gitlab-mcp
-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Dynamic action filtering with multi-level description customization #32
Copy link
Copy link
Closed
Labels
enhancementNew feature, new MCP tool, new capabilityNew feature, new MCP tool, new capability
Description
Summary
Add comprehensive customization system for CQRS tools with discriminated union schema architecture: filter specific actions (removing their exclusive parameters), customize descriptions at all levels, and dynamically transform schemas for AI context optimization.
Motivation
Current limitations:
GITLAB_DENIED_TOOLS_REGEXcan only disable entire toolsGITLAB_TOOL_{NAME}only overrides top-level tool description- Flat schemas don't track which parameters belong to which action - can't remove action-specific params
- Tool descriptions contain hardcoded action lists that become stale when filtering
- Long parameter descriptions consume AI context unnecessarily
With CQRS consolidation (61 tools), we need finer control to:
- Disable specific actions AND their exclusive parameters (token savings!)
- Customize descriptions at every level for specific use cases
- Keep AI context clean by removing unnecessary information
Architectural Decision: Discriminated Union Schemas
Problem with Current Flat Schemas
// Current: flat schema - can't know which params belong to which action
const ManageMilestoneSchema = z.object({
action: z.enum(['create', 'update', 'delete', 'promote']),
namespace: z.string(), // shared by all
milestone_id: z.string().optional(), // update/delete/promote only
title: z.string().optional(), // create/update only
state_event: z.enum(['close', 'activate']).optional(), // update only
}).refine(...);If we disable delete action, we still export milestone_id because it's also used by update and promote. But if we disable ALL of update, delete, promote - we should remove milestone_id entirely. Flat schemas can't express this.
Solution: Discriminated Union + Runtime Flattening
// New: discriminated union - each action has its own parameter set
const ManageMilestoneSchema = z.discriminatedUnion('action', [
z.object({
action: z.literal('create'),
namespace: z.string(),
title: z.string(),
description: z.string().optional(),
due_date: z.string().optional(),
}),
z.object({
action: z.literal('update'),
namespace: z.string(),
milestone_id: z.string(),
title: z.string().optional(),
state_event: z.enum(['close', 'activate']).optional(),
}),
z.object({
action: z.literal('delete'),
namespace: z.string(),
milestone_id: z.string(),
}),
z.object({
action: z.literal('promote'),
namespace: z.string(),
milestone_id: z.string(),
}),
]);Benefits:
- Action filtering = branch removal → exclusive params automatically disappear
- Type-safe - TypeScript knows exactly which params each action needs
- Future-proof - when Claude API supports oneOf/anyOf, we can send native schema
- Cleaner handlers - discriminated union provides better type narrowing
Schema Pipeline
Source Schema (discriminated union)
↓
Filter denied actions (remove branches)
↓
Apply description overrides
↓
Transform to flat (for current AI clients)
↓
Output Schema (flat, minimal context)
Proposed Solution
Three-Level Customization System
Level 1: Tool Description (existing)
# Already implemented - override entire tool description
GITLAB_TOOL_BROWSE_MILESTONES="Milestone operations"Level 2: Action Filtering & Description
# Filter out specific actions (removes from schema + their exclusive params!)
GITLAB_DENIED_ACTIONS="browse_milestones:burndown,manage_milestone:promote,manage_milestone:delete"
# Override action field description (optional)
GITLAB_ACTION_MANAGE_MILESTONE_CREATE="Create new milestone"Level 3: Parameter Description
# Override parameter descriptions to shorten context
GITLAB_PARAM_BROWSE_MILESTONES_NAMESPACE="Project/group path"
GITLAB_PARAM_MANAGE_MILESTONE_TITLE="Title"Schema Output Mode (Future)
# When AI clients support discriminated unions natively
GITLAB_SCHEMA_MODE="discriminated" # or "flat" (default)Implementation Plan
Phase 1: Infrastructure ✅ (Done)
- Add
GITLAB_DENIED_ACTIONSparsing to config.ts - Add
getActionDescriptionOverrides()function - Add
getParamDescriptionOverrides()function - Add
isActionDenied()andgetAllowedActions()helpers - Unit tests for config parsing
Phase 2: Schema Architecture Migration 🔄 (Current)
- Create
src/utils/schema-utils.tswith:filterDiscriminatedUnion(schema, allowedActions)- remove branchesflattenDiscriminatedUnion(schema)- convert to flat for AI clientsapplyDescriptionOverrides(schema, overrides)- apply custom descriptions
- Migrate ONE schema as pilot (e.g.,
manage_milestone) - Verify handler still works with discriminated union
- Verify flat output matches current behavior
Phase 3: Full Schema Migration
- Migrate all CQRS command schemas (
manage_*) - Migrate all CQRS query schemas (
browse_*,list_*) - Update unit tests for new schema format
Phase 4: Integration
- Update
registry-manager.tsto apply full pipeline:- Filter denied actions from discriminated union
- Apply description overrides
- Flatten to current format
- Add runtime validation in handlers (reject denied actions)
- Integration tests
Phase 5: Documentation & Release
- Update CONFIGURATION.md with new env vars
- Add examples for common use cases
- Update README with customization section
Example: Token Savings
Before (all actions enabled):
{
"action": {"enum": ["create", "update", "delete", "promote"]},
"namespace": {...},
"milestone_id": {..., "description": "Required for update/delete/promote"},
"title": {...},
"description": {...},
"due_date": {...},
"start_date": {...},
"state_event": {...}
}~400 tokens for schema
After (only create enabled):
{
"action": {"enum": ["create"]},
"namespace": {...},
"title": {...},
"description": {...},
"due_date": {...},
"start_date": {...}
}~200 tokens - 50% reduction!
Files to Modify
src/utils/schema-utils.ts- NEW: schema transformation utilitiessrc/entities/*/schema.ts- Migrate to discriminated unionsrc/registry-manager.ts- Apply transformation pipelinesrc/config.ts- Already done ✅docs/CONFIGURATION.md- Document new env vars
Related Issues
- refactor(labels): CQRS consolidation - 5 tools → 2 tools #8 Labels CQRS consolidation
- refactor(variables): CQRS consolidation - 5 tools → 2 tools #9 Variables CQRS consolidation
- refactor(wiki): CQRS consolidation - 5 tools → 2 tools #10 Wiki CQRS consolidation
- refactor(workitems): CQRS consolidation - 5 tools → 2 tools #11 Work Items CQRS consolidation
- refactor(milestones): CQRS consolidation - 9 tools → 2 tools #13 Milestones consolidation ✅
- refactor(pipelines): CQRS consolidation - 12 tools → 3 tools #14 Pipelines consolidation ✅
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature, new MCP tool, new capabilityNew feature, new MCP tool, new capability