npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@joaodotwork/plantas-github-projects-mcp

v1.5.3

Published

Plantas GitHub Projects v2 MCP server (unofficial) - automation for creating projects, milestones, issues, and iterations

Downloads

513

Readme

GitHub Projects MCP Server

A Model Context Protocol (MCP) server for automating GitHub Projects v2 workflows - create projects, milestones, issues, and iterations programmatically.

Works with: Claude Desktop (desktop app) and Claude Code (VS Code extension)

Features

  • Create Projects: Set up new GitHub Projects v2 boards
  • Create Milestones: Organize work into milestones
  • Create Issues: Bulk create issues with milestones and labels
  • Add to Projects: Automatically add issues to project boards
  • Iteration Fields: Create weekly/sprint iteration fields
  • Add/Update Iterations: Add new iterations to existing fields or update existing ones
  • Assign Iterations: Distribute issues across sprints
  • Sub-issue Management: Add, remove, and reprioritize sub-issues
  • Update Status: Change project item status with human-readable values
  • Project Status Updates: Add and retrieve project-level status updates (On Track, At Risk, etc.)
  • Update Project: Modify project settings like title, description, and visibility
  • Get Info: Retrieve repository and project metadata

Installation

Prerequisites

  • Node.js 20+
  • Option A: GitHub Personal Access Token (PAT) with repo and project scopes
  • Option B: GitHub OAuth App with Device Flow enabled (auto-refreshing tokens)

Quick Start (Recommended)

Use npx to run the server directly without installation:

npx -y @joaodotwork/plantas-github-projects-mcp

Install as global npm package

npm install -g @joaodotwork/plantas-github-projects-mcp

Build from source (Development)

git clone https://github.com/joaodotwork/plantas-github-projects-mcp.git
cd plants-github-projects-mcp
npm install
npm run build

Configuration

Authentication

The server supports two authentication methods:

Option A: Personal Access Token (simplest)

export GITHUB_TOKEN=ghp_your_token_here

Option B: OAuth Device Flow (recommended)

Uses a GitHub OAuth App with auto-refreshing tokens stored in encrypted local storage. No need to manually manage tokens.

export GITHUB_CLIENT_ID=your_oauth_app_client_id
export GITHUB_CLIENT_SECRET=your_oauth_app_client_secret

On first tool call, the server will prompt you to authorize via browser. Authentication is deferred until needed, so the server starts instantly — no risk of timeouts in Claude Code or other MCP hosts. Tokens are stored encrypted at ~/.config/github-projects-mcp/credentials.enc and refresh automatically.

Configure Claude

For Claude Code (CLI):

# With PAT
claude mcp add github-projects --env GITHUB_TOKEN=ghp_your_token_here -- npx -y @joaodotwork/plantas-github-projects-mcp

# With OAuth
claude mcp add github-projects \
  --env GITHUB_CLIENT_ID=your_client_id \
  --env GITHUB_CLIENT_SECRET=your_client_secret \
  -- npx -y @joaodotwork/plantas-github-projects-mcp

For Gemini CLI:

gemini mcp add github-projects npx -e GITHUB_TOKEN=ghp_your_token_here -- -y @joaodotwork/plantas-github-projects-mcp

For Claude Desktop: Add to ~/Library/Application Support/Claude/claude_desktop_config.json

See INSTALL.md for detailed platform-specific instructions.

{
  "mcpServers": {
    "github-projects": {
      "command": "npx",
      "args": ["-y", "@joaodotwork/plantas-github-projects-mcp"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here"
      }
    }
  }
}

3. Restart

Claude Desktop: Completely quit and reopen the app

Claude Code: Reload VS Code window (Cmd+Shift+P → "Developer: Reload Window")

Available Tools

create_project

Create a new GitHub Projects v2 board.

Parameters:

  • owner (string, required): GitHub username or organization
  • title (string, required): Project title
  • description (string, optional): Project description

Example:

{
  "owner": "joaodotwork",
  "title": "v1.0 Production Release",
  "description": "Sprint to ship v1.0"
}

Returns:

{
  "id": "PVT_kwHOAwJiCM4BNC20",
  "number": 7,
  "title": "v1.0 Production Release",
  "url": "https://github.com/users/joaodotwork/projects/7"
}

create_milestone

Create a milestone in a repository.

Parameters:

  • owner (string, required): Repository owner
  • repo (string, required): Repository name
  • title (string, required): Milestone title
  • description (string, optional): Milestone description
  • dueOn (string, optional): Due date in ISO 8601 format

Example:

{
  "owner": "joaodotwork",
  "repo": "dpds-arkiv",
  "title": "Epic 1: GitHub Metadata Workflow",
  "description": "Automate GitHub Projects sync (1 issue)"
}

Returns:

{
  "id": "MI_kwDOPxqaGM4A3o8i",
  "number": 4,
  "title": "Epic 1: GitHub Metadata Workflow",
  "url": "https://github.com/joaodotwork/dpds-arkiv/milestone/4"
}

create_issue

Create an issue with optional milestone, labels, and assignees.

Parameters:

  • owner (string, required): Repository owner
  • repo (string, required): Repository name
  • title (string, required): Issue title
  • body (string, required): Issue body (markdown)
  • milestoneNumber (number, optional): Milestone number
  • labelIds (string[], optional): Array of label IDs
  • assignees (string[], optional): Array of usernames

Example:

{
  "owner": "joaodotwork",
  "repo": "dpds-arkiv",
  "title": "Implement GitHub Projects Sync Workflow",
  "body": "**Epic:** GitHub Metadata Workflow\n...",
  "milestoneNumber": 4,
  "labelIds": ["LA_kwDOPxqaGM8AAAACVcj5iQ"],
  "assignees": ["joaodotwork"]
}

Returns:

{
  "id": "I_kwDOPxqaGM6RkGzw",
  "number": 80,
  "title": "Implement GitHub Projects Sync Workflow",
  "url": "https://github.com/joaodotwork/dpds-arkiv/issues/80"
}

add_issue_to_project

Add an issue to a Projects v2 board.

Parameters:

  • projectId (string, required): Project node ID
  • issueId (string, required): Issue node ID

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "issueId": "I_kwDOPxqaGM6RkGzw"
}

Returns:

{
  "id": "PVTI_lAHOAwJiCM4BNC20zgXYZ..."
}

create_iteration_field

Create an iteration field with weekly sprints.

Parameters:

  • projectId (string, required): Project node ID
  • fieldName (string, required): Field name (e.g., "Sprint")
  • duration (number, required): Duration in days (typically 7)
  • startDate (string, required): Start date (YYYY-MM-DD)
  • iterations (array, required): Array of iteration definitions

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "fieldName": "Sprint",
  "duration": 7,
  "startDate": "2026-01-20",
  "iterations": [
    { "title": "Week 1", "startDate": "2026-01-20", "duration": 7 },
    { "title": "Week 2", "startDate": "2026-01-27", "duration": 7 },
    { "title": "Week 3", "startDate": "2026-02-03", "duration": 7 }
  ]
}

Returns:

{
  "id": "PVTIF_lAHOAwJiCM4BNC20zg8J544",
  "name": "Sprint",
  "configuration": {
    "iterations": [
      {
        "id": "bab3ba50",
        "title": "Week 1",
        "startDate": "2026-01-20",
        "duration": 7
      },
      ...
    ]
  }
}

assign_issue_to_iteration

Assign an issue to a specific iteration.

Parameters:

  • owner (string, required): Repository owner
  • repo (string, required): Repository name
  • projectNumber (number, required): Project number
  • issueNumber (number, required): Issue number
  • fieldId (string, required): Iteration field ID
  • iterationId (string, required): Iteration ID

Example:

{
  "owner": "joaodotwork",
  "repo": "dpds-arkiv",
  "projectNumber": 7,
  "issueNumber": 80,
  "fieldId": "PVTIF_lAHOAwJiCM4BNC20zg8J544",
  "iterationId": "bab3ba50"
}

add_iteration

Add a new iteration to an existing iteration field.

Parameters:

  • projectId (string, required): Project node ID
  • fieldId (string, required): Iteration field ID
  • title (string, required): Iteration title (e.g., "Sprint 5")
  • startDate (string, required): Start date (YYYY-MM-DD)
  • duration (number, required): Duration in days (typically 7 or 14)

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "fieldId": "PVTIF_lAHOAwJiCM4BNC20zg8J544",
  "title": "Phase 4: Production hardening",
  "startDate": "2026-02-10",
  "duration": 14
}

update_iteration

Update an existing iteration's title, start date, or duration.

