Skip to content

fix(ci): remove generated artifacts from repo, fix MCPB 404 race condition on Pages #181

@polaz

Description

@polaz

Problem

Three related issues with generated artifacts and documentation freshness:

1. MCPB 404 at /downloads/gitlab-mcp-latest.mcpb

URL: https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-latest.mcpb
Status: Always returns 404

Root cause — race condition between workflows:

Timeline:
1. ci-cd.yml → semantic-release creates release v6.41.1 → fires `release: [published]` event
2. docs.yml is triggered immediately by `release: [published]`
3. ci-cd.yml → mcpb-bundle job starts AFTER semantic-release (needs version output)
4. docs.yml tries to `gh release download "*.mcpb"` → "no assets to download" (not uploaded yet!)
5. docs.yml deploys Pages WITHOUT the .mcpb file
6. mcpb-bundle uploads .mcpb to release (too late, Pages already deployed)

Evidence from ALL recent docs runs:

build  Download latest MCPB bundle  2026-01-24T14:29:37Z no assets to download
build  Download latest MCPB bundle  2026-01-24T14:16:31Z no assets to download
build  Download latest MCPB bundle  2026-01-24T11:18:25Z no assets to download

The .mcpb IS on the release (confirmed: v6.41.1 has gitlab-mcp-6.41.1.mcpb), but it arrives after docs deploy finishes.

2. docs/TOOLS.md committed to git (should be generated artifact)

Currently:

  • .releaserc.json@semantic-release/exec generates docs/TOOLS.md
  • .releaserc.json@semantic-release/git commits docs/TOOLS.md to repo
  • File is tracked in git: git ls-files shows docs/TOOLS.md
  • Every release creates a commit with the regenerated file

This is a build artifact that should only exist in CI, not pollute git history.

3. Curated docs out of sync with actual tool capabilities

The curated pages in docs/tools/ (code-review.md, ci-cd.md, project-management.md, repository.md) have fallen behind the auto-generated TOOLS.md. Missing actions/capabilities:

Tool Missing from curated docs
manage_work_item add_link, remove_link actions (work item linking)
browse_files download_attachment action
browse_releases assets action
manage_release update, delete, delete_link actions
browse_members list_group, get_group, list_all_project, list_all_group actions
manage_member add_to_group, remove_from_group, remove_from_project, update_group actions

Additionally, 14 tools have NO use-case page at all (only in overview table): browse_events, browse_users, manage_context, browse_search, browse_todos/manage_todos, browse_webhooks/manage_webhook, browse_snippets/manage_snippet, browse_integrations/manage_integration, browse_wiki/manage_wiki, browse_iterations.

4. Link to GitHub file will break

docs/tools/index.md:218 links to https://github.com/.../docs/TOOLS.md. After removing from git, this will 404.


Solution

Part A: Auto-syncing curated docs via marker injection

Concept: Curated docs keep custom prose/examples but action tables are auto-generated from schemas at build time.

Markers in curated .md files:

## browse_merge_requests

Find and inspect merge requests.

<!-- @autogen:tool browse_merge_requests -->
| Action | Description |
|--------|-------------|
| `list` | List merge requests with filtering |
...
<!-- @autogen:end -->

### Custom Examples
... (manual content preserved)

Pre-build injection script (scripts/inject-tool-refs.ts):

/**
 * Scans docs/tools/*.md for markers:
 *   <!-- @autogen:tool TOOL_NAME -->...<!-- @autogen:end -->
 * 
 * Replaces content between markers with freshly generated
 * action tables from the tool registry/schemas.
 * 
 * Run: yarn inject-tool-refs
 * Used in: docs.yml workflow before yarn docs:build
 */

import { RegistryManager } from '../src/registry-manager.js';

interface MarkerMatch {
  file: string;
  toolName: string;
  startIdx: number;
  endIdx: number;
}

// 1. Find all markers in docs/tools/*.md
// 2. For each marker, load tool schema from registry
// 3. Generate actions table (Action | Tier | Description)
// 4. Replace content between markers
// 5. Write updated files

function generateActionsTable(tool: ToolDefinition): string {
  // Extract actions from discriminated union schema
  // Format as markdown table: | Action | Tier | Description |
}

function generateParamsTable(tool: ToolDefinition): string {
  // Extract per-action parameters
  // Format as markdown tables grouped by action
}

Package.json script:

"inject-tool-refs": "tsx scripts/inject-tool-refs.ts"

CI integration (in docs.yml before docs:build):

- name: Generate dynamic documentation
  run: |
    yarn prisma generate
    yarn build
    yarn list-tools --export --toc > docs/TOOLS.md
    yarn inject-tool-refs

Benefits:

  • Curated pages are ALWAYS in sync with code (actions, params, tiers)
  • Custom prose, examples, tips remain manual (between markers)
  • No VitePress plugins needed (pure pre-build step)
  • Content visible in GitHub (last-generated state in markers)
  • Deterministic output → easy to test

Tests (src/__tests__/inject-tool-refs.test.ts):

describe('inject-tool-refs', () => {
  it('finds all @autogen:tool markers in docs', () => {
    // Scan docs/tools/*.md, verify all tool names are valid
  });

  it('generates correct actions table for each tool', () => {
    // For each registered tool, verify table has all actions
    // Compare with registry schema
  });

  it('preserves content outside markers', () => {
    // Given a .md with markers + manual content
    // After injection, manual content is unchanged
  });

  it('is idempotent', () => {
    // Running twice produces same output
  });

  it('fails on unknown tool name in marker', () => {
    // <!-- @autogen:tool nonexistent_tool --> should error
  });

  it('validates all curated tools have markers', () => {
    // Cross-check: every tool mentioned in docs/tools/*.md
    // overview tables should have a @autogen marker
  });
});

