gitlab mcp
You can use this MCP server to inspect and manage GitLab projects, merge requests, issues, repositories, and collaboration workflows.
Review merge requests: approval state, MR details, diffs, changed files, file diffs, discussions, and notes.
Collaborate on merge requests: create/update MRs, add review threads or notes, and resolve threads.
Manage issues: create/update issues, patch descriptions, add notes, and list issue discussions.
Explore repositories: search projects, get project details/members/labels, list branches and repository trees, read files, list commits, get commit diffs, and view file blame.
Check authentication and server status with
whoamiandhealth_check.Discover and activate additional tool categories with
discover_tools, and get workflow guidance withhelp.Reduce response size using optional JMESPath filtering and summary/full-response controls.
Allows interaction with GitLab repositories including creating/updating files, pushing multiple files, searching repositories, creating repositories, getting file contents, creating issues, creating merge requests, forking repositories, creating branches, getting merge request details and diffs, updating merge requests, and creating notes/comments.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@gitlab mcplist open merge requests for project 123"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
GitLab MCP Server
English | 한국어 | 简体中文 | Português (Brasil)
📖 Documentation → · llms.txt · llms-full.txt
Default: 40 tools (38 core + discover_tools + help). 288 tools exist in total (285 in toolsets + execute_graphql + discover_tools + help). Start lean; call discover_tools to activate more for this session.
Token budget: MCP clients send the whole
tools/listto the model at session start. Keep the default (~40 tools, ~12k schema tokens). Calldiscover_toolsto activate a category for this session (session-only; withOAUTH_STATELESS_MODE=truepersist a namedGITLAB_TOOLSETSlist), or use Skill + CLI and skip MCP schemas. Do not setGITLAB_TOOLSETS=all— it loads ~all tools and costs ~73k schema tokens. See tools/list size and comparison.
Install the zereight-mcp-gitlab binary first with npm install -g @zereight/mcp-gitlab, or Homebrew brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp and brew install zereight/gitlab-mcp/zereight-mcp-gitlab. Official MCP Registry listing: io.github.zereight/gitlab-mcp. One-liner: npx -y @zereight/mcp-gitlab@latest.
Without → With
Without this MCP | With this MCP |
Paste MR URLs and diffs into chat |
|
Hunt job logs in the GitLab UI |
|
Re-explain the project path every turn |
|
Three install paths
Path | When | How |
Local IDE | Cursor, Claude Code, Codex on your machine | stdio + PAT or local OAuth |
Shared HTTP | Team or hosted MCP | Streamable HTTP URL + remote auth or MCP OAuth |
Claude.ai | Claude web connectors | Public HTTPS + |
Install
Install the binary first (npm install -g @zereight/mcp-gitlab, or Homebrew brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp then brew install zereight/gitlab-mcp/zereight-mcp-gitlab). Read the token without echo:
read -rs GITLAB_PERSONAL_ACCESS_TOKEN && export GITLAB_PERSONAL_ACCESS_TOKEN# Claude Code
claude mcp add gitlab --transport stdio --scope local --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab
# Codex
codex mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlabOther clients: VS Code · GitHub Copilot · JSON clients · Cursor details
Agent paste-prompt
Copy this into an agent that can edit MCP config:
Install the GitLab MCP server (@zereight/mcp-gitlab) for this workspace.
Binary: zereight-mcp-gitlab (npm i -g @zereight/mcp-gitlab, or npx -y @zereight/mcp-gitlab@latest).
Auth: GITLAB_PERSONAL_ACCESS_TOKEN plus GITLAB_API_URL=https://gitlab.com/api/v4 (or GITLAB_USE_OAUTH=true).
Local: claude mcp add gitlab --transport stdio --scope local --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab
Or: codex mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab
Cursor: use the README deeplink or docs/clients/cursor.md.
Remote HTTP: point the client at https://mcp.example.com/mcp (Streamable HTTP). Claude.ai needs GITLAB_MCP_OAUTH on that host.
Default list: 40 tools (38 core + discover_tools + help). Call discover_tools to expand. Do not set GITLAB_TOOLSETS=all (loads ~all schemas, ~73k tokens). Do not enable the api toolset unless you accept its bypass risk.
Equal non-MCP path: npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill plus the zereight-mcp-gitlab CLI.Remote HTTP
First-class option for a hosted or self-hosted server. Point the client at a Streamable HTTP URL:
{
"mcpServers": {
"gitlab": {
"type": "http",
"url": "https://mcp.example.com/mcp"
}
}
}Hosted / Claude.ai:
GITLAB_MCP_OAUTH=trueon the server (see MCP OAuth)Per-user PAT headers:
REMOTE_AUTHORIZATION=true(see Remote Authorization)Local Docker examples are in Usage
Skill + CLI (no MCP required)
Skill + CLI is an equal path, not a fallback. Same workflows, full payloads in a terminal, no MCP registration.
npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill
zereight-mcp-gitlab user whoami
zereight-mcp-gitlab mr listSee CLI without MCP and skills/gitlab-mcp/.
MCP vs Human CLI
Use MCP when | Use the CLI when |
The agent needs structured tools in chat | You need the full payload (diffs, logs, artifacts) |
|
|
You already registered the server | You have a PAT or ran |
Human CLI is never compacted. Destructive tools and GITLAB_TOOL_POLICY_APPROVE tools need --yes.
Tips
project_id is a numeric ID or a URL-encoded path. Example: group group, project project, merge request !123 → project_id=group%2Fproject, merge_request_iid=123. Nested groups use %2F between every segment (group%2Fsubgroup%2Fproject).
FAQ
How do I authenticate? Local desktop: GITLAB_PERSONAL_ACCESS_TOKEN (or GITLAB_PERSONAL_ACCESS_TOKEN_FILE) is the simplest. Local OAuth is GITLAB_USE_OAUTH=true. Remote Claude.ai uses GITLAB_MCP_OAUTH. Multi-user HTTP uses REMOTE_AUTHORIZATION and a per-request token header.
Why do I only see ~40 tools? The default core toolset is 38 tools plus always-on discover_tools and help. That is intentional: a client sends every listed schema to the model up front. Call discover_tools with no args to list categories, then pass a category (pipelines, wiki, …) to activate it for this session. Session-only; with OAUTH_STATELESS_MODE=true persist a named GITLAB_TOOLSETS list. Do not set GITLAB_TOOLSETS=all — it loads ~all schemas (~73k tokens) and still does not enable api.
Local OAuth vs MCP OAuth vs remote auth? Local OAuth opens a browser on the same machine as the server. MCP OAuth is for a public HTTPS server and clients such as Claude.ai. Remote authorization forwards the caller's PAT or job token; there is no OAuth dance.
How do I shrink huge replies? Pass jmespath on any tool call. Or set GITLAB_MCP_COMPACT_RESULTS=true so oversized MCP replies become a preview plus a CLI command. Use the CLI when you need the full payload.
Why is the api toolset dangerous? gitlab_api_request bypasses group/project allowlists, other tool filters, and per-tool safety checks. Prompt injection can drive it. Enable it only by listing api in GITLAB_TOOLSETS. all, discover_tools, and GITLAB_TOOLS do not.
Cursor rule / CLAUDE.md snippet
GitLab merge requests, issues, and pipelines go through this MCP (@zereight/mcp-gitlab).
Start with the default core tools. Call discover_tools to expand. Do not set GITLAB_TOOLSETS=all.
Prefer list_merge_request_changed_files, then batched get_merge_request_file_diff.
Use jmespath or compact results; use the CLI for full diffs and job logs.
@zereight/mcp-gitlab
Agent-workflow-optimized GitLab MCP — manage projects, merge requests, issues, pipelines, wiki, releases, tags, milestones, and more through stdio, SSE, and Streamable HTTP.
Supports PAT, OAuth, read-only mode, dynamic API URLs, and remote authorization for VS Code, Claude, Cursor, Copilot, and other MCP clients.
Why use this GitLab MCP?
Default 40 tools (38
core+discover_tools+help); 288 total — start lean; calldiscover_toolsto activate more without CQRS-style grouping.GITLAB_TOOLSETS=allloads ~all schemas (~73k tokens); prefer discover-on-demand or Skill + CLIMR 2-step review —
list_merge_request_changed_files→ batchedget_merge_request_file_diffAgent Skill built in — workflow guidance in
skills/gitlab-mcp/Flexible auth — Personal Access Token, local OAuth2 browser flow, MCP OAuth proxy, and per-request remote authorization
Multiple transports — stdio for local clients, SSE for legacy clients, and Streamable HTTP for modern remote deployments
Client-friendly setup — examples for Claude Code, Codex, Antigravity, OpenCode, Copilot, Cline, Roo Code, Cursor, Kilo Code, and Amp Code
Self-hosted ready — works with custom GitLab instances, proxy settings, and dynamic API URL routing
JMESPath result filtering — optional
jmespathon tool calls (seetools/list) shrinks JSON results without changing GitLab API requests; when response masking is enabled, JMESPath runs on masked data.
How we compare
@zereight/mcp-gitlab | GitLab MCP A (community CQRS-style) | GitLab official MCP server | |
Best for | AI agent workflows | Enterprise multi-instance / grouped tools | Built into GitLab, no separate install |
Tool model | 288 tools: 285 in toolsets + | ~50–60 grouped | Toolsets chosen with an HTTP header |
MR review | 2-step batched diff | Varies |
|
Node.js | >=20.0.0 | Often >=24 | Node.js 20+ for stdio via |
License | MIT | Varies | Part of GitLab |
tools/list size (measured 2026-11-05)
A client sends the whole tools/list result to the model at session start. Token estimate is UTF-8 bytes / 4.
Profile | Tools | JSON bytes | Est. tokens |
Default ( | 40 | 46,943 | 11,736 |
| 39 | 45,935 | 11,484 |
| 286 | 293,906 | 73,477 |
Re-measure with npm run build && npm run test:mock (test/tools-list-budget.test.ts) after description or schema changes.
GitLab also ships an official MCP server.
Free, Premium, and Ultimate. Moved from Premium to Free in GitLab 19.2. Generally available in GitLab 19.5.
On GitLab.com, a top-level group Owner allows access to the MCP server. On GitLab Self-Managed and GitLab Dedicated, an administrator controls the instance setting. Default rules are on the official page.
Remote clients use HTTP
https://<gitlab.example.com>/api/v4/mcpwith OAuth 2.0 dynamic client registration.stdio goes through
mcp-remoteand needs Node.js 20 or later.Toolsets use the
X-Gitlab-Enabled-Mcp-Server-Toolsetsheader. An optionalX-Gitlab-Mcp-Server-Tool-Name-Prefixheader keeps the first 32 characters of a tool-name prefix.
Full comparison with the official GitLab MCP server →
Quick start: choose either Personal Access Token or OAuth2 setup below, install @zereight/mcp-gitlab, and use zereight-mcp-gitlab in your MCP client configuration.
Client Setup Guides
JSON-Based MCP Clients Setup Guide - for Factory AI Droid, OpenClaw, and OpenCode style clients
Related MCP server: gitlab-mcp
Usage
Setup Overview
Authentication Methods
The server supports four authentication methods:
For local/desktop use (most common):
Personal Access Token (
GITLAB_PERSONAL_ACCESS_TOKENorGITLAB_PERSONAL_ACCESS_TOKEN_FILE) — simplest setupOAuth2 — Local Browser (
GITLAB_USE_OAUTH) — recommended for better security
For server/remote deployments:
OAuth2 — MCP Proxy (
GITLAB_MCP_OAUTH) — for remote MCP clients such as Claude.aiRemote Authorization (
REMOTE_AUTHORIZATION) — multi-user deployments where each caller provides their own token
Quick setup paths
Claude Code: see Claude Code Setup Guide
VS Code: see VS Code Setup Guide
GitHub Copilot: see GitHub Copilot Setup Guide
Codex: see Codex Setup Guide
Cursor: see Cursor Setup Guide
Factory AI Droid / OpenClaw / OpenCode style clients: see JSON-Based MCP Clients Setup Guide
OAuth browser flow details: see OAuth2 Authentication Setup Guide
OAuth without a localhost callback (SSO, remote shell, background clients): run
zereight-mcp-gitlab auth(GitLab 17.9+ device flow; 17.2–17.8 needoauth2_device_grant_flow), then start the server withGITLAB_USE_OAUTH=true. See standalone device-flow command.
For the simplest local setup, start with a Personal Access Token. For browser-based local auth, use OAuth2. For remote or multi-user deployments, continue to the MCP OAuth and Remote Authorization sections later in this README.
Install the server once:
brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp
brew install zereight/gitlab-mcp/zereight-mcp-gitlabOr with npm:
npm install -g @zereight/mcp-gitlabOr with Nix, by adding this flake to your own:
# flake.nix
inputs.gitlab-mcp.url = "github:zereight/gitlab-mcp";
# wherever you configure your MCP client:
command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;The store path is pinned by your lock file; update it with nix flake update gitlab-mcp.
The examples use zereight-mcp-gitlab, a less collision-prone alias for the legacy mcp-gitlab binary. If your MCP client cannot find it, use the absolute path from which zereight-mcp-gitlab.
No global install? Pin npx to the previous stable release (the version these docs recommend), for example npx -y @zereight/mcp-gitlab@2.3.21. If you always want the newest release, use npx -y @zereight/mcp-gitlab@latest instead. To try a fix merged to main before the next stable release, use npx -y @zereight/mcp-gitlab@next, a pre-release build that is not meant for production. The server prints a notice to stderr on startup when a newer version is available (disable with GITLAB_DISABLE_VERSION_CHECK=true).
Claude Desktop one-click install (MCP Bundle)
Every GitHub release after v2.3.1 ships a gitlab-mcp.mcpb MCP Bundle. Download the latest bundle and open it with Claude Desktop (or drag it into Settings → Extensions). Claude Desktop asks for your Personal Access Token (stored as a sensitive value) and lets you set GITLAB_API_URL, GITLAB_PERMISSION_MODE, GITLAB_TOOLSETS, and GITLAB_MASKING_ENABLED. No separate Node.js or npm install is needed.
To build the bundle from source, run npm run pack:mcpb (writes gitlab-mcp.mcpb).
Using CLI Arguments (for clients with env var issues)
Some MCP clients (like GitHub Copilot CLI) have issues with environment variables. Use CLI arguments instead:
{
"mcpServers": {
"gitlab": {
"command": "zereight-mcp-gitlab",
"args": ["--token=YOUR_GITLAB_TOKEN", "--api-url=https://gitlab.com/api/v4"],
"tools": ["*"]
}
}
}Available CLI arguments:
--token- GitLab Personal Access Token (replacesGITLAB_PERSONAL_ACCESS_TOKEN)--api-url- GitLab API URL (replacesGITLAB_API_URL)--read-only=true- Deprecated (removed in next major (v3.0.0)); use--permission-mode=readonlyinstead (replacesGITLAB_READ_ONLY_MODE)--permission-mode- Permission level:readonly,modify(no delete or teardown tools), orfull(replacesGITLAB_PERMISSION_MODE, defaultfull)--toolsets- Named toolsets (replacesGITLAB_TOOLSETS; unset uses the leancoredefault). Do not passallunless you accept ~73k schema tokens.gitlab_api_requestneeds--toolsets=api--tools=list_issues- Add individual tools (replacesGITLAB_TOOLS)--use-wiki=true- Deprecated (removed in next major (v3.0.0)); use--toolsets=core,wikiinstead (replacesUSE_GITLAB_WIKI)--use-milestone=true- Deprecated (removed in next major (v3.0.0)); use--toolsets=core,milestonesinstead (replacesUSE_MILESTONE)--use-pipeline=true- Deprecated (removed in next major (v3.0.0)); use--toolsets=core,pipelinesand appendvalidate_ci_lint,validate_project_ci_lintto the existing--toolslist (or set--tools=validate_ci_lint,validate_project_ci_lintwhen that list is unset) (replacesUSE_PIPELINE)--disable-version-check=true- Disable the startup new-version notice (replacesGITLAB_DISABLE_VERSION_CHECK)--masking-enabled=true- Enable text-response masking (replacesGITLAB_MASKING_ENABLED)--masking-config- Path to a masking configuration file (replacesGITLAB_MASKING_CONFIG)--masking-policy-file- Path to a protected managed-policy file (replacesGITLAB_MASKING_POLICY_FILE)--masking-workspace-dir- Directory used to resolve masking files (replacesGITLAB_MASKING_WORKSPACE_DIR)--download-dir- Directorydownload_attachmentanddownload_job_artifactssave files under (replacesGITLAB_DOWNLOAD_DIR; default.gitlab-mcp-downloads)--compact-results=true- Truncate oversized MCP tool replies and attach a CLI command for the full payload (replacesGITLAB_MCP_COMPACT_RESULTS; default off)--compact-result-chars- Character threshold for compacting (replacesGITLAB_MCP_COMPACT_RESULT_CHARS; default4000)--compact-tools- Comma-separated tool names to compact when oversized, without turning global compact on (replacesGITLAB_MCP_COMPACT_TOOLS)--list-summary-default=true-list_*tools andmr_discussionstreat an omittedsummaryargument astrue;summary: falsestill returns the full JSON (replacesGITLAB_MCP_LIST_SUMMARY_DEFAULT; default off)--tool-profile-full(default) orslim.slimdrops draft notes, emoji reactions, labels, CI catalog tools, andcreate_groupfrom the initial list. Ignored whenGITLAB_TOOLSETSis set (replacesGITLAB_TOOL_PROFILE)
If you already set GITLAB_TOOLSETS or --toolsets, append wiki, milestones, or pipelines to that list instead of replacing it. If you already set GITLAB_TOOLS or --tools, append validate_ci_lint and validate_project_ci_lint to that list instead of replacing it. An explicit list replaces the default core toolset; it does not merge.
CLI arguments take precedence over environment variables.
zereight-mcp-gitlab auth is a subcommand (not an MCP server flag). It runs GitLab device flow and exits. See CLI Arguments.
The same binary is also a gh-style GitLab CLI (tool <name> or curated forms such as mr list). No MCP registration is needed — set a PAT, or run auth and set GITLAB_USE_OAUTH=true: see CLI without MCP. setup --cursor / setup --claude prints client config; doctor checks token, API URL, toolsets, and version. Use it for the full payload in a terminal. MCP replies stay in the chat unless you set GITLAB_MCP_COMPACT_RESULTS=true (or --compact-results), which replaces oversized tool replies with a preview and a CLI command. Human CLI is never compacted. Same permission mode, toolsets, denied-tools regex, and tool-policy filters. Destructive tools and GITLAB_TOOL_POLICY_APPROVE tools need --yes. See Human CLI.
Fine-grained tool filtering: use
GITLAB_PERMISSION_MODE=modifyto allow create/update while blocking every delete tool and the destructive teardown tools (cancel_pipeline,cancel_pipeline_job,stop_environment,stop_stale_environments,unprotect_branch,unprotect_tag) — including destructive mutations (deletion and teardown verbs) throughexecute_graphqlandpush_filesdelete/moveactions — orGITLAB_PERMISSION_MODE=readonlyfor read-only access. You can also enable toolset groups withGITLAB_TOOLSETS=<group,…>, allow-list individual tools withGITLAB_TOOLS=<tool,…>(e.g. read-only groups plus a few specific write tools), and deny-list by pattern withGITLAB_DENIED_TOOLS_REGEX. The legacyUSE_GITLAB_WIKI/USE_MILESTONE/USE_PIPELINEflags are deprecated (removed in next major (v3.0.0)). UseGITLAB_TOOLSETS=core,wiki,core,milestones, orcore,pipelines(USE_PIPELINEalso needsvalidate_ci_lint,validate_project_ci_lintappended to an existingGITLAB_TOOLSlist instead of replacing it). If you already setGITLAB_TOOLSETS, append the toolset to your existing list instead of replacing it. IfGITLAB_TOOLSis unset, setGITLAB_TOOLS=validate_ci_lint,validate_project_ci_lint. If it is already set, appendvalidate_ci_lint,validate_project_ci_lintinstead of replacing that list. See Tools Reference and Environment Variables.
gitlab_api_request (toolset api) bypasses GITLAB_ALLOWED_GROUPS and other group restrictions, project allowlists, tool-level restrictions (GITLAB_TOOLS, GITLAB_DENIED_TOOLS_REGEX on other tools), and individual tool safety checks. The full token permission scope is exposed. Prompt injection can drive this tool. Operators who rely on these restrictions must NOT enable it.
Enable it only by listing api in GITLAB_TOOLSETS (GITLAB_TOOLSETS=all, discover_tools, GITLAB_TOOLS, legacy USE_* flags, and GITLAB_TOOL_PROFILE do not). With GITLAB_ALLOWED_PROJECT_IDS or a session project scope, only /projects/:id paths for an allowed project are accepted. Endpoints such as /search, /users, /groups/:id, and /runners are rejected. Body and query parameters that name another project are not checked. GITLAB_PROJECT_ID and OAuth group allowlists are not enforced.
sse
Pass the variable name only. The Docker client copies the exported GITLAB_PERSONAL_ACCESS_TOKEN into the container.
docker run -i --rm \
-e HOST=0.0.0.0 \
-e GITLAB_PERSONAL_ACCESS_TOKEN \
-e GITLAB_API_URL="https://gitlab.com/api/v4" \
-e GITLAB_PERMISSION_MODE=readonly \
-e GITLAB_TOOLSETS=core,wiki,milestones,pipelines \
-e SSE=true \
-e SSE_AUTH_TOKEN=your_mcp_sse_token \
-p 3333:3002 \
zereight050/gitlab-mcp{
"mcpServers": {
"gitlab": {
"type": "sse",
"url": "http://localhost:3333/sse",
"headers": {
"Authorization": "Bearer your_mcp_sse_token"
}
}
}
}streamable-http
docker run -i --rm \
-e HOST=0.0.0.0 \
-e REMOTE_AUTHORIZATION=true \
-e GITLAB_API_URL="https://gitlab.com/api/v4" \
-e GITLAB_PERMISSION_MODE=readonly \
-e GITLAB_TOOLSETS=core,wiki,milestones,pipelines \
-e STREAMABLE_HTTP=true \
-p 3333:3002 \
zereight050/gitlab-mcp{
"mcpServers": {
"gitlab": {
"type": "streamable-http",
"url": "http://localhost:3333/mcp",
"headers": {
"Authorization": "Bearer glpat-..."
}
}
}
}Using MCP OAuth Proxy (GITLAB_MCP_OAUTH)
For server/remote deployments only. This mode requires the MCP server to be deployed with a publicly accessible HTTPS URL. For local/desktop use, see
GITLAB_USE_OAUTHabove.
For remote MCP clients that support the MCP OAuth specification (e.g. Claude.ai).
The server acts as a full OAuth 2.0 authorization server — unauthenticated requests
receive a 401 + WWW-Authenticate response, which triggers the OAuth browser flow
automatically on the client side.
Remote MCP clients such as OpenCode, MCPJam, and Claude.ai can send their own
callback URL during authorization. If you cannot register every client callback
URL in GitLab, enable GITLAB_OAUTH_CALLBACK_PROXY=true. With callback proxy
mode, GitLab only needs one registered redirect URI: {MCP_SERVER_URL}/callback.
GITLAB_OAUTH_REDIRECT_URI is for local OAuth (GITLAB_USE_OAUTH) only. It does
not override remote MCP OAuth client callback URLs and should not be used to fix
remote Unregistered redirect_uri errors.
This variable exists because the local OAuth flow starts a browser on the same
machine as the MCP server and listens for the callback on a local HTTP server,
for example http://127.0.0.1:8888/callback.
Remote MCP OAuth is different. In GITLAB_MCP_OAUTH=true mode, the MCP client
provides its own callback URL during /authorize. GITLAB_OAUTH_REDIRECT_URI
does not replace that client-provided URL.
Mode | Enable with | Callback variable | GitLab redirect URI |
Local OAuth |
|
|
|
Remote MCP OAuth |
|
|
|
Use GITLAB_OAUTH_REDIRECT_URI only when the MCP server itself owns the local
browser callback. Use GITLAB_OAUTH_CALLBACK_PROXY=true when a remote MCP client
owns the callback URL.
How it works: You deploy this MCP server somewhere with a public HTTPS URL. MCP
clients connect to {MCP_SERVER_URL}/mcp. The server handles the OAuth 2.0 flow,
exchanging credentials with GitLab on behalf of the client.
Prerequisites:
A publicly accessible HTTPS server URL (
MCP_SERVER_URL) — use ngrok for local testingA pre-registered GitLab OAuth application with
api(orread_api) scopes — Go toAdmin area→Applications, set Redirect URI to{MCP_SERVER_URL}/callback
Environment Variable | Required | Description |
| ✅ | Set to |
| ✅ | GitLab API base URL. Do not embed credentials ( |
| ✅ | GitLab OAuth Application ID |
| ✅ | Public HTTPS URL of this MCP server |
| ✅ | Must be |
| optional | Set to |
| optional | Client callback URLs that callback proxy mode will redirect to (default: Claude, ChatGPT, Cursor and loopback callbacks; |
| optional | Comma-separated scopes (default: |
| optional | Comma-separated group full paths — only members (and subgroup members) may use the server (replaces deprecated |
| optional | Set to |
When STREAMABLE_HTTP=true, server-side GitLab credentials (GITLAB_PERSONAL_ACCESS_TOKEN, GITLAB_JOB_TOKEN, GITLAB_AUTH_COOKIE_PATH, or GITLAB_USE_OAUTH) require REMOTE_AUTHORIZATION=true, GITLAB_MCP_OAUTH=true, or STREAMABLE_HTTP_AUTH_TOKEN.
Troubleshooting
Unregistered redirect_uriCheck the
redirect_uriin the browser URL. If it points to a client callback such ashttp://127.0.0.1:xxxxx/.../callback, enable:GITLAB_OAUTH_CALLBACK_PROXY=trueDo not fix remote MCP OAuth by changing
GITLAB_OAUTH_REDIRECT_URI. That variable is for local OAuth (GITLAB_USE_OAUTH) only.
docker run -i --rm \
-e HOST=0.0.0.0 \
-e GITLAB_MCP_OAUTH=true \
-e GITLAB_OAUTH_CALLBACK_PROXY=true \
-e STREAMABLE_HTTP=true \
-e MCP_SERVER_URL=https://your-server.example.com \
-e GITLAB_API_URL="https://gitlab.com/api/v4" \
-e GITLAB_OAUTH_APP_ID=your_app_id \
-p 3000:3002 \
zereight050/gitlab-mcpMCP client configuration:
{
"mcpServers": {
"gitlab": {
"type": "http",
"url": "https://your-server.example.com/mcp"
}
}
}Using Remote Authorization (REMOTE_AUTHORIZATION)
For server/remote deployments only. Each HTTP caller provides their own GitLab token directly in request headers — no OAuth flow involved.
For multi-user or multi-tenant deployments where each caller provides their own GitLab token in the HTTP request header. No OAuth flow — the MCP server forwards the token to GitLab on behalf of the caller.
Header priority: Private-Token > JOB-TOKEN > Authorization: Bearer
Environment Variable | Required | Description |
| ✅ | Set to |
| ✅ | Must be |
| optional | Allow per-request GitLab URL via |
| optional | Comma-separated allowed |
| optional | Allow unauthenticated |
| optional | Allowed public |
| optional | Trust |
GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY=true is intended for MCP gateways
or admin UIs that need to inspect tool metadata before a user provides a GitLab
token. Leave it disabled unless the tool list is safe to expose in your deployment.
When MCP_SERVER_URL is not set, remote download URLs fall back to the local
server address. Set MCP_TRUST_PROXY=true only if the server is reachable through a
trusted reverse proxy and direct client access to the MCP server is blocked.
This enables Express trust proxy for Streamable HTTP and SSE, derives public
download URLs from Forwarded / X-Forwarded-Proto / X-Forwarded-Host /
X-Forwarded-Prefix, and keeps OAuth endpoint rate limiting working when
proxies send X-Forwarded-For with a client port (for example 1.2.3.4:5678).
Existing OAuth+proxy deployments must set this explicitly after the flag was
introduced.
Example request headers:
Private-Token: glpat-xxxxxxxxxxxxxxxxxxxxor using a Bearer token:
Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx⚠️
REMOTE_AUTHORIZATIONis not compatible with SSE transport.STREAMABLE_HTTP=trueis required.
Environment Variables
Use the dedicated reference for the full environment variable list:
Most users only need one of these starting sets:
Local PAT:
GITLAB_PERSONAL_ACCESS_TOKEN,GITLAB_API_URLLocal OAuth:
GITLAB_USE_OAUTH=true,GITLAB_OAUTH_CLIENT_ID,GITLAB_OAUTH_REDIRECT_URI,GITLAB_API_URLRemote multi-user HTTP:
STREAMABLE_HTTP=true,REMOTE_AUTHORIZATION=true(orGITLAB_MCP_OAUTH=true),MCP_TRUST_PROXY=true(behind a reverse proxy),MAX_REQUESTS_PER_MINUTE=300,MCP_SERVER_URLorMCP_ALLOWED_HOSTS,HOST,PORTMultiple side-by-side deployments: set a distinct
MCP_SERVER_NAMEper instance (e.g.gitlab-selfhosted-readonly) so clients, logs, and telemetry can tell them apartMulti-pod HPA (stateless): above +
OAUTH_STATELESS_MODE=true,OAUTH_STATELESS_SECRET(same across all pods). See Stateless Mode.
Commonly referenced variables:
GITLAB_API_URLGITLAB_PERSONAL_ACCESS_TOKENGITLAB_USE_OAUTHREMOTE_AUTHORIZATIONMCP_TRUST_PROXYMAX_REQUESTS_PER_MINUTEMAX_SESSIONSMCP_ALLOWED_HOSTSMCP_ALLOWED_ORIGINSGITLAB_MCP_OAUTHGITLAB_OAUTH_CALLBACK_PROXYGITLAB_OAUTH_ALLOWED_REDIRECT_URISOAUTH_REGISTER_RATE_LIMIT_PER_HOUROAUTH_DISABLE_REFRESH_TOKENOAUTH_STATELESS_MODEOAUTH_STATELESS_SECRET
The reference document also covers:
auth and OAuth variables
MCP OAuth proxy variables
project and tool filtering variables
dynamic tool discovery via
discover_tools(on-demand toolset activation)transport and session variables
proxy and TLS variables
For callback proxy mode details, see GitLab MCP OAuth Callback Proxy.
SSE session limits
GET /sse is subject to the same remote-transport controls as Streamable HTTP:
Capacity: at most
MAX_SESSIONSconcurrent SSE sessions (default 1000); further connections get503.Creation rate limit: new connections are limited to
MAX_REQUESTS_PER_MINUTEper client IP (default 60); excess connections get429.Idle timeout: a session that receives no
POST /messagesrequest forSESSION_TIMEOUT_SECONDS(default 1 hour) is closed, so an idle client must reconnect instead of holding a capacity slot. Unlike Streamable HTTP, holding the SSE stream open does not count as activity./healthreturns503withstatus: "degraded"while the instance is at capacity.
Tune these with MAX_SESSIONS, MAX_REQUESTS_PER_MINUTE, and SESSION_TIMEOUT_SECONDS.
Streamable HTTP session timeout
Streamable HTTP sessions use the same SESSION_TIMEOUT_SECONDS idle timeout in every mode, including a server-side token without REMOTE_AUTHORIZATION or GITLAB_MCP_OAUTH: a session with no POST /mcp request for that long is closed, and its next request gets 404 so the client re-initializes. An open GET /mcp stream pauses the timer until the stream closes or the next POST /mcp arrives, so a client with a stream open still expires SESSION_TIMEOUT_SECONDS after its last POST.
Remote Authorization Setup (Multi-User Support)
When using REMOTE_AUTHORIZATION=true, the MCP server can support multiple users, each with their own GitLab token passed via HTTP headers. This is useful for:
Shared MCP server instances where each user needs their own GitLab access
IDE integrations that can inject user-specific tokens into MCP requests
Setup Example:
# Start server with remote authorization
docker run -d \
-e HOST=0.0.0.0 \
-e STREAMABLE_HTTP=true \
-e REMOTE_AUTHORIZATION=true \
-e GITLAB_API_URL="https://gitlab.com/api/v4" \
-e GITLAB_PERMISSION_MODE=readonly \
-e SESSION_TIMEOUT_SECONDS=3600 \
-p 3333:3002 \
zereight050/gitlab-mcpClient Configuration:
Your IDE or MCP client must send one of these headers with each request:
Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxxor
Private-Token: glpat-xxxxxxxxxxxxxxxxxxxxThe token is stored per session (identified by mcp-session-id header) and reused for subsequent requests in the same session. The session belongs to the GitLab user of that token: a request with another user's token gets 404 Session not found, and GET / DELETE /mcp without a token get 401.
Remote Authorization Client Configuration Example with Cursor
{
"mcpServers": {
"GitLab": {
"url": "http(s)://<your_mcp_gitlab_server>/mcp",
"headers": {
"Authorization": "Bearer glpat-..."
}
}
}
}Important Notes:
Remote authorization only works with Streamable HTTP transport
Each session is isolated - tokens from one session cannot access another session's data Tokens are automatically cleaned up when sessions close
Session timeout: Auth tokens expire after
SESSION_TIMEOUT_SECONDS(default 1 hour) of inactivity. After timeout the session is closed and its next request gets404, so the client re-initializes with its auth headers.Each request resets the timeout timer for that session
Rate limiting:
/mcprequests are limited toMAX_REQUESTS_PER_MINUTEper client IP, and per MCP session when using OAuth or remote authorization (default 60). The per-IP limit uses a fixed 60-second window, counts per server process, and also coversGET /mcp; stateless mode skips the per-session limit. See environment-variables.md.Capacity limit: Server accepts up to
MAX_SESSIONSconcurrent sessions (default 1000)
MCP OAuth Setup (Claude.ai Native OAuth)
When using GITLAB_MCP_OAUTH=true, the server acts as an OAuth proxy to your GitLab
instance. Claude.ai (and any MCP-spec-compliant client) handles the entire browser
authentication flow automatically — no manual Personal Access Token management needed.
Prerequisites:
A pre-registered GitLab OAuth application is required. GitLab restricts dynamically
registered (unverified) applications to the mcp scope, which is insufficient for API
calls (need api or read_api).
Go to your GitLab instance → Admin Area > Applications (instance-wide) or User Settings > Applications (personal)
Create a new application with:
Confidential: unchecked
Scopes:
api,read_api,read_user(or whichever scopes you intend to request viaGITLAB_OAUTH_SCOPES)
Save and copy the Application ID — this is your
GITLAB_OAUTH_APP_ID
How it works:
User adds your MCP server URL in Claude.ai
Claude.ai discovers OAuth endpoints via
/.well-known/oauth-authorization-serverClaude.ai registers itself via Dynamic Client Registration (
POST /register) — handled locally by the MCP server (each client gets a virtual client ID)Claude.ai redirects the user's browser to GitLab's login page using the pre-registered OAuth application
User authenticates; GitLab redirects back to
https://claude.ai/api/mcp/auth_callbackClaude.ai sends
Authorization: Bearer <token>on every MCP requestServer validates the token with GitLab and stores it per session
Server setup:
docker run -d \
-e STREAMABLE_HTTP=true \
-e GITLAB_MCP_OAUTH=true \
-e GITLAB_OAUTH_APP_ID="your-gitlab-oauth-app-client-id" \
-e GITLAB_API_URL="https://gitlab.example.com/api/v4" \
-e MCP_SERVER_URL="https://your-mcp-server.example.com" \
-p 3002:3002 \
zereight050/gitlab-mcpFor local development (HTTP allowed):
MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URL=true \
STREAMABLE_HTTP=true \
GITLAB_MCP_OAUTH=true \
GITLAB_OAUTH_APP_ID=your-gitlab-oauth-app-client-id \
MCP_SERVER_URL=http://localhost:3002 \
GITLAB_API_URL=https://gitlab.com/api/v4 \
node build/index.jsClaude.ai configuration:
{
"mcpServers": {
"GitLab": {
"url": "https://your-mcp-server.example.com/mcp"
}
}
}No headers field is needed — Claude.ai obtains the token via OAuth automatically.
Environment variables:
Variable | Required | Description |
| Yes | Set to |
| Yes | Client ID of the pre-registered GitLab OAuth application |
| Yes | Public HTTPS URL of your MCP server; also allowed for |
| Yes | Your GitLab instance API URL (e.g. |
| Yes | Must be |
| No | Comma-separated GitLab scopes to request (e.g. |
| No | Per-IP limit (fixed 1-hour window) for Dynamic Client Registration ( |
| No | Set |
| No | Set |
Important Notes:
MCP OAuth only works with Streamable HTTP transport (
SSE=trueis incompatible)Each user session stores its own OAuth token — sessions are fully isolated
Session timeout, rate limiting, and capacity limits apply identically to the
REMOTE_AUTHORIZATIONmode (SESSION_TIMEOUT_SECONDS,MAX_REQUESTS_PER_MINUTE,MAX_SESSIONS)DCR rate limiting:
POST /registeris limited toOAUTH_REGISTER_RATE_LIMIT_PER_HOURper client IP (default 20/hour). Separate from/mcplimits and GitLab API quotas. See environment-variables.md.Header auth fallback: when
Private-TokenorJOB-TOKENrequest headers are present, OAuth validation is skipped and the raw token is used directly for that session. This allows PATs and CI job tokens to be used alongside the OAuth flow on the same server instance.Authorization: Beareris always treated as an OAuth token — usePrivate-Tokenfor PAT-based header auth.
Agent Skill Files
Skill + CLI is an equal path to MCP (see Skill + CLI). Pre-built skill files are available in skills/gitlab-mcp/ for AI agents that support skill/instruction loading (Claude Code, GitHub Copilot, Cursor, etc.).
SKILL.md — Core guide (~800 tokens) with toolset overview, key workflows, and parameter hints
reference/ — Detailed workflow docs for code review, merge requests, issues, pipelines, and vulnerability triage
Install with the skills CLI:
npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skillRegister the skill directory in your AI client to get optimal tool usage guidance without relying solely on the full ListTools response.
Tools 🛠️
merge_merge_request- Merge a merge requestapprove_merge_request- Approve a merge requestunapprove_merge_request- Unapprove a merge requestget_merge_request_approval_state- Get merge request approval details including approversget_merge_request_conflicts- Get the conflicts of a merge requestlist_merge_request_pipelines- List pipelines for a merge request with paginationexecute_graphql- Execute a GitLab GraphQL querycreate_or_update_file- Create or update a file in a GitLab projectsearch_repositories- Search for GitLab projectscreate_repository- Create a new GitLab projectcreate_group- Create new group or subgroupget_file_contents- Get contents of a file or directory from a GitLab projectpush_files- Push multiple files in a single commitcreate_issue- Create a new issuecreate_merge_request- Create a new merge requestfork_repository- Fork a project to your account or specified namespacecreate_branch- Create a new branchget_branch- Get branch details (commit, protection status)list_branches- List branches in project with search filterdelete_branch- Delete branch from projectlist_protected_branches- List protected branches in a project, supports search filterget_protected_branch- Get details of a single protected branch (access levels, force push settings)protect_branch- Protect a repository branch (set push/merge/unprotect access levels)update_protected_branch- Update an existing protected branch rule in place (access levels, force push, code owner approval)unprotect_branch- Remove protection from a previously protected branchupdate_default_branch- Change the default branch of a projectget_merge_request- Get details of a merge request (merge_request_iid or source_branch required). Set include_summaries=true for deployment/commit/approval summariesget_merge_request_diffs- Get the changes/diffs of a merge request (merge_request_iid or source_branch required)list_merge_request_changed_files- List changed file paths in a merge request without diff content (merge_request_iid or source_branch required)list_merge_request_diffs- List merge request diffs with pagination (merge_request_iid or source_branch required)get_merge_request_file_diff- Get diffs for specific files from a merge request (merge_request_iid or source_branch required)list_merge_request_versions- List all versions of a merge requestget_merge_request_version- Get a specific version of a merge requestget_branch_diffs- Get diffs between two branches or commitsupdate_merge_request- Update a merge request (merge_request_iid or source_branch required)create_note- Create a new note (comment) to an issue or merge requestcreate_merge_request_thread- Create a new thread on a merge requestresolve_merge_request_thread- Resolve a thread on a merge requestmr_discussions- List discussion items for a merge requestget_merge_request_discussion- Get a single discussion item for a merge requestdelete_merge_request_discussion_note- Delete a discussion note on a merge requestupdate_merge_request_discussion_note- Update a discussion note on a merge requestcreate_merge_request_discussion_note- Add a new discussion note to an existing merge request threadcreate_merge_request_note- Add a new note to a merge requestdelete_merge_request_note- Delete an existing merge request noteget_merge_request_note- Get a specific note for a merge requestget_merge_request_notes- List notes for a merge requestupdate_merge_request_note- Modify an existing merge request noteget_draft_note- Get a single draft note from a merge requestlist_draft_notes- List draft notes for a merge requestcreate_draft_note- Create a draft note for a merge requestupdate_draft_note- Update an existing draft notedelete_draft_note- Delete a draft notepublish_draft_note- Publish a single draft notebulk_publish_draft_notes- Publish all draft notes for a merge request. Optionally sets reviewer_state and posts a summary note (GitLab 19.2+). Can set reviewer_state even with no drafts.list_merge_request_emoji_reactions- List all emoji reactions on a merge requestlist_merge_request_note_emoji_reactions- List all emoji reactions on a merge request note. Pass discussion_id for discussion thread replies.create_merge_request_emoji_reaction- Add an emoji reaction to a merge request (e.g. thumbsup, rocket, eyes)delete_merge_request_emoji_reaction- Remove an emoji reaction from a merge requestcreate_merge_request_note_emoji_reaction- Add an emoji reaction to a merge request note. Pass discussion_id for discussion thread replies.delete_merge_request_note_emoji_reaction- Remove an emoji reaction from a merge request note. Pass discussion_id for discussion thread replies.update_issue_note- Modify an existing issue thread notecreate_issue_note- Add a note to an issue, optionally replying to a discussion threadlist_issue_emoji_reactions- List all emoji reactions on an issuelist_issue_note_emoji_reactions- List all emoji reactions on an issue note. Pass discussion_id for discussion thread replies.create_issue_emoji_reaction- Add an emoji reaction to an issue (e.g. thumbsup, rocket, eyes)delete_issue_emoji_reaction- Remove an emoji reaction from an issuecreate_issue_note_emoji_reaction- Add an emoji reaction to an issue note. Pass discussion_id for discussion thread replies.delete_issue_note_emoji_reaction- Remove an emoji reaction from an issue note. Pass discussion_id for discussion thread replies.list_issues- List issues (default: created by current user; use scope='all' for all)my_issues- List issues assigned to the authenticated userget_issue- Get one issue. Slim nested milestone by default; full_response=true for the complete milestoneupdate_issue- Update an issue. Slim confirmation by default; full_response=true for the complete objectupdate_issue_description_patch- Patch an issue description (search/replace or unified diff) without resending the full body. dry_run previews; create_note summarizesreorder_issue- Move an issue within the manual sort order shown on issue boards. move_after_id and move_before_id take the neighbor issue's global id (theidfield), not its iid; pass at least one. Returns the reordered issue.delete_issue- Delete an issuelist_todos- List GitLab to-do items for the current usermark_todo_done- Mark a GitLab to-do item as donemark_all_todos_done- Mark all pending GitLab to-do items as done for the current userlist_issue_links- List all issue links for a specific issuelist_issue_discussions- List discussions for an issueget_issue_link- Get a specific issue linkcreate_issue_link- Create an issue link between two issuesdelete_issue_link- Delete an issue linklist_namespaces- List all namespaces (users and groups) available to the current user. Filter by kind='group' for groups only.get_namespace- Get details of a namespace (user or group) by ID or path. Groups are namespaces with kind='group'.verify_namespace- Verify if a namespace path exists. Use parent_id to scope the check to a specific parent namespace — required for nested namespaces where the same path may exist under different parents.get_project- Get details of a specific projectlist_projects- List projects accessible by the current userupdate_project- Update project settings such as description, visibility, default branch, and feature access levelslist_project_members- List members of a GitLab projectlist_group_members- List members of a GitLab group with optional name or username searchlist_labels- List labels for a projectget_label- Get a single label from a projectcreate_label- Create a new label in a projectupdate_label- Update an existing label in a projectdelete_label- Delete a label from a projectlist_group_projects- List projects in a grouplist_wiki_pages- List wiki pages in a projectget_wiki_page- Get details of a specific wiki pagecreate_wiki_page- Create a wiki page in a projectupdate_wiki_page- Update a wiki page in a projectdelete_wiki_page- Delete a wiki page from a projectlist_group_wiki_pages- List wiki pages in a groupget_group_wiki_page- Get details of a specific group wiki pagecreate_group_wiki_page- Create a wiki page in a groupupdate_group_wiki_page- Update a wiki page in a groupdelete_group_wiki_page- Delete a wiki page from a groupget_repository_tree- List files and directories in a repositorylist_pipelines- List pipelines with filtering optionsget_pipeline- Get details of a specific pipelineget_pipeline_variables- Get variables configured for a pipelineget_pipeline_test_report- Get pipeline test reportget_pipeline_test_report_summary- Get pipeline test report summarydelete_pipeline- Delete a pipeline. Requires the project Owner role, cannot be undone, and does not automatically delete child pipelines.update_pipeline_metadata- Update pipeline metadatalist_deployments- List deployments with filtering optionsget_deployment- Get deployment details, including approval_summary, approvals, and pending_approval_count when GitLab provides themcreate_deployment- Create a deploymentupdate_deployment- Update a deployment statusdelete_deployment- Delete a deploymentlist_deployment_merge_requests- List merge requests shipped with a deploymentapprove_deployment- Approve or reject a protected-environment deploymentlist_environments- List environments in a projectget_environment- Get details of a specific environmentupdate_environment- Update an environmentdelete_environment- Delete a stopped environmentstop_environment- Stop an environmentstop_stale_environments- Stop eligible stale environments; protected environments are excluded and environments are stopped, not deleteddelete_review_app_environments- Schedule deletion of stopped review-app environments one week later; dry_run defaults to true and actual scheduling requires dry_run=falselist_pipeline_triggers- List project pipeline trigger tokensget_pipeline_trigger- Get a project pipeline triggercreate_pipeline_trigger- Create a project pipeline triggerupdate_pipeline_trigger- Update a project pipeline triggerdelete_pipeline_trigger- Delete a project pipeline triggertrigger_pipeline- Trigger a pipeline with a pipeline trigger tokenlist_pipeline_jobs- List all jobs in a specific pipelinelist_pipeline_trigger_jobs- List trigger jobs (bridges) in a pipelineget_pipeline_job- Get details of a GitLab pipeline job numberget_pipeline_job_output- Get a pipeline job trace, with end-based pagination or full-log substring/regex searchvalidate_ci_lint- Validate provided GitLab CI/CD YAML content for a projectvalidate_project_ci_lint- Validate an existing .gitlab-ci.yml configuration for a projectlist_ci_catalog_resources- List GitLab CI/CD Catalog resources/components visible to the userget_ci_catalog_resource- Get details for a GitLab CI/CD Catalog resource, including versions and componentscreate_pipeline- Create a new pipeline for a branch or tagretry_pipeline- Retry a failed or canceled pipelinecancel_pipeline- Cancel a running pipelinelist_pipeline_schedules- List pipeline schedules in a project, optionally filtered to active or inactiveget_pipeline_schedule- Get details of a specific pipeline schedule, including its variables and last pipelinelist_pipeline_schedule_pipelines- List the pipelines that a pipeline schedule has triggeredcreate_pipeline_schedule- Create a new pipeline schedule for a branch or tagupdate_pipeline_schedule- Update an existing pipeline scheduledelete_pipeline_schedule- Delete a pipeline scheduleplay_pipeline_schedule- Run a pipeline schedule immediatelytake_ownership_pipeline_schedule- Take ownership of a pipeline scheduleget_pipeline_schedule_variable- Get a single variable of a pipeline schedulecreate_pipeline_schedule_variable- Create a variable for a pipeline scheduleupdate_pipeline_schedule_variable- Update a variable of a pipeline scheduledelete_pipeline_schedule_variable- Delete a variable from a pipeline scheduleplay_pipeline_job- Run a manual pipeline jobplay_pipeline_jobs- Play multiple manual pipeline jobs sequentiallyretry_pipeline_job- Retry a failed or canceled pipeline jobcancel_pipeline_job- Cancel a running pipeline joberase_pipeline_job- Erase a pipeline job log and artifactswait_for_pipeline- Wait for a pipeline to reach a terminal statuswait_for_job- Wait for a job to reach a terminal statuslist_job_artifacts- List artifact files in a job's archivedownload_job_artifacts- Download job artifact archive (zip) and save it under the download directoryget_job_artifact_file- Get content of a single file from a job's artifactslist_merge_requests- List merge requests (without project_id: user's MRs; with project_id: project MRs)list_group_merge_requests- List merge requests across all projects of a group and its subgroupslist_milestones- List milestones with filtering optionsget_milestone- Get details of a specific milestonecreate_milestone- Create a new milestoneedit_milestone- Edit an existing milestonedelete_milestone- Delete a milestoneget_milestone_issue- Get issues associated with a specific milestoneget_milestone_merge_requests- Get merge requests associated with a specific milestonepromote_milestone- Promote a milestone to the next stageget_milestone_burndown_events- Get burndown events for a specific milestonelist_group_milestones- List group milestones with filtering optionsget_group_milestone- Get details of a specific group milestonecreate_group_milestone- Create a new group milestoneedit_group_milestone- Edit an existing group milestonedelete_group_milestone- Delete a group milestoneget_group_milestone_issue- Get issues associated with a specific group milestoneget_group_milestone_merge_requests- Get merge requests associated with a specific group milestoneget_group_milestone_burndown_events- Get burndown events for a specific group milestoneget_users- Get GitLab user details by usernamesget_user- Get user details by IDwhoami- Get current authenticated user detailslist_commits- List repository commits with filtering optionsget_commit- Get details of a specific commitget_commit_diff- Get changes/diffs of a specific commitget_file_blame- Get git blame for a file at a given ref. Each entry maps a contiguous range of source lines to the commit that last changed them (id, author, authored_date, message). Use range_start/range_end to limit blame to specific lines.list_commit_statuses- List statuses for a commitcreate_commit_status- Create or update the status of a commitlist_group_iterations- List group iterations with filtering optionsget_group_iteration- Get a group iteration by ID, IID, or GraphQL GIDupdate_group_iteration- Update a manual group iteration's title, description, or datescreate_group_iteration- Create a group iteration, optionally in a given iteration cadencedelete_group_iteration- Delete a group iteration by ID, IID, or GraphQL GIDlist_project_iterations- List the iterations available to a project with filtering optionslist_group_iteration_cadences- List a group's iteration cadences with filtering optionscreate_group_iteration_cadence- Create an iteration cadence in a groupupdate_group_iteration_cadence- Update an iteration cadence's title, description, schedule, or automationdelete_group_iteration_cadence- Delete an iteration cadenceupload_markdown- Upload a file for use in markdown contentdownload_attachment- Download an uploaded file from a project (images returned as base64; other files, or images with local_path, are saved as new files under the download directory)health_check- Check auth and versions. Always includes mcp_server_version. When authenticated, also GitLab version, revision, and enterprise from GET /api/v4/version. Version lookup failures omit those fields instead of failinglist_events- List events for the authenticated user (before/after: YYYY-MM-DD)get_project_events- List events for a project (before/after: YYYY-MM-DD)list_releases- List all releases for a projectget_release- Get a release by tag namecreate_release- Create a new releaseupdate_release- Update an existing releasedelete_release- Delete a release (does not delete the tag)create_release_evidence- Create release evidence (Premium/Ultimate)download_release_asset- Download a release asset file by direct asset pathlist_tags- List repository tags for a projectget_tag- Get a repository tag by namecreate_tag- Create a new repository tagdelete_tag- Delete a repository tagget_tag_signature- Get the X.509 signature of a signed tag (404 if unsigned)list_protected_tags- List protected tags in a projectget_protected_tag- Get details of a single protected tag or wildcard (create access levels)protect_tag- Protect a repository tag or wildcard (set who can create it)unprotect_tag- Remove protection from a previously protected tag or wildcardget_work_item- Get a work item with full details including status, hierarchy, type, and widgetslist_work_items- List work items with filters (type, state, search, assignees, labels)create_work_item- Create a work item (issue, task, incident, epic, etc.) with full field supportupdate_work_item- Update a work item (title, description, labels, assignees, state, parent, custom fields, etc.)convert_work_item_type- Convert a work item to a different typelist_work_item_statuses- List available statuses for a work item type (Premium/Ultimate)list_custom_field_definitions- List custom field definitions for a work item typemove_work_item- Move a work item to a different projectlist_work_item_notes- List notes and discussions on a work itemcreate_work_item_note- Add a note to a work item (supports Markdown, internal notes, threads)list_work_item_emoji_reactions- List all emoji reactions on a work itemlist_work_item_note_emoji_reactions- List all emoji reactions on a work item note (comment, thread, or thread reply)create_work_item_emoji_reaction- Add an emoji reaction to a work item (e.g. thumbsup, rocket, eyes)delete_work_item_emoji_reaction- Remove an emoji reaction from a work itemcreate_work_item_note_emoji_reaction- Add an emoji reaction to a work item note (comment, thread, or thread reply)delete_work_item_note_emoji_reaction- Remove an emoji reaction from a work item note (comment, thread, or thread reply)get_timeline_events- List timeline events for an incidentcreate_timeline_event- Create a timeline event on an incidentlist_webhooks- List webhooks for a project or groupcreate_webhook- Create a webhook on a project or groupupdate_webhook- Update an existing project or group webhookdelete_webhook- Delete a project or group webhooklist_webhook_events- List recent webhook events (past 7 days)get_webhook_event- Get full details of a specific webhook eventsearch_code- Search for code across all projects (requires advanced search or Zoekt)search_project_code- Search for code within a specific project (requires advanced search or Zoekt)search_group_code- Search for code within a specific group (requires advanced search or Zoekt)list_project_variables- List CI/CD variables for a projectget_project_variable- Get a single CI/CD variable from a projectcreate_project_variable- Create a CI/CD variable for a projectupdate_project_variable- Update an existing CI/CD variable in a projectdelete_project_variable- Delete a CI/CD variable from a projectlist_group_variables- List CI/CD variables for a groupget_group_variable- Get a single CI/CD variable from a groupcreate_group_variable- Create a CI/CD variable for a groupupdate_group_variable- Update an existing CI/CD variable in a groupdelete_group_variable- Delete a CI/CD variable from a groupget_dependency_proxy_settings- Get dependency proxy settings for a groupupdate_dependency_proxy_settings- Update dependency proxy settings for a group (enable/disable, credentials for authenticated Docker Hub pulls)list_dependency_proxy_blobs- List cached dependency proxy blobs for a grouppurge_dependency_proxy_cache- Schedule purge of all cached dependency proxy blobs for a grouplist_project_vulnerabilities- List vulnerabilities for a project with optional state, severity, and report type filters (GraphQL-backed, cursor pagination)get_vulnerability- Get full details of a specific vulnerabilitydismiss_vulnerability- Dismiss a vulnerability with a reason (acceptable_risk, false_positive, used_in_tests, mitigating_control, not_applicable) and optional commentconfirm_vulnerability- Confirm a vulnerability as a real finding requiring remediationorbit_query- Execute a GitLab Orbit graph query over the indexed SDLC knowledge graphorbit_get_schema- Fetch the current GitLab Orbit graph schema (node and edge types)orbit_get_status- Check GitLab Orbit indexing status for the enabled scopeorbit_list_tools- List the MCP tool definitions exposed by GitLab Orbitlist_snippets- List snippets — project snippets when project_id is given, otherwise personal snippetsget_snippet- Get a snippet's metadata. Set include_content=true to also fetch the raw file content.create_snippet- Create a snippet — project-scoped when project_id is given, otherwise a personal snippet. Requires title plus either file_name + content (single file) or files[] (multi-file); the two shapes cannot be mixed.update_snippet- Update an existing snippet (provide at least one field to change). For multi-file edits — renames, deletions, additions — pass files[] with action (create/update/delete/move) and previous_path. The file_name + content shortcut still works for single-file content replacement.delete_snippet- Delete a snippetlist_project_runners- List runners available to a project (type, status, paused, tag_list). Omits registration and authentication tokens.get_runner- Get a runner's tag_list, run_untagged, locked, and access_level. When a project allowlist is active, the runner must be available to an allowed project. Omits registration and authentication tokens.rebase_merge_request- Rebase the source branch of a merge request onto its target branchgitlab_api_request- Send one GitLab REST call under /api/v4. Enabled only when GITLAB_TOOLSETS lists api. Readonly allows GET; modify rejects DELETE.discover_tools- List or activate a toolset for this session. Omit category to list; pass one to enable. Prefer this over GITLAB_TOOLSETS=all (loads ~all schemas). Session-only; with OAUTH_STATELESS_MODE=true persist GITLAB_TOOLSETS.help- Return a short GitLab workflow guide. Omit topic for the overview and topic list.
Wiki page titles vs. slugs
GitLab derives a wiki page's slug (its URL, /-/wikis/<slug>) from the page title. Passing title to update_wiki_page / update_group_wiki_page therefore renames the page and changes its URL — for nested pages it can also move the page to a different path — which breaks existing links.
To change only the displayed title while keeping the URL stable, do not pass title. Instead, store the display title in the page content's YAML front matter and update the content:
---
title: My Custom Display Title
---
Page body…GitLab keeps the slug/URL untouched and shows the front-matter title in the UI. Read it back with get_wiki_page using render_html: true, which populates the front_matter field — the plain title field always reflects the slug-derived value.
Testing 🧪
The project includes comprehensive test coverage including remote authorization:
# Run all tests (API validation + remote auth)
npm test
# Run only remote authorization tests
npm run test:remote-auth
# Run all tests including readonly MCP tests
npm run test:all
# Run only API validation
npm run test:integrationAll remote authorization tests use a mock GitLab server and do not require actual GitLab credentials.
Available Tools
40 toolscreate_issueB
Create a new issue. Open a new issue. Use update_issue for an existing issue and create_issue_note for discussion.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Issue title | |
| labels | No | Label names | |
| weight | No | Issue weight | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| issue_type | No | issue, incident, test_case, or task | issue |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| description | No | Issue description | |
| assignee_ids | No | Assignee user IDs | |
| milestone_id | No | Milestone ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The only annotation is openWorldHint=true, so the description carries the burden for a mutation tool. It says nothing about required permissions, whether creation triggers notifications or side effects, what happens on duplicate titles, or what the call returns. Beyond the word 'Create,' no behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences are useful and one is pure redundancy ('Open a new issue'). The tool-routing sentence is valuable but should lead or merge with the purpose statement to be properly front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Nine parameters, no output schema, and a write operation in an open world – the description gives no information about permission requirements, return payload, or side effects. An agent can call this but cannot predict the consequences or interpret the response from the definition alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including enum values for issue_type and guidance on project_id, so the schema does the heavy lifting. The description adds no meaning about parameters, not even the two required ones or the optional result-filtering jmespath. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb+resource ('Create a new issue'). The second sentence, 'Open a new issue,' is a near-verbatim restatement and adds nothing. Sibling differentiation is handled in the third sentence rather than the purpose line itself, so the intent is clear but not tightly front-loaded.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use `update_issue` for existing issues and `create_issue_note` for discussion. That covers the most likely mis-selection among siblings. It stops short of stating preconditions (e.g. project must exist, membership required) or when not to create at all.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_issue_noteA
Add a note to an issue, optionally replying to a discussion thread. Add a note to an existing issue, optionally as a reply. Use update_issue for issue fields.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | The content of the note or reply | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| issue_iid | Yes | The IID of an issue | |
| created_at | No | Date the note was created at (ISO 8601 format) | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| discussion_id | No | The ID of a thread. If provided, replies to that thread; otherwise creates a top-level note |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare openWorldHint, so the description carries most of the behavioral burden. It implies a write/append and clarifies the top-level vs threaded-reply outcome, but says nothing about required permissions, whether the note is editable/deletable, rate limits, or idempotency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first two sentences are near-duplicates ('optionally replying to a discussion thread' vs 'optionally as a reply'), so a third of the text is wasted. The routing sentence is well-placed at the end but the definition could be half its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and six parameters, the description leaves return shape, the purpose of created_at and jmespath, and mutation side effects unaddressed. It is adequate for the core invocation but not complete for a create operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter including discussion_id and jmespath. The description adds only the reply-vs-top-level distinction, which the schema already states, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Add a note to an issue') plus the optional reply mode, and explicitly distinguishes itself from update_issue. It does not, however, differentiate itself from other issue-adjacent siblings like list_issue_discussions or get_issue.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tool (update_issue) and the condition that selects it ('for issue fields'), which is genuine routing guidance. It lacks any statement of prerequisites or when not to add a note, so it falls short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_merge_requestA
Create a new merge request. Open a merge request from an existing source branch to a target. Use update_merge_request after it exists.
| Name | Required | Description | Default |
|---|---|---|---|
| draft | No | Create as draft | |
| title | Yes | Merge request title | |
| labels | No | MR labels | |
| squash | No | Squash commits on merge | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| description | No | Merge request description | |
| assignee_ids | No | Assignee user IDs | |
| reviewer_ids | No | Reviewer user IDs | |
| source_branch | Yes | Source branch | |
| target_branch | Yes | Target branch | |
| target_project_id | No | Target project numeric ID | |
| allow_collaboration | No | Allow eligible upstream members to push to the fork source branch | |
| remove_source_branch | No | Remove source branch on merge |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The only annotation is openWorldHint=true, so the description carries most of the behavioral burden. It usefully discloses the prerequisite that the source branch must already exist, but says nothing about write-access requirements, draft/squash side effects, cross-project forking, or error behavior when branches are identical or missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and followed by scope and the lifecycle handoff. No filler and nothing redundant with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter write tool with no output schema, the description covers purpose and lifecycle routing but leaves the agent without any statement about return content, permissions, or the meaning of the riskier options (draft, squash, cross-project). Adequate but thin relative to the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all 14 parameters including target_project_id, jmespath, and allow_collaboration are already self-documented. The description adds only the source-to-target branch relationship, which the schema fields already convey, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Create a new merge request") and adds the key topology detail that it runs from an existing source branch to a target. This distinguishes it from read siblings like get_merge_request and list_merge_requests, though it never names which sibling creates the source branch it depends on.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to `update_merge_request` for post-creation changes, which is a clear when-to-use-which rule. It does not state any when-not conditions, such as preferring an existing MR path or what to do if an MR already exists for the branch pair.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_merge_request_threadA
Create a new thread on a merge request. Start a review thread. Use create_merge_request_note for an unthreaded note and create_merge_request_discussion_note to reply.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | The content of the thread | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| position | No | Position when creating a diff note | |
| created_at | No | Date the thread was created at (ISO 8601 format) | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only expose `openWorldHint`, so the description carries most of the behavioral burden. It clearly signals a write operation by saying 'Create' and 'Start a review thread', but it does not disclose permission needs, rate limits, reversibility, or how diff-note positioning affects behavior. It is adequate but has clear gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences, front-loads the primary action, and immediately routes to alternatives. Every sentence contributes to selecting or using the tool, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The input schema is unusually rich, including detailed guidance for diff positions and multiline comments, so the description does not need to repeat those semantics. It is complete enough for tool selection and routing, though it could mention that supplying `position` creates a diff note rather than a general MR thread.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters, including the complex nested `position` object. The description adds no parameter-level meaning beyond the high-level distinction between thread, note, and reply, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: creating a new thread on a merge request, and explicitly frames it as starting a review thread. It also distinguishes this tool from note-creation and reply alternatives, so an agent can identify its role without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing guidance: use this tool for a new thread, `create_merge_request_note` for an unthreaded note, and `create_merge_request_discussion_note` to reply. The alternatives and their conditions are named directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
discover_toolsARead-only
List or activate a toolset for this session. Omit category to list; pass one to enable. Prefer this over GITLAB_TOOLSETS=all (loads ~all schemas). Session-only; with OAUTH_STATELESS_MODE=true persist GITLAB_TOOLSETS=core,<category> instead. Categories: core, merge_requests, issues, repositories, branches, projects, labels, ci, groups, pipelines, milestones, wiki, releases, tags, snippets, users, workitems, webhooks, search, variables, dependency_proxy, vulnerabilities, orbit. Response lists already-active ones. api is explicit-only.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Toolset to activate (e.g. pipelines, wiki). Omit to list. Prefer a category over GITLAB_TOOLSETS=all. Session-only; persist `GITLAB_TOOLSETS=core,<category>` when OAUTH_STATELESS_MODE=true. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the bar is lower, yet the description adds real context beyond them: activation is session-scoped and non-persistent, the stateless-mode workaround, and that the response lists already-active toolsets. The one gap is that 'activate a toolset' is a session-state change that sits in mild tension with readOnlyHint=true, and the description never reconciles that — no note that no remote data is modified.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the list/enable switch before any caveats, and no sentence is filler — even the long category enumeration is load-bearing since the schema has no enum. It is dense at roughly one paragraph plus a 24-item list, which is near the upper bound of comfortable scanning but justified by the missing enum.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing the return ('Response lists already-active ones'), and it covers the persistence model, the stateless-mode alternative, the preferred alternative to all-schemas loading, and the full valid value set. For a two-parameter session tool, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description does add genuine value the schema lacks, enumerating all 24 valid category values where the schema only offers two examples ('e.g. pipelines, wiki'), but it adds nothing about the jmespath parameter beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise dual-purpose statement: 'List or activate a toolset for this session,' then immediately disambiguates the two modes ('Omit category to list; pass one to enable'). This is clearly distinct from every sibling tool, which performs GitLab domain operations, so an agent can identify this as a tool-discovery/toolset-management utility without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit conditional guidance for both arguments (omit vs pass a category) and names the alternative it should replace: 'Prefer this over GITLAB_TOOLSETS=all (loads ~all schemas).' It also supplies the correct substitute path for stateless deployments ('with OAUTH_STATELESS_MODE=true persist `GITLAB_TOOLSETS=core,<category>` instead') and flags 'api is explicit-only,' leaving little to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_branchARead-only
Get branch details (commit, protection status). To find resources, use the matching list or search tool.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| branch_name | Yes | Name of the branch |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety profile is covered by structured data. The description adds that the result contains commit and protection status, which is useful context, but says nothing about permissions, error behavior, or response shape beyond those two fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, no filler, with the core purpose front-loaded before the disambiguation hint. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only single-resource fetch with fully documented parameters and readOnlyHint annotations, the description covers purpose plus partial return content. No output schema exists, so a slightly fuller account of the returned object would help, but it is close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so project_id, branch_name, and the jmespath filter are all documented in the schema itself. The description adds no additional parameter meaning, which is the expected baseline when the schema does the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Get branch details") and enumerates the returned fields (commit, protection status), which distinguishes it from mutation tools like update_merge_request. It does not explicitly name the sibling list_branches, so differentiation is only implied.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence routes the agent to "the matching list or search tool" when it needs to find resources, which sets a usage boundary. However, it never names list_branches or any concrete alternative, so the routing guidance is generic and requires the agent to infer the sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_commitBRead-only
Get details of a specific commit. To find resources, use the matching list or search tool.
| Name | Required | Description | Default |
|---|---|---|---|
| sha | Yes | The commit hash or name of a repository branch or tag | |
| stats | No | Include commit stats | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds nothing beyond that: no mention of what 'details' includes, that stats are optional, that jmespath filters the payload, or any auth/rate-limit context. For a read tool this is thin but not contradictory.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core purpose front-loaded and no filler. The second sentence carries mild value as a discovery hint, though it is near-boilerplate.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A simple read-only tool with no output schema, so the description needn't explain return values. Still, 'details' is underspecified — the agent gets no sense of what fields come back or how stats/jmespath change the result, which would matter for constructing follow-up calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are fully documented in the schema itself (sha as hash/branch/tag, stats toggle, jmespath filter). The description contributes no additional parameter meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Get details of a specific commit.' An agent can tell it retrieves a single commit. However, it does not distinguish itself from siblings like get_commit_diff or list_commits, so the agent must infer that this returns commit metadata rather than a diff.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The line 'To find resources, use the matching list or search tool' implies the SHA must be discovered via list_commits first, which is useful. But it is generic boilerplate, gives no explicit when-not-to-use guidance, and never mentions get_commit_diff as the alternative for diff content.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_commit_diffARead-only
Get changes/diffs of a specific commit. Return the file diffs for one commit. Use get_commit for metadata without the patch.
| Name | Required | Description | Default |
|---|---|---|---|
| sha | Yes | The commit hash or name of a repository branch or tag | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| full_diff | No | Whether to return the full diff or only first page (default: false) | |
| project_id | Yes | Project ID or complete URL-encoded path to project |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds that the payload is a patch rather than metadata, but says nothing about diff size, truncation, or that paging is controlled by full_diff — behavior an agent would want to know before fetching a large commit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with the core purpose front-loaded and the routing hint last. Slight redundancy between 'Get changes/diffs' and 'Return the file diffs' keeps it from being maximally tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only retrieval tool with a fully documented schema and no output schema, this covers purpose, scope, and sibling disambiguation. The only real gap is what a returned diff looks like and whether large diffs are truncated, which is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with all four parameters documented including the full_diff paging flag and jmespath. The description adds no parameter-level meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get changes/diffs of a specific commit') and reinforces it with 'Return the file diffs for one commit.' It explicitly separates itself from the sibling get_commit, so an agent can choose between them without reading schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative (get_commit) and the condition that selects it ('metadata without the patch'), which is the exact routing decision an agent faces. It stops short of covering other near-neighbors like get_merge_request_diffs or list_commit_changed_files, so it is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_file_blameARead-only
Get git blame for a file at a given ref. Each entry maps a contiguous range of source lines to the commit that last changed them (id, author, authored_date, message). Use range_start/range_end to limit blame to specific lines.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes | The name of branch, tag or commit (required by GitLab blame API) | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| file_path | Yes | The full path of the file to blame, relative to repo root | |
| range_end | No | Last line of the blame range (inclusive, 1-based). Both range[start] and range[end] must be set together. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| range_start | No | First line of the blame range (inclusive, 1-based). Both range[start] and range[end] must be set together. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the description does not need to repeat safety semantics. It adds behavior beyond the annotations by explaining the entry structure: contiguous source-line ranges map to the commit with id, author, authored_date, and message. It does not cover pagination or edge cases, but the read-only hint plus output-shape context is meaningful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two well-structured sentences. The first front-loads the action and resource; the second communicates the return shape and the optional range limitation. Every phrase contributes information, and there is no filler or duplication of schema text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description supplies the essential return semantics by naming the fields a caller can expect in each entry. The schema covers all parameters, and the read-only annotation covers the safety profile. Missing details such as pagination or behavior on nonexistent refs are minor for a straightforward blame call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema itself documents all six parameters including range_start, range_end, ref, and file_path. The description adds only a light hint that range_start/range_end limit the blame to specific lines, which is useful but does not materially go beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Get git blame for a file at a given ref.' This clearly separates it from read-content tools like get_file_contents and commit-history tools like get_commit-repository. It also states the central output concept (line ranges mapped to commits), removing ambiguity about what GitLab blame returns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear operational context: run blame at a specific ref dat and optionally constrain the result to a range of lines with range_start/range_end. It does not explicitly name sibling alternatives or say when not to use this tool, but 'git blame' is a distinct enough operation that the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_file_contentsCRead-only
Get contents of a file or directory from a GitLab project.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Branch/tag/commit to get contents from | |
| path | No | Alias of file_path | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| file_path | No | Path to the file or directory. Takes precedence over 'path' when both are provided | |
| project_id | No | Project ID or URL-encoded path (optional; falls back to env) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds no behavioral context at all: it doesn't say what happens when path points at a directory (listing vs error), what happens if ref is omitted, or whether large files are truncated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single well-formed sentence with zero filler and the resource front-loaded. It is efficient, though its brevity comes at the cost of the missing usage and behavioral detail noted elsewhere.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The rich schema covers parameters and the annotations cover safety, but with five parameters, no required fields, and no output schema, the description should clarify the file-vs-directory return shape and default ref behavior. As written it is minimally adequate rather than complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters (including the path/file_path precedence rule and the project_id env fallback) are already documented in the schema. The description contributes nothing parameter-specific, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get contents of a file or directory') scoped to a GitLab project, which is enough to distinguish it from most siblings like get_file_blame or get_repository_tree. It stops short of explicitly naming how it differs from those adjacent tools, so a 4 rather than a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use or when-not-to-use guidance, and no alternatives are named even though get_file_blame, get_repository_tree, and get_commit_diff all overlap in scope. The agent must infer selection purely from the tool name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_issueARead-only
Get one issue. Slim nested milestone by default; full_response=true for the complete milestone. Use this for issue management. Use list_issues or my_issues to discover issues first.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| issue_iid | Yes | Issue IID | |
| project_id | Yes | Project ID or URL-encoded path | |
| full_response | No | If true, include the complete milestone (including description). Default is slim (id, iid, title, state, web_url). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so safety is covered; the description adds useful behavioral context by disclosing that the milestone is slimmed by default and that full_response=true is needed for the complete object. It does not describe error behavior for a missing issue or permission failures, but the added default-response detail is meaningful beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action and the default return shape. The middle sentence ("Use this for issue management") is filler that does not earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only single-resource fetch with no output schema, the description covers the action, the default return shape, how to get the full version, and how to find issues first. Nothing critical for calling it correctly is missing, though error/not-found behavior is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and each parameter (including full_response and jmespath) is documented in the schema itself. The description mentions full_response but repeats the schema's own wording rather than adding new semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ("Get one issue") and immediately states the returned shape (slim nested milestone by default), which separates it from list-oriented siblings. The only weak line is "Use this for issue management," which restates the obvious rather than narrowing scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes discovery to `list_issues` or `my_issues` "first," giving the agent a clear alternative and the condition that selects it. It stops short of stating when-not to use this tool (e.g., bulk retrieval) or any prerequisites such as project membership.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_requestARead-only
Get details of a merge request (merge_request_iid or source_branch required). Set include_summaries=true for deployment/commit/approval summaries. To find resources, use the matching list or search tool.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or URL-encoded path | |
| source_branch | No | Source branch name | |
| include_summaries | No | If true, include deployment, commit, and approval summaries (extra API calls). Default false. | |
| merge_request_iid | No | Merge request IID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds genuinely new behavioral context: the identifier requirement that the schema does not enforce (only project_id is required) and the fact that include_summaries triggers extra API calls, which signals added latency/cost. It does not cover failure behavior when neither identifier is supplied, but the value added beyond annotations is real.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with purpose, then the identifier constraint, then the optional flag and the discovery alternative. Every sentence carries distinct information with no repetition of the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only fetch tool with a fully documented 5-parameter schema and no output schema, the description covers purpose, required identifiers, and the cost of summaries. The main remaining gap is that it never sketches what 'details' includes (fields, size of payload) or how the jmespath filter interacts with the result, which matters somewhat given no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description goes further by stating the cross-parameter constraint (one of merge_request_iid or source_branch must be provided) that the schema's required list does not capture. It also clarifies the practical effect of include_summaries as extra API calls, beyond the schema's 'extra API calls' phrasing. This is meaningful semantics beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Get details of a merge request'), which clearly separates it from list_merge_requests and the diff/note/discussion siblings. It does not name a specific sibling it competes with, instead referring generically to 'the matching list or search tool', so it falls short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage conditions: an identifier (merge_request_iid or source_branch) is required, and include_summaries=true should be set when deployment/commit/approval summaries are wanted. It also routes agents to the list/search tools for discovery. There is no explicit when-not guidance, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_approval_stateARead-only
Get merge request approval details including approvers. Inspect approval rules and approvers before merging. Use approve_merge_request to change approval state.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| merge_request_iid | Yes | The IID of the merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds no further behavioral context — no permission requirements, no note on what happens when no approval rules exist, and no indication of the response shape beyond "details including approvers".
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core verb and result, followed by usage context and the alternative. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A simple three-parameter read tool with full schema coverage and no output schema; the description conveys what comes back (approval rules and approvers) and when to call it. Minor gap: it does not clarify behavior when approvals are disabled or the MR is not in an approvable state.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so project_id, merge_request_iid, and jmespath are all documented in the schema itself. The description adds no parameter-level meaning, which is acceptable at this coverage level but not above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: retrieves merge request approval details including approvers. It also separates itself from the mutating sibling by naming `approve_merge_request`, so an agent can distinguish read vs write without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Inspect approval rules and approvers before merging" gives a concrete usage moment, and the final sentence routes state changes to `approve_merge_request`. It stops short of saying when to prefer it over `get_merge_request`, which may also surface related MR data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_diffsBRead-only
Get the changes/diffs of a merge request (merge_request_iid or source_branch required). To find resources, use the matching list or search tool.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | Diff view type | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or URL-encoded path | |
| source_branch | No | Source branch name | |
| merge_request_iid | No | Merge request IID | |
| excluded_file_patterns | No | Array of regex patterns to exclude files from the diff results. Each pattern is a JavaScript-compatible regular expression that matches file paths to ignore. Examples: ["^vendor/", "^test/mocks/", "\.spec\.ts$", "package-lock\.json"] |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is known. The description adds the useful constraint that one of merge_request_iid or source_branch must be supplied, but says nothing about pagination, diff size limits, or behavior of the excluded_file_patterns filtering.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core action and the key required-input condition front-loaded. There is no padding, though the sibling-routing sentence is vague rather than pointed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and six parameters, the description covers the essential invocation contract but omits the filtering and view options and does not clarify result shape or size. It is adequate but leaves gaps relative to the tool's surface area.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including view, jmespath, and excluded_file_patterns is already documented. The description only re-emphasizes the merge_request_iid/source_branch choice, adding marginal meaning beyond the schema, which fits the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get the changes/diffs of a merge request') and clarifies the conditional requirement for merge_request_iid or source_branch. It does not, however, differentiate this tool from close siblings such as list_merge_request_diffs, get_merge_request_changed_files, or get_merge_request_file_diff, so an agent cannot distinguish them from the text alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'To find resources, use the matching list or search tool' provides only generic routing advice and implies discovery workflow, but it never names the specific alternative (e.g., list_merge_request_diffs) or says when this tool should be preferred for a single merge request.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_discussionARead-only
Get a single discussion item for a merge request. Fetch one discussion by id. Use mr_discussions for a collection and get_merge_request_note for a flat note.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| discussion_id | Yes | The ID of a thread | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the read-only, external-facing profile is covered. The description adds nothing about return shape (e.g., whether the thread's notes are included) or how jmespath affects output, so it is only marginally additive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the core purpose front-loaded before the disambiguation clause. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a fetch-by-id tool with full schema coverage and annotations covering safety, this is nearly complete. The one minor gap is not stating what the returned discussion contains (notes? resolved state?), which the absence of an output schema leaves implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so project_id, merge_request_iid, discussion_id, and jmespath are all documented in the schema. The description mentions 'by id' but adds no syntax or semantic detail beyond the schema, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a single discussion item for a merge request') and reinforces the singular scope with 'Fetch one discussion by id.' This clearly distinguishes it from the collection sibling mr_discussions and the flat-note sibling get_merge_request_note.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names both alternatives and the condition selecting each: 'Use `mr_discussions` for a collection and `get_merge_request_note` for a flat note.' The agent knows exactly when this tool is and is not the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_file_diffARead-only
Get diffs for specific files from a merge request (merge_request_iid or source_branch required).
| Name | Required | Description | Default |
|---|---|---|---|
| unidiff | No | Present diff in the unified diff format. Default is false. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| file_paths | Yes | List of file paths to retrieve diffs for (e.g. ['src/api/users.ts', 'src/repo/user.go']). Call list_merge_request_changed_files first to get the full list of changed paths. | |
| project_id | Yes | Project ID or URL-encoded path | |
| source_branch | No | Source branch name | |
| merge_request_iid | No | Merge request IID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered and the description need not repeat it. The description adds the either/or MR identifier constraint, but says nothing about diff size limits, truncation, or response shape — relevant gaps for a diff-returning tool with no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the action and resource and ends with the key constraint. Nothing is redundant and nothing needs reordering.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter, read-only retrieval tool with no output schema, the description covers what it returns at a high level and the identifier constraint. It leaves out practical behavior an agent would want — whether all requested paths are returned in one call, how large diffs are handled, and how this differs from the sibling diff tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description contributes a genuine cross-parameter constraint: merge_request_iid OR source_branch, neither of which appears in the schema's required list. That is meaning the schema does not enforce on its own.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get diffs') plus a narrowing scope ('for specific files from a merge request'), which separates it from the broader list_merge_request_diffs and get_merge_request_diffs siblings. It stops short of naming those alternatives, so the differentiation is inferable rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical '(merge_request_iid or source_branch required)' gives a precondition for calling, which is useful. However, it never says when to prefer this over get_merge_request_diffs or list_merge_request_diffs, nor that the file_paths prerequisite (list_merge_request_changed_files) lives only in the schema, so routing guidance is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_noteARead-only
Get a specific note for a merge request. Fetch one note by id. Use get_merge_request_notes for a collection and mr_discussions for threads.
| Name | Required | Description | Default |
|---|---|---|---|
| note_id | Yes | The ID of a thread note | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful clarity that this fetches exactly one note by id, but it does not add behavioral detail such as response shape, permissions, or rate limits beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core purpose, followed by the specific action and alternatives. There is no redundant or low-value text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple read-only retrieval tool with complete schema documentation and annotations covering safety. The description supplies enough context to invoke it correctly and route between the relevant sibling tools, with no output schema required for a basic get-by-id operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented in the schema. The description only reinforces that lookup is by id and does not add syntax, format, or constraint details beyond what the schema provides; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: get a specific note for a merge request, fetching one note by id. It also distinguishes the tool from collection and thread-oriented siblings, so an agent can identify its singular-note role without inspecting the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly names alternatives: get_merge_request_notes for a collection and mr_discussions for threads. These conditions directly tell the agent when to choose this tool versus its closest siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_merge_request_notesARead-only
List notes for a merge request. List flat notes. Use mr_discussions when thread structure and resolution state are required.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination | |
| sort | No | The sort order of the notes | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| order_by | No | The field to sort the notes by | |
| per_page | No | Number of items per page | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only, open-world operation. The description adds relevant behavioral context by clarifying that returned notes are flat rather than threaded, but it does not mention pagination behavior or any practical limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, with the core purpose and the key exclusion front-loaded. There is no redundant or wasted language.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with a fully documented schema and annotations, the description is nearly complete. The only minor gap is that it does not describe the return shape or pagination expectations, though the flat-note distinction gives useful context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the input schema already explains all seven parameters. The description adds no parameter-level details beyond the operation itself, which is appropriate baseline behavior when the schema carries the burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific operation and resource: listing notes for a merge request. It further distinguishes the result as flat notes and explicitly names the sibling tool to use when thread structure is needed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit alternative: use `mr_discussions` when thread structure and resolution state are required. This directly tells the agent when to choose this tool versus a closely related sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectBRead-only
Get details of a specific project. To find resources, use the matching list or search tool.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or URL-encoded path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds no behavioral context beyond that—it does not describe what 'details' includes, permission requirements, or any special handling like URL-encoded paths.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with the core purpose front-loaded. The second sentence adds useful routing context without unnecessary verbosity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter retrieval tool with annotations covering safety, the description is minimally adequate. However, it does not explain what project details are returned or how JMESPath filtering affects the response, leaving some contextual gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters (project_id and jmespath) are fully documented in the input schema. The description adds no additional meaning beyond what the schema provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get details of a specific project'), making the tool's purpose clear. It does not fully distinguish itself from sibling retrieval tools like list_projects, but the routing sentence helps clarify its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly directs the agent to use a matching list or search tool when trying to find resources, implying this tool is for retrieving a known project. This gives clear usage context, though it does not name a specific sibling or state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_repository_treeCRead-only
List files and directories in a repository.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Branch or tag. Defaults to the default branch. | |
| page | No | Offset page number from 1 (items + next_page) | |
| path | No | Path inside the repository | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page | |
| recursive | No | Recursive tree | |
| page_token | No | Keyset token from the previous next_page_token | |
| pagination | No | Use keyset for large trees (items + next_page_token). Omit both page and pagination for the legacy array (deprecated). | |
| project_id | Yes | Project ID or URL-encoded path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. Beyond that the description discloses nothing about the behavior that actually matters here: three mutually exclusive pagination modes including a deprecated legacy array, item + next_page_token response shapes, and how recursive affects result size. For a nine-parameter listing tool this is a substantial behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero filler, and the core purpose lands immediately. It is clean, though its brevity is achieved by omission rather than by tight editing of richer content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With nine parameters, no output schema, and a pagination design that includes a deprecated default mode, one sentence is not enough for an agent to call this correctly on large trees. The description should at minimum point at recursive/path scoping and warn against omitting both page and pagination.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the nine parameters is already documented, which sets the baseline at 3. The description adds no meaning on top — it says nothing about what recursive returns, what path scoping does, or the three-way pagination choice (keyset, page, deprecated legacy array).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"List files and directories in a repository" gives a specific verb and resource, and it implicitly reads as a tree/listing operation distinct from get_file_contents. However, it never names get_file_contents or get_repository_tree's own scope boundary (e.g. single-file retrieval vs. directory traversal), so sibling differentiation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to prefer this over get_file_contents, get_branch, or search_repositories. Nothing tells the agent to set recursive for deep traversal, to use path to scope a subtree, or which pagination mode to pick — all decisions the caller must guess at.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_checkARead-only
Check auth and versions. Always includes mcp_server_version. When authenticated, also GitLab version, revision, and enterprise from GET /api/v4/version. Version lookup failures omit those fields instead of failing.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered; the description earns credit for adding behavior annotations cannot express: the upstream endpoint (GET /api/v4/version) and, notably, that version lookup failures omit those fields rather than failing the call. That partial-degradation contract is exactly the kind of context an agent needs and cannot get from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, zero filler, and the always-present field is front-loaded before the conditional fields. Every clause carries distinct information: what is checked, what is always returned, what is conditionally returned, and what happens on failure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by enumerating the returned fields (mcp_server_version always; version, revision, enterprise when authenticated) and the failure mode. It stops short of explaining what the response looks like when unauthenticated beyond 'always includes mcp_server_version', which leaves a small gap for a diagnostic tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single optional jmespath parameter that the schema documents fully with its own description. The tool description adds nothing about the parameter, so the baseline 3 applies — the schema does all the work.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-plus-resource statement ('Check auth and versions') and immediately clarifies what is always returned versus conditionally returned. It is clearly not a data-fetching sibling, though it never distinguishes itself from whoami, the other auth/identity-adjacent tool in the sibling list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the tool to call to verify credentials or server version, and the phrase 'When authenticated' hints at a pre-flight role. There is no explicit when-to-use, when-not-to-use, or named alternative (e.g. whoami) that would raise this above implied guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
helpARead-only
Return a short GitLab workflow guide. Omit topic for the overview and topic list. Topics: code-review, merge-requests, issues, pipelines, search, token-saving. Prefer discover_tools over GITLAB_TOOLSETS=all. With OAUTH_STATELESS_MODE=true persist GITLAB_TOOLSETS instead.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | Guide to return. Omit for the overview and the list of topics. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds that output is a 'short' guide and that behavior shifts under OAUTH_STATELESS_MODE, which is genuinely non-obvious, but the environment-variable sentences are terse and read more like toolset configuration advice than disclosure about this tool's operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the core purpose and topic list before the routing advice. The trailing environment-variable sentences are the weakest part and could be trimmed or clarified without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only two optional parameters and no output schema, the definition covers enough: what it returns, how to select a topic, and how it relates to discover_tools. The absence of any hint about the shape of the returned guide is a minor gap given there is no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the topic enum already lists every value with its own description, so the description's topic list and 'omit for the overview' note largely restate structured data. The jmespath parameter, the one piece an agent might want explained, gets no mention here at all.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Return a short GitLab workflow guide') and enumerates the exact topics available, which lets an agent distinguish this documentation tool from the operational siblings (get_project, create_merge_request, etc.). It also names discover_tools as the related-but-different tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit call guidance ('Omit topic for the overview and topic list') and names an alternative tool with a preference rule ('Prefer discover_tools over GITLAB_TOOLSETS=all'). What it lacks is when-not-to-use guidance for the GitLab workflow topics themselves — e.g., when to read a guide versus just calling get_merge_request.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_branchesBRead-only
List branches in project with search filter. For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| search | No | Search term to filter branches by name | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| project_id | Yes | Project ID or complete URL-encoded path to project |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds only the existence of a search filter, which the schema already documents, and says nothing about pagination behavior, default result size, ordering, or how much data a full listing can return — the practical concerns for a list endpoint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the primary action and followed by the alternative-route hint. Nothing is padded, though the second sentence is slightly awkwardly worded ('the matching get tool') rather than crisp.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple read-only list tool with a fully documented schema and annotations covering safety, so not much is required. Still, for a paginated endpoint with a default of 20 and a max of 100, a brief note on pagination or result-size expectations would close the remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so page, per_page, search, summary, jmespath and project_id are all documented in the schema itself. The description merely echoes the search filter, adding no format, syntax, or interaction detail beyond what the structured fields provide. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('List branches in project') plus the scoping modifier ('with search filter'), so an agent immediately knows what the tool returns. It stops short of naming the sibling 'get_branch' explicitly, referring only to 'the matching get tool', which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'For one known resource, use the matching get tool' establishes the list-vs-get split, which is exactly the decision an agent faces here. The guidance is directional but generic — it does not name get_branch or state what counts as a 'known resource' — so it is clear context rather than explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_commitsBRead-only
List repository commits with filtering options. For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| all | No | Every commit in the repository | |
| page | No | Page number (default 1) | |
| path | No | File path | |
| order | No | default or topo | |
| since | No | Commits on or after this ISO 8601 datetime | |
| until | No | Commits on or before this ISO 8601 datetime | |
| author | No | Commit author | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| ref_name | No | Branch, tag, or revision range. Default: default branch. | |
| trailers | No | Include Git trailers | |
| project_id | Yes | Project ID or URL-encoded path | |
| with_stats | No | Include per-commit stats | |
| first_parent | No | Follow only the first parent of merges |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already supply readOnlyHint and openWorldHint, so the description's main job is to add the operational detail they don't cover. It says nothing about pagination defaults, full-vs-summary payload behavior, ordering semantics, or result size limits, so an agent learns nothing about runtime behavior it could not already infer from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the verb and resource, no filler adjectives or restated titles. The second sentence is slightly boilerplate and vague, which keeps it out of the top band.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 15 parameters and no output schema, the description is thin, but the schema is fully described and the annotations cover the safety profile, so the essential calling information is present. What is missing is guidance on the interaction of paging, summary/jmespath shaping, and traversal flags (all, first_parent) that matter for a commit listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the 15 parameters is already documented in the schema, including the nuanced summary, jmespath, and ref_name entries. The description's "filtering options" adds no meaning beyond that, making the baseline 3 correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"List repository commits with filtering options" states a specific verb plus resource and implies the filterable axes. It also gestures at separation from the single-resource getter, though it never names get_commit, so the sibling differentiation is suggestive rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"For one known resource, use the matching get tool" gives a real when-not-to-use condition (single commit already identified), which is more than nothing. But "matching get tool" is unresolved phrasing among 37 siblings, and nothing says when to prefer filters like path/ref_name/since versus list_branches or search_repositories.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_issue_discussionsBRead-only
List discussions for an issue. List threaded discussions for an issue. Use list_issues or get_issue for issue records.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| issue_iid | Yes | The internal ID of the project issue | |
| project_id | Yes | Project ID or URL-encoded path |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety and reach are covered structurally. Beyond that the description adds almost nothing behavioral: it does not say the result is threaded notes, whether pagination is required to collect all discussions, or that empty results mean no discussion thread exists. The word "threaded" is the only behavioral signal, and it merely restates the resource name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first two sentences are near-duplicates — "List discussions for an issue" and "List threaded discussions for an issue" — so one is pure waste in a three-sentence description. The routing sentence is well placed at the end, but the tapering redundancy drags down an otherwise short text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple read-only list tool with fully documented parameters and no output schema, so much of the burden is off the description. Still, an agent gets no sense of what a discussion object contains (threaded notes) or how paging interacts with the result set, which are the two things that would round out a listing tool like this.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and all six parameters (including `page`, `per_page`, `summary`, and `jmespath`) are documented in the schema itself. The description adds no meaning beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ("List threaded discussions for an issue") and explicitly routes issue-record needs to `list_issues`/`get_issue`, so it is distinguishable from the closest siblings. It does not distinguish itself from discussion-oriented siblings such as `mr_discussions` or `get_merge_request_discussion`, but resource scope (issue vs. merge request) is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides one explicit exclusion — use `list_issues` or `get_issue` for issue records rather than this tool — which is useful negative guidance. It never states the positive trigger case (e.g., reading comment threads on an issue to review feedback) or mentions pagination-driven iteration, so the guidance is partial rather than complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_issuesARead-only
List issues (default: created by current user; use scope='all' for all). Use this for issue management. Optional project_id. Use get_issue when the iid is known and my_issues for assignments.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| scope | No | Issue scope | |
| state | No | Issue state | |
| labels | No | Label names | |
| search | No | Search terms | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| due_date | No | Due date | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| author_id | No | Author user ID. Mutually exclusive with author_username. | |
| milestone | No | Milestone title | |
| issue_type | No | issue, incident, test_case, or task | |
| project_id | No | Project ID or URL-encoded path. Omit to list issues across accessible projects. | |
| assignee_id | No | User ID, none, or any. Mutually exclusive with assignee_username. | |
| confidential | No | Confidential or public | |
| iteration_id | No | Iteration ID, none (no iteration), or any (has an iteration). | |
| created_after | No | Created after | |
| updated_after | No | Updated after | |
| created_before | No | Created before | |
| updated_before | No | Updated before | |
| author_username | No | Author username. Mutually exclusive with author_id. | |
| assignee_username | No | Username. Mutually exclusive with assignee_id. | |
| with_labels_details | No | Include label details |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds a genuinely non-obvious behavioral fact — that results are silently filtered to issues created by the current user unless scope='all' — which is not stated in the schema. It does not mention pagination limits or the summary/jmespath output-shaping behavior, but those are documented in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the scope default that most affects results, followed by alternatives. The middle sentence 'Use this for issue management' is generic filler that could be dropped without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 23-parameter, no-required-param list tool with full schema descriptions and read-only annotations, the description supplies what the schema cannot: the implicit scope default and sibling routing. Missing only output-shape/pagination expectations, which the schema's page, per_page, and summary fields largely cover.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3. The description adds the missing default value for the scope parameter (created_by_me), which the schema only labels 'Issue scope'. The note that project_id is optional and omitting it spans all accessible projects restates the schema rather than extending it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('List issues') and immediately qualifies the scope with the default behavior (created by current user). It also names the sibling tools get_issue and my_issues so the agent can distinguish the listing role, though the filler sentence 'Use this for issue management' adds nothing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete routing: use scope='all' to broaden beyond the default, use get_issue when the iid is known, and use my_issues for assignments. That covers the main decision points, but there is no guidance on when to use this versus other listing tools like list_projects or list_merge_requests, nor when to omit project_id.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_labelsBRead-only
List labels for a project. For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| search | No | Keyword to filter labels by | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| project_id | Yes | Project ID or URL-encoded path | |
| with_counts | No | Whether to include issue and merge request counts | |
| include_ancestor_groups | No | Include ancestor groups |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered, but the description adds essentially no behavior beyond that: nothing on pagination limits, default page size, whether ancestor-group labels are included by default, or how with_counts affects payload size. The one useful nugget — that a targeted get tool exists for single-resource reads — is a routing hint rather than behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core purpose front-loaded and the alternative surfaced immediately after. Nothing is wasted or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an eight-parameter list tool with no output schema, the description is minimal but the schema carries the parameter burden. It still leaves the agent guessing about default result shape and pagination behavior, which matters given the summary and jmespath options.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all eight parameters (page, per_page, search, summary, jmespath, with_counts, include_ancestor_groups, project_id) are already documented in the schema. The description adds no parameter semantics of its own, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource scoped to a project ("List labels for a project"), which is clearly distinct from the merge-request, issue, and branch siblings. It does not name the counterpart get tool explicitly, so the differentiation is directional rather than precise.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence gives one routing rule — fetch a single known label via the matching get tool rather than listing — which is genuine when-to-use guidance. However, no guidance is given on when to use the search/per_page/page parameters versus narrowing some other way, and no mention of the non-label siblings an agent might confuse this with.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_merge_request_changed_filesARead-only
List changed file paths in a merge request without diff content (merge_request_iid or source_branch required).
| Name | Required | Description | Default |
|---|---|---|---|
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or URL-encoded path | |
| source_branch | No | Source branch name | |
| merge_request_iid | No | Merge request IID | |
| excluded_file_patterns | No | Array of regex patterns to exclude files. Examples: ["^vendor/", "\.pb\.go$"] |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already state readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds useful behavior by saying no diff content is returned and one MR selector is required, but it omits pagination, ordering, and what happens if both selectors are supplied.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is a single front-loaded sentence with no filler. The key scope, payload distinction, and selector requirement are all stated efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter read-only list tool with no output schema, the description adequately conveys the return focus: changed file paths without diff content. It could more fully explain result ordering or pagination, but the schema documents the remaining parameters well.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds a meaningful conditional constraint not expressed in the schema's required list: either merge_request_iid or source_branch must be provided.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: list changed file paths in a merge request. The phrase 'without diff content' distinguishes it from diff-oriented siblings such as list_merge_request_diffs and get_merge_request_file_diff.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for using this tool when only file paths are needed, and it specifies that merge_request_iid or source_branch is required. It does not explicitly name alternative tools or when not to use it, which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_merge_request_diffsARead-only
List merge request diffs with pagination (merge_request_iid or source_branch required). For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination (default: 1) | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| unidiff | No | Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Number of items per page (max: 100, default: 20) | |
| project_id | Yes | Project ID or URL-encoded path | |
| source_branch | No | Source branch name | |
| merge_request_iid | No | Merge request IID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered and the description only needs to add context. It contributes the pagination behavior and the requirement that an IID or source branch be supplied, but says nothing about ordering, diff truncation, size limits, or response shape. Adequate against an already-rich annotation and schema set, but thin on behavior beyond them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, and the invocation-critical constraint sits in the opening line ahead of the alternative-tool routing. Every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 parameters, no output schema, and readOnlyHint covering safety, the description covers the essentials: what it lists, that it paginates, and the required selector. The main shortfall is the unspecified "matching get tool," which forces the agent to disambiguate among several diff-related siblings on its own.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds a constraint the schema does not encode: it states merge_request_iid or source_branch is required, while the schema lists only project_id as required. That is real meaning beyond the schema and useful for correct invocation. It leaves page/per_page interaction and the summary/unidiff tradeoffs entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description pairs a specific verb and resource ("List merge request diffs") with a scope constraint (pagination; merge_request_iid or source_branch required), which lets an agent distinguish this list operation from the get_merge_request_diffs sibling. It stops short of naming the sibling explicitly, so differentiation is implied by the singular/plural distinction rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"For one known resource, use the matching get tool" gives a genuine when-to-use rule: list when the target is not pinned down, get when it is. The gap is that "the matching get tool" is not named, and with siblings like get_merge_request_diffs, get_merge_request_file_diff, and list_merge_request_changed_files available, the agent must infer which one is meant.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_merge_requestsARead-only
List merge requests (without project_id: user's MRs; with project_id: project MRs). For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| wip | No | WIP filter | |
| page | No | Page number (default 1) | |
| sort | No | asc or desc | |
| scope | No | MR scope | |
| state | No | MR state | |
| labels | No | Label names | |
| search | No | Search terms | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| order_by | No | Sort field | |
| per_page | No | Items per page (max 100, default 20) | |
| author_id | No | Author user ID. Mutually exclusive with author_username. | |
| milestone | No | Milestone title | |
| project_id | No | Project ID or URL-encoded path. Omit to list the user's accessible MRs. | |
| assignee_id | No | User ID, none, or any. Mutually exclusive with assignee_username. | |
| reviewer_id | No | Reviewer user ID, none, or any. Mutually exclusive with reviewer_username. | |
| created_after | No | Created after | |
| source_branch | No | Source branch | |
| target_branch | No | Target branch | |
| updated_after | No | Updated after | |
| created_before | No | Created before | |
| updated_before | No | Updated before | |
| author_username | No | Author username. Mutually exclusive with author_id. | |
| assignee_username | No | Username. Mutually exclusive with assignee_id. | |
| reviewer_username | No | Reviewer username. Mutually exclusive with reviewer_id. | |
| with_labels_details | No | Include label details | |
| approved_by_usernames | No | Approved by these usernames |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered; the description adds the scope-switching semantics, which is genuinely useful behavioral context. However it says nothing about pagination defaults, result size, or the summary/jmespath response-shaping options that materially change what comes back.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with the resource and scope rule, with zero redundant wording. Every clause carries a distinct instruction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 27-parameter listing tool with no output schema, the description covers the key scope decision and the alternative tool but skips pagination behavior and the response-shaping options (summary, jmespath) that an agent must understand to get usable output. Adequate, not thorough.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including enums, mutual-exclusion notes, and the summary/jmespath options, so the schema carries the parameter burden. The description only restates the project_id semantics that the schema already documents. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List merge requests') and immediately explains the two scoping modes: user's MRs when project_id is omitted, project MRs when supplied. It doesn't enumerate the filterable dimensions (state, scope, labels, dates) that distinguish it from other listing tools, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit hand-off rule: for a single known resource, use the matching get tool (get_merge_request). It does not state when-not to use it (e.g. versus search-based sibling listing) or mention pagination expectations, but the core routing decision is spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_project_membersARead-only
List members of a GitLab project. Search project members by name or username. Use list_group_members for a group.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination (default: 1) | |
| query | No | Search for members by name or username | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Number of items per page (default: 20, max: 100) | |
| user_ids | No | Filter by user IDs | |
| project_id | Yes | Project ID or URL-encoded path | |
| skip_users | No | User IDs to exclude | |
| include_inheritance | No | Include inherited members. Defaults to false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety and reach profile is covered. The description adds only the search capability and the group alternative; it says nothing about pagination behavior, the default exclusion of inherited members, or result shape beyond what the `summary`/`jmespath` params already document.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the purpose, then the search nuance, then the sibling routing. No filler, and each sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A read-only list tool with fully documented params and annotations declaring safety — the description covers purpose and the one real routing ambiguity. It omits that inherited members are excluded by default, which matters for a project-member listing, but no output schema is needed to explain returns since `summary` and `jmespath` handle shaping.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all nine parameters are already self-documenting. The description's 'search by name or username' merely restates the `query` param, and it offers no extra semantics (e.g., interaction between `user_ids`, `skip_users`, and `include_inheritance`), so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List members of a GitLab project') with explicit scope, then names the sibling it is not ('Use `list_group_members` for a group'). An agent can distinguish project vs group member listing without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives one explicit routing rule to the group-level alternative, which is the main ambiguity an agent would face. It does not state when to use search/filtering versus a plain listing, or note that the referenced `list_group_members` is not in the current toolset, leaving a small inference gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsARead-only
List projects accessible by the current user. For one known resource, use the matching get tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| sort | No | asc or desc | |
| owned | No | Owned by current user | |
| topic | No | Topic tag | |
| search | No | Search term | |
| simple | No | Limited fields only | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| archived | No | Archived projects | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| order_by | No | Sort field | |
| per_page | No | Items per page (max 100, default 20) | |
| membership | No | Current user is a member | |
| visibility | No | public, internal, or private | |
| min_access_level | No | Minimum access level | |
| search_namespaces | No | Set true when search is a full path | |
| with_issues_enabled | No | Issues enabled | |
| with_merge_requests_enabled | No | Merge requests enabled |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety and reach are covered. The description adds the access-scoping behavior (results limited to what the current user can see), but says nothing about pagination defaults, result volume, or the fact that the default response is full, potentially large JSON.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero filler, and the primary scope statement is front-loaded ahead of the alternative redirection. Nothing is redundant or buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 17-parameter list tool with no output schema, the description covers only the core purpose and the get-vs-list split. Subtle knobs like summary vs simple vs jmespath, and paging via page/per_page, are left entirely to the schema; adequate because of full schema coverage, but thin for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every one of the 17 parameters already carries its own description and enums. The description adds no meaning about the filters (owned, membership, visibility, min_access_level) or the interaction between summary, simple, and jmespath, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("List projects") and a scope ("accessible by the current user"), which distinguishes it from the mutation siblings. The second sentence routes away from it for single-resource lookups, though it says "the matching get tool" rather than naming get_project, so differentiation is slightly indirect.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-to-use (enumerating accessible projects) and an explicit when-not (a single known resource should use the corresponding get tool). It does not address the overlap with other search-style siblings such as search_repositories or list_project_members, nor does it note when filters should be preferred over client-side filtering.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mr_discussionsARead-only
List discussion items for a merge request. List complete discussion threads. Use get_merge_request_notes for flat notes.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| summary | No | If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON. | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds only the thread-vs-note distinction and says nothing about pagination semantics (whether paging applies to threads or notes), ordering, or that unresolved/resolvable state is included, which matters for a discussions listing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler; the core listing behavior is front-loaded and the routing hint follows immediately. Nothing is repeated from the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given six fully documented parameters and no output schema, the definition covers purpose and alternative routing adequately. However, with no output schema present, the description would be more complete if it sketched the shape of a discussion thread (id, notes array, resolved flag) so an agent knows what to do with the GitLab JSON.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, documenting page, per_page, summary, jmespath, project_id and merge_request_iid fully. The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('List discussion items for a merge request') and clarifies the granularity as 'complete discussion threads', which distinguishes it from the singular get_merge_request_discussion. The slight tension between 'discussion items' and 'threads' in the first two sentences introduces a small ambiguity about the returned unit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly names the alternative, `get_merge_request_notes`, and the condition that selects it ('flat notes'). It stops short of stating exclusions or prerequisites such as needing the MR to exist or how resolving threads interacts with the resolve_merge_request_thread sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
my_issuesARead-only
List issues assigned to the authenticated user. Use this for issue management. Use list_issues for project-wide listing and get_issue for one issue. Requires classic read_user or fine-grained User:Read.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number for pagination (default: 1) | |
| state | No | Return issues with a specific state (default: opened) | |
| labels | No | Array of label names to filter by | |
| search | No | Search for specific terms in title and description | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Number of items per page (default: 20, max: 100) | |
| milestone | No | Milestone title to filter by | |
| project_id | No | Project ID or URL-encoded path (optional to search across all accessible projects) | |
| created_after | No | Return issues created after the given time (ISO 8601) | |
| updated_after | No | Return issues updated after the given time (ISO 8601) | |
| created_before | No | Return issues created before the given time (ISO 8601) | |
| updated_before | No | Return issues updated before the given time (ISO 8601) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds a genuinely useful prerequisite — the required classic read_user or fine-grained User:Read scope — which tells the agent an auth failure is possible and why. Beyond that it says nothing about pagination behavior or that results span all accessible projects when project_id is omitted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the scoping statement, then alternatives, then auth — a sensible order with no wasted length. The sentence 'Use this for issue management' carries no information and could be cut, keeping it from a perfect score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter, zero-required read tool with no output schema and annotations covering safety, the description covers purpose, alternatives, and auth prerequisites. It is slightly thin on result shape and pagination expectations, but the fully-described schema closes most of that gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all twelve parameters are already documented in the schema, including pagination, state enum, date filters, and the project_id cross-project note. The description adds no parameter-level meaning, which is the baseline-3 case when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with explicit scope: 'List issues assigned to the authenticated user.' The scope (assigned to me) is exactly what separates it from list_issues and get_issue, so an agent can identify it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names both alternatives and the condition that selects each: 'Use `list_issues` for project-wide listing and `get_issue` for one issue.' The one soft sentence, 'Use this for issue management,' is redundant but harmless next to the explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_merge_request_threadA
Resolve a thread on a merge request. Mark an existing review thread resolved. Use update_merge_request_discussion_note to change note text.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| resolved | Yes | Whether to resolve the thread | |
| project_id | Yes | Project ID or complete URL-encoded path to project | |
| discussion_id | Yes | The ID of a thread | |
| merge_request_iid | Yes | The IID of a merge request |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide only openWorldHint, so the description carries most of the behavioral burden. It implies a state mutation on a review thread and what specifically changes (resolution status), which is useful, but it omits permission requirements, reversibility, and the fact that resolved=false can unresolve a thread. For a mutation tool with no destructive/readOnly annotations, that is a notable gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action, followed by a targeted disambiguation pointer. No redundant restatement of the title or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is a mutation with no output schema and only an openWorldHint annotation, so the description should do more: it does not cover the unresolve case, permission/auth expectations, or what the call returns. Adequate to invoke correctly, but incomplete for a state-changing operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters are already documented and the baseline is 3. The description adds no syntax or semantics beyond the schema; notably it does not clarify that the boolean 'resolved' also supports unresolving when false, which is the one place it could have added value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Resolve a thread on a merge request') and reinforces it with 'Mark an existing review thread resolved.' It also explicitly names the sibling tool to use for a different operation (editing note text), so an agent can distinguish it from update_merge_request_discussion_note without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the use case (marking an existing thread resolved) and routes the agent to update_merge_request_discussion_note for note-text editing, which is a concrete alternative. It stops short of stating exclusions or prerequisites (e.g., what happens if the thread is already resolved, or permission requirements), so it is not a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_repositoriesARead-only
Search for GitLab projects. If the identifier is known, use a typed get or list tool.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | Page number (default 1) | |
| query | No | Search query (alias for 'search') | |
| search | No | Search query | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| per_page | No | Items per page (max 100, default 20) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered structurally. The description adds nothing beyond that: no match behavior, no default result set size, no note that an empty result is normal for a search, and no pagination guidance despite page/per_page being present. With annotations doing the heavy lifting, a 3 is the right ceiling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the purpose and with zero filler or repetition. It is arguably under-sized rather than concise, which keeps it off a 5, but every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Subtracting the schema (which fully documents all five parameters) and the annotations (read-only, open-world), the description covers the one thing structured fields cannot: how to choose the tool at all. It stops short of a 5 because scoping details, such as whether results span accessible projects only, are omitted for an open-world search.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The most confusing aspect, that 'query' is an alias for 'search', is documented only in the schema, not the description, and the description adds no meaning about what the search string matches against.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource ('Search for GitLab projects'), which is clear enough to act on. It falls short of a 5 because it never says what field is searched (name, path, description) or how results differ from the sibling list_projects, so an agent still has to infer the distinction from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence gives an explicit routing rule: when the identifier is known, use a typed get or list tool instead. That is real when-to-use and when-not guidance naming an alternative path. It does not name the concrete siblings (get_project, list_projects) or cover the case where the identifier is only partially known.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_issueA
Update an issue. Slim confirmation by default; full_response=true for the complete object. Change fields on an existing issue. Use update_issue_description_patch for a targeted description edit and create_issue_note for discussion.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Issue title | |
| labels | No | Label names | |
| weight | No | Issue weight | |
| due_date | No | Due date (YYYY-MM-DD) | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| issue_iid | Yes | Issue IID | |
| issue_type | No | issue, incident, test_case, or task | |
| project_id | Yes | Project ID or URL-encoded path | |
| description | No | Issue description | |
| state_event | No | close or reopen | |
| assignee_ids | No | Assignee user IDs | |
| confidential | No | Confidential | |
| milestone_id | No | Milestone ID | |
| full_response | No | If true, return the complete updated issue. Default is slim (iid, title, state, web_url, updated_at). | |
| discussion_locked | No | Lock discussions |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations supply only openWorldHint=true, so the description carries most of the behavioral burden. It usefully discloses the default return shape (slim: iid, title, state, web_url, updated_at) versus full_response=true — but that same detail is already in the `full_response` schema description, so the added value is limited. For a mutation tool it says nothing about permission requirements, reversibility, or side effects of `state_event` closing/reopening.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the verb+resource, and no padding. Minor redundancy: "Update an issue" and "Change fields on an existing issue" say the same thing twice, and the response-shape sentence is duplicated in the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Adequate for a 15-parameter mutation tool: field coverage lives in the schema and return shape is addressed. However, with no output schema and no annotation coverage of safety/permissions, the description should say more about the consequences of state transitions and what the slim confirmation actually omits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the 15 parameters is already documented (enums for state_event and issue_type, date format for due_date, JMESPath filtering). The description adds no meaning beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Update an issue" / "Change fields on an existing issue") that an agent can match to intent immediately. It also distinguishes two nearby siblings, but only partially — it never contrasts with other write tools in the set (update_merge_request, create_issue) or clarifies that it cannot create issues.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent away from this tool for two cases: targeted description edits go to `update_issue_description_patch`, and discussion goes to `create_issue_note`. There is no when-not-to-use guidance for the broader class of writes (e.g., creating an issue, updating an MR), which keeps it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_issue_description_patchA
Patch an issue description (search/replace or unified diff) without resending the full body. dry_run previews; create_note summarizes.
| Name | Required | Description | Default |
|---|---|---|---|
| patch | Yes | The patch content to apply to the issue description | |
| dry_run | No | If true, preview changes without updating the issue | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| issue_iid | Yes | The internal ID of the project issue | |
| patch_type | Yes | Type of patch format to apply | |
| project_id | Yes | Project ID or URL-encoded path | |
| create_note | No | If true, add a note summarizing the change after update | |
| allow_multiple | No | For search_replace: allow multiple matches to all be replaced (default: false — fail on duplicate) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply openWorldHint, so the description carries most of the burden. It usefully discloses two behavioral flags (dry_run previews, create_note summarizes after the update) but says nothing about permissions, match-failure behavior, or what happens to unmentioned description content.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero filler, front-loading the core action and formats before the optional behaviors. Every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an eight-parameter mutation tool with only openWorldHint for annotations and no output schema, the definition covers the happy path but leaves out error semantics (patch mismatch, duplicate matches) and permission requirements. Adequate but with clear gaps given the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all eight parameters are already documented in the schema. The description's notes on dry_run and create_note largely restate the schema text and it adds nothing for allow_multiple, jmespath, or patch_type beyond naming the formats. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (patch) plus resource (issue description) and names the two supported formats (search/replace, unified diff). The clause 'without resending the full body' implicitly separates it from the sibling update_issue, though it never names that tool outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by contrasting with a full-body update, and it explains what dry_run and create_note do. But it gives no explicit when-to-use/when-not guidance and no prerequisite or failure conditions (e.g., what happens when a search pattern doesn't match).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_merge_requestA
Update a merge request (merge_request_iid or source_branch required). Use the create tool for new resources and a note tool for comments.
| Name | Required | Description | Default |
|---|---|---|---|
| draft | No | Draft / WIP | |
| title | No | MR title | |
| labels | No | MR labels | |
| squash | No | Squash commits on merge | |
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. | |
| project_id | Yes | Project ID or URL-encoded path | |
| description | No | MR description | |
| state_event | No | close or reopen | |
| assignee_ids | No | Assignee user IDs | |
| milestone_id | No | Milestone ID. 0 unassigns. Null is omitted. | |
| reviewer_ids | No | Reviewer user IDs | |
| source_branch | No | Source branch name | |
| target_branch | No | Target branch | |
| merge_request_iid | No | Merge request IID | |
| remove_source_branch | No | Remove source branch on merge |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The only annotation is openWorldHint=true, so the description carries the full behavioral burden for a mutation tool and largely drops it. It never states that this is a mutation, that changes are applied immediately without confirmation, or that state_event can close or reopen an MR, and it says nothing about which settings are left untouched when omitted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and the routing advice immediately after. Every clause carries information; the only minor cost is that the parenthetical constraint is buried mid-sentence rather than stated as a standalone requirement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 15 parameters, a mutation surface, and no output schema, the definition is thinner than the tool's complexity warrants. The fully documented schema compensates for parameter meaning, but the description omits confirmation semantics and the close/reopen side effect that an agent should warn about before calling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds a real constraint absent from the schema: that merge_request_iid or source_branch is required. The schema lists only project_id as required, so this note prevents a validation-level mistake. It adds nothing about the enum-constrained state_event or the merge-time flags.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Update a merge request" gives a specific verb plus resource, and the parenthetical identifier constraint narrows the target further. It stops short of distinguishing itself from other merge-request siblings by name (e.g. get_merge_request, create_merge_request), so an agent must infer the read/write split.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-not guidance is present: creation of new resources goes to the create tool, and commenting goes to a note tool. That routes the two most likely mis-selections. It does not cover the read-side alternative (get_merge_request) or prerequisites such as permissions or MR state.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiARead-only
Get current authenticated user details. Requires classic read_user or fine-grained User:Read. Use get_user or get_users to look up another user.
| Name | Required | Description | Default |
|---|---|---|---|
| jmespath | No | Optional JMESPath expression filtering the JSON result before return. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint and openWorldHint, and the description adds genuinely new context: the required OAuth scopes (classic read_user or fine-grained User:Read), which an agent cannot infer from structured fields. It stops short of describing the returned payload or any rate-limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with the core action front-loaded, followed by the auth prerequisite and the sibling routing. No wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-required-param read tool with annotations and full schema coverage, this covers purpose, auth prerequisites and alternatives. Only the shape of the returned user object is unspecified, which is a minor gap absent an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single optional jmespath parameter is fully documented in the schema; the description adds nothing about it, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get current authenticated user details') and explicitly scopes it to the caller, distinguishing it from user-lookup siblings by naming get_user and get_users.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives both when to use this tool and when not to, routing the agent to the named alternatives for looking up another user. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
22 tool updates
v2.3.22- Changed
create_issue5 fields changed- changed
Input schema / properties / assignee_ids / descriptionPrevious value: -"Array of user IDs to assign"New value: +"Assignee user IDs" - changed
Input schema / properties / issue_type / descriptionPrevious value: -"The type of issue. One of issue, incident, test_case or task."New value: +"issue, incident, test_case, or task" - changed
Input schema / properties / labels / descriptionPrevious value: -"Array of label names"New value: +"Label names" - changed
Input schema / properties / milestone_id / descriptionPrevious value: -"Milestone ID to assign"New value: +"Milestone ID" - changed
Input schema / properties / weight / descriptionPrevious value: -"Weight of the issue (numeric, typically hours of work)"New value: +"Issue weight"
- Changed
create_merge_request10 fields changed- changed
Input schema / properties / allow_collaboration / descriptionPrevious value: -"Allow commits from upstream members"New value: +"Allow eligible upstream members to push to the fork source branch" - changed
Input schema / properties / assignee_ids / descriptionPrevious value: -"The ID of the users to assign the MR to"New value: +"Assignee user IDs" - changed
Input schema / properties / draft / descriptionPrevious value: -"Create as draft merge request"New value: +"Create as draft" - changed
Input schema / properties / labels / descriptionPrevious value: -"Labels for the MR"New value: +"MR labels" - changed
Input schema / properties / remove_source_branch / descriptionPrevious value: -"Flag indicating if a merge request should remove the source branch when merging."New value: +"Remove source branch on merge" - changed
Input schema / properties / reviewer_ids / descriptionPrevious value: -"The ID of the users to assign as reviewers of the MR"New value: +"Reviewer user IDs" - changed
Input schema / properties / source_branch / descriptionPrevious value: -"Branch containing changes"New value: +"Source branch" - changed
Input schema / properties / squash / descriptionPrevious value: -"If true, squash all commits into a single commit on merge."New value: +"Squash commits on merge" - changed
Input schema / properties / target_branch / descriptionPrevious value: -"Branch to merge into"New value: +"Target branch" - changed
Input schema / properties / target_project_id / descriptionPrevious value: -"Numeric ID of the target project."New value: +"Target project numeric ID"
- Changed
discover_tools1 field changed- changed
Input schema / properties / category / descriptionPrevious value: -"Toolset category to activate (e.g. 'pipelines', 'wiki'). Omit to list available categories."New value: +"Toolset to activate (e.g. pipelines, wiki). Omit to list. Prefer a category over GITLAB_TOOLSETS=all. Session-only; persist `GITLAB_TOOLSETS=core,<category>` when OAUTH_STATELESS_MODE=true."
- Changed
get_issue2 fields changed- changed
Input schema / properties / full_response / descriptionPrevious value: -"If true, include the complete milestone object, including its description, on the returned issue. Default returns the issue with a slim milestone (id, iid, title, state, web_url) to reduce token usage."New value: +"If true, include the complete milestone (including description). Default is slim (id, iid, title, state, web_url)." - changed
Input schema / properties / issue_iid / descriptionPrevious value: -"The internal ID of the project issue"New value: +"Issue IID"
- Changed
get_merge_request3 fields changed- changed
Input schema / properties / include_summaries / descriptionPrevious value: -"If true, include deployment_summary, commit_addition_summary and approval_summary (extra API calls, larger response). Default false to reduce token usage."New value: +"If true, include deployment, commit, and approval summaries (extra API calls). Default false." - changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path"
- Changed
get_merge_request_diffs2 fields changed- changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path"
- Changed
get_merge_request_file_diff2 fields changed- changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path"
- Changed
get_repository_tree8 fields changed- added
Input schema / properties / pageAdded value: +{ + "description": "Offset page number from 1 (items + next_page)", + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "type": "integer" +} - changed
Input schema / properties / page_token / descriptionPrevious value: -"Token for keyset pagination. Use the next_page_token value returned in the previous response to retrieve the next page."New value: +"Keyset token from the previous next_page_token" - changed
Input schema / properties / pagination / descriptionPrevious value: -"Pagination method. Use 'keyset' for keyset-based pagination (required for repositories with many files). Non-keyset calls keep the legacy array response for backward compatibility; that legacy response shape is deprecated and may be removed in a future major release. Keyset calls return a structured response with items and next_page_token when more pages are available."New value: +"Use keyset for large trees (items + next_page_token). Omit both page and pagination for the legacy array (deprecated)." - changed
Input schema / properties / path / descriptionPrevious value: -"The path inside the repository"New value: +"Path inside the repository" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of results to show per page"New value: +"Items per page" - changed
Input schema / properties / project_id / descriptionPrevious value: -"The ID or URL-encoded path of the project"New value: +"Project ID or URL-encoded path" - changed
Input schema / properties / recursive / descriptionPrevious value: -"Boolean value to get a recursive tree"New value: +"Recursive tree" - changed
Input schema / properties / ref / descriptionPrevious value: -"The name of a repository branch or tag. Defaults to the default branch."New value: +"Branch or tag. Defaults to the default branch."
- Changed
help1 field changed- changed
Input schema / properties / topic / descriptionPrevious value: -"Guide to return. Omit for the overview and the list of topics. Values: overview, code-review, merge-requests, issues, pipelines, search, token-saving."New value: +"Guide to return. Omit for the overview and the list of topics."
- Changed
list_branches2 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)"
- Changed
list_commits13 fields changed- changed
Input schema / properties / all / descriptionPrevious value: -"Retrieve every commit from the repository"New value: +"Every commit in the repository" - changed
Input schema / properties / author / descriptionPrevious value: -"Search commits by commit author"New value: +"Commit author" - changed
Input schema / properties / first_parent / descriptionPrevious value: -"Follow only the first parent commit upon seeing a merge commit"New value: +"Follow only the first parent of merges" - changed
Input schema / properties / order / descriptionPrevious value: -"List commits in order"New value: +"default or topo" - changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / path / descriptionPrevious value: -"The file path"New value: +"File path" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path" - changed
Input schema / properties / ref_name / descriptionPrevious value: -"The name of a repository branch, tag or revision range, or if not given the default branch"New value: +"Branch, tag, or revision range. Default: default branch." - changed
Input schema / properties / since / descriptionPrevious value: -"Only commits after or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"New value: +"Commits on or after this ISO 8601 datetime" - changed
Input schema / properties / trailers / descriptionPrevious value: -"Parse and include Git trailers for every commit"New value: +"Include Git trailers" - changed
Input schema / properties / until / descriptionPrevious value: -"Only commits before or on this date are returned in ISO 8601 format YYYY-MM-DDTHH:MM:SSZ"New value: +"Commits on or before this ISO 8601 datetime" - changed
Input schema / properties / with_stats / descriptionPrevious value: -"Stats about each commit are added to the response"New value: +"Include per-commit stats"
- Changed
list_issue_discussions2 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)"
- Changed
list_issues20 fields changed- changed
Input schema / properties / assignee_id / descriptionPrevious value: -"Return issues assigned to the given user ID (user id, none, or any). Mutually exclusive with assignee_username."New value: +"User ID, none, or any. Mutually exclusive with assignee_username." - changed
Input schema / properties / assignee_username / descriptionPrevious value: -"Return issues assigned to the given username. Mutually exclusive with assignee_id."New value: +"Username. Mutually exclusive with assignee_id." - changed
Input schema / properties / author_id / descriptionPrevious value: -"Return issues created by the given user ID. Mutually exclusive with author_username."New value: +"Author user ID. Mutually exclusive with author_username." - changed
Input schema / properties / author_username / descriptionPrevious value: -"Return issues created by the given username. Mutually exclusive with author_id."New value: +"Author username. Mutually exclusive with author_id." - changed
Input schema / properties / confidential / descriptionPrevious value: -"Filter confidential or public issues"New value: +"Confidential or public" - changed
Input schema / properties / created_after / descriptionPrevious value: -"Return issues created after the given time"New value: +"Created after" - changed
Input schema / properties / created_before / descriptionPrevious value: -"Return issues created before the given time"New value: +"Created before" - changed
Input schema / properties / due_date / descriptionPrevious value: -"Return issues that have the due date"New value: +"Due date" - changed
Input schema / properties / issue_type / descriptionPrevious value: -"Filter to a given type of issue. One of issue, incident, test_case or task"New value: +"issue, incident, test_case, or task" - changed
Input schema / properties / iteration_id / descriptionPrevious value: -"Return issues assigned to the given iteration ID. None returns issues that do not belong to an iteration. Any returns issues that belong to an iteration. "New value: +"Iteration ID, none (no iteration), or any (has an iteration)." - changed
Input schema / properties / labels / descriptionPrevious value: -"Array of label names"New value: +"Label names" - changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or URL-encoded path (optional - if not provided, lists issues across all accessible projects)"New value: +"Project ID or URL-encoded path. Omit to list issues across accessible projects." - changed
Input schema / properties / scope / descriptionPrevious value: -"Return issues from a specific scope"New value: +"Issue scope" - changed
Input schema / properties / search / descriptionPrevious value: -"Search for specific terms"New value: +"Search terms" - changed
Input schema / properties / state / descriptionPrevious value: -"Return issues with a specific state"New value: +"Issue state" - changed
Input schema / properties / updated_after / descriptionPrevious value: -"Return issues updated after the given time"New value: +"Updated after" - changed
Input schema / properties / updated_before / descriptionPrevious value: -"Return issues updated before the given time"New value: +"Updated before" - changed
Input schema / properties / with_labels_details / descriptionPrevious value: -"Return more details for each label"New value: +"Include label details"
- Changed
list_labels2 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)"
- Changed
list_merge_request_changed_files2 fields changed- changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path"
- Changed
list_merge_request_diffs2 fields changed- changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path"
- Changed
list_merge_requests24 fields changed- changed
Input schema / properties / approved_by_usernames / descriptionPrevious value: -"Returns merge requests approved by the given usernames (array)."New value: +"Approved by these usernames" - changed
Input schema / properties / assignee_id / descriptionPrevious value: -"Return MRs assigned to the given user ID (integer), 'none', or 'any'. Mutually exclusive with assignee_username."New value: +"User ID, none, or any. Mutually exclusive with assignee_username." - changed
Input schema / properties / assignee_username / descriptionPrevious value: -"Returns merge requests assigned to the given username. Mutually exclusive with assignee_id."New value: +"Username. Mutually exclusive with assignee_id." - changed
Input schema / properties / author_id / descriptionPrevious value: -"Returns merge requests created by the given user ID (integer). Mutually exclusive with author_username."New value: +"Author user ID. Mutually exclusive with author_username." - changed
Input schema / properties / author_username / descriptionPrevious value: -"Returns merge requests created by the given username. Mutually exclusive with author_id."New value: +"Author username. Mutually exclusive with author_id." - changed
Input schema / properties / created_after / descriptionPrevious value: -"Return merge requests created after the given time"New value: +"Created after" - changed
Input schema / properties / created_before / descriptionPrevious value: -"Return merge requests created before the given time"New value: +"Created before" - changed
Input schema / properties / labels / descriptionPrevious value: -"Array of label names"New value: +"Label names" - changed
Input schema / properties / order_by / descriptionPrevious value: -"Return merge requests ordered by the given field"New value: +"Sort field" - changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)" - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or URL-encoded path (optional - if not provided, lists all merge requests the user has access to)"New value: +"Project ID or URL-encoded path. Omit to list the user's accessible MRs." - changed
Input schema / properties / reviewer_id / descriptionPrevious value: -"Returns merge requests which have the user as a reviewer. Must be an integer, 'none', or 'any'. Mutually exclusive with reviewer_username."New value: +"Reviewer user ID, none, or any. Mutually exclusive with reviewer_username." - changed
Input schema / properties / reviewer_username / descriptionPrevious value: -"Returns merge requests which have the user as a reviewer by username. Mutually exclusive with reviewer_id."New value: +"Reviewer username. Mutually exclusive with reviewer_id." - changed
Input schema / properties / scope / descriptionPrevious value: -"Return merge requests from a specific scope"New value: +"MR scope" - changed
Input schema / properties / search / descriptionPrevious value: -"Search for specific terms"New value: +"Search terms" - changed
Input schema / properties / sort / descriptionPrevious value: -"Return merge requests sorted in ascending or descending order"New value: +"asc or desc" - changed
Input schema / properties / source_branch / descriptionPrevious value: -"Return merge requests from a specific source branch"New value: +"Source branch" - changed
Input schema / properties / state / descriptionPrevious value: -"Return merge requests with a specific state"New value: +"MR state" - changed
Input schema / properties / target_branch / descriptionPrevious value: -"Return merge requests targeting a specific branch"New value: +"Target branch" - changed
Input schema / properties / updated_after / descriptionPrevious value: -"Return merge requests updated after the given time"New value: +"Updated after" - changed
Input schema / properties / updated_before / descriptionPrevious value: -"Return merge requests updated before the given time"New value: +"Updated before" - changed
Input schema / properties / wip / descriptionPrevious value: -"Filter merge requests against their wip status"New value: +"WIP filter" - changed
Input schema / properties / with_labels_details / descriptionPrevious value: -"Return more details for each label"New value: +"Include label details"
- Changed
list_projects15 fields changed- changed
Input schema / properties / archived / descriptionPrevious value: -"Filter for archived projects"New value: +"Archived projects" - changed
Input schema / properties / membership / descriptionPrevious value: -"Filter for projects where current user is a member"New value: +"Current user is a member" - changed
Input schema / properties / min_access_level / descriptionPrevious value: -"Filter by minimum access level"New value: +"Minimum access level" - changed
Input schema / properties / order_by / descriptionPrevious value: -"Return projects ordered by field"New value: +"Sort field" - changed
Input schema / properties / owned / descriptionPrevious value: -"Filter for projects owned by current user"New value: +"Owned by current user" - changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)" - changed
Input schema / properties / search / descriptionPrevious value: -"Search term for projects"New value: +"Search term" - changed
Input schema / properties / search_namespaces / descriptionPrevious value: -"Needs to be true if search is full path"New value: +"Set true when search is a full path" - changed
Input schema / properties / simple / descriptionPrevious value: -"Return only limited fields"New value: +"Limited fields only" - changed
Input schema / properties / sort / descriptionPrevious value: -"Return projects sorted in ascending or descending order"New value: +"asc or desc" - changed
Input schema / properties / topic / descriptionPrevious value: -"Filter by topic (projects tagged with this topic)"New value: +"Topic tag" - changed
Input schema / properties / visibility / descriptionPrevious value: -"Filter by project visibility"New value: +"public, internal, or private" - changed
Input schema / properties / with_issues_enabled / descriptionPrevious value: -"Filter projects with issues feature enabled"New value: +"Issues enabled" - changed
Input schema / properties / with_merge_requests_enabled / descriptionPrevious value: -"Filter projects with merge requests feature enabled"New value: +"Merge requests enabled"
- Changed
mr_discussions2 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)"
- Changed
search_repositories2 fields changed- changed
Input schema / properties / page / descriptionPrevious value: -"Page number for pagination (default: 1)"New value: +"Page number (default 1)" - changed
Input schema / properties / per_page / descriptionPrevious value: -"Number of items per page (max: 100, default: 20)"New value: +"Items per page (max 100, default 20)"
- Changed
update_issue13 fields changed- changed
Input schema / properties / assignee_ids / descriptionPrevious value: -"Array of user IDs to assign issue to"New value: +"Assignee user IDs" - changed
Input schema / properties / confidential / descriptionPrevious value: -"Set the issue to be confidential"New value: +"Confidential" - changed
Input schema / properties / description / descriptionPrevious value: -"The description of the issue"New value: +"Issue description" - changed
Input schema / properties / discussion_locked / descriptionPrevious value: -"Flag to lock discussions"New value: +"Lock discussions" - changed
Input schema / properties / due_date / descriptionPrevious value: -"Date the issue is due (YYYY-MM-DD)"New value: +"Due date (YYYY-MM-DD)" - changed
Input schema / properties / full_response / descriptionPrevious value: -"If true, return the complete updated issue object. Default returns a slim confirmation (iid, title, state, web_url, updated_at) to reduce token usage."New value: +"If true, return the complete updated issue. Default is slim (iid, title, state, web_url, updated_at)." - changed
Input schema / properties / issue_iid / descriptionPrevious value: -"The internal ID of the project issue"New value: +"Issue IID" - changed
Input schema / properties / issue_type / descriptionPrevious value: -"The type of issue. One of issue, incident, test_case or task."New value: +"issue, incident, test_case, or task" - changed
Input schema / properties / labels / descriptionPrevious value: -"Array of label names"New value: +"Label names" - changed
Input schema / properties / milestone_id / descriptionPrevious value: -"Milestone ID to assign"New value: +"Milestone ID" - changed
Input schema / properties / state_event / descriptionPrevious value: -"Update issue state (close/reopen)"New value: +"close or reopen" - changed
Input schema / properties / title / descriptionPrevious value: -"The title of the issue"New value: +"Issue title" - changed
Input schema / properties / weight / descriptionPrevious value: -"Weight of the issue (numeric, typically hours of work)"New value: +"Issue weight"
- Changed
update_merge_request13 fields changed- changed
Input schema / properties / assignee_ids / descriptionPrevious value: -"The ID of the users to assign the MR to"New value: +"Assignee user IDs" - changed
Input schema / properties / description / descriptionPrevious value: -"The description of the merge request"New value: +"MR description" - changed
Input schema / properties / draft / descriptionPrevious value: -"Work in progress merge request"New value: +"Draft / WIP" - changed
Input schema / properties / labels / descriptionPrevious value: -"Labels for the MR"New value: +"MR labels" - changed
Input schema / properties / merge_request_iid / descriptionPrevious value: -"The IID of a merge request"New value: +"Merge request IID" - changed
Input schema / properties / milestone_id / descriptionPrevious value: -"Milestone ID to assign. Set to 0 to unassign. Null is treated as omitted."New value: +"Milestone ID. 0 unassigns. Null is omitted." - changed
Input schema / properties / project_id / descriptionPrevious value: -"Project ID or complete URL-encoded path to project"New value: +"Project ID or URL-encoded path" - changed
Input schema / properties / remove_source_branch / descriptionPrevious value: -"Flag indicating if the source branch should be removed"New value: +"Remove source branch on merge" - changed
Input schema / properties / reviewer_ids / descriptionPrevious value: -"The ID of the users to assign as reviewers of the MR"New value: +"Reviewer user IDs" - changed
Input schema / properties / squash / descriptionPrevious value: -"Squash commits into a single commit when merging"New value: +"Squash commits on merge" - changed
Input schema / properties / state_event / descriptionPrevious value: -"New state (close/reopen) for the MR"New value: +"close or reopen" - changed
Input schema / properties / target_branch / descriptionPrevious value: -"The target branch"New value: +"Target branch" - changed
Input schema / properties / title / descriptionPrevious value: -"The title of the merge request"New value: +"MR title"
12 tool updates
v2.3.8- Added
help - Changed
list_branches1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_commits1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_issue_discussions1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_issues1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_labels1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_merge_request_changed_files1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_merge_request_diffs1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_merge_requests1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_project_members1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
list_projects1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
- Changed
mr_discussions1 field changed- added
Input schema / properties / summaryAdded value: +{ + "description": "If true, return only high-signal fields (id, iid, title, state, web_url, …). Default false keeps the full GitLab JSON.", + "type": "boolean" +}
80 tool updates
v2.2.6- Removed
approve_merge_request - Removed
bulk_publish_draft_notes - Removed
create_branch - Removed
create_commit_status - Removed
create_draft_note - Removed
create_group - Removed
create_issue_emoji_reaction - Removed
create_issue_link - Removed
create_issue_note_emoji_reaction - Removed
create_label - Removed
create_merge_request_discussion_note - Removed
create_merge_request_emoji_reaction - Removed
create_merge_request_note - Removed
create_merge_request_note_emoji_reaction - Removed
create_note - Removed
create_or_update_file - Removed
create_repository - Removed
delete_branch - Removed
delete_draft_note - Removed
delete_issue - Removed
delete_issue_emoji_reaction - Removed
delete_issue_link - Removed
delete_issue_note_emoji_reaction - Removed
delete_label - Removed
delete_merge_request_discussion_note - Removed
delete_merge_request_emoji_reaction - Removed
delete_merge_request_note - Removed
delete_merge_request_note_emoji_reaction - Removed
download_attachment - Removed
fork_repository - Removed
get_branch_diffs - Removed
get_ci_catalog_resource - Removed
get_draft_note - Changed
get_issue1 field changed- changed
Input schema / properties / full_response / descriptionPrevious value: -"If true, return the complete issue object including the full milestone description. Default returns a slim milestone (id, iid, title, state, web_url) to reduce token usage."New value: +"If true, include the complete milestone object, including its description, on the returned issue. Default returns the issue with a slim milestone (id, iid, title, state, web_url) to reduce token usage."
- Removed
get_issue_link - Removed
get_label - Removed
get_merge_request_conflicts - Removed
get_merge_request_version - Removed
get_namespace - Removed
get_project_events - Removed
get_protected_branch - Removed
get_user - Removed
get_users - Removed
list_ci_catalog_resources - Removed
list_commit_statuses - Removed
list_draft_notes - Removed
list_events - Removed
list_group_iterations - Removed
list_group_members - Removed
list_group_merge_requests - Removed
list_group_projects - Removed
list_issue_emoji_reactions - Removed
list_issue_links - Removed
list_issue_note_emoji_reactions - Removed
list_merge_request_emoji_reactions - Removed
list_merge_request_note_emoji_reactions - Removed
list_merge_request_pipelines - Removed
list_merge_request_versions - Removed
list_namespaces - Removed
list_protected_branches - Removed
list_todos - Removed
mark_all_todos_done - Removed
mark_todo_done - Removed
merge_merge_request - Removed
protect_branch - Removed
publish_draft_note - Removed
push_files - Removed
unapprove_merge_request - Removed
unprotect_branch - Removed
update_default_branch - Removed
update_draft_note - Removed
update_issue_note - Removed
update_label - Removed
update_merge_request_discussion_note - Removed
update_merge_request_note - Removed
update_project - Removed
upload_markdown - Removed
validate_ci_lint - Removed
validate_project_ci_lint - Removed
verify_namespace
118 tool updates
v2.1.66- Changed
approve_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
bulk_publish_draft_notes1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_commit_status1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_draft_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_group1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_issue1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_issue_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_issue_link1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_issue_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_issue_note_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_label1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request_discussion_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request_note_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_merge_request_thread1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_or_update_file1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
create_repository1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_draft_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_issue1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_issue_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_issue_link1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_issue_note_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_label1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_merge_request_discussion_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_merge_request_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_merge_request_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
delete_merge_request_note_emoji_reaction1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
discover_tools1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
download_attachment1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
fork_repository1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_branch_diffs1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_ci_catalog_resource1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_commit1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_commit_diff1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_draft_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_file_blame1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_file_contents1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_issue1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_issue_link1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_label1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_approval_state1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_conflicts1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_diffs1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_discussion1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_file_diff1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_notes1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_merge_request_version1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_namespace1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_project1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_project_events1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_protected_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_repository_tree1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_user1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
get_users1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
health_check1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_branches1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_ci_catalog_resources1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_commit_statuses1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_commits1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_draft_notes1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_events1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_group_iterations1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_group_members1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_group_merge_requests1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_group_projects1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_issue_discussions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_issue_emoji_reactions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_issue_links1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_issue_note_emoji_reactions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_issues1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_labels1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_changed_files1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_diffs1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_emoji_reactions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_note_emoji_reactions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_pipelines1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_request_versions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_merge_requests1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_namespaces1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_project_members1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_projects1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_protected_branches1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
list_todos1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
mark_all_todos_done1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
mark_todo_done1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
merge_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
mr_discussions1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
my_issues1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
protect_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
publish_draft_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
push_files1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
resolve_merge_request_thread1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
search_repositories1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
unapprove_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
unprotect_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_default_branch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_draft_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_issue1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_issue_description_patch1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_issue_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_label1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_merge_request1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_merge_request_discussion_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_merge_request_note1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
update_project1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
upload_markdown1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
validate_ci_lint1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
validate_project_ci_lint1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
verify_namespace1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
- Changed
whoami1 field changed- added
Input schema / properties / jmespathAdded value: +{ + "description": "Optional JMESPath expression filtering the JSON result before return.", + "type": "string" +}
1 tool update
v2.1.63- Added
get_merge_request_discussion
37 tool updates
v2.1.62- Changed
create_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "branch", - "project_id" -]New value: +[ + "project_id", + "branch" +]
- Changed
create_commit_status1 field changed- changed
Input schema / requiredPrevious value: -[ - "sha", - "state", - "project_id" -]New value: +[ + "project_id", + "sha", + "state" +]
- Changed
create_draft_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "merge_request_iid" -]New value: +[ + "project_id", + "merge_request_iid", + "body" +]
- Changed
create_issue1 field changed- changed
Input schema / requiredPrevious value: -[ - "title", - "project_id" -]New value: +[ + "project_id", + "title" +]
- Changed
create_issue_emoji_reaction1 field changed- changed
Input schema / requiredPrevious value: -[ - "name", - "project_id", - "issue_iid" -]New value: +[ + "project_id", + "issue_iid", + "name" +]
- Changed
create_issue_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "issue_iid" -]New value: +[ + "project_id", + "issue_iid", + "body" +]
- Changed
create_issue_note_emoji_reaction1 field changed- changed
Input schema / requiredPrevious value: -[ - "name", - "project_id", - "issue_iid", - "note_id" -]New value: +[ + "project_id", + "issue_iid", + "note_id", + "name" +]
- Changed
create_label1 field changed- changed
Input schema / requiredPrevious value: -[ - "name", - "color", - "project_id" -]New value: +[ + "project_id", + "name", + "color" +]
- Changed
create_merge_request1 field changed- changed
Input schema / requiredPrevious value: -[ - "title", - "source_branch", - "target_branch", - "project_id" -]New value: +[ + "project_id", + "title", + "source_branch", + "target_branch" +]
- Changed
create_merge_request_discussion_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "merge_request_iid", - "discussion_id" -]New value: +[ + "project_id", + "merge_request_iid", + "discussion_id", + "body" +]
- Changed
create_merge_request_emoji_reaction1 field changed- changed
Input schema / requiredPrevious value: -[ - "name", - "project_id", - "merge_request_iid" -]New value: +[ + "project_id", + "merge_request_iid", + "name" +]
- Changed
create_merge_request_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "merge_request_iid" -]New value: +[ + "project_id", + "merge_request_iid", + "body" +]
- Changed
create_merge_request_note_emoji_reaction1 field changed- changed
Input schema / requiredPrevious value: -[ - "name", - "project_id", - "merge_request_iid", - "note_id" -]New value: +[ + "project_id", + "merge_request_iid", + "note_id", + "name" +]
- Changed
create_merge_request_thread1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "merge_request_iid" -]New value: +[ + "project_id", + "merge_request_iid", + "body" +]
- Changed
create_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "noteable_type", - "body", - "project_id", - "noteable_iid" -]New value: +[ + "project_id", + "noteable_type", + "noteable_iid", + "body" +]
- Changed
create_or_update_file1 field changed- changed
Input schema / requiredPrevious value: -[ - "file_path", - "content", - "commit_message", - "branch", - "project_id" -]New value: +[ + "project_id", + "file_path", + "content", + "commit_message", + "branch" +]
- Changed
create_repository1 field changed- added
Input schema / properties / namespace_id / maximumAdded value: +9007199254740991
- Changed
delete_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "branch_name", - "project_id" -]New value: +[ + "project_id", + "branch_name" +]
- Changed
get_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "branch_name", - "project_id" -]New value: +[ + "project_id", + "branch_name" +]
- Changed
get_branch_diffs1 field changed- changed
Input schema / requiredPrevious value: -[ - "from", - "to", - "project_id" -]New value: +[ + "project_id", + "from", + "to" +]
- Changed
get_commit1 field changed- changed
Input schema / requiredPrevious value: -[ - "sha", - "project_id" -]New value: +[ + "project_id", + "sha" +]
- Changed
get_commit_diff1 field changed- changed
Input schema / requiredPrevious value: -[ - "sha", - "project_id" -]New value: +[ + "project_id", + "sha" +]
- Changed
get_file_blame5 fields changed- added
Input schema / properties / range_end / maximumAdded value: +9007199254740991 - added
Input schema / properties / range_end / minimumAdded value: +-9007199254740991 - added
Input schema / properties / range_start / maximumAdded value: +9007199254740991 - added
Input schema / properties / range_start / minimumAdded value: +-9007199254740991 - changed
Input schema / requiredPrevious value: -[ - "file_path", - "ref" -]New value: +[ + "project_id", + "file_path", + "ref" +]
- Changed
get_protected_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "branch_name", - "project_id" -]New value: +[ + "project_id", + "branch_name" +]
- Changed
list_commit_statuses1 field changed- changed
Input schema / requiredPrevious value: -[ - "sha", - "project_id" -]New value: +[ + "project_id", + "sha" +]
- Changed
list_merge_request_pipelines1 field changed- changed
Input schema / requiredPrevious value: -[ - "merge_request_iid", - "project_id" -]New value: +[ + "project_id", + "merge_request_iid" +]
- Changed
protect_branch7 fields changed- added
Input schema / properties / merge_access_level / maximumAdded value: +9007199254740991 - added
Input schema / properties / merge_access_level / minimumAdded value: +-9007199254740991 - added
Input schema / properties / push_access_level / maximumAdded value: +9007199254740991 - added
Input schema / properties / push_access_level / minimumAdded value: +-9007199254740991 - added
Input schema / properties / unprotect_access_level / maximumAdded value: +9007199254740991 - added
Input schema / properties / unprotect_access_level / minimumAdded value: +-9007199254740991 - changed
Input schema / requiredPrevious value: -[ - "branch_name" -]New value: +[ + "project_id", + "branch_name" +]
- Changed
push_files2 fields changed- removed
Input schema / properties / files / items / additionalPropertiesRemoved value: -false - changed
Input schema / requiredPrevious value: -[ - "branch", - "files", - "commit_message", - "project_id" -]New value: +[ + "project_id", + "branch", + "files", + "commit_message" +]
- Changed
unprotect_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "branch_name", - "project_id" -]New value: +[ + "project_id", + "branch_name" +]
- Changed
update_default_branch1 field changed- changed
Input schema / requiredPrevious value: -[ - "default_branch", - "project_id" -]New value: +[ + "project_id", + "default_branch" +]
- Changed
update_issue_description_patch1 field changed- changed
Input schema / requiredPrevious value: -[ - "patch_type", - "patch", - "project_id", - "issue_iid" -]New value: +[ + "project_id", + "issue_iid", + "patch_type", + "patch" +]
- Changed
update_issue_note1 field changed- added
Input schema / requiredAdded value: +[ + "project_id", + "issue_iid", + "discussion_id", + "note_id" +]
- Changed
update_merge_request_discussion_note1 field changed- added
Input schema / requiredAdded value: +[ + "project_id", + "merge_request_iid", + "discussion_id", + "note_id" +]
- Changed
update_merge_request_note1 field changed- changed
Input schema / requiredPrevious value: -[ - "body", - "project_id", - "merge_request_iid", - "note_id" -]New value: +[ + "project_id", + "merge_request_iid", + "note_id", + "body" +]
- Changed
update_project1 field changed- added
Input schema / requiredAdded value: +[ + "project_id" +]
- Changed
validate_ci_lint1 field changed- changed
Input schema / requiredPrevious value: -[ - "content", - "project_id" -]New value: +[ + "project_id", + "content" +]
- Changed
verify_namespace2 fields changed- added
Input schema / properties / parent_id / maximumAdded value: +9007199254740991 - added
Input schema / properties / parent_id / minimumAdded value: +-9007199254740991
TDQS
Scored across 40 tools
Most tools target distinct resources, but the merge request surface has several closely related note, discussion, and diff tools (e.g., get_merge_request_discussion vs get_merge_request_note vs mr_discussions, and list_merge_request_diffs vs get_merge_request_diffs vs get_merge_request_file_diff). Descriptions provide 'use X instead' guidance, but an agent still has meaningful risk of selecting the wrong granularity.
The majority of tools follow a predictable verb_noun snake_case pattern (list_issues, get_merge_request, create_issue). There are notable deviations like mr_discussions, my_issues, whoami, help, and health_check, but these are limited and still readable.
At 40 tools, the surface is heavy for a single MCP server and includes very granular merge request diff/note variants. While GitLab is a broad domain, the presence of discover_tools implies these should be split into toolsets rather than loaded all at once.
Core GitLab workflows are only partially covered: branch creation/deletion, MR merge/approve, label management, and user lookup tools are missing, even though related tools reference them (e.g., get_user, approve_merge_request, update_merge_request_discussion_note). Agents will hit dead ends for common write operations.
Maintenance
Related MCP Connectors
GitLab MCP — wraps the GitLab REST API v4 (BYO API key)
A MCP server built for developers enabling Git based project management with project and personal…
Go MCP server for GitLab: 2 dynamic tools reach 1000+ REST/GraphQL actions. Free/CE, no paid tier.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server for GitLab CI/CD — pipelines, jobs, schedules, branches, tags, merge requests and repository files. Works with any GitLab (SaaS gitlab.com or self-hosted) via python-gitlab.24316 PyPI2MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for interacting with GitLab API, supporting both self-hosted instances and gitlab.com. Provides tools for managing issues, merge requests, code review, pipelines, milestones, releases, search, and file access.345 npmMIT
- AlicenseAqualityAmaintenanceModel Context Protocol (MCP) server for GitLab — exposes 1006 GitLab REST & GraphQL API operations as MCP tools (42 meta-tools / 57 enterprise), 24 resources, 38 prompts, and 17 completion types for AI assistants. Written in Go, single static binary, stdio and HTTP transport.246MIT
- AlicenseCqualityBmaintenanceMCP server for interacting with GitLab API, supporting dynamic tool selection and enterprise-grade security.21010MIT