cd /news/ai-agents/contributing-to-gitlab-mcp-lessons-f… · home › topics › ai-agents › article
[ARTICLE · art-160198] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Contributing to GitLab & MCP: Lessons from a Week of Upstream Open-Source Engineering

A developer contributed a series of upstream merge requests to GitLab and the GitLab Language Server (gitlab-lsp), extending GitLab's Model Context Protocol (MCP) tooling that connects AI agents and IDE assistants like GitLab Duo to GitLab's API. The changes added an update_note method to the save_note tool so agents can edit and resolve comments in place, introduced a list_user_events tool with pagination and date filters, folded merge-request pipeline creation into save_pipeline via an optional merge_request_iid, and added parent_iid support to list_work_items. The developer also fixed a race condition in gitlab-lsp where stale microtasks could dispatch messages to a newly created session, and documented two pitfalls: the false.blank? trap for boolean arguments and an invalid "date" JSON Schema type that broke strict MCP clients.

by read2 min views3 publishedOct 29, 2026

Over the past sprint, I contributed a series of upstream enhancements and bug fixes to GitLab (gitlab-org/gitlab) and the GitLab Language Server ( gitlab-org/editor-extensions/gitlab-lsp).

Most of these changes focus on GitLab’s implementation of the Model Context Protocol (MCP)—the protocol connecting AI agents and IDE assistants (like GitLab Duo) to GitLab's API—as well as race-condition resilience in Language Server protocols.

Here is a comprehensive retrospective on what was built, the architectural decisions behind them, and lessons learned getting complex merge requests to 100% green pipelines under GitLab's rigorous review standards.

save_note Tool (!264854) The MCP save_note tool allowed AI agents to post comments, reply to discussion threads, and resolve discussions on merge requests and work items. However, agents could not edit their existing comments or refine feedback in-place, leading to comment sprawl.

We introduced the update_note method to save_note:

Mutations::Notes::Update::Base (updateNote) with proper authorization checks and quick-action guards. gid://gitlab/Note/123). We updated the tool schema to accept oneOf: [{ type: 'string' }, { type: 'integer' }] and automatically coerce them.project, so we ensured the governance container resolver properly fell back to note.namespace to enforce project/group tool policies.false.blank? Trap:true. When validating method arguments for boolean fields like resolved: false, a naive .blank? check erroneously flagged the parameter as missing. We implemented strict string-blankness checking (val.nil? || (val.is_a?(String) && val.blank?)) to guarantee boolean stability. Agents needed visibility into recent user activity to assist with sprint summaries and standups. While /users/:id/events existed as a REST endpoint, it was not exposed as an MCP tool.

list_user_events in the :core toolset with pagination, action, and target-type filters.ApiTool::TYPE_CONVERSIONS): before and after with type: Date. Grape's MCP tool mapper previously lacked a mapping for Date, emitting "type": "date" in the generated JSON Schema—which is invalid according to the JSON Schema meta-schema and caused strict MCP clients to reject the tool catalog. We added 'Date' => 'string' to map dates cleanly to ISO 8601 strings.mcp_server_tools.md. save_pipeline (!264858) An earlier draft introduced a separate tool to create merge request pipelines. Reviewers pointed out that having both save_pipeline and a dedicated merge request pipeline tool introduced fragmentation and API redundancy.

SavePipelineService using an optional merge_request_iid parameter.parent_iid support to the list_work_items MCP tool, enabling agents to query tasks and child items belonging to a specific parent issue or epic.gitlab-lsp (!4539) In the GitLab Language Server (gitlab-lsp), when a user ran /new to initiate a clean session while pending wake messages were queued, old microtasks could resolve and dispatch messages to the newly instantiated session, causing stale state corruption.

await flushMicrotasks() during session teardown.false.blank? == true. Always check .nil? or type-check when accepting booleans."date" will break tool discovery across ecosystems. All Merge Requests linked above are open or merged in GitLab's official repositories. Happy hacking!

── more in #ai-agents 4 stories · sorted by recency
── more on @gitlab 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/contributing-to-gitl…] indexed:0 read:2min 2026-10-29 · —