{
  "markdown": "# github-project-info-mcp\n\n[![CI](https://github.com/shubhtoy/github-project-info-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/shubhtoy/github-project-info-mcp/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/github-project-info-mcp.svg)](https://www.npmjs.com/package/github-project-info-mcp)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n[![Node >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)\n[![MCP](https://img.shields.io/badge/MCP-server-purple)](https://modelcontextprotocol.io)\n\nAn [MCP](https://modelcontextprotocol.io) server for reading **public GitHub Projects (v2)\nboards without authentication** — including item-level data (status, custom fields, story\npoints) for boards that GitHub's own official API can't read unauthenticated.\n\n**Runs entirely locally via stdio** (`npx -y github-project-info-mcp`, no server, no\nCloudflare, no infrastructure of any kind) — this is the primary, standard way to use it. A\nbrowser client and a self-hostable Cloudflare Worker are also included as **optional extras**\nfor the specific case of calling this from client-side JavaScript (see\n[Browser usage](#browser-usage-no-server-no-deploy-required)); neither is needed for normal\nMCP usage and neither is a runtime dependency of the stdio server.\n\nAlso ships as an [Agent Skill](./SKILL.md) — see [Skill](#skill) below.\n\n## Why this exists\n\nGitHub's official REST API for Projects v2 has an authentication gap:\n\n| Endpoint | Org-owned project | User-owned project |\n|---|---|---|\n| Project metadata (title, state, dates) | ✅ unauthenticated for public projects | ✅ unauthenticated for public projects |\n| Project **items** (status, fields, points) | ✅ unauthenticated for public projects | ❌ **401, even when the project is public** |\n\nThis is confirmed live against GitHub's current API, not just inferred from docs — see\n[`docs/investigation.md`](./docs/investigation.md) for the full trail. If your project board\nis owned by your **personal GitHub user account** (the common case for solo/personal\nprojects), there is no official, documented, unauthenticated way to read its items.\n\nThis library closes that gap for user-owned projects using a public fallback: the project\nboard's own webpage embeds full item data as JSON, unauthenticated, for any public project.\nThis tool reads that instead.\n\n## What's official vs. unofficial\n\n- **`get_project_metadata`** — uses GitHub's official, documented REST API\n  (`GET /users|orgs/{owner}/projectsV2/{n}`). Stable, unauthenticated, works for any public project.\n- **`list_project_items`** — for **org-owned** projects, uses GitHub's official REST API\n  (unauthenticated for public projects, per GitHub's docs). For **user-owned** projects, falls\n  back to reading the public board page's embedded JSON (`<script id=\"memex-paginated-items-data\">`).\n  This fallback is **undocumented and unofficial** — it depends on GitHub's current page markup,\n  not a published API contract, and could break without notice if GitHub changes it.\n- **`get_project_item`** — fetches a single item via an internal endpoint GitHub's own web UI\n  uses (`github.com/memexes/{projectId}/items`). Returns **every field on the project**,\n  including custom fields (Priority, Story Points) that the bulk `list_project_items` above\n  can't see. Also **undocumented and unofficial**, same caveats as above.\n\nUse this if you need it and understand the tradeoff. If GitHub ever publishes an official\nunauthenticated items API for user-owned projects, switch to that instead — this project\nwould then be unnecessary for that use case.\n\n## Installation\n\n**As an MCP server (standard path)**: the conventional way to distribute and run an MCP\nserver is via npm + `npx`, so it can be launched with no manual clone/build step:\n\n```bash\nnpx -y github-project-info-mcp\n```\n\n*(Requires the package to be published to npm first — see [Publishing](#publishing-maintainers)\nif you're maintaining a fork.)*\n\n**From source** (for development, or to use the library/Worker/browser-client parts):\n\n```bash\ngit clone https://github.com/shubhtoy/github-project-info-mcp.git\ncd github-project-info-mcp\nnpm install\nnpm run build\n```\n\n## Usage as an MCP server\n\nAdd to your MCP client config (Claude Desktop, Kiro, etc.):\n\n```json\n{\n  \"mcpServers\": {\n    \"github-project-info\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"github-project-info-mcp\"]\n    }\n  }\n}\n```\n\nOr, running from a local clone instead of the published package:\n\n```json\n{\n  \"mcpServers\": {\n    \"github-project-info\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/github-project-info-mcp/dist/index.js\"]\n    }\n  }\n}\n```\n\n### Tools\n\n- **`get_project_metadata(ownerType, owner, projectNumber)`** — project title, description,\n  state, dates.\n- **`list_project_items(ownerType, owner, projectNumber)`** — all items with their fields\n  (status, labels, sub-issue progress, etc — whatever's visible in the board's default view).\n  Status/select field values are resolved to human-readable names automatically for\n  user-owned projects. Custom fields outside the default view (Priority, Story Points, etc)\n  are **not** included here — use `get_project_item` for those.\n- **`get_project_item(projectId, itemId, owner?, projectNumber?)`** — single item's full field\n  data, **including custom fields** (Priority, Story Points, etc) that `list_project_items`\n  doesn't return — confirmed live: the bulk endpoint only reflects the board's active view,\n  while this per-item endpoint returns every field defined on the project. Get `projectId`\n  from `get_project_metadata`'s `id` field (the plain numeric database ID — NOT `nodeId`, the\n  GraphQL node ID, which does not work with this endpoint), and `itemId` from\n  `list_project_items`. Pass `owner`/`projectNumber` too to resolve custom field names and\n  single-select option names (adds one extra request); omit them to get raw field/option IDs\n  instead.\n- **`get_project_fields(owner, projectNumber)`** — field definitions for a user-owned\n  project, including single-select option names/colors (e.g. Status: Todo/In Progress/Done)\n  and saved views.\n- **`list_user_projects(username)`** — list all public projects owned by a user account.\n  There's no official API for this at all (Projects aren't a GitHub Search API resource\n  type); this reads the user's profile page Projects tab.\n\n## Browser usage (no server, no deploy required)\n\nNone of the fallback endpoints this library calls send `Access-Control-Allow-Origin`, so a\nbrowser can't call them directly — see [CORS note](#cors-note). `src/browser-client.ts`\nsolves this with zero setup by default, routing through a free public CORS proxy\n([AllOrigins](https://allorigins.win)):\n\n```js\nimport { getProjectItemsBrowser, getProjectMetadataBrowser } from 'github-project-info-mcp/browser'\n\nconst metadata = await getProjectMetadataBrowser('users', 'someuser', 4) // no proxy needed — official API already sends CORS headers\nconst items = await getProjectItemsBrowser('someuser', 4) // routed through the public proxy by default\n```\n\nThis works immediately, no account or deploy needed. The tradeoff: you're depending on a\nthird-party proxy service — it's rate-limited and its uptime isn't guaranteed. Fine for\nprototyping, demos, or low-traffic pages.\n\n### Upgrade path: self-hosted Worker (more reliable, still free)\n\nFor anything you need to be reliable, deploy your own instance instead — same free tier, but\nyou own it. See [Deploying your own instance](#deploying-your-own-instance-cloudflare-free)\nbelow for the full steps; once deployed, pass the URL to the browser client instead of using\nthe default proxy:\n\n```js\nconst items = await getProjectItemsBrowser('someuser', 4, {\n  workerBaseUrl: 'https://your-worker.workers.dev',\n})\n```\n\nOr call the Worker's HTTP API directly:\n\n```\nGET /users/:username/projects\nGET /projects/:owner/:number/metadata?ownerType=user|org\nGET /projects/:owner/:number/items?ownerType=user|org\nGET /projects/:owner/:number/fields\n```\n\nNo secrets or environment variables are needed for either path — every endpoint involved is\npublic and unauthenticated by design.\n\n## Skill\n\nThis repo also ships [`SKILL.md`](./SKILL.md), following the\n[Agent Skills](https://github.com/anthropics/skills) format, so agents (Claude, Kiro, etc.)\nthat support skills can discover when and how to use this MCP server automatically — install\nvia [skills.sh](https://skills.sh) (`npx skills add shubhtoy/github-project-info-mcp`) or by\npointing an agent at this repo directly.\n\n## Publishing (maintainers)\n\nPublishing to npm is the standard distribution path for MCP servers — once published, anyone\ncan run `npx -y github-project-info-mcp` with no clone/build step. To publish a new version:\n\n```bash\nnpm version patch   # or minor/major — bumps package.json AND creates a local git tag\ngit push --tags\nnpm publish\ngh release create v$(node -p \"require('./package.json').version\") --generate-notes\n```\n\n`npm version` already creates the git tag; `git push --tags` (or `git push --follow-tags`)\npushes it, and `gh release create` turns it into a GitHub Release with auto-generated notes\nfrom commits since the last tag (edit them afterward for a cleaner summary if needed).\n\nThe `files` field in `package.json` is already scoped to ship only `dist/`, `README.md`, and\n`LICENSE` — no source, tests, or dev config get published. `prepublishOnly` isn't currently\nwired to auto-build; run `npm run build` before publishing, or add that hook if you want it\nenforced.\n\nThere's also an official [MCP Registry](https://modelcontextprotocol.io/registry) (in preview\nas of writing) for centralized discovery across clients — worth publishing there too once this\npackage is stable, via the `mcp-publisher` CLI.\n\n## (Optional) Deploying your own Cloudflare Worker\n\nNot needed for standard MCP usage — this only matters if you want the browser client to skip\nthe public proxy dependency (see [Browser usage](#browser-usage-no-server-no-deploy-required)\nabove), or want a remote (non-stdio) MCP endpoint. Nothing in this section is required to run\nthe server via `npx github-project-info-mcp` or any normal MCP client config.\n\nA demo instance is deployed for quick testing (not an SLA'd service — it's a personal\nCloudflare account's free tier, could go away or hit rate limits with heavy use; deploy your\nown per below for anything you depend on):\n\n- CORS-proxy HTTP API: `https://github-project-info-api.shubhmittal-sm.workers.dev`\n- Remote MCP server: `https://github-project-info-mcp.shubhmittal-sm.workers.dev/mcp`\n\nTo deploy your own instead:\n\n```bash\nnpx wrangler login      # one-time, opens a browser to authorize a free Cloudflare account\nnpm run worker:deploy       # deploys the CORS-proxy HTTP API\nnpm run mcp-worker:deploy   # deploys the remote MCP server (Streamable HTTP, at /mcp)\n```\n\nBoth deploy independently to Cloudflare's free tier (100,000 requests/day each, no credit\ncard required) and print your live `*.workers.dev` URL on success. Test locally first with\n`npm run worker:dev` / `npm run mcp-worker:dev` before deploying.\n\n## Usage as a library\n\n```typescript\nimport { getProjectMetadata, listProjectItems } from 'github-project-info-mcp/client'\n\nconst metadata = await getProjectMetadata('users', 'someuser', 4)\nconst { items } = await listProjectItems('users', 'someuser', 4)\n```\n\n## CORS note\n\nOnly the fallback endpoints for user-owned project **items** lack CORS headers (the board-page\nscrape, the memex per-item endpoint) — that's the whole reason `browser-client.ts` and\n`worker.ts` exist; see [Browser usage](#browser-usage-no-server-no-deploy-required) above for\nthe two ways to work around it. GitHub's official metadata endpoint already sends\n`Access-Control-Allow-Origin: *` and needs no proxy.\n\n## Limitations\n\n- Only works for **public** projects. Private projects need real authentication — use\n  GitHub's official API/SDK/CLI for those.\n- The user-owned-items fallback depends on undocumented GitHub internals and may stop working\n  if GitHub changes its page structure. If it breaks, please open an issue — this repo will be\n  updated if a fix or better path is found.\n- Board-scrape pagination: the board page returns whatever items are in GitHub's default view\n  for that project. If a project has items excluded from the default view (e.g. archived, or\n  filtered out by a saved view), they won't appear via this path.\n\n## Security\n\nDependencies are pinned to versions with known `npm audit` advisories patched (checked at the\ntime of writing — re-run `npm audit` yourself before relying on this in anything sensitive).\nNotably `@modelcontextprotocol/sdk` is pinned to `1.29.0`+, which patches a DNS-rebinding-\nprotection gap (CVE-2025-66414) — that specific advisory affects unauthenticated\n`localhost`-bound HTTP servers using the SDK's raw transport classes directly; this repo's\n`worker-mcp.ts` runs on Cloudflare Workers (not localhost) via the `agents` package's own\n`WorkerTransport`, a different code path, so the advisory's exact preconditions likely don't\napply here — noted for transparency, not as a claim this repo was specifically audited against\nit.\n\n## License\n\nMIT\n",
  "bytes": 13216,
  "sha": "1876bbf89ffda295293b4d839ec2170116580e4494fd5a2d7ea44b9c91195523",
  "repo_slug": "shubhtoy/github-project-info-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_shubhtoy_github_project_info_22d7effb/readme"
}