Parameters:

  • projectId (string, required): Project node ID
  • fieldId (string, required): Iteration field ID
  • iterationId (string, required): Iteration ID to update
  • title (string, optional): New title
  • startDate (string, optional): New start date (YYYY-MM-DD)
  • duration (number, optional): New duration in days

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "fieldId": "PVTIF_lAHOAwJiCM4BNC20zg8J544",
  "iterationId": "bab3ba50",
  "title": "Sprint 3 (extended)",
  "duration": 14
}

add_subissue

Add a sub-issue to a parent issue.

Parameters:

  • issueId (string, required): Node ID of the parent issue
  • subIssueId (string, optional): Node ID of the sub-issue
  • subIssueUrl (string, optional): URL of the sub-issue
  • replaceParent (boolean, optional): Replace parent issue if one already exists

Example:

{
  "issueId": "I_kwDOPxqaGM6RkGzw",
  "subIssueId": "I_kwDOPxqaGM6RkHAB"
}

Returns:

{
  "success": true,
  "message": "Sub-issue added successfully"
}

remove_subissue

Remove a sub-issue from a parent issue.

Parameters:

  • issueId (string, required): Node ID of the parent issue
  • subIssueId (string, required): Node ID of the sub-issue to remove

Example:

{
  "issueId": "I_kwDOPxqaGM6RkGzw",
  "subIssueId": "I_kwDOPxqaGM6RkHAB"
}

Returns:

{
  "success": true,
  "message": "Sub-issue removed successfully"
}

reprioritize_subissue

Reprioritize a sub-issue within a parent issue.

Parameters:

  • issueId (string, required): Node ID of the parent issue
  • subIssueId (string, required): Node ID of the sub-issue to reprioritize
  • afterId (string, optional): ID of the sub-issue to be prioritized after
  • beforeId (string, optional): ID of the sub-issue to be prioritized before

Note: Specify either afterId OR beforeId, not both.

Example:

{
  "issueId": "I_kwDOPxqaGM6RkGzw",
  "subIssueId": "I_kwDOPxqaGM6RkHAB",
  "afterId": "I_kwDOPxqaGM6RkHCD"
}

Returns:

{
  "success": true,
  "message": "Sub-issue reprioritized successfully"
}

update_item_status

Update the status of a project item using human-readable status values.

Parameters:

  • projectId (string, required): Project node ID
  • itemId (string, required): Project item node ID
  • status (string, required): Human-readable status (e.g., "Todo", "In Progress", "Done")

Note: The tool automatically finds the Status field and matches the status name (case-insensitive). It will show available options if the status is not found.

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "itemId": "PVTI_lAHOAwJiCM4BNC20zgXYZ...",
  "status": "In Progress"
}

Returns:

{
  "success": true,
  "message": "Status updated to 'In Progress'",
  "itemId": "PVTI_lAHOAwJiCM4BNC20zgXYZ..."
}

update_project_settings

Update project settings like title, description, README, or visibility.

Parameters:

  • projectId (string, required): Project node ID
  • title (string, optional): New project title
  • shortDescription (string, optional): New short description
  • readme (string, optional): New README content (markdown)
  • public (boolean, optional): Set project visibility (true = public, false = private)

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "title": "Q1 2025 Product Launch",
  "shortDescription": "Sprint planning for v2.0 release",
  "public": true
}

Returns:

{
  "success": true,
  "message": "Project settings updated successfully",
  "project": {
    "id": "PVT_kwHOAwJiCM4BNC20",
    "title": "Q1 2025 Product Launch",
    "shortDescription": "Sprint planning for v2.0 release",
    "public": true,
    "url": "https://github.com/users/joaodotwork/projects/7"
  }
}

get_repository_info

Get repository ID, labels, and milestones.

Parameters:

  • owner (string, required): Repository owner
  • repo (string, required): Repository name

Example:

{
  "owner": "joaodotwork",
  "repo": "dpds-arkiv"
}

Returns:

{
  "id": "R_kgDOPxqaGA",
  "name": "dpds-arkiv",
  "labels": {
    "nodes": [
      { "id": "LA_kwDOPxqaGM8...", "name": "priority:high" },
      ...
    ]
  },
  "milestones": {
    "nodes": [
      { "id": "MI_kwDOPxqaGM4...", "number": 4, "title": "Epic 1..." },
      ...
    ]
  }
}

get_project_info

Get project ID, fields, and iteration IDs.

Parameters:

  • owner (string, required): Project owner
  • projectNumber (number, required): Project number

Example:

{
  "owner": "joaodotwork",
  "projectNumber": 7
}

Returns:

