# GitHub Project Manager

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.

## Projects v2 API Update

This package has been updated to use GitHub's Projects v2 API instead of the deprecated classic Projects API.

### Key Changes:

- 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

### Getting a Project ID:

To find a Project ID for use with this API, you can use the following GraphQL query:

```graphql
query {
    organization(login: "YOUR_ORG_NAME") {
        projectV2(number: PROJECT_NUMBER) {
            id
        }
    }
}
```

Or for user projects:

```graphql
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`).

## Features

### GitHub Issue Management

- Create issues
- Update issues
- List issues with filtering options
- Get issue details
- Add comments to issues
- Close issues

### GitHub Pull Request Management

- 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

### GitHub Project Management

- Create projects
- Add issues to projects
- Update project items (move between columns)
- List project items

## Installation

```bash
npm install @monsoft/mcp-github-project-manager
```

## Usage

### Quick Start with npx

The quickest way to use the GitHub Project Manager is directly with npx:

```bash
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.

### Transport Options

The GitHub Project Manager supports two transport methods:

#### Stdio Transport (Default)

This is the default transport, ideal for direct CLI integrations and local usage:

```bash
# Start with default Stdio transport
npx -y @monsoft/mcp-github-project-manager --GITHUB_PERSONAL_TOKEN=your_github_token_here
```

#### Server-Sent Events (SSE) Transport

For remote setups and web integrations, you can use the SSE transport which starts an HTTP server:

```bash
# 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`

### Setting Up with MCP Clients

To use this with AI assistants like Claude in Anthropic or Cursor:

```bash
# 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.

### Programmatic Usage

To use the GitHub Project Manager in your own code:

```typescript
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:

```bash
node your-app.js --GITHUB_PERSONAL_TOKEN=your_github_token_here
```

You can also specify the transport type and other options:

```bash
# 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:

```typescript
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);
```

## API Reference

### Issue Management

#### Create an Issue

```typescript
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'],
});
```

#### Get Issue Details

```typescript
const issue = await manager.getIssue({
    owner: 'organization-name',
    repo: 'repository-name',
    issue_number: 123,
});
```

#### Update an Issue

```typescript
await manager.updateIssue({
    owner: 'organization-name',
    repo: 'repository-name',
    issue_number: 123,
    title: 'Updated title',
    body: 'Updated description',
    state: 'closed',
});
```

#### List Issues

```typescript
const issues = await manager.listIssues({
    owner: 'organization-name',
    repo: 'repository-name',
    state: 'open',
    labels: ['bug'],
    sort: 'created',
    direction: 'desc',
});
```

#### Add Issue Comment

```typescript
await manager.addIssueComment({
    owner: 'organization-name',
    repo: 'repository-name',
    issue_number: 123,
    body: 'This is a comment',
});
```

### Pull Request Management

#### Create a Pull Request

```typescript
const pr = await manager.createPullRequest({
    owner: 'organization-name',
    repo: 'repository-name',
    title: 'Pull request title',
    body: 'Description of changes',
    head: 'feature-branch',
    base: 'main',
});
```

#### Get Pull Request Details

```typescript
const pullRequest = await manager.getPullRequest({
    owner: 'organization-name',
    repo: 'repository-name',
    pull_number: 456,
});
```

#### Merge a Pull Request

```typescript
await manager.mergePullRequest({
    owner: 'organization-name',
    repo: 'repository-name',
    pull_number: 456,
    merge_method: 'squash',
});
```

#### Create a Review

```typescript
await manager.createPullRequestReview({
    owner: 'organization-name',
    repo: 'repository-name',
    pull_number: 456,
    event: 'APPROVE',
    body: 'LGTM! Great work.',
});
```

### Project Management

#### Create a Project

```typescript
const project = await manager.createProject({
    owner: 'organization-name',
    name: 'Project Name',
    body: 'Project description',
});
```

#### Get Project Fields and Columns

```typescript
// 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' }
// ]
```

#### Add Item to Project

```typescript
// 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
});
```

#### Move Item Between Columns

```typescript
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
});
```

#### List Project Items

```typescript
const items = await manager.listProjectItems({
    projectId: 'graphql-project-id',
    first: 50, // Optionally limit number of results
});
```

## Error Handling

The package provides custom error classes for handling common error scenarios:

```typescript
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

## GitHub Token Permissions

Your GitHub personal access token needs the following permissions:

- `repo` - Full access to repositories
- `project` - Access to projects
- `issues` - Access to issues

## Development

### Building

```bash
npm run build
```

### Validation

```bash
npm run validate
```

### Testing

```bash
npm test
```

### Linting

```bash
npm run lint
```

## License

MIT
