Verified plugins

GitLab

The verified connector ai.oz0/gitlab - GitLab's issues, merge requests, pipelines and repositories through GitLab's own MCP server, on GitLab.com or your own instance, on your own OAuth application, with GitLab's webhooks as events.

For: tenant administrators and plugin users.

Connect GitLab issues, merge requests, pipelines and repositories through GitLab's MCP server. The connector supports GitLab.com, self-managed GitLab and GitLab Dedicated, uses your tenant's OAuth application, and receives GitLab webhooks as events.

Manifest namegitlab (hub name ai.oz0/gitlab), kind: connector
Toolsgitlab: GitLab's MCP server, https://<host>/api/v4/mcp; gitlab_events: the webhooks' normaliser, which reaches nothing
Connectiongitlab: authorization code with PKCE on your own non-confidential OAuth application, the mcp scope, refreshed by the edge
Event sourcegitlab: issue, merge request and pipeline events, checked against the webhook's secret token
Agentgitlab, a generic delegate on the default alias
Pinsnapshots/gitlab.json (21 functions) and the toolsets header
EgressThe connection's host only: gitlab.com, or your instance's

Sources, read 2026-10-17: GitLab MCP server, its tools, OAuth 2.0 identity provider API, GitLab as an OAuth 2.0 provider, webhooks and webhook events.

Functions

The tool sends X-Gitlab-Enabled-Mcp-Server-Toolsets: core,work_items,merge_requests,repository,ci with every request, so GitLab lists those toolsets and meta, and never duo_agent_platform (which needs a GitLab Duo licence), wikis or code_security. The plugin pins 21 of the functions GitLab lists there, and the connection gives a token to those only: GitLab's other functions (merging, committing, running pipelines) show in the catalog but cannot be called through this plugin.

FunctionDoesAsks a person by default
gitlab.list_work_itemsLists or searches issues and other work items in a project or groupno
gitlab.get_work_itemReads one work item, with its notes when askedno
gitlab.get_work_item_typesLists the work item types a project or group hasno
gitlab.list_merge_requestsLists or searches merge requestsno
gitlab.get_merge_requestReads a merge request, with its diffs, commits, notes or pipelines when askedno
gitlab.list_pipelinesLists a project's pipelinesno
gitlab.get_pipelineReads a pipeline, with its jobs when askedno
gitlab.get_jobReads a CI/CD job, with its log when askedno
gitlab.get_repository_fileReads a file at a branch, tag or commitno
gitlab.list_repository_treeLists a directoryno
gitlab.list_commitsLists commitsno
gitlab.get_commitReads a commit, with its diff when askedno
gitlab.list_branchesLists branchesno
gitlab.get_project, gitlab.list_projectsReads a project, lists projectsno
gitlab.get_userReads a user, or the signed-in oneno
gitlab.searchSearches the instanceno
gitlab.search_labelsSearches a project's or group's labelsno
gitlab.get_mcp_server_versionReads the MCP server's versionno
gitlab.save_noteComments on a work item or merge requestyes
gitlab.save_work_itemCreates an issue, or changes one (title, description, labels, state)yes

The two writes wait for an operator who did not start the job, unless your tool policy names other deciders.

Connect it

  1. Allow MCP access at GitLab. On GitLab.com an Owner allows access to the MCP server for the top-level group; on a self-managed instance or Dedicated an administrator allows it for the instance.
  2. Create an OAuth application at GitLab, for a user, a group or the instance: clear Confidential (it has no client secret), select the mcp scope, and give it the redirect URL that oz0 connection show gitlab prints under "calls back".
  3. Connect. The host defaults to gitlab.com; give your instance's for a self-managed one or Dedicated:
Terminal
oz0 connection set gitlab --param host=gitlab.example.com --param client_id=<the application ID>
oz0 connection start gitlab     # opens GitLab's sign-in; the edge keeps and refreshes the token