{
  "id": "PVT_kwHOAwJiCM4BNC20",
  "title": "v1.0 Production Release",
  "number": 7,
  "fields": {
    "nodes": [
      {
        "id": "PVTIF_lAHOAwJiCM4BNC20zg8J544",
        "name": "Sprint",
        "dataType": "ITERATION",
        "configuration": {
          "iterations": [...]
        }
      },
      ...
    ]
  }
}

create_project_status_update

Create a status update for a project board.

Parameters:

  • projectId (string, required): Project node ID
  • status (string, required): The status level (INACTIVE, ON_TRACK, AT_RISK, OFF_TRACK, COMPLETE)
  • body (string, optional): Status update body (markdown)
  • startDate (string, optional): Start date (YYYY-MM-DD)
  • targetDate (string, optional): Target date (YYYY-MM-DD)

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "status": "ON_TRACK",
  "body": "Project is proceeding as planned. All milestones for this week are met."
}

get_project_status_updates

Get recent status updates for a project.

Parameters:

  • projectId (string, required): Project node ID
  • limit (number, optional): Number of updates to retrieve (default: 5)

Example:

{
  "projectId": "PVT_kwHOAwJiCM4BNC20",
  "limit": 3
}

Usage Examples

Example 1: Create Complete Sprint Setup

// 1. Create project
const project = await create_project({
  owner: "joaodotwork",
  title: "v1.0 Production Release",
  description: "Sprint to ship v1.0"
});

// 2. Create milestones
const milestone1 = await create_milestone({
  owner: "joaodotwork",
  repo: "dpds-arkiv",
  title: "Epic 1: GitHub Metadata Workflow",
  description: "Automate GitHub Projects sync (1 issue)"
});

// 3. Get repository info (for label IDs)
const repoInfo = await get_repository_info({
  owner: "joaodotwork",
  repo: "dpds-arkiv"
});

// 4. Create issue
const issue = await create_issue({
  owner: "joaodotwork",
  repo: "dpds-arkiv",
  title: "Implement GitHub Projects Sync Workflow",
  body: "...",
  milestoneNumber: milestone1.number,
  labelIds: [repoInfo.labels.nodes[0].id],
  assignees: ["joaodotwork"]
});

// 5. Add issue to project
await add_issue_to_project({
  projectId: project.id,
  issueId: issue.id
});

// 6. Create iteration field
const iterationField = await create_iteration_field({
  projectId: project.id,
  fieldName: "Sprint",
  duration: 7,
  startDate: "2026-01-20",
  iterations: [
    { title: "Week 1", startDate: "2026-01-20", duration: 7 },
    { title: "Week 2", startDate: "2026-01-27", duration: 7 },
    { title: "Week 3", startDate: "2026-02-03", duration: 7 }
  ]
});

// 7. Assign issue to iteration
await assign_issue_to_iteration({
  owner: "joaodotwork",
  repo: "dpds-arkiv",
  projectNumber: project.number,
  issueNumber: issue.number,
  fieldId: iterationField.id,
  iterationId: iterationField.configuration.iterations[0].id
});

Example 2: Bulk Create Issues

const issues = [
  {
    title: "Issue 1",
    body: "Description...",
    milestoneNumber: 4
  },
  {
    title: "Issue 2",
    body: "Description...",
    milestoneNumber: 5
  }
];

for (const issueData of issues) {
  const issue = await create_issue({
    owner: "joaodotwork",
    repo: "dpds-arkiv",
    ...issueData
  });

  await add_issue_to_project({
    projectId: "PVT_kwHOAwJiCM4BNC20",
    issueId: issue.id
  });
}

Troubleshooting

"401 Unauthorized" Error

  • PAT users: Check that GITHUB_TOKEN is set correctly and has repo and project scopes
  • OAuth users: Your token may have expired. Restart the MCP server to trigger a refresh or re-authentication
  • The server validates tokens on first tool call and provides actionable error messages

"Issue not found in project" Error

  • Ensure the issue has been added to the project first using add_issue_to_project
  • Verify the projectNumber is correct

MCP Server Not Loading

  • Check Claude Desktop config file path
  • Verify JSON syntax in config file
  • Restart Claude Desktop completely
  • Check logs: ~/Library/Logs/Claude/mcp*.log

Development

# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run dev

# Test locally
node dist/index.js

License

MIT

Author

João Doria de Souza (@joaodotwork)


Built with the MCP SDK - Model Context Protocol for Claude Desktop