Consolidate GitLab API tools into generic gitlab_api_get and gitlab_graphql tools

Problem Statement

Currently, Duo Workflow Chat exposes numerous specialized tools for interacting with GitLab resources, including:

  • get_merge_request, list_merge_request_diffs, list_all_merge_request_notes, gitlab_merge_request_search
  • get_issue, list_issues, list_issue_notes, get_issue_note
  • get_project
  • Similar patterns for commits, pipelines, jobs, epics, work items, vulnerabilities, security findings, audit events, etc.

This approach has several limitations:

  1. High token consumption: Each specialized tool adds to the token count in the system prompt, reducing available context for actual work
  2. Limited functionality: We can only expose GitLab API endpoints that have been explicitly implemented as tools
  3. Maintenance overhead: Every new GitLab API feature requires implementing and maintaining a new tool class
  4. Inconsistent coverage: Some resources have comprehensive tooling while others have gaps

Proposed Solution

Replace specialized read-only Get* and List* tools with two generic tools:

1. gitlab_api_get

A generic REST API tool for read operations only that accepts:

  • endpoint: The API path (e.g., /api/v4/projects/:id/merge_requests/:iid)
  • params: Optional query parameters as a dictionary
  • URL parsing support to extract resource IDs from GitLab URLs

Security constraint: Only supports GET requests. All write operations (POST, PUT, DELETE) remain as specialized tools with proper validation.

2. gitlab_graphql

A generic GraphQL tool that accepts:

  • query: The GraphQL query string (queries only, no mutations)
  • variables: Optional variables dictionary

Security constraint: Only supports GraphQL queries, not mutations. Write operations remain as specialized tools.

Benefits

  1. Reduced token usage: Two generic read tools instead of 50+ specialized tools significantly reduces system prompt size
  2. Complete read API access: LLM can access any GitLab REST or GraphQL read endpoint, not just pre-implemented ones
  3. Simplified maintenance: No need to implement wrapper tools for every read-only API endpoint
  4. Future-proof: New GitLab API features automatically available without code changes
  5. More flexible: LLM can construct custom queries for complex data requirements

Implementation Considerations

Preserve these specialized tools:

  • All write operations: create_merge_request, create_issue, update_merge_request, create_merge_request_note, etc. (these require validation, business logic, and approval workflows)
  • Custom tools with complex processing: list_merge_request_diffs (applies DiffExclusionPolicy), build_review_merge_request_context, etc.
  • Tools that bundle multiple operations or have special behavior

Replace these with generic tools:

  • get_merge_requestgitlab_api_get
  • list_issuesgitlab_api_get
  • get_projectgitlab_api_get
  • list_all_merge_request_notesgitlab_api_get
  • get_issue_notegitlab_api_get
  • Similar patterns for commits, pipelines, jobs, epics, work items, vulnerabilities, security findings, audit events, users, etc.

URL parsing:

  • Generic tools should support the same URL parsing capabilities that specialized tools currently have (extracting project_id, merge_request_iid, issue_iid, etc. from GitLab URLs)
  • Example: gitlab_api_get(url="https://gitlab.com/namespace/project/-/merge_requests/42") should work equivalently to gitlab_api_get(endpoint="/api/v4/projects/namespace%2Fproject/merge_requests/42")

Documentation:

  • System prompt should include examples of common API patterns
  • Inline documentation for frequently-used endpoints (projects, merge requests, issues, pipelines)
  • Reference to GitLab API documentation

Error handling:

  • Generic tools should provide clear error messages including status codes and response bodies
  • Maintain consistency with current error handling patterns

Example Usage

Current approach:

# Requires 3 separate specialized tools in system prompt
get_merge_request(project_id=13, merge_request_iid=42)
list_all_merge_request_notes(project_id=13, merge_request_iid=42)
get_issue(project_id=13, issue_iid=10)

New approach:

# Single generic tool can handle all GET requests
gitlab_api_get(endpoint="/api/v4/projects/13/merge_requests/42")
gitlab_api_get(endpoint="/api/v4/projects/13/merge_requests/42/notes")
gitlab_api_get(endpoint="/api/v4/projects/13/issues/10")

# Or with URL parsing
gitlab_api_get(url="https://gitlab.com/namespace/project/-/merge_requests/42")

# With query parameters
gitlab_api_get(
    endpoint="/api/v4/projects/13/merge_requests",
    params={"state": "opened", "author_username": "janedoe"}
)

# GraphQL for complex queries combining multiple resources
gitlab_graphql(query="""
  query($projectPath: ID!, $iid: String!) {
    project(fullPath: $projectPath) {
      mergeRequest(iid: $iid) {
        title
        description
        author { username }
        diffStats { additions deletions }
        notes { nodes { body author { username } } }
      }
    }
  }
""", variables={"projectPath": "namespace/project", "iid": "42"})

Security Notes

  • Generic tools are read-only by design - no POST, PUT, PATCH, or DELETE support
  • GraphQL tool only accepts queries, not mutations
  • All write operations require explicit specialized tools with proper validation and approval workflows
  • This maintains security boundaries while maximizing flexibility for read operations
Edited by 🤖 GitLab Bot 🤖