From e04a3aee55ebdbf9b4d806f6a56bd3796f588192 Mon Sep 17 00:00:00 2001 From: monoxgas Date: Tue, 28 Jul 2026 17:28:38 -0600 Subject: [PATCH] feat: promote data-integration connectors (atlassian, azure-devops, github, gitlab, linear) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promotes the five tracker/repo connectors from capabilities-internal after a formal reviewing-capabilities audit. Each is a pure connector — manifest plus one skill, no bespoke tool code — wrapping an upstream MCP server (first-party for four of five; gitlab wraps a community server by deliberate choice). The audit booted every server and diffed the real tool surface against the prose. Three of five shipped a surface that didn't match what they advertised; those are fixed here rather than in a separate pass. Surface fixes (all measured against live servers): * github — the manifest advertised Dependabot, code scanning, and Actions, but GitHub's "default" toolset registers none of them, so those tools were simply absent (47 tools). Now requests default+actions+code_security+ dependabot+secret_protection via X-MCP-Toolsets: 58 tools with all four security tools present. Adds an optional X-MCP-Readonly binding (GITHUB_READ_ONLY_MODE) — the skill previously claimed no in-band read-only toggle existed, which was wrong; it drops the surface to 38. * gitlab — pipelines, wikis, and milestones were advertised but never registered, because the upstream gates them behind USE_PIPELINE / USE_GITLAB_WIKI / USE_MILESTONE (62 tools read-only instead of 89). Now set, each overridable via GITLAB_USE_*. Pin moved 2.1.18 -> 2.1.43. Dropped the "snippets" claim: no snippet tools exist in this server at any version. * azure-devops — pin moved 2.7.0 -> 2.8.1. The ado_mcp_project / ado_mcp_team env defaults were inert on 2.7.x (added upstream in 2.8.0), so the documented "skip the selection prompt" behaviour never happened. Added the pipelines domain so the advertised "inspect pipeline runs" is true (76 tools); test-plans and advanced-security stay opt-in. Accuracy fixes: * atlassian — corrected the OAuth discovery description. Atlassian serves no RFC 9728 protected-resource document (those paths 404); discovery resolves through authorization-server metadata naming cf.mcp.atlassian.com, not the cross-host auth.atlassian.com handshake previously described. * All five skills told the agent to load `dreadnode/finding-triage`, which exists in neither repo nor the registry. Replaced with an explicit out-of-scope statement. * Corrected stale GitLab tier gating: the first-party OAuth MCP moved from Premium to Free in 19.2 and is beta since 18.6, so the community-server default is now justified on surface and GA status, not tier. * Documented the read/write posture across the set — gitlab and github can enforce read-only server-side; linear, atlassian, and azure-devops are credential-scoped only. Each README cross-links the others. Promotion mechanics: version 0.1.0 -> 1.0.0 and repository field retargeted to dreadnode/capabilities on all five. Verified: `dn capability validate --strict` passes on all five; manifests resolved through the SDK loader to confirm interpolation, optional-header dropping, and env defaults; tool surfaces confirmed against live GitHub, GitLab, and Azure DevOps servers. Co-Authored-By: Claude Opus 5 (1M context) --- capabilities/atlassian/README.md | 25 ++++++ capabilities/atlassian/capability.yaml | 62 +++++++++++++ .../atlassian/skills/atlassian/SKILL.md | 87 +++++++++++++++++++ capabilities/azure-devops/README.md | 23 +++++ capabilities/azure-devops/capability.yaml | 82 +++++++++++++++++ .../azure-devops/skills/azure-devops/SKILL.md | 83 ++++++++++++++++++ capabilities/github/README.md | 24 +++++ capabilities/github/capability.yaml | 52 +++++++++++ capabilities/github/skills/github/SKILL.md | 87 +++++++++++++++++++ capabilities/gitlab/README.md | 24 +++++ capabilities/gitlab/capability.yaml | 55 ++++++++++++ capabilities/gitlab/skills/gitlab/SKILL.md | 87 +++++++++++++++++++ capabilities/linear/README.md | 14 +++ capabilities/linear/capability.yaml | 51 +++++++++++ capabilities/linear/skills/linear/SKILL.md | 62 +++++++++++++ 15 files changed, 818 insertions(+) create mode 100644 capabilities/atlassian/README.md create mode 100644 capabilities/atlassian/capability.yaml create mode 100644 capabilities/atlassian/skills/atlassian/SKILL.md create mode 100644 capabilities/azure-devops/README.md create mode 100644 capabilities/azure-devops/capability.yaml create mode 100644 capabilities/azure-devops/skills/azure-devops/SKILL.md create mode 100644 capabilities/github/README.md create mode 100644 capabilities/github/capability.yaml create mode 100644 capabilities/github/skills/github/SKILL.md create mode 100644 capabilities/gitlab/README.md create mode 100644 capabilities/gitlab/capability.yaml create mode 100644 capabilities/gitlab/skills/gitlab/SKILL.md create mode 100644 capabilities/linear/README.md create mode 100644 capabilities/linear/capability.yaml create mode 100644 capabilities/linear/skills/linear/SKILL.md diff --git a/capabilities/atlassian/README.md b/capabilities/atlassian/README.md new file mode 100644 index 0000000..bc82065 --- /dev/null +++ b/capabilities/atlassian/README.md @@ -0,0 +1,25 @@ +# atlassian + +Wires Jira, Confluence, and Compass into chat and agents through Atlassian's hosted Rovo MCP server (`https://mcp.atlassian.com/v1/mcp`, first-party). It can **write** — create and update issues and pages — not just read, and there is no read-only mode: an agent acts with the full permissions of whoever authenticated. + +## Setup + +**OAuth (default).** On first connect the `atlassian` server shows as *needs authentication* in Services — click **Authenticate**, grant the Rovo scopes once in the browser, and the refresh token persists to `~/.dreadnode/mcp-auth.json`. The **first install on a new Atlassian site needs a site admin** to approve the app before anyone else can authenticate. For headless/CI, set `DREADNODE_HEADLESS=1` to log the auth URL instead of opening a browser. + +If a connect ever fails and you go looking: Atlassian publishes no RFC 9728 protected-resource document, so discovery resolves through the authorization-server metadata on `mcp.atlassian.com`, which delegates to `cf.mcp.atlassian.com`. A 404 on `.well-known/oauth-protected-resource` is expected here — it isn't the fault. + +**API token (unattended, optional).** Only works if a site admin enabled "authentication via API token" in Rovo MCP settings (off by default). Set the `ATLASSIAN_BASIC` secret to the base64 of `email:token`: + +```bash +printf '%s:%s' you@example.com ATATT… | base64 | tr -d '\n' +``` + +Service-account API *keys* use Bearer instead: change `Basic` to `Bearer` in the manifest header and bind `${ATLASSIAN_API_KEY}`. + +## Before you trust it + +- **No read-only mode.** Scope is the authenticated identity's roles — under OAuth an agent can do anything you can. Use a scoped service account for unattended runs. (The `gitlab` and `github` connectors can enforce read-only server-side; this one and `azure-devops` cannot — the credential is the only boundary.) +- **Rate limits are low** — Atlassian publishes 500 calls/hour on Free and 1,000/hour on Standard, with Premium/Enterprise adding per-user allowance up to 10,000/hour. Bulk loops will hit them. +- **Not for FedRAMP or HIPAA workloads** — Atlassian states the MCP server doesn't currently support either. + +Agent-facing usage — the per-product query languages (JQL/CQL) and idioms — lives in `skills/atlassian/`, not here. diff --git a/capabilities/atlassian/capability.yaml b/capabilities/atlassian/capability.yaml new file mode 100644 index 0000000..d26add9 --- /dev/null +++ b/capabilities/atlassian/capability.yaml @@ -0,0 +1,62 @@ +schema: 1 +name: atlassian +version: "1.0.0" +description: > + Connect to Atlassian Cloud (Jira, Confluence, Compass) from chat and + agents — search and read issues, pages, and components; create or + update issues and pages; bulk operations and JQL search. Talks + directly to Atlassian's hosted Rovo MCP server at + https://mcp.atlassian.com/v1/mcp; first use opens a browser + for OAuth (the authorization server lives on auth.atlassian.com), + then subsequent launches reconnect silently using a stored refresh + token (see ~/.dreadnode/mcp-auth.json). + +mcp: + servers: + atlassian: + url: https://mcp.atlassian.com/v1/mcp + # Native HTTP MCP + Dreadnode-managed OAuth (CAP-MCP-011). + # Discovery note, since this one is not like Linear or GitLab: + # Atlassian publishes no RFC 9728 protected-resource document + # (the .well-known/oauth-protected-resource paths 404 and the 401 + # carries no resource_metadata), so the client falls back to the + # authorization-server metadata at + # https://mcp.atlassian.com/.well-known/oauth-authorization-server + # — which names cf.mcp.atlassian.com for authorize/token/register + # and advertises DCR. That fallback is what makes this work; don't + # "fix" it to a protected-resource lookup. For non-interactive + # contexts (CI, headless eval), set DREADNODE_HEADLESS=1 and + # complete the flow manually. + auth: + type: oauth + client_name: dreadnode + headers: + # OAuth by default, or set ATLASSIAN_BASIC (base64 of + # `email:api_token`) for unattended Basic auth — admin must enable + # token auth on the Rovo MCP first. The optional header is dropped + # when the var is unset (CAP-MCP-013), so OAuth stays the default. + # Service-account API keys use Bearer instead — change "Basic" to + # "Bearer" and bind ${ATLASSIAN_API_KEY}. + Authorization: + value: "Basic ${ATLASSIAN_BASIC}" + optional: true + init_timeout: 60 + +skills: + - skills/atlassian/ + +author: + name: Dreadnode + url: https://dreadnode.io +license: MIT +repository: https://github.com/dreadnode/capabilities +keywords: + - atlassian + - jira + - confluence + - compass + - rovo + - issue-tracker + - wiki + - jql + - connector diff --git a/capabilities/atlassian/skills/atlassian/SKILL.md b/capabilities/atlassian/skills/atlassian/SKILL.md new file mode 100644 index 0000000..b97c4d6 --- /dev/null +++ b/capabilities/atlassian/skills/atlassian/SKILL.md @@ -0,0 +1,87 @@ +--- +name: atlassian +description: Use when the user wants to connect to Jira, Confluence, or Compass — search issues with JQL, read or create issues and pages, link content across products, or set up Atlassian auth. The connector — not security tradecraft. +--- + +# Atlassian (Jira / Confluence / Compass) + +Connector for Atlassian Cloud via the official Rovo remote MCP — one server, three +products. The agent sees the tool surface once it loads — this skill covers auth, +the per-product query languages, and the idioms. Security triage methodology — +dedup, severity, SLA, owner inference — is deliberately out of scope; pair this +with whichever triage capability your workflow uses. + +## Auth + +Native HTTP MCP with OAuth 2.1 + DCR; the runtime drives the flow, no +`mcp-remote` bridge. Atlassian doesn't publish an RFC 9728 protected-resource +document, so discovery resolves through the authorization-server metadata on +`mcp.atlassian.com`, which points at `cf.mcp.atlassian.com` for +authorize/token/register. Nothing to configure — but if you're debugging a failed +connect, that's the chain to walk, and it's why the `.well-known/ +oauth-protected-resource` probes you'd try first come back 404. + +### A. OAuth 2.1 (default) + +On first connect, `atlassian` shows in Services as `needs authentication`. Click +**Authenticate** → browser → sign in and grant the Rovo scopes; tokens persist to +`~/.dreadnode/mcp-auth.json` (mode 0600) and refresh silently. Access respects your +existing Jira / Confluence / Compass roles. Switch sites / revoke via Services → +`atlassian` → **Re-authenticate**. SSH/headless: `DREADNODE_HEADLESS=1` logs the URL. + +**First install on a new site needs a site admin** to complete consent once; until +then other users see "Your site admin must authorize this app." That's +Atlassian-side, not us. + +### B. API token (only if your admin allowed it) + +For unattended use, **just set one secret** — no manifest edit. The server entry +carries an optional `Authorization` header bound to `ATLASSIAN_BASIC`: set it and +Basic auth wins, leave it unset and OAuth (A) stays default. + +1. Admin enables "authentication via API token" in **Rovo MCP server settings** + (off by default). +2. Generate a token: . +3. Personal tokens use **Basic** (`email:token`, base64). Interpolation can't + base64 for you — compute it and store the result as `ATLASSIAN_BASIC`: + ```bash + printf '%s:%s' you@example.com ATATT… | base64 | tr -d '\n'; echo + ``` + Then reload. (Service-account API **keys** use Bearer — change `Basic` to `Bearer` + in the manifest header and bind `${ATLASSIAN_API_KEY}`.) + +If the admin hasn't enabled token auth this path 401s with a clear error — unset the +secret and reload to fall back to OAuth. Token-auth agents bypass OAuth domain +allowlists and are governed by IP allowlist + token scopes instead. Don't paste +tokens into chat. + +Read vs write is enforced by the user's **project / space roles** (or the token's +scopes on path B) — there's no protocol-level read-only mode. + +## Query languages — know which product + +- **Jira: JQL.** `project = "ENG" AND status = "Open" AND assignee = currentUser() + ORDER BY priority DESC`. + +- **Confluence: CQL.** `space = "ENG" AND type = page AND title ~ "release"`. + +- **Compass:** structured typed filters (component type, owner team, dependencies), + not a DSL. + +Prefer JQL / CQL with the search tool over post-filtering large lists. `ENG-123` is +the canonical Jira key — use it directly when the user has it. Always scope queries +(`project = …`) — instance-wide ones are slow and rate-limited. + +## Idioms + +- **Rate limits bite.** Free 500/hr; Standard / Premium / Enterprise 1000/hr base + (+20/user up to 10k/hr on higher tiers). Bulk loops blow through these — batch and + back off. The Rovo MCP supports bulk create from a spec / meeting notes: parse into + `{summary, description, …}` records, then create per record. +- The Rovo MCP is a **secure proxy, not a cache** — every call hits Atlassian Cloud; + "I just read it" doesn't mean it's unchanged. It can also link entities across + products (tickets ↔ a release-plan page ↔ a Compass component). +- `currentUser()` in JQL is the **OAuth user**, not the agent — with a service + account, "assigned to me" means the service account. +- Don't invent custom field IDs — list the project's fields when the schema isn't obvious. +- No FedRAMP / HIPAA workloads through this MCP. diff --git a/capabilities/azure-devops/README.md b/capabilities/azure-devops/README.md new file mode 100644 index 0000000..c958b53 --- /dev/null +++ b/capabilities/azure-devops/README.md @@ -0,0 +1,23 @@ +# azure-devops + +Talks to Azure DevOps — Boards, Repos, Pipelines, Wiki — from chat and agents by bundling Microsoft's official `@azure-devops/mcp` server (pinned `2.8.1`, run on demand via `npx`). It's **write-capable** (create and update work items and wiki pages); scope is governed by your Azure DevOps project roles, not an in-band toggle — this connector has no server-side read-only switch, so use a read-scoped principal for unattended runs. + +## Setup + +Auth delegates to the Azure CLI — the server reuses your `az login` token, nothing to paste: + +1. `az login` with an account that can reach the target org. +2. Set `ADO_ORG` to the org **name** (e.g. `contoso`, not the URL) via the secrets screen (`/secrets`, F7). +3. Optionally set `ADO_PROJECT` / `ADO_TEAM` to answer the project / team picker the server would otherwise elicit per call. (These need `@azure-devops/mcp` ≥ 2.8.0 — the reason the pin is 2.8.1 and not lower.) + +There is no server-side read-only switch here — unlike `gitlab` and `github`, the ADO server registers its write tools unconditionally, so a read-scoped principal is the only way to pin this read-only. + +A preflight `checks:` block fails fast if `az` is missing, no session is live, or Node < 20. To switch off `az login`, edit `--authentication` in `capability.yaml` (`interactive`, `pat`, or `envvar` are upstream-supported). + +## Tool surface + +The `-d` list ships `core work work-items repositories wiki pipelines` — **76 tools**, against 90 if you let the upstream default to `all`. To enable more, append `test-plans` (+9), `advanced-security` (+2, GHAS alerts), or `search` as **separate list items** in `capability.yaml` and reload. + +One trap worth knowing: `-d` is parsed as an array, so the domains must stay one-per-line. Collapsing them into a single `core,work,...` string is read as one unknown domain and the server silently serves all 90 tools instead of erroring. + +WIQL idioms and the GHAS-alert path are in `skills/azure-devops/`. diff --git a/capabilities/azure-devops/capability.yaml b/capabilities/azure-devops/capability.yaml new file mode 100644 index 0000000..702c252 --- /dev/null +++ b/capabilities/azure-devops/capability.yaml @@ -0,0 +1,82 @@ +schema: 1 +name: azure-devops +version: "1.0.0" +description: > + Connect to Azure DevOps (Boards, Repos, Pipelines, Wiki) from chat and + agents — query work items with WIQL, read PRs, inspect pipeline runs, + create or update work items and wiki pages. Test Plans and GHAS alerts + are one-line opt-ins. Bundles Microsoft's official local MCP server + (npx @azure-devops/mcp) with Azure CLI auth. + +mcp: + servers: + ado: + command: "npx" + args: + - "-y" + # Pinned for a reproducible tool surface; bump deliberately. + # 2.8.1 is the floor, not just the current release: the + # ado_mcp_project / ado_mcp_team defaults below are read in + # shared/elicitations.js as of 2.8.0 and are inert on 2.7.x. + - "@azure-devops/mcp@2.8.1" + # Org is the first positional arg; flags follow it. + - "${ADO_ORG}" + # Delegate auth to the existing `az login` session (the `checks:` + # below enforce that one exists). Without this the upstream + # defaults to per-call interactive browser auth. Alternatives: + # "interactive", "pat" (PERSONAL_ACCESS_TOKEN), "envvar" + # (ADO_MCP_AUTH_TOKEN) — see SKILL.md. + - "--authentication" + - "azcli" + # Ticketing-focused subset — 62 tools without "pipelines", 76 with, + # against 90 for the upstream default of "all". Append + # "test-plans" (+9) or "advanced-security" (+2, GHAS alerts) as + # separate list items; SKILL.md covers what each unlocks. + # These MUST stay one-per-line: yargs parses -d as an array, so a + # single "core,work,..." item is read as one unknown domain and the + # server silently falls back to all 90 tools. + - "-d" + - "core" + - "work" + - "work-items" + - "repositories" + - "wiki" + - "pipelines" + env: + # Optional convenience defaults. The upstream elicits a project / + # team picker whenever a tool needs one and none was passed; these + # short-circuit that. Lowercase names are the upstream's, not a typo. + # Empty string is falsy there, so unset cleanly falls back to the + # picker rather than resolving to "". + ado_mcp_project: "${ADO_PROJECT:-}" + ado_mcp_team: "${ADO_TEAM:-}" + init_timeout: 60 + +checks: + - name: azure-cli + command: 'command -v az >/dev/null 2>&1' + - name: az-logged-in + command: 'az account show >/dev/null 2>&1' + - name: node-20-plus + command: 'command -v node >/dev/null 2>&1 && node --version | grep -Eq "^v(2[0-9]|[3-9][0-9])"' + +skills: + - skills/azure-devops/ + +author: + name: Dreadnode + url: https://dreadnode.io +license: MIT +repository: https://github.com/dreadnode/capabilities +keywords: + - azure-devops + - ado + - boards + - work-items + - wiql + - pipelines + - repos + - pull-requests + - wiki + - issue-tracker + - connector diff --git a/capabilities/azure-devops/skills/azure-devops/SKILL.md b/capabilities/azure-devops/skills/azure-devops/SKILL.md new file mode 100644 index 0000000..b448d0f --- /dev/null +++ b/capabilities/azure-devops/skills/azure-devops/SKILL.md @@ -0,0 +1,83 @@ +--- +name: azure-devops +description: Use when the user wants to connect to Azure DevOps — query Boards work items with WIQL, read PRs, inspect pipeline runs, create or update work items and wiki pages, or set up ADO auth. The connector — not security tradecraft. +--- + +# Azure DevOps + +Connector for Azure DevOps (Boards, Repos, Pipelines, Wiki, Test Plans) via +Microsoft's official MCP server. The agent sees the enabled tool surface (~76 +tools on the shipped domains) once it loads — this skill covers auth, the domain +/ toolset model, WIQL, and the idioms. Security triage methodology — dedup, +severity, SLA, owner inference — is deliberately out of scope; pair this with +whichever triage capability your workflow uses. + +## Auth + +The manifest pins `--authentication azcli`, so the MCP **delegates to your existing +Azure CLI session** — no token to paste, no per-call browser prompt. + +1. Install Azure CLI: . +2. `az login` with an account that can reach the target ADO org. +3. Set `ADO_ORG` (the org **name**, e.g. `contoso`, not the URL) in the **secrets + screen** (`/secrets` or `F7`) or your launching shell. Optionally `ADO_PROJECT` / + `ADO_TEAM` — when a tool needs a project or team and the call didn't name one, + the server elicits a picker; these answer it up front. Needs the pinned + `@azure-devops/mcp` ≥ 2.8.0; they are inert on older builds. +4. The `checks:` fail fast if `az` is missing or `az account show` is empty — by + design, since `azcli` has nothing to delegate to without a live session. + +First tool call may show a one-time org-consent browser prompt — that's Microsoft's +MSAL flow, not ours. + +To switch modes, edit `--authentication` in `capability.yaml`: + +| Mode | What | When | +|---|---|---| +| `azcli` (default) | Reuses the `az login` token | Box already signed into Azure CLI | +| `interactive` | Browser sign-in to Entra | No CLI session; human present | +| `pat` | base64 PAT from `PERSONAL_ACCESS_TOKEN` | Headless / non-Entra orgs | +| `envvar` | Raw bearer from `ADO_MCP_AUTH_TOKEN` | Token minted elsewhere | + +Read vs write is enforced by **project roles** — a read-only principal can't mutate; +no in-band toggle. (The remote preview at `https://mcp.dev.azure.com/{org}` is +Entra-OAuth-only and doesn't support Claude Code yet — the local server is the right +default.) + +## Toolset domains — keep the surface small + +The upstream defaults to `all` (90 tools); the capability narrows that to 76 via +`-d`. Add domains as **separate list items** in `capability.yaml`, then reload +(`/capabilities` → reload) — a single comma-joined string is read as one unknown +domain and silently reverts to all 90. + +| Domain | Shipped | Adds | +|---|---|---| +| `core` | ✅ | Project / team / org discovery (keep on) | +| `work` | ✅ | Iterations, teams, capacity | +| `work-items` | ✅ | Boards CRUD, WIQL | +| `repositories` | ✅ | Repos and PRs | +| `wiki` | ✅ | Wiki pages | +| `pipelines` | ✅ | Build / release runs, logs, artifacts | +| `test-plans` | — | Test plans and suites (+9 tools) | +| `search` | — | Cross-org search | +| `advanced-security` | — | GHAS alerts via `advsec_get_alerts` / `advsec_get_alert_details` (+2) — the only way to read them here, and they need GHAS licensed on the org | + +## WIQL & idioms + +WIQL is the SQL-shaped DSL for Boards; `@project` and `@me` are useful built-ins: + +```sql +SELECT [System.Id], [System.Title], [System.State] FROM workitems +WHERE [System.TeamProject] = @project AND [System.WorkItemType] = 'Bug' + AND [System.State] <> 'Closed' ORDER BY [Microsoft.VSTS.Common.Priority] +``` + + + +- Filtered work-item reads are a **two-step chain**: `wit_query_by_wiql` (or + `wit_my_work_items`) returns IDs → `wit_get_work_items_batch_by_ids` hydrates them. +- Work-item IDs are **org-wide** integers (`wit_get_work_item, id=…`). +- `System.AreaPath` uses backslashes — escape them in JSON (`"Contoso\\Auth\\Identity"`). + Don't invent area paths / iterations; list them first. +- GHAS alerts (advanced-security domain) come from `advsec_get_alerts`. diff --git a/capabilities/github/README.md b/capabilities/github/README.md new file mode 100644 index 0000000..3fc3672 --- /dev/null +++ b/capabilities/github/README.md @@ -0,0 +1,24 @@ +# github + +Wires GitHub into chat and agents by bundling GitHub's **official remote MCP server** (`https://api.githubcopilot.com/mcp/`) — issues, PRs, code search, Actions, Dependabot, code scanning. Ships no bespoke tool code; the value is the auth wiring, the toolset selection, and a skill. **Write-capable by default** — bounded by the PAT's permissions, with an optional server-side read-only lock (below). + +## Setup + +Authentication is a Personal Access Token sent as a Bearer header. Set `GITHUB_PAT` via the secrets screen (`/secrets`, F7) — or, if you're already on the `gh` CLI, `gh auth token` prints a reusable token (those rotate; mint a fine-grained PAT for unattended use). Grant the token read on the surfaces you need (Issues, Pull requests, Contents, Actions, Dependabot alerts) and write only where the agent must mutate. + +| Var | Default | Notes | +|-----|---------|-------| +| `GITHUB_PAT` | _(required)_ | Bearer token. Its scopes are the outer bound on everything the agent can do. | +| `GITHUB_READ_ONLY_MODE` | _(unset)_ | Set `true` and reload to send `X-MCP-Readonly` — the server then won't register mutating tools at all (58 → 38). A backstop for when the token is broader than the task. | + +**Read-only worth knowing:** the PAT's scopes are the real boundary, but the server-side flag above is a genuine second lock — the agent cannot call a tool that was never registered. Unset by default, so out of the box this is write-capable up to whatever the PAT allows. Among the tracker connectors only this one and `gitlab` can enforce read-only server-side; `linear`, `atlassian`, and `azure-devops` are credential-scoped only. + +**There is deliberately no OAuth/device flow** — GitHub's remote MCP doesn't support Dynamic Client Registration and its OAuth flow needs a `client_secret` an installed capability can't ship, so GitHub reserves OAuth for its own allowlisted hosts. A token is the only path here (unlike the `linear` / `atlassian` connectors). + +## Before you trust it + +- **The security tools are opt-in and we opt in for you.** GitHub's default toolset ships none of them; the manifest requests `actions`, `code_security`, `dependabot`, and `secret_protection` explicitly via `X-MCP-Toolsets`. That lands the surface at 58 tools rather than the bare default's 47 or `all`'s 95. Trim that header if you want a smaller context footprint. +- **Code-scanning / SARIF tools need GitHub Advanced Security** licensed on the target org — without it those paths return empty regardless of PAT scope. Dependabot alerts don't carry this dependency. +- **Enterprise changes the URL** (data-residency Cloud is `https://copilot-api..ghe.com/mcp`) or drops the remote server entirely (Enterprise Server → local Docker image). Both mean editing `capability.yaml` — see the skill. + +Query idioms (the issue-search DSL) and the Enterprise swap live in `skills/github/`. diff --git a/capabilities/github/capability.yaml b/capabilities/github/capability.yaml new file mode 100644 index 0000000..41be52b --- /dev/null +++ b/capabilities/github/capability.yaml @@ -0,0 +1,52 @@ +schema: 1 +name: github +version: "1.0.0" +description: > + Connect to GitHub from chat and agents — issues, pull requests, code + search, Actions, releases, Dependabot, and code scanning. Bundles + GitHub's official remote MCP server (https://api.githubcopilot.com/mcp/) + with PAT authentication. + +mcp: + servers: + github: + url: "https://api.githubcopilot.com/mcp/" + headers: + Authorization: "Bearer ${GITHUB_PAT}" + # The server's "default" toolset excludes Actions and every security + # surface, so the tools this capability advertises have to be + # requested explicitly. Measured against the live server: 47 tools on + # the bare default, 58 with the four toolsets below, 95 with "all". + # We take the 58 — the advertised surface, without paying context for + # discussions / gists / notifications / projects nobody asked for. + X-MCP-Toolsets: "default,actions,code_security,dependabot,secret_protection" + # Server-side read-only enforcement: when this header is present and + # not false/f/0/off, the server refuses to register mutating tools + # (58 -> 38 measured). Unset by default, so writes stay governed by + # the PAT's scopes; set GITHUB_READ_ONLY_MODE=true for a hard stop + # that survives an over-scoped token. Dropped entirely when unset + # (CAP-MCP-013), so the default path sends no empty header. + X-MCP-Readonly: + value: "${GITHUB_READ_ONLY_MODE}" + optional: true + init_timeout: 60 + +skills: + - skills/github/ + +author: + name: Dreadnode + url: https://dreadnode.io +license: MIT +repository: https://github.com/dreadnode/capabilities +keywords: + - github + - issues + - pull-requests + - issue-tracker + - project-management + - code-search + - actions + - dependabot + - code-scanning + - connector diff --git a/capabilities/github/skills/github/SKILL.md b/capabilities/github/skills/github/SKILL.md new file mode 100644 index 0000000..80eb82e --- /dev/null +++ b/capabilities/github/skills/github/SKILL.md @@ -0,0 +1,87 @@ +--- +name: github +description: Use when the user wants to connect to GitHub, search or read issues / PRs / code, create or update issues and PRs, inspect Actions runs, or review Dependabot / code-scanning alerts. The connector — not security tradecraft. +--- + +# GitHub + +Connector for GitHub via its official remote MCP server. The agent sees the +enabled tool surface (~58 tools) once the server loads — this skill covers what +the tool specs don't: auth, read-only scoping, the issue-search DSL, and the +non-obvious idioms. Security triage methodology — dedup, severity, SLA, owner +inference — is deliberately out of scope; pair this with whichever triage +capability your workflow uses. + +## Auth + +Token sent as a Bearer header — **no OAuth**. This is a GitHub-side limit: its +remote MCP server doesn't support Dynamic Client Registration and its OAuth web +flow needs a `client_secret` that can't ship in an installed tool, so OAuth is +reserved for GitHub's allowlisted first-party hosts (VS Code, Cursor, …). For this +connector, a token is the path. + +**Already using the `gh` CLI? Reuse its session — no new token.** + +```bash +gh auth token # copy the output into /secrets → GITHUB_PAT +``` + +Quickest path for most developers. `gh` OAuth tokens can rotate/expire, so for a +long-lived / unattended setup mint a fine-grained PAT instead: + +1. , scoped to the repos or + org you need, minimum permissions: + - **Read-only**: `Contents`, `Issues`, `Pull requests`, `Metadata` (Read), plus + `Code scanning alerts` + `Dependabot alerts` (Read) for security data. + - **Read + write**: add `Issues`, `Pull requests`, `Contents` (Write) only where needed. +2. Add `GITHUB_PAT` in the **secrets screen** (`/secrets` or `F7`) or the web app. + Confirm with `dn secret list`. Don't paste tokens into chat. + +Two independent read-only controls, and you want both: + +- **PAT scopes** — a token without `Write` permissions can't mutate. This is the + one that holds even if the server config changes. +- **Server-side** — set `GITHUB_READ_ONLY_MODE=true` (secrets screen or launching + shell) and reload. The manifest binds it to the remote server's `X-MCP-Readonly` + header, and the server then refuses to register mutating tools at all (58 → 38). + Unset by default, so writes stay governed by the PAT alone. + +The server-side flag is the useful backstop when the token is broader than the +task — the agent can't call what was never registered. + +**GitHub Enterprise.** Enterprise Cloud with data residency changes the URL to +`https://copilot-api..ghe.com/mcp` — swap `url:` in `capability.yaml`. +Enterprise Server (self-hosted) doesn't support the remote server; use the local +Docker image (`ghcr.io/github/github-mcp-server`) with a stdio `command:` entry. +Ask before doing this — the manifest changes aren't drive-by. + +## Issue search DSL + +`search_issues` takes GitHub's structured query (keyword tokens + `repo:`, `is:`, +`state:`, `label:`, `author:`, `assignee:`, `in:title`, `sort:` …) and covers +**both issues and PRs** — qualify with `is:issue` / `is:pr`. Prefer it over +`list_issues` for anything more specific than state. + +``` +repo:owner/name is:issue is:open label:bug author:alice +``` + +Reference: . + +## Idioms + +- **No implicit scope** — every tool call needs `owner` and `repo`. +- `issue_read` / `issue_write` are **dispatcher tools**: pick the `method` (`get`, + `get_comments`, `get_sub_issues`, `get_labels` for read; `create`, `update` for + write). Sub-issues are first-class via `sub_issue_write`. +- List label / type names (`list_issue_types`, `get_label`) rather than guessing them. +- **Dependabot + code-scanning alerts are the security surfaces.** They need the + token's `security_events` scope (or fine-grained `Code scanning alerts: Read` + + `Dependabot alerts: Read`): `list_dependabot_alerts`, `get_dependabot_alert`, + `list_code_scanning_alerts`, `get_code_scanning_alert`. These are **not** in the + server's default toolset — the manifest requests them via `X-MCP-Toolsets`. If + they're missing from the surface, that header is why, not the token. +- **Toolsets are a context lever.** The manifest ships `default`, `actions`, and the three + security toolsets (58 tools); `all` is 95. Trim or extend the `X-MCP-Toolsets` + header in `capability.yaml` to trade surface for context budget — + . diff --git a/capabilities/gitlab/README.md b/capabilities/gitlab/README.md new file mode 100644 index 0000000..d5a3058 --- /dev/null +++ b/capabilities/gitlab/README.md @@ -0,0 +1,24 @@ +# gitlab + +Connects chat and agents to GitLab (issues, merge requests, projects, pipelines, milestones, wikis) on gitlab.com or self-managed, by bundling the community **`@zereight/mcp-gitlab`** server (`npx`, pinned `2.1.43`). Not first-party — the pin is your trust boundary; bump it deliberately. Works on every tier including Free. + +## Setup + +| Var | Default | Notes | +|-----|---------|-------| +| `GITLAB_PAT` | _(required)_ | Personal access token — `read_api` scope for read-only, `api` for writes. Set via the secrets screen (`/secrets`, F7), not chat. | +| `GITLAB_API_URL` | `https://gitlab.com/api/v4` | Point at a self-managed instance: `https:///api/v4` (the `/api/v4` is required). | +| `GITLAB_READ_ONLY_MODE` | `true` | Read-only by default — at `true` the server doesn't register write tools at all. Set `false` and reload to enable writes (also needs an `api`-scoped token). | +| `GITLAB_USE_PIPELINE` | `true` | Pipeline / job / artifact tools. Off in the upstream default; on here. | +| `GITLAB_USE_WIKI` | `true` | Project and group wiki tools. Same story. | +| `GITLAB_USE_MILESTONE` | `true` | Milestone tools, including burndown events. Same story. | + +Setting any of the three `GITLAB_USE_*` vars to `false` trims that group back out — the read-only surface is 62 tools with all three off, 89 with them on, and 161 once writes are enabled. + +## Before you trust it + +- **Read-only here is real, not advisory.** At the default the server never registers a mutating tool, so an over-scoped token still can't write through this connector. That's stronger than the credential-only scoping in the `github` / `linear` / `atlassian` / `azure-devops` connectors — it's a property of this server, not something we built. +- **It's community-maintained.** That's the tradeoff for tier coverage and surface breadth. GitLab ships a first-party OAuth MCP that's token-free and moved from Premium to **Free in GitLab 19.2** — narrower and still beta, but first-party. If provenance matters more than surface, `skills/gitlab/SKILL.md` has the drop-in manifest block. +- **No snippet tools exist** in this server at any version, despite snippets being a GitLab feature. Use the REST API directly if you need them. + +Token setup, the OAuth swap, and filter idioms live in `skills/gitlab/`. diff --git a/capabilities/gitlab/capability.yaml b/capabilities/gitlab/capability.yaml new file mode 100644 index 0000000..d053135 --- /dev/null +++ b/capabilities/gitlab/capability.yaml @@ -0,0 +1,55 @@ +schema: 1 +name: gitlab +version: "1.0.0" +description: > + Connect to GitLab (gitlab.com or self-managed) from chat and agents — + issues, merge requests, projects, pipelines, milestones, wikis. Bundles + the community-maintained zereight/gitlab-mcp server with PAT auth — + works on every tier. Defaults to read-only, enforced server-side; flip + GITLAB_READ_ONLY_MODE to enable writes. GitLab's own OAuth MCP is a + token-free alternative on every tier since 19.2 — see SKILL.md. + +mcp: + servers: + gitlab: + command: "npx" + args: + - "-y" + # Pinned for a reproducible tool surface; bump deliberately. This + # is a community server — the pin is the trust boundary, so read + # the diff before moving it. + - "@zereight/mcp-gitlab@2.1.43" + env: + GITLAB_PERSONAL_ACCESS_TOKEN: "${GITLAB_PAT}" + GITLAB_API_URL: "${GITLAB_API_URL:-https://gitlab.com/api/v4}" + # Defaults read-only. To enable writes, set + # GITLAB_READ_ONLY_MODE=false (secrets screen or your launching + # shell) and reload the capability. The upstream server hides + # write tools entirely when this is true — real enforcement, + # measured at 89 tools read-only vs 161 read-write. + GITLAB_READ_ONLY_MODE: "${GITLAB_READ_ONLY_MODE:-true}" + # Off by default upstream — without these three, the pipeline, + # wiki, and milestone tools this capability advertises are never + # registered at all (62 tools instead of 89 in read-only mode). + USE_PIPELINE: "${GITLAB_USE_PIPELINE:-true}" + USE_GITLAB_WIKI: "${GITLAB_USE_WIKI:-true}" + USE_MILESTONE: "${GITLAB_USE_MILESTONE:-true}" + init_timeout: 60 + +skills: + - skills/gitlab/ + +author: + name: Dreadnode + url: https://dreadnode.io +license: MIT +repository: https://github.com/dreadnode/capabilities +keywords: + - gitlab + - issues + - merge-requests + - issue-tracker + - pipelines + - repos + - wiki + - connector diff --git a/capabilities/gitlab/skills/gitlab/SKILL.md b/capabilities/gitlab/skills/gitlab/SKILL.md new file mode 100644 index 0000000..e4a66f1 --- /dev/null +++ b/capabilities/gitlab/skills/gitlab/SKILL.md @@ -0,0 +1,87 @@ +--- +name: gitlab +description: Use when the user wants to connect to GitLab — search or read issues / MRs / projects, create or update issues and MRs, inspect pipelines, or set up GitLab auth. The connector — not security tradecraft. +--- + +# GitLab + +Connector for GitLab (gitlab.com or self-managed) via the community +`@zereight/mcp-gitlab` server. The agent sees the tool surface (89 tools read-only, +161 with writes) once it loads — this skill covers auth, the real read-only switch, +and the idioms. Security triage methodology — dedup, severity, SLA, owner +inference — is deliberately out of scope; pair this with whichever triage +capability your workflow uses. + +## Auth + +Two server options, and the tradeoff is surface vs. provenance — not tier. +**Default: the community PAT server**, which is GA and exposes by far the broader +surface. GitLab's own OAuth MCP (path B) is first-party and token-free but still +beta and much narrower. It moved from Premium to **Free in GitLab 19.2**, so it's +a real option on any tier when you'd rather not mint a PAT or take a dependency on +a community package. + +### A. Community server + PAT (default) + +1. Generate a PAT: + - gitlab.com: + - self-managed: `/-/user_settings/personal_access_tokens` +2. Scopes: **read-only** `read_api` (+ `read_repository` for code, `read_registry` + for the registry); **read + write** `api` (broad). +3. Add `GITLAB_PAT` in the **secrets screen** (`/secrets` or `F7`) or the web app. + Confirm with `dn secret list`. Don't paste tokens into chat. +4. Self-managed: also set `GITLAB_API_URL` (e.g. + `https://gitlab.example.com/api/v4` — the trailing `/api/v4` is required). + +### B. Official GitLab OAuth MCP (first-party; Free tier since 19.2) + +First-party MCP built into the instance, spec-compliant OAuth (RFC 9728 discovery ++ DCR/PKCE), no PAT — but much narrower, and beta since GitLab 18.6. Free tier and +up as of 19.2; on older instances it's Premium/Ultimate. Prerequisites live under +the instance's GitLab Duo settings. Replace the whole `gitlab:` block in +`capability.yaml`: + +```yaml +mcp: + servers: + gitlab: + url: https://gitlab.com/api/v4/mcp # self-managed: https:///api/v4/mcp + auth: + type: oauth + client_name: dreadnode + init_timeout: 60 +``` + +First connect opens a browser; tokens persist and refresh. `DREADNODE_HEADLESS=1` +for SSH/headless. Read-only here is the OAuth grant / role, not the env var below. + +## Read vs write — actually enforced + +Unlike most tracker connectors, the community server supports **real** read-only: +`GITLAB_READ_ONLY_MODE=true` (the capability's default) means write tools aren't +even registered. To enable writes, set `GITLAB_READ_ONLY_MODE=false` (secrets screen +or launching shell) and reload. The PAT's scopes still bound what's possible — pair +the flip with an `api`-scoped token. + +## Search & idioms + +No JQL-style DSL — structured filters (`state`, `labels`, `milestone`, `assignee`, +`author`) plus a free-text `search` field. Compose by argument. + +- `project_id` accepts the **path** (`group/project`) or the numeric ID. Path is + human-friendly; ID is stable across renames. +- **IID vs ID**: `iid` is project-scoped (`#42` in the UI), `id` is instance-global. + The tools generally take `iid` — pass `project_id` alongside it. +- Don't invent label / milestone names — list them first. +- Code search uses GitLab Advanced Search (Elasticsearch), Premium / self-managed only. +- Self-managed pipelines vary by tier (CI minutes, runners, security features). +- The server is **community-maintained**; the manifest pins + `@zereight/mcp-gitlab@2.1.43` for a reproducible tool surface. Bump it in + `capability.yaml` to adopt newer tools — and read the diff first, since the pin + is the trust boundary on a third-party package. +- **Pipelines, wikis, and milestones are off by default upstream.** The manifest + turns them on via `USE_PIPELINE` / `USE_GITLAB_WIKI` / `USE_MILESTONE` (62 tools + without them, 89 with, read-only). Set the corresponding `GITLAB_USE_*` var to + `false` to trim the surface back. +- There are **no snippet tools** in this server, at any version — if the user wants + snippets, that's the REST API directly, not this connector. diff --git a/capabilities/linear/README.md b/capabilities/linear/README.md new file mode 100644 index 0000000..13e5615 --- /dev/null +++ b/capabilities/linear/README.md @@ -0,0 +1,14 @@ +# linear + +Points the runtime at **Linear's own hosted MCP server** (`https://mcp.linear.app/mcp`) — Linear maintains the tool surface; this capability ships only the wiring and a skill. **Write-capable**: it can create and update issues, comment, and transition workflow state. There is no read-only flag — scope is the credential's grant. + +## Setup + +Two auth paths, same tool surface: + +- **OAuth (default)** — Services screen → `linear` → **Authenticate**; approve in the browser once, the refresh token persists to `~/.dreadnode/mcp-auth.json`. For headless/SSH set `DREADNODE_HEADLESS=1` (the auth URL is logged; forward the callback port it prints). +- **API key** — set `LINEAR_API_KEY` via the secrets screen (`/secrets`, F7); the header activates automatically and takes precedence over OAuth. For unattended/agent use, prefer an OAuth app install with `actor=app` over a personal key — actions attribute to the app and don't burn a billable seat. + +For enforced read-only, mint a Read-permission key — Linear supports per-key Read / Write / Admin permissions and team scoping, so this is a real boundary even though it lives in the credential rather than the server. (The `gitlab` and `github` connectors can additionally refuse to register write tools server-side; Linear, Atlassian, and Azure DevOps cannot.) + +Auth detail and filter idioms live in `skills/linear/`. diff --git a/capabilities/linear/capability.yaml b/capabilities/linear/capability.yaml new file mode 100644 index 0000000..4131bbf --- /dev/null +++ b/capabilities/linear/capability.yaml @@ -0,0 +1,51 @@ +schema: 1 +name: linear +version: "1.0.0" +description: > + Connect to Linear from chat and agents — search and read issues, + projects, cycles, and teams; create and update issues; comment and + transition state. Talks directly to Linear's hosted MCP server at + https://mcp.linear.app/mcp; first use opens a browser for OAuth, then + subsequent launches reconnect silently using a stored refresh token + (see ~/.dreadnode/mcp-auth.json). + +mcp: + servers: + linear: + url: https://mcp.linear.app/mcp + # Native HTTP MCP + Dreadnode-managed OAuth (CAP-MCP-011). On + # first connect the runtime opens the user's browser to Linear's + # OAuth authorize endpoint and receives the callback on a + # localhost ephemeral port. Tokens persist to disk and refresh + # transparently. For non-interactive contexts (CI, headless eval), + # set DREADNODE_HEADLESS=1 and complete the flow manually. + auth: + type: oauth + client_name: dreadnode + headers: + # OAuth by default, or set LINEAR_API_KEY for a static token + # (CI / service accounts). The optional header is dropped when + # the var is unset (CAP-MCP-013), so OAuth stays the default with + # no empty `Authorization: Bearer` on the wire. When the key is + # set, the static header wins and reactive OAuth stays dormant. + Authorization: + value: "Bearer ${LINEAR_API_KEY}" + optional: true + init_timeout: 60 + +skills: + - skills/linear/ + +author: + name: Dreadnode + url: https://dreadnode.io +license: MIT +repository: https://github.com/dreadnode/capabilities +keywords: + - linear + - issue-tracker + - project-management + - tickets + - tasks + - engineering-workflow + - connector diff --git a/capabilities/linear/skills/linear/SKILL.md b/capabilities/linear/skills/linear/SKILL.md new file mode 100644 index 0000000..f413bfe --- /dev/null +++ b/capabilities/linear/skills/linear/SKILL.md @@ -0,0 +1,62 @@ +--- +name: linear +description: Use when the user wants to connect to Linear, search or read Linear issues / projects / cycles, create or update issues, or set up Linear auth. The connector — not the triage workflow. +--- + +# Linear + +Connector for Linear via its official remote MCP server. The agent sees the tool +surface once it loads — this skill covers auth, scope, the filter model, and the +idioms. Security triage methodology — dedup, severity, SLA, owner inference — is +deliberately out of scope; pair this with whichever triage capability your +workflow uses. + +## Auth + +Native HTTP MCP with spec-compliant OAuth (RFC 8414 + 9728 + DCR + PKCE S256); the +runtime drives the flow — no `mcp-remote` bridge. + +### A. Interactive OAuth (default; individual users) + +On first connect, `linear` shows in the Services screen as `needs authentication`. +Click **Authenticate** → browser → approve; tokens persist to +`~/.dreadnode/mcp-auth.json` (mode 0600, keyed by server URL) and refresh silently. +To switch workspaces or after revoking access, Services → `linear` → +**Re-authenticate** (clears just this server's tokens). For SSH/headless, set +`DREADNODE_HEADLESS=1`; the auth URL is logged — complete it on a machine with a +browser and forward the callback port it prints (`ssh -R :localhost:`). + +### B. API key (service / agent accounts) + +For unattended use, **just set one secret** — no manifest edit. The server entry +carries an optional `Authorization` header bound to `LINEAR_API_KEY`: set it and the +static token wins, leave it unset and OAuth (A) stays default. + +1. Linear → **Settings → Account → Security & Access** → generate a key. Per-key + permissions (Read / Write / Admin) and team scoping are supported — pick **Read** + + one team for enforced, least-privilege read-only. +2. Add `LINEAR_API_KEY` in the **secrets screen** (`/secrets` or `F7`) or web app, + reload, confirm with `dn secret list`. Don't paste keys into chat. + +> **Agent identity.** When the consumer is an agent / service, prefer an OAuth app +> install with `actor=app` over a personal key — actions attribute to the app, not +> the installing user, and it doesn't burn a billable seat. +> . + +Scope is enforced by the **key or OAuth grant** — the tool surface is identical +either way, so a write-scoped key can mutate. Want read-only? Issue a read-only key. + +## Filters & idioms + +No JQL-style string — structured search with `team`, `state`, `assignee`, `project`, +`priority`, `labels`, plus a free-text `query`. Compose by argument, not a query +string. Reference: . + +- `ABC-123` (team prefix + number) is the canonical identifier — prefer it over + free-text when the user has it. Internal numeric IDs are a different thing and + rarely what the user means. +- `query` is broad — narrow with `team` / `state` / `project` rather than stuffing + keywords in. +- Use the team's **actual** workflow state names (list them with the team-info tool); + don't guess. Same for labels / projects before creating. +- Cycles are time-boxed — "the current cycle" shifts between calls.