Skip to content

Plantas GitHub Projects v2 MCP Server (unofficial) - Automation for creating projects, milestones, issues, and iterations with iteration field support

License

Notifications You must be signed in to change notification settings

joaodotwork/plantas-github-projects-mcp

Repository files navigation

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
  • 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+
  • GitHub Personal Access Token with repo and project scopes

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

1. Set up GitHub Token

Create a .env file or set environment variable:

export GITHUB_TOKEN=ghp_your_token_here

2. Configure Claude

For Claude Code (CLI):

# Using npx (Recommended)
claude mcp add github-projects --env GITHUB_TOKEN=ghp_your_token_here -- npx -y @joaodotwork/plantas-github-projects-mcp

For Gemini CLI:

# Using npx
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_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

  • Check that your GITHUB_TOKEN is set correctly
  • Verify the token has repo and project scopes
  • Token format should be ghp_... (Personal Access Token)

"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

About

Plantas GitHub Projects v2 MCP Server (unofficial) - Automation for creating projects, milestones, issues, and iterations with iteration field support

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •