A Model Context Protocol (MCP) implementation for managing GitHub projects and issues. This package provides a seamless interface for AI assistants and applications to interact with GitHub repositories, issues, pull requests, and projects.
This package has been updated to use GitHub's Projects v2 API instead of the deprecated classic Projects API.
- Uses GraphQL API instead of REST API
- Requires a token with
project
scope - Returns different ID formats (GraphQL node IDs)
- Different parameter names in the API calls
To find a Project ID for use with this API, you can use the following GraphQL query:
query {
organization(login: "YOUR_ORG_NAME") {
projectV2(number: PROJECT_NUMBER) {
id
}
}
}
Or for user projects:
query {
user(login: "YOUR_USERNAME") {
projectV2(number: PROJECT_NUMBER) {
id
}
}
}
Replace PROJECT_NUMBER
with the number from your project URL (e.g., for https://github.com/orgs/your-org/projects/5
, use 5
).
- Create issues
- Update issues
- List issues with filtering options
- Get issue details
- Add comments to issues
- Close issues
- Create pull requests
- Update pull requests
- List pull requests with filtering options
- Get pull request details
- Merge pull requests
- Check if a pull request has been merged
- Create and manage pull request reviews
- Add and list review comments
- Request and remove reviewers
- Update pull request branches
- Create projects
- Add issues to projects
- Update project items (move between columns)
- List project items
npm install @monsoft/mcp-github-project-manager
The quickest way to use the GitHub Project Manager is directly with npx:
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here
This starts the MCP server which can then be connected to by MCP clients.
The GitHub Project Manager supports two transport methods:
This is the default transport, ideal for direct CLI integrations and local usage:
# Start with default Stdio transport
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here
For remote setups and web integrations, you can use the SSE transport which starts an HTTP server:
# Start with SSE transport on default port (3010)
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here --RUN_SSE=1
# Start with SSE transport on a custom port
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here --RUN_SSE=1 --PORT=8080
When using SSE transport, the server will be accessible at:
- SSE endpoint:
http://localhost:<PORT>/sse
- Messages endpoint:
http://localhost:<PORT>/messages
To use this with AI assistants like Claude in Anthropic or Cursor:
# Start the MCP server in your terminal
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here
Then configure your AI assistant to use this MCP server. The exact configuration depends on the client you're using.
To use the GitHub Project Manager in your own code:
import { GitHubProjectManager } from '@monsoft/mcp-github-project-manager';
// The token will be automatically loaded from command line arguments
const manager = new GitHubProjectManager();
// Now you can use the manager to interact with GitHub projects
When running your application, provide the GitHub token as a command-line argument:
node your-app.js --GITHUB_PERSONAL_TOKEN=your_github_token_here
You can also specify the transport type and other options:
# Use SSE transport
node your-app.js --GITHUB_PERSONAL_TOKEN=your_github_token_here --RUN_SSE=1 --PORT=3010
# Use default Stdio transport
node your-app.js --GITHUB_PERSONAL_TOKEN=your_github_token_here
If you need to programmatically start the server with specific transport options:
import {
startGitHubProjectManagerServer,
startGitHubProjectManagerServerSSE,
} from '@monsoft/mcp-github-project-manager';
// Start with Stdio transport
await startGitHubProjectManagerServer('your_github_token_here');
// Or start with SSE transport
await startGitHubProjectManagerServerSSE('your_github_token_here', 3010);
const newIssue = await manager.createIssue({
owner: 'organization-name',
repo: 'repository-name',
title: 'Issue title',
body: 'Detailed description of the issue',
labels: ['bug', 'priority-high'],
assignees: ['username1', 'username2'],
});
const issue = await manager.getIssue({
owner: 'organization-name',
repo: 'repository-name',
issue_number: 123,
});
await manager.updateIssue({
owner: 'organization-name',
repo: 'repository-name',
issue_number: 123,
title: 'Updated title',
body: 'Updated description',
state: 'closed',
});
const issues = await manager.listIssues({
owner: 'organization-name',
repo: 'repository-name',
state: 'open',
labels: ['bug'],
sort: 'created',
direction: 'desc',
});
await manager.addIssueComment({
owner: 'organization-name',
repo: 'repository-name',
issue_number: 123,
body: 'This is a comment',
});
const pr = await manager.createPullRequest({
owner: 'organization-name',
repo: 'repository-name',
title: 'Pull request title',
body: 'Description of changes',
head: 'feature-branch',
base: 'main',
});
const pullRequest = await manager.getPullRequest({
owner: 'organization-name',
repo: 'repository-name',
pull_number: 456,
});
await manager.mergePullRequest({
owner: 'organization-name',
repo: 'repository-name',
pull_number: 456,
merge_method: 'squash',
});
await manager.createPullRequestReview({
owner: 'organization-name',
repo: 'repository-name',
pull_number: 456,
event: 'APPROVE',
body: 'LGTM! Great work.',
});
const project = await manager.createProject({
owner: 'organization-name',
name: 'Project Name',
body: 'Project description',
});
// Get all fields in a project including Status, Assignees, etc.
const fields = await manager.getProjectFields({
projectId: 'graphql-project-id',
});
// Get just the Status field and its column options
const { statusFieldId, columns } = await manager.getProjectColumns({
projectId: 'graphql-project-id',
});
console.log('Status Field ID:', statusFieldId);
console.log('Available Columns:', columns);
// Example output:
// [
// { id: 'f75ad846', name: 'Todo' },
// { id: '47fc9ee4', name: 'In Progress' },
// { id: '98236657', name: 'Done' }
// ]
// Simple add without specifying column
await manager.addProjectItem({
projectId: 'graphql-project-id',
contentId: 'graphql-issue-id',
});
// Add and place in a specific column in one operation
await manager.addProjectItemWithColumn({
projectId: 'graphql-project-id',
contentId: 'graphql-issue-id',
fieldId: 'status-field-id', // Get this from getProjectColumns
columnId: 'column-id', // Get this from getProjectColumns
});
await manager.updateProjectItem({
projectId: 'graphql-project-id',
itemId: 'graphql-item-id',
fieldId: 'status-field-id', // Get this from getProjectColumns
columnId: 'target-column-id', // Get this from getProjectColumns
});
const items = await manager.listProjectItems({
projectId: 'graphql-project-id',
first: 50, // Optionally limit number of results
});
The package provides custom error classes for handling common error scenarios:
try {
// GitHub operations
} catch (error) {
if (error instanceof MissingGitHubTokenError) {
console.error('GitHub token is missing. Please provide one via command line.');
} else if (error instanceof AuthenticationError) {
console.error('Failed to authenticate with GitHub. Check your token.');
} else if (error instanceof RateLimitError) {
console.error('GitHub API rate limit exceeded.');
} else {
console.error('An unexpected error occurred:', error.message);
}
}
Available error classes:
-
MissingGitHubTokenError
: Thrown when a GitHub token is not provided -
AuthenticationError
: Thrown when authentication fails -
ResourceNotFoundError
: Thrown when a requested resource doesn't exist -
ValidationError
: Thrown when input validation fails -
RateLimitError
: Thrown when GitHub API rate limits are exceeded -
NetworkError
: Thrown when network communication issues occur -
GitHubApiError
: General error for GitHub API issues
Your GitHub personal access token needs the following permissions:
-
repo
- Full access to repositories -
project
- Access to projects -
issues
- Access to issues
npm run build
npm run validate
npm test
npm run lint
MIT