github-projects
by kmosoti
README.md
# github-projects
A plugin for **Claude Code and Codex**: Pydantic v2 models, PEP 544
protocols, and an MCP server for managing **GitHub Projects v2** boards
(e.g. `github.com/users/<owner>/projects/<n>`) — with first-class support
for the draft **HTTP QUERY** method.
## Architecture
```
server.py MCP server (mcp SDK v2, stdio) — 19 tools, structured output
│ depends on
protocols.py ProjectsBackend / GraphQLTransport (runtime-checkable Protocols)
│ implemented by
service.py GitHubProjectsService — GraphQL over the transport,
project-id + field caching, string→typed field-value coercion
graphql.py GraphQL documents (works for both user and org owners)
http.py QueryClient — HTTP QUERY (draft-ietf-httpbis-safe-method-w-body)
with per-origin capability memory and POST fallback
models.py Frozen Pydantic v2 models, __typename-discriminated unions
```
- The MCP layer depends only on the `ProjectsBackend` protocol, so backends
are swappable and tests substitute fakes structurally.
- `QueryClient` sends `QUERY` optimistically, records `Accept-Query`
advertisements, retries once on transport errors (QUERY is safe and
idempotent), and permanently falls back to `POST` per origin on 405/501 —
so it works against GitHub today and upgrades itself when GitHub ships
QUERY support.
## Setup
The primary runtime is CPython 3.14.7 free-threaded (`3.14.7t`). It also
requires the gh CLI to be authenticated **with the `project` scope**:
```bash
gh auth refresh -s project # grants read + write for Projects v2
```
Tokens are resolved from `GITHUB_TOKEN` / `GH_TOKEN`, else `gh auth token`.
```bash
uv sync
uv run pytest # 32 tests
uv run gh-projects-mcp # run the server on stdio
```
## Using it from Claude Code and Codex
From the repository root:
```bash
# Claude Code (registered user-wide)
claude mcp add --scope user github-projects -- uv --directory "$PWD" run gh-projects-mcp
# Codex
codex mcp add github-projects -- uv --directory "$PWD" run gh-projects-mcp
```
Plugin manifests live in `.claude-plugin/plugin.json` (with the MCP server
declared via `${CLAUDE_PLUGIN_ROOT}`) and `.codex-plugin/plugin.json`; a
usage skill for both hosts is in `skills/github-projects/SKILL.md`.
## Tools
| Tool | Purpose |
|---|---|
| `list_projects` | List boards for a user/org (optional search) |
| `get_project` | Board by owner + number |
| `list_fields` | Fields incl. single-select options and iterations |
| `list_items` | Items with content + field values, optionally evaluated through a saved-view filter query |
| `create_project` / `update_project` | Create board; edit title/readme/visibility/closed |
| `add_item` | Add an issue/PR by URL |
| `add_draft_issue` | Add a draft issue |
| `update_field_value` | Set a field; values are strings coerced by field type — single-select and iteration match by name (`Status` → `"Done"`) |
| `clear_field_value` | Clear a field |
| `archive_item` / `delete_item` | Archive or remove an item |
| `plan_project` / `apply_project` | Idempotent desired-state reconciliation: fields and option aliases, semantically verified leaf/container views, ordered columns, explicit retirements, item metadata, epic/sub-issue hierarchy, native issue dependencies, and legacy dependency-prose cleanup |
| `sprint_board` | Status-column view of one iteration (or all items + unplanned bucket) |
| `epic_breakdown` | Per-epic completion rollup from the native sub-issue hierarchy |
| `list_views` | Saved views with name, layout, filter, and ordered visible fields |
| `post_status_update` / `list_status_updates` | The project's long-horizon context trail |
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues