Skip to content

Completions

Completions provide real-time autocomplete suggestions for the arguments of prompts and resource templates. Instead of memorizing project paths, branch names, or user logins, you type a few characters and GitLab MCP Server queries GitLab for matching values, returning them through the MCP completion/complete protocol method. This transforms a multi-step lookup into a single, interactive selection.

MCP completes two things: the arguments of a prompt (a ref/prompt reference) and the parameters of a resource URI template (a ref/resource reference). The parameters of a tool are not part of the protocol’s completion, so a tool call is never autocompleted; the assistant fills those in itself.

GitLab MCP Server completes 18 argument names (the prompt arguments and resource URI parameters the completion/complete handler recognizes), organized into global completers that work anywhere and per-project completers that search within a chosen project. Every suggestion is fetched live and up to 10 values are returned, so results always reflect the current state of the connected GitLab instance. A request reaches GitLab at most once per listing it needs: once for most arguments, and twice for from, to and ref, which merge the branch and tag listings.

Without completions, supplying an identifier to a prompt means looking it up first, and that often costs an extra tool call. With completions, the client resolves the value inline as the user types, so a separate discovery step is no longer required.

Without completions:
Prompt review_mr asks for project_id → What's the path? → Must run project.list first
With completions:
User types "mcp" into project_id → Server suggests: "group/gitlab-mcp-server", "group/redmine-mcp-server"

This collapses a multi-step lookup into a single, interactive selection.

When the user starts typing the value of a prompt argument or a resource URI parameter, the MCP client sends a completion/complete request to the server. The server queries the matching GitLab endpoint, then returns the matches as suggestions the client renders in a dropdown. The whole round-trip happens as the user types.

GitLab APIMCP ServerMCP ClientUserGitLab APIMCP ServerMCP ClientUserStarts typing argument valuecompletion/complete (arg: "project_id", value: "mcp")GET /projects?membership=true&search=mcpMatching projectsCompletion suggestionsShows dropdown with options

Each request is answered in five steps:

  1. The client sends completion/complete with a reference (ref/prompt with a prompt name, or ref/resource with a URI), the argument’s name and the partial value typed so far, and, optionally, context.arguments with the values already chosen for the other arguments.
  2. A ref/prompt naming a prompt this server does not serve is refused with -32602, the code the specification names for an invalid prompt name.
  3. An argument whose data comes only from actions the operator removed with --exclude-tools answers an empty list without reaching GitLab.
  4. The argument’s name picks the completer. A per-project completer reads project_id from context.arguments and answers an empty list without one.
  5. The completer queries GitLab with the partial value and returns up to 10 matching values.

GitLab MCP Server completes 18 argument names, organized into global and per-project completers. Global completers resolve values that exist instance-wide, while per-project completers take the project_id the client sends in context.arguments and search only within that project. Prompt arguments (ref/prompt) get the full set; resource URI templates (ref/resource) complete project_id, group_id, merge_request_iid and issue_iid.

Two ways of matching are used. Arguments backed by a GitLab search (projects, groups, users, branches, tags, labels and milestones) pass what you typed to GitLab’s own search filter for that list, which decides what matches and is not limited to the start of a name. Arguments that are numbers or hashes (merge request and issue IIDs, pipeline and job IDs, commit SHAs) read one page of 20 recent items and keep those whose identifier starts with what you typed.

These work without a project context:

ArgumentCompletesHow it is matchedExample
project_idProject paths, by path or nameGitLab project search, among projects you are a member ofmy-group/my-project
group_idGroup paths, by nameGitLab group searchengineering
usernameGitLab usernamesGitLab user search, active users onlyjohn.doe

These require a project_id in context.arguments and search within that project:

ArgumentCompletesHow it is matchedExample
branch, source_branch, target_branchBranch namesGitLab branch searchfeature/login
from, to, refBranch and tag namesBranch search and tag search, merged with branches firstv1.2.0, feature/login
tagTag namesGitLab tag searchv1.2.0
merge_request_iidOpen MR IIDsThe 20 newest open merge requests, by IID prefix42
issue_iidOpen issue IIDsThe 20 newest open issues, by IID prefix100
pipeline_idRecent pipeline IDsThe 20 newest pipelines, by ID prefix12345
shaRecent commit SHAsThe 20 newest commits of the default branch, by SHA prefix, any caseddcc2f13
labelLabel namesGitLab label searchpriority::high
milestone_idMilestone IDsGitLab milestone search, active milestones only7
milestoneMilestone titles (falls back to group_id)GitLab milestone search, active milestones onlySprint 14
job_idJob IDs in a pipeline (needs pipeline_id)One page of 20 jobs of the pipeline, by ID prefix501

Two completers take a different context. milestone resolves against project_id when one is present and against group_id otherwise, so the group milestone prompts complete too. job_id needs both project_id and pipeline_id in context.arguments. A sha prefix is matched against the full commit hash, so pasting a whole SHA still matches, and the value returned is the short SHA.

FieldValue
valuesAt most 10 bare values, always an array (empty rather than absent). Each is the literal string that replaces what you typed: a project path, an IID, a ref, never a label such as 15: Fix login
totalThe number of matches GitLab reports in its X-Total header, for the arguments backed by a GitLab search; left out when GitLab does not send it, and for the IID, ID and SHA arguments, which are filtered after the read
hasMoretrue when more matches exist than the values returned; left out otherwise

The server reads up to 20 items from GitLab so it can tell when more than 10 match. Results are never cached. On protocol 2026-07-28 the result also carries "resultType": "complete".

An empty list is the normal answer whenever there is nothing useful to suggest, and it never blocks the client:

  • GitLab fails. Any error from the GitLab call answers an empty list rather than an error. The cause is logged at debug level and never shown to the client.
  • Context is missing. A per-project argument without project_id in context.arguments, job_id without pipeline_id, and milestone with neither project_id nor group_id all answer an empty list.
  • The argument is not one of the 18, or a resource-template argument is not one of the four.
  • The operator removed the data. Completion is narrowed by --exclude-tools (GITLAB_MCP_EXCLUDE_TOOLS) like the tool, resource, subscription and prompt surfaces. An operator who removes issue.list removes it here too, so the completion for issue_iid answers an empty list without reaching GitLab. An argument served by more than one action keeps the half that was left: removing only tag.list still completes from, to and ref with branches. For milestone, the scope decides: with a project_id, an excluded project.milestone_list answers empty rather than falling through to the group’s milestones.
  • The server is at capacity. A completion refused by the rate limit, or in HTTP mode by the process’s ceiling on calls held open at once, is answered with an empty list too.

One failure is an error instead. A ref/prompt naming a prompt this server does not serve is refused with -32602, the same code prompts/get answers for that name, because it is something the caller sent and has to change. On GITLAB_MCP_CAPABILITY_SURFACE=minimal, where no prompt is served, every prompt reference is refused this way rather than answered with live GitLab data for a prompt prompts/list and prompts/get have already denied. A prompt an operator’s exclusions removed is refused the same way.

A resource URI is not checked. The URI of a ref/resource is not compared with the templates the server holds, and the specification does not ask for it: a client may send a concrete URI where the server holds only a template. The argument’s name alone decides the answer, so an unrecognized URI is never refused.

  • Errors never reach the client. A GitLab failure answers an empty list, with no GitLab detail. The one refusal, an unserved prompt name, names the prompt the caller asked for and nothing else.
  • Your own credential, your own view. Each completion runs under the caller’s own GitLab credential, so it returns only what that token can see, and project_id searches only the projects you are a member of. In HTTP mode a completion the server cannot attribute to a credential is answered with an empty list and a warning in the server log, never under another caller’s token.
  • Bounded cost. A request makes at most one GitLab call per listing it needs (two for from, to and ref), and reads at most 20 items from each.
  • Rate limited. When the rate limit is on (GITLAB_MCP_RATE_LIMIT_RPS or --rate-limit-rps, on by default in HTTP mode), completions draw on a bucket of their own, ten times the rate and burst of the tool-call bucket, because an editor sends one per keystroke. A completion the bucket refuses answers an empty list.
  • Exclusions hold. An action removed with --exclude-tools cannot be read back through completion.

The examples show a whole JSON-RPC exchange, as a client on protocol 2025-11-25 sees it.

A project path for a prompt. The user types mcp into the project_id argument of the review_mr prompt:

{
"jsonrpc": "2.0",
"id": 7,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "review_mr" },
"argument": { "name": "project_id", "value": "mcp" }
}
}
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"completion": {
"values": ["group/gitlab-mcp-server", "group/redmine-mcp-server"],
"total": 2
}
}
}

A ref for comparison. The compare_branches prompt already has its project; the user types v1.1 into from, and branches come before tags:

{
"jsonrpc": "2.0",
"id": 8,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "compare_branches" },
"argument": { "name": "from", "value": "v1.1" },
"context": { "arguments": { "project_id": "group/gitlab-mcp-server" } }
}
}
{
"jsonrpc": "2.0",
"id": 8,
"result": {
"completion": {
"values": ["release/v1.1", "v1.1.5", "v1.1.6", "v1.1.7"],
"total": 4
}
}
}