The person who connects signs in as themselves, and every call acts as them, within what GitLab lets them see and do. The edge refreshes the token before it expires (GitLab's live two hours) and asks for the connection to be connected again when GitLab refuses a refresh. A changed host gets no token until the connection is connected again for it, so a token GitLab issued for one instance never goes to another.

A host on a private network needs it allowed: oz0 server start --connect-allow-net <CIDR>.

Webhooks as events

Point a project's or group's webhook at https://<edge>/events/<tenant>/gitlab, with Secret token set to the value of the tenant secret GITLAB_WEBHOOK_TOKEN (oz0 secret set GITLAB_WEBHOOK_TOKEN --signing --host <edge>:7443 reads it from standard input; the edge takes it only as a signing key bound to its own address), and select issue, merge request and pipeline events. The edge compares X-Gitlab-Token with the secret before anything reads the delivery, and takes a redelivery once by its Idempotency-Key. A routine fires on them:

triage.yaml
triggers:
  - name: opened
    event:
      source: gitlab
      types: [issue]
      filter: event.action == 'open'

Each event has a type (issue, merge_request or pipeline), an action (GitLab's, such as open, update, merge, or a pipeline's status, such as failed), a subject (group/project#7, group/project!3, group/project/pipelines/31), attributes for filters (project, iid, state, branches, labels, failed jobs) and the text an agent reads, which is outside input: what an issue's author wrote is in it.

GitLab sends every kind of work item under its issue events. Only issues (and Service Desk issues) become issue events, with attributes.work_item_type set to Issue; tasks, incidents, epics, objectives and key results are accepted and ignored, so GitLab never counts them as failed deliveries and never turns the webhook off for them.

Limits

  • Writes ask a person by default (save_note and save_work_item, through the plugin's suggested policy, which an admin may switch with a reason; up to 1.0.0 under requires_approval, and an update from it keeps asking), and are not safe to repeat: GitLab's MCP server takes no idempotency key, so a save_note sent twice comments twice. Orchestrator Zero makes an approved call once.
  • No push of changes. The plugin cannot apply a reviewed changeset: its writes are save_note and save_work_item. When it can, it refuses a change to a plugin's tests or rules, and to CODEOWNERS or CI workflows, without the second approval those need, as oz0_github.push_changes does (protected paths).
  • The AI label goes at the start of save_note's body and save_work_item's description: GitLab reads nothing Orchestrator Zero sends beside the call, so the node puts the tenant's label in the text people read, after the approval. A work item's title carries no label.
  • No annotations or output schemas from GitLab. GitLab documents neither for its MCP tools. The plugin marks the reads read-only and the writes as writes, and declares the output schemas of the single-object reads (get_*) from what GitLab's documentation says they return, with no required fields; the lists and searches answer in text.

Rate limits

GitLab.com allows 60 MCP requests a minute per user on Free and 600 on Premium and Ultimate, and counts them toward its general limits too; a self-managed instance's administrator sets one instance-wide limit. Each call is one session of its own. Above the limit GitLab answers 429 and the call is not made. A read is called again after the wait GitLab asks for, once your tenant approved the plugin's listing; a write is not, and the agent reads an error that says it is retryable and how long GitLab asks to wait.

  • Sign-in. OAuth only, on your own application. Personal, project and group access tokens of the legacy kind cannot carry the mcp scope (GitLab answers 403), fine-grained personal access tokens are not offered, and dynamic client registration is not used.
  • A refresh replaces the token in force. GitLab revokes the access token a refresh replaces, so a call that read the old token a moment before can fail once with 401; the next call gets the new one.
  • Webhooks with a secret token, not a signing token. GitLab's signing token (HMAC per the Standard Webhooks specification, GitLab 19.0 and later) is not checked yet; set the secret token, which GitLab sends over TLS.
  • Issues only, of the work items. Tasks, incidents, epics, objectives and key results arrive under GitLab's issue events and are ignored, not refused, so they never count against the webhook.
  • No EU regional host on GitLab.com. GitLab Dedicated and self-managed instances run where their owner chooses.
  • Licence. The toolsets the plugin uses are on GitLab's Free tier; nothing it calls needs GitLab Duo.
  • Installing or updating runs the delegate's eval as the quality gate, on the tenant's own models.
  • Tested against a fake of GitLab's server and OAuth endpoints, shaped from GitLab's documentation, not against GitLab itself. "Verified" means the project tested, pinned and secured the plugin, never that GitLab endorses it.
Copyright © 2026