Part B: Remove TOOLS.md from git

  1. Add to .gitignore:
    # Generated documentation (built in CI)
    docs/TOOLS.md
    
  2. Remove from git: git rm --cached docs/TOOLS.md
  3. Remove from .releaserc.json@semantic-release/gitassets (keep only ["CHANGELOG.md", "package.json"])
  4. Remove docs/TOOLS.md generation from .releaserc.json@semantic-release/execprepareCmd

Part C: Fix MCPB race condition

Replace release: [published] trigger with workflow_run:

on:
  push:
    branches: [main]
    paths:
      - 'docs/**'
      - 'package.json'
      - 'yarn.lock'
      - '.github/workflows/docs.yml'
  workflow_run:
    workflows: ["CI/CD Pipeline"]
    types: [completed]
    branches: [main]
  workflow_dispatch:

With condition:

if: >
  github.event_name != 'workflow_run' ||
  github.event.workflow_run.conclusion == 'success'

Part D: Fix links and navigation

  1. Replace GitHub link in docs/tools/index.md:218:

    [TOOLS.md](/TOOLS)
  2. Add to VitePress sidebar:

    "/tools/": [
      {
        text: "Tool Reference",
        items: [
          { text: "Overview", link: "/tools/" },
          { text: "Full API Reference", link: "/TOOLS" },
        ],
      },
      // ... existing By Use-Case section
    ],

Part E: Add markers to curated docs

Update docs/tools/code-review.md, ci-cd.md, project-management.md, repository.md:

  • Wrap action tables with <!-- @autogen:tool TOOL_NAME -->...<!-- @autogen:end -->
  • Fix missing actions (the injection script will auto-populate from schemas)
  • Keep all custom examples, tips, and workflow documentation

Part F: SEO Metadata

  1. VitePress config (docs/.vitepress/config.mts):

    • titleTemplate: "%s | GitLab MCP" for SERP formatting
    • transformHead() hook auto-generates per-page OG/Twitter meta tags (og:title, og:description, og:url, twitter:card, twitter:title, twitter:description)
  2. robots.txt (docs/public/robots.txt):

    • Allow all crawlers + reference sitemap.xml
  3. Frontmatter on all 72 documentation pages:

    • Each page gets title + description (max 160 chars) in YAML frontmatter
    • VitePress uses these for <title> and <meta name="description">
    • transformHead feeds them to OG/Twitter tags
  4. sitemap.xml — VitePress sitemap generation with hostname config

Part G: inject-tool-refs Test Coverage

Unit tests (tests/unit/cli/inject-tool-refs.test.ts):

  • 45 tests covering extractActions, generateActionsTable, findMarkers, processFile, main
  • 98.91% line coverage, 97.43% branch coverage, 100% function coverage
  • Tests oneOf discriminated union + flat enum schemas
  • Tests marker detection, error cases, idempotency
  • Export internal functions from src/cli/inject-tool-refs.ts for testability

Files to create

File Purpose
src/cli/inject-tool-refs.ts Pre-build marker injection script
tests/unit/cli/inject-tool-refs.test.ts 45 unit tests (98.91% line coverage)
docs/public/robots.txt SEO: allow crawlers + sitemap reference

Files to modify

File Change
.gitignore Add docs/TOOLS.md
.releaserc.json Remove docs/TOOLS.md from exec and git plugin
.github/workflows/docs.yml Add TOOLS.md + inject-tool-refs steps; replace release trigger with workflow_run
docs/TOOLS.md git rm --cached
docs/tools/index.md Replace GitHub link with local /TOOLS
docs/.vitepress/config.mts Sidebar link + titleTemplate + transformHead + sitemap
docs/tools/code-review.md Add @autogen:tool markers around action tables
docs/tools/ci-cd.md Add @autogen:tool markers around action tables
docs/tools/project-management.md Add @autogen:tool markers + fix missing actions
docs/tools/repository.md Add @autogen:tool markers + fix missing actions
package.json Add inject-tool-refs script
docs/**/*.md (72 files) Add title + description YAML frontmatter

Verification

After implementation:

  1. yarn inject-tool-refs updates curated docs with fresh action tables
  2. yarn test passes injection script tests (3878 tests, 125 suites)
  3. yarn docs:build succeeds with generated TOOLS.md + injected curated docs + sitemap
  4. yarn lint — 0 errors
  5. inject-tool-refs coverage: 98.91% lines, 97.43% branches, 100% functions
  6. Push to main → ci-cd.yml → semantic-release + mcpb-bundle complete
  7. docs.yml triggers via workflow_run → generates TOOLS.md + injects tool refs + downloads .mcpb
  8. https://gitlab-mcp.sw.foundation/downloads/gitlab-mcp-latest.mcpb returns 200
  9. https://gitlab-mcp.sw.foundation/TOOLS.html renders full reference
  10. Curated docs show current actions (auto-synced from schemas)
  11. git log no longer shows TOOLS.md in release commits
  12. All pages render with correct OG/Twitter meta tags for social sharing

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions