Skip to main content
Glama
kmosoti

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 |