pro MCP server
Commit Nov 12, 2026Manages Giant Swarm's GitHub Projects V2 boards, allowing AI assistants to list, filter, create, and update roadmap and customer issues.
Also known as giantswarm/pro
- Stars
- 1
- Tools
- 15
- Downloads, 30 days
- β
- Latest version
- β
- Last commit
- Nov 12, 2026
- License
- Apache-2.0
What is pro MCP?
pro manages Giant Swarm's GitHub Projects V2 boards, allowing AI assistants to list, filter, create, and update roadmap and customer issues. It exposes 15 tools, such as get_board_schema, get_item_by_issue, list_issues.
Summary generated from the project's README
About pro MCP server
Managing Giant Swarm's GitHub Projects V2 boards is what this MCP server enables for AI assistants. It provides direct access to the Roadmap board for tracking company quarterly goals and team issues, as well as the Customer board for managing requests from private repositories. Developers can use it to list, filter, create, and update items across these specific project boards.
The server operates via stdio for local integration with clients like Claude Desktop, Cursor, or Continue, or through a streamable HTTP transport for remote deployment in Docker or Kubernetes. To function, it requires Node.js 20+ and a GitHub Personal Access Token with project:write and repo:write scopes. It supports various authentication modes including environment tokens, OAuth 2.1, and bearer-only configurations for aggregators.
What distinguishes this server is its ability to dynamically discover board structures. By using the get_board_schema tool, an AI assistant can read available fields and valid values, allowing it to perform generic filtering on arbitrary field name and value pairs. This makes the assistant capable of handling complex queries involving single-select options, iterations, and date comparisons.
What you can do with it
- 1Filter roadmap items by teamAsk the AI to find all issues assigned to a specific team on the roadmap board.
Written from the project's README. Every use case is checked against a quote from it.
pro MCP tools 15
Detected from the READMEget_board_schemaget_item_by_issuelist_issuesget_issue_detailslist_issue_relationslist_issue_commentsget_server_versionget_issue_timelineupdate_issue_fieldcreate_issue_in_projectadd_existing_issuearchive_item
| get_board_schema | β | |
| get_item_by_issue | β | |
| list_issues | β | |
| get_issue_details | β | |
| list_issue_relations | β | |
| list_issue_comments | β | |
| get_server_version | β | |
| get_issue_timeline | β | |
| update_issue_field | β | |
| create_issue_in_project | β | |
| add_existing_issue | β | |
| archive_item | β |
Show all 15 toolsShow fewer tools
close_issuereopen_issueupdate_issue_labels
| close_issue | β | |
| reopen_issue | β | |
| update_issue_labels | β |
Configuration
GITHUB_API_TOKEN
| Name | Description | |
|---|---|---|
| GITHUB_API_TOKEN | β |
Automated checks
Ran Nov 14, 2026Full report βNot verified yet. A server needs a score of 80, no serious finding, and enough data for us to check. How checks work
- Source repository linked and reachablegiantswarm/pro is public and reachablegithub.com/giantswarm/pro βPass
- Package names this repository as its sourceNot checked
- Build provenance (Sigstore attestation)Not checked
- Open source license (OSI)Apache-2.0spdx.org/licenses/Apache-2.0.html βPass
- Commit or release in the last yearLast commit or release 2026-11-12github.com/giantswarm/pro βPass
- OpenSSF ScorecardOpenSSF Scorecard 5.6 / 10; weakest: Token-Permissions 0, CII-Best-Practices 0, Vulnerabilities 0scorecard.dev/viewer/?uri=github.com/giantswarm/pro βPartial 8/15
- Package name not close to a popular packageNot checked
- No critical advisory in the package or its dependenciesNot checked
- No hidden instructions to the model15 tool descriptions and the README read; no override phrases, credential paths or hidden charactersPass
- Destructive tools are labelledNo tool named like delete, drop or execPass
- Remote endpoint answers the MCP handshakeNot checked
README
View on GitHubGiant Swarm Portfolio Roadmap Organizer (PRO)
An MCP server for managing Giant Swarm's project boards on GitHub Projects V2.
Overview
PRO exposes Giant Swarm project boards to AI assistants via the Model Context Protocol. It supports multiple boards:
- Roadmap Board (#273) -- Company quarterly goals (rocks), team/SIG/WG issues
- Customer Board (#345) -- Customer-related activities and requests from private customer repositories
The server provides tools for listing, filtering, creating, and updating issues on either board, along with per-board schema resources that describe the available fields and their valid values. Field filtering is generic -- the LLM reads the board's schema resource to discover available fields, then passes arbitrary field name/value pairs as filters.
Requirements
- Node.js 20+
- GitHub Personal Access Token with
project:writeandrepo:writescopes
Installation
git clone https://github.com/giantswarm/pro.git
cd pro
npm install
To make the pro command available globally (required for the MCP client config and self-update), install it into your user path -- no sudo needed:
Option A: Using nvm or fnm (recommended)
If you manage Node.js with nvm or fnm, npm's global prefix is already in your home directory:
npm install -g .
Option B: Configure npm's global prefix
Without a version manager, npm's default global prefix is a system path. Redirect it to a user-local directory:
npm config set prefix ~/.local
Make sure ~/.local/bin is in your PATH (add to ~/.bashrc or ~/.zshrc):
export PATH="$HOME/.local/bin:$PATH"
Then install:
npm install -g .
Option C: Use the full path in MCP config
If you prefer not to install globally, point your MCP client config directly at the checkout:
{
"mcpServers": {
"giantswarm-pro": {
"command": "node",
"args": ["/path/to/pro/bin/index.js"],
"env": {
"GITHUB_API_TOKEN": "your-github-token"
}
}
}
}
Note: this skips the global binary, so pro --self-update won't be available.
Configuration
HTTP transport authentication
With --transport=streamable-http the server picks one of three modes:
| Mode | Configuration | Who holds the GitHub credential |
|---|---|---|
| Env token | GITHUB_API_TOKEN only |
the server (one identity for every caller) |
| OAuth 2.1 | GITHUB_OAUTH_CLIENT_ID + GITHUB_OAUTH_CLIENT_SECRET (+ OAUTH_ISSUER_URL) |
this server, acting as authorization server in front of GitHub; each caller signs in through it |
| Bearer-only | OAUTH_BEARER_ONLY=true (+ OAUTH_ISSUER_URL) |
the caller: every /mcp request carries a GitHub token as bearer, verified via the GitHub API and used for that request. No /authorize, /token, /register; /.well-known/oauth-protected-resource[/mcp] names https://github.com/login/oauth as the authorization server. Made for an MCP aggregator such as muster that holds the person's GitHub grant itself. |
In the OAuth and bearer-only modes GitHub calls run as the caller, so board
changes are attributed to the person. Scoped tokens (classic OAuth, classic
PAT) must cover repo, project and read:org (a wider scope counts:
admin:org or write:org for read:org); GitHub App user-to-server tokens
and fine-grained PATs have no scopes -- GitHub reports an empty scope list for
them -- and are accepted as they are, GitHub enforcing their permissions on
each call.
Environment Variables
GITHUB_API_TOKEN(required for stdio and the env-token HTTP mode): GitHub PAT withproject:writeandrepo:writescopes.OAUTH_BEARER_ONLY(optional, HTTP transport):trueselects the bearer-only mode described above.GITHUB_APP_SLUG(optional, bearer-only mode): the slug of the GitHub App whose user access tokens alone are accepted (giantswarm-pro, pro's own App, installed on every repository of the organization). Every write is then the person's own, capped by that App's permissions on the repository at hand; a token of another App, an OAuth App or a PAT is answered 401.HTTP_PORT(optional): Port for HTTP transport (default: 8080).PRO_VERSION(set by the Helm chart): the version the server reports in its startup log and MCPserverInfo, the image tag the chart deploys. Unset, the server reports thepackage.jsonversion, which the npm package carries from its release tag; a checkout reports0.0.0-dev.
Transport Modes
The server supports two transport modes, selected via the --transport flag:
stdio (default)
For local AI client integration (Claude Desktop, Cursor, Continue):
node bin/index.js
# or explicitly:
node bin/index.js --transport=stdio
Streamable HTTP
For remote deployment (Kubernetes, Docker):
node bin/index.js --transport=streamable-http
This starts an HTTP server on port 8080 (configurable via HTTP_PORT) with:
POST/GET/DELETE /mcp-- MCP streamable HTTP endpointGET /healthz-- Liveness probe (always 200)GET /readyz-- Readiness probe (200 when MCP server is connected)
MCP Client Configuration (stdio)
Add to your MCP client config (e.g., Claude Desktop, Cursor, Continue):
{
"mcpServers": {
"giantswarm-pro": {
"command": "pro",
"args": [],
"env": {
"GITHUB_API_TOKEN": "your-github-token"
}
}
}
}
See mcp-config-example.json for a template.
Claude Desktop config locations:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Kubernetes Deployment
A Helm chart is available for deploying PRO in Kubernetes with the streamable HTTP transport.
Prerequisites:
-
Create a namespace:
kubectl create namespace mcp-pro -
Create a secret with your GitHub token (requires
project:writeandrepo:writescopes):kubectl -n mcp-pro create secret generic pro-github-token \ --from-literal=token=your-github-token
Install:
helm install pro ./helm/pro -n mcp-pro
Verify:
kubectl -n mcp-pro get pods
kubectl -n mcp-pro port-forward svc/pro 8080:8080
curl http://localhost:8080/healthz # {"status":"ok"}
curl http://localhost:8080/readyz # {"status":"ready"}
The Helm chart configures --transport=streamable-http automatically. The deployment includes liveness (/healthz) and readiness (/readyz) probes, runs as a non-root user, and enforces a read-only root filesystem.
Key Helm values:
| Value | Default | Description |
|---|---|---|
image.repository |
gsoci.azurecr.io/giantswarm/pro |
Container image registry and name |
image.tag |
default .Chart.AppVersion |
Image tag |
service.port |
8080 |
Service port |
env |
GitHub token from secret | Environment variables for the container |
ingress.enabled |
false |
Enable ingress (disabled by default) |
Docker
docker run -d \
-p 8080:8080 \
-e GITHUB_API_TOKEN=your-github-token \
gsoci.azurecr.io/giantswarm/pro:v1.2.15
The container defaults to --transport=streamable-http.
Boards
| Board | Project | Description |
|---|---|---|
roadmap |
#273 | Company quarterly goals, team/SIG/WG issues |
customer |
#345 | Customer activities and requests from private repos |
The board parameter defaults to "roadmap" on every board-scoped tool for backward compatibility. Tools that resolve purely by item ID (e.g. get_issue_details, update_issue_labels) don't take a board parameter at all.
MCP Tools
Read Tools
-
get_board_schema-- Describe a board's fields for a UI: name, type (singleSelect,iteration,date,text,other), the options of single-select fields and the iterations of iteration fields. The{board}://schemaresource as a tool result. -
get_item_by_issue-- Find the board item of one GitHub issue or pull request of any repository on the board (URL,owner/repo#N, or owner/repo/number) without scanning the board;item: nullwith areasonwhen the issue is not on the board, does not resolve, or is no issue. -
list_issues-- List and filter issues from a project board using generic field filters. Specifyboardto choose the board ("roadmap"or"customer"). Usefilters(a field name-to-value map) to filter by any field: single-select options (comma-separated for OR), iteration titles or@current/@next/@previous, date and number comparisons (">2026-01-01","1..3"), exact text; it is the only place for a field filter, and any other top-level argument the tool does not declare is refused with an error naming it, like every other tool's.excludetakes the same keys (plus the issue filter namesrepository,assignee,label,milestone,type,parentIssue,updated,created,closed,reason) and leaves matching items out.milestone,type(issue type) andparentIssuefilter on those issue attributes. UseemptyFieldsto find items missing specific field values,nonEmptyFieldsfor items that have them. Read the board's schema resource first to discover available fields and valid options. An item with open dependencies carries their counts asopenBlockedByandopenBlocking. The counts come in a request of their own: an issue whose counts cannot be read just carries none, and when the request fails the list stays anddependencyCountsErrornames why. Migration: earlier releases took an unknown top-level string argument as a field filter (so a misspelled argument silently became one). A call likelist_issues(board="roadmap", Team="Honey Badger")is nowlist_issues(board="roadmap", filters={"Team": "Honey Badger"}); the refusal says so for a capitalized field name. The undeclaredprojectalias ofboardis gone as well. Returns at mostlimititems (default 50;0for every matching item), reading the board only as far as the limit needs. Next tocount, the result carrieshidden(matching items left out because their content could not be read, e.g. issues in private repos the server's GitHub identity cannot access) andtotalCount(GitHub's count for the server-side query, including unreadable items, draft issues and pull requests); a cut result says so withtruncated: trueand anextCursor, which the next call passes ascursorwith the same filters to continue. -
get_issue_details-- Get full details for a specific item: repository metadata, title, body text, comments with timestamps, assignees, labels, dates, all field values, and the issue's relations (blockedBy,blocking,relatesTo: the first 50 of each with their state;hiddencounts the related issues the caller cannot read, and a list with more than were read saystruncated: trueand itstotalCount). The relations come in a request of their own: when it fails, the rest of the details stay andrelationsErrornames why; a pull request or draft carries neither. Board-independent (queries by item ID). -
list_issue_relations-- List the issues that block an issue (blockedBy), that it blocks (blocking) and that it relates to (relatesTo), with their state; the first 100 of each (hiddencounts the related issues the caller cannot read; a list with more than were read saystruncated: trueand itstotalCount). Takes any issue asissueUrl(URL orowner/repo#N), on a board or not. Parent/child links stay withlist_sub_issuesandget_parent_issue. -
list_issue_comments-- Fetch comments for multiple board items in a single call. Board-independent (queries by item ID). Resolves each item to its underlying issue and returns comment author/timestamps/body, with an optionalsincecutoff. Each comment includescreatedAt, plusupdatedAtwhen it differs fromcreatedAt(i.e. the comment was edited). Bounded response: max 25itemIdsper call, newest 20 comments per issue by default (override withmaxPerIssue), and long comment bodies are truncated with an explicit indicator. Withoutsince, "newest" means newest by creation time, and per-issue REST pagination is capped (surfaced via atruncatedPagesflag if more comments exist); withsince, "newest" means newest by last-updated time, so a recently-edited older comment isn't dropped in favor of an untouched newer one, and itsupdatedAtshows why. The response'sitemCountcounts result items (including error entries), not comments. -
get_server_version-- The running server's name, version (the release tag, as in the MCPserverInfo) andisDevBuild. -
get_issue_timeline-- Get the compact activity timeline for a board item's underlying issue: label changes, assignments, milestones, renames, cross-references, and close reasons. Board-independent (queries by item ID). Optionalsince/until/eventTypesfilters (applied client-side; malformedsince/untilvalues return an error). When more than 200 events qualify, only the most recent 200 are returned, with atruncatedflag.
Write Tools
-
update_issue_field-- Update a single-select, iteration or date field value. Name the item byitemIdor by the issue asissueUrl(URL orowner/repo#N); provide human-readable field and option names; the server resolves them to GitHub node IDs. Specifyboardto target the correct board. -
create_issue_in_project-- Create a new GitHub Issue in a repository and add it to a board. Optionally set initial status, assignees, and labels. Public issues ingiantswarm/roadmaprequireconfirmPublicSafe=true. Labels must already exist in the repository -- non-existent labels are rejected before the issue is created rather than being auto-created. If applying labels fails after the issue has already been created and added to the board, the issue is not rolled back -- the response reportssuccess: truewith awarningexplaining that labels were not applied. -
add_existing_issue-- Add an existing GitHub issue to a board by URL or node ID. -
add_issue_relation/remove_issue_relation-- Set or remove a relation between two issues of any repository:issueUrl,relation("blocked_by":relatedIssueUrlblocksissueUrl;"blocking":issueUrlblocksrelatedIssueUrl;"relates_to") andrelatedIssueUrl. A dependency set this way shows on both issues in GitHub, unlike a "Blocked by" line in an issue body. -
archive_item-- Archive a project item from the active board view. -
close_issue-- Close the GitHub issue underlying a single project item. Board-independent (queries by item ID). Accepts an optionalstateReason("completed"or"not_planned", defaults to"completed"; any other value returns an error) and an optionalcommentposted before closing. Comments on issues in public repos requireconfirmPublicSafe=true. One item per call -- no bulk close. Closing the issue does not update the board's Status field; unless the board has GitHub's built-in "item closed -> set Status" workflow enabled, pair this withupdate_issue_fieldif the board Status should reflect the closure. -
reopen_issue-- Reopen the GitHub issue underlying a single project item. Board-independent (queries by item ID). Accepts an optionalcommentposted before reopening. Comments on issues in public repos requireconfirmPublicSafe=true. One item per call -- no bulk reopen. Reopening the issue does not update the board's Status field; unless the board has GitHub's built-in "item closed -> set Status" workflow enabled, pair this withupdate_issue_fieldif the board Status should reflect the reopening. -
update_issue_labels-- Add and/or remove labels on the issue underlying a project item. Board-independent (queries by item ID). At least one ofaddLabels/removeLabelsis required. Labels being added must already exist in the repository -- non-existent labels are rejected with a clear error instead of being auto-created.addedandremovedin the response both reflect effective changes only -- labels not already present pre-call foradded, labels that were actually present pre-call forremoved-- rather than echoing the requested sets.
MCP Resources
Resources are provided per board. Read the schema resource before querying to understand the available fields and their valid option values.
| Resource | Description |
|---|---|
roadmap://schema |
Field schema for the Roadmap Board |
roadmap://overview |
Stats and status distribution for the Roadmap Board |
customer://schema |
Field schema for the Customer Board |
customer://overview |
Stats and status distribution for the Customer Board |
Repository Safety Guidance
giantswarm/roadmapis public. Use it only for sanitized, public-safe issue content.giantswarm/giantswarmis internal/private. Use it for internal and customer-specific operational details.- Customer board issues live in private customer repositories (e.g.
giantswarm/<customer>). The board itself is a public GitHub project, but issue content is only visible to users with repository access. - The server enforces an explicit confirmation (
confirmPublicSafe=true) before creating issues ingiantswarm/roadmap, and before posting a comment viaclose_issue/reopen_issueon an issue in any public repository.
Example Conversations
Roadmap -- Product Owner Workflow:
You: "Show me all roadmap issues for Team Honey Badger that are missing a function field"
AI: [Reads roadmap://schema, then uses list_issues with board="roadmap", filters={"Team": "Honey Badger"}, emptyFields=["Function"]]
You: "Set the function for issue PVTI_xxx to 'Security'"
AI: [Uses update_issue_field with board="roadmap"]
Customer Board -- Account Engineer Workflow:
You: "Show me all customer issues that are blocked"
AI: [Reads customer://schema, then uses list_issues with board="customer", filters={"Status": "Blocked"}]
You: "What customer issues are assigned to Team Tenet?"
AI: [Uses list_issues with board="customer", filters={"Team": "Tenet"}]
Cross-board Workflow:
You: "Create a new feature request in the customer repo and add it to the customer board"
AI: [Uses create_issue_in_project with board="customer"]
You: "Add issue https://github.com/giantswarm/example/issues/42 to the roadmap board"
AI: [Uses add_existing_issue with board="roadmap"]
Library Usage
The board core is importable as @giantswarm-io/pro, independent of the MCP server. Consumers (e.g. the Backstage roadmap backend plugin) get the same board registry, GraphQL queries, and field semantics the MCP server uses.
npm install @giantswarm-io/pro
# or, before the package is on npm / for unreleased versions:
npm install github:giantswarm/pro#v1.2.53
import {
BOARDS, resolveBoardId,
listItems, getItemByID, updateItemField,
listFields, findFieldByName, findMatchingOption,
listSubIssues, addSubIssue, removeSubIssue, getParentIssue
} from '@giantswarm-io/pro';
const boardId = resolveBoardId('roadmap');
// Reads -- every function accepts an optional per-request token as its last
// argument (falls back to the GITHUB_API_TOKEN environment variable).
const { data } = await listItems({ boardId, filters: { Team: 'Bumblebeeπ' }, token });
const item = await getItemByID('PVTI_xxx', token);
// Writes -- resolve field and option names to node IDs, then mutate.
const field = await findFieldByName('Status', boardId, token);
const option = findMatchingOption(field.options, 'In Progress βοΈ');
await updateItemField('PVTI_xxx', field.id, { singleSelectOptionId: option.id }, boardId, token);
// Sub-issues (REST) -- targets take explicit owner/repo/issue_number,
// child issues are referenced by their integer ID (use resolveIssueId).
await addSubIssue({ owner: 'giantswarm', repo: 'giantswarm', issue_number: 1234, subIssueId: 987654321 }, token);
The exported surface is defined in src/index.js. The MCP server and CLI are not part of the library entry point.
Releases
The Publish package workflow runs on every GitHub Release (created automatically by the Auto-release workflow), sets the package version from the release tag, attaches the npm tarball to the release, and publishes @giantswarm-io/pro to npm (skipped while the NPM_TOKEN repository secret is not configured).
Development
Install the npm dependencies first: a fresh clone or git worktree has no node_modules, and every test fails until npm ci ran. make test does it for you when node_modules is missing.
# Install the dependencies (once per clone or worktree)
npm ci
# Run the tests
make test
# Start the MCP server locally (stdio)
node bin/index.js
# Start with HTTP transport
node bin/index.js --transport=streamable-http
License
Copyright (c) 2025 Giant Swarm GmbH. All Rights Reserved.
pro MCP questions
What tools does pro MCP provide?
It exposes 15 tools, including get_board_schema, get_item_by_issue, list_issues, get_issue_details, list_issue_relations.