A merge request IID in a resource URI. The user fills in gitlab://project/{project_id}/mr/{merge_request_iid} and types 1. IIDs are filtered after the read, so no total comes back:

{
"jsonrpc": "2.0",
"id": 9,
"method": "completion/complete",
"params": {
"ref": { "type": "ref/resource", "uri": "gitlab://project/{project_id}/mr/{merge_request_iid}" },
"argument": { "name": "merge_request_iid", "value": "1" },
"context": { "arguments": { "project_id": "group/gitlab-mcp-server" } }
}
}
{
"jsonrpc": "2.0",
"id": 9,
"result": {
"completion": {
"values": ["15", "14", "12"]
}
}
}

The values are bare IIDs. A client that wants to show titles in its dropdown reads them separately, for example from the merge request resource.

A prompt the server does not serve:

{
"jsonrpc": "2.0",
"id": 10,
"error": { "code": -32602, "message": "unknown prompt \"no_such_prompt\"" }
}

Completions do not change how the assistant calls tools. What they change is the input it starts from: the values a user picks for a prompt or a resource URI come from GitLab, so the prompt the assistant receives names things that exist.

Without completionsWith completions
A prompt’s branch is typed from memory and may not existIt is picked from the branches GitLab returns
A merge request IID is recalled from memoryIt is picked from the project’s open merge requests
A tag name is guessedIt is picked from the project’s real tags

In practice:

  1. Eliminates typos. The user selects from validated suggestions instead of typing exact values.
  2. Reduces round-trips. There is no need to run project.list to find a path before filling in a prompt.
  3. Returns bare values. Suggestions are the literal strings an argument takes (paths, IIDs, refs), never decorated labels, so a pick can be passed straight through.
  4. Real-time search. Results update as the user types, with no caching, so a deleted branch is never suggested.

This is most valuable for per-project values such as branch names, labels and milestones, which vary across projects and cannot be guessed reliably.

Frequently asked questions

What are MCP completions?

Completions are real-time autocomplete suggestions for the arguments of prompts and resource templates. MCP completes those two and never the parameters of a tool. You type a few characters into an argument and GitLab MCP Server queries GitLab through the MCP completion/complete method, returning matching projects, branches, users, labels, and more. This turns a lookup, such as finding a project's path before filling in a prompt, into a single interactive selection. GitLab MCP Server completes 18 argument names across global and per-project completers.

Which argument types support completion?

GitLab MCP Server completes 18 argument names. Three global completers need no project context: project_id, group_id, and username. The per-project completers resolve against the project_id already given in the same request: branch, source_branch, target_branch, from, to, ref, tag, merge_request_iid, issue_iid, pipeline_id, sha, label, milestone_id, milestone (which falls back to group_id for the group milestone prompts), and job_id (which also needs pipeline_id). Each suggestion is fetched live from GitLab, so results reflect the current state of the instance.

How do completions help the assistant?

Completions put real identifiers into the prompts and resource URIs the assistant receives, in four ways: there are no typos, because the value is picked from what GitLab returned; there is no separate lookup, such as running project.list to find a path before filling in a prompt; the values are the bare strings an argument takes (paths, IIDs, refs); and the search updates as characters are typed, with no cache, so a deleted branch is never suggested. The net effect is fewer prompts that start from an identifier that does not exist.

What if my MCP client does not support completions?

Completions require the MCP client to support the completion/complete protocol method. If your client lacks it, GitLab MCP Server simply does not offer suggestions and tool functionality is unaffected. You can still discover valid values by running the domain's list action (project.list, branch.list or project.label_list through gitlab_execute_action on the default surface, or the list action of the matching meta-tool with GITLAB_MCP_TOOL_SURFACE=meta) and then supply the chosen value directly.

Are completions always available?

The server declares completions on both capability surfaces, so they are available whenever it runs. The client still has to use the completion/complete method, and not every client triggers it automatically. On GITLAB_MCP_CAPABILITY_SURFACE=minimal no prompt is served, so every prompt reference is refused with -32602, while resource-template arguments are still completed.

Why is there no caching?

Freshness matters more than speed here. Branches are created and deleted and issues are opened and closed all the time, and a cached suggestion for a branch that no longer exists is worse than a slightly slower lookup. Each completion asks GitLab at the moment it is requested.

What happens if a project has thousands of branches?

The server returns at most 10 values per request and sets hasMore when there are more matches. Typing more characters narrows the search, which keeps the response fast and the dropdown manageable.