Skip to content

valiot/mcp-deployable

Repository files navigation

GitHub MCP Server

A Model Context Protocol (MCP) server for GitHub operations, enabling LLMs to interact with GitHub repositories through a standardized interface. Deployable to Cloudflare Workers for production use.

Features

  • 🔌 MCP Protocol Compliant: Works with any MCP-compatible LLM (OpenAI, Claude, Cursor, etc.)
  • 🚀 9 GitHub Operations: Comprehensive PR management capabilities
  • Type-Safe: Full TypeScript with runtime validation using Zod
  • ☁️ Cloudflare Workers Ready: Deploy to the edge with zero configuration
  • 🧪 Tested: Golden tests for schema and behavior validation
  • 🔐 Secure: GitHub Personal Access Token authentication

Available Tools

  1. list_prs - List pull requests with filters (state, base, head)
  2. get_pr - Get detailed PR information
  3. create_pr - Create new pull request
  4. update_pr - Update PR title, description, state, or base branch
  5. add_pr_comment - Add comment to a PR
  6. merge_pr - Merge PR with specified method (merge/squash/rebase)
  7. request_pr_reviewers - Request PR reviewers (users or teams)
  8. add_pr_labels - Add labels to PR
  9. remove_pr_labels - Remove labels from PR

Architecture

┌─────────────┐
│     LLM     │  (OpenAI, Claude, Cursor, etc.)
│  (Client)   │
└──────┬──────┘
       │ MCP Protocol
       │ (stdio or HTTP)
       ▼
┌─────────────────┐
│   MCP Server    │
│  (This repo)    │
├─────────────────┤
│ • Tool Registry │
│ • Validation    │
│ • Error Handler │
└──────┬──────────┘
       │
       │ Octokit REST API
       ▼
┌─────────────────┐
│   GitHub API    │
└─────────────────┘

Setup

Prerequisites

  • Node.js 18+
  • GitHub Personal Access Token with appropriate permissions

Installation

# Clone or create project
npm install

# Set GitHub token
export GITHUB_TOKEN="ghp_your_token_here"

# Build project
npm run build

Creating a GitHub Token

  1. Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Generate new token with these scopes:
    • repo (Full control of private repositories)
    • read:org (if working with organization repos)
  3. Copy the token and set as GITHUB_TOKEN environment variable

Usage

Local Development (stdio)

Run the MCP server locally using stdio transport:

export GITHUB_TOKEN="your_token"
npm run dev

The server will run on stdio and can be connected to by MCP clients.

Test Client

Run the example test client to see the server in action:

export GITHUB_TOKEN="your_token"
npm run client

This will:

  1. Start the MCP server
  2. Connect via stdio transport
  3. List available tools
  4. Execute example operations (list PRs, get PR details)
  5. Display results

Integration with Cursor

To use with Cursor, add to your MCP configuration:

{
  "mcpServers": {
    "github": {
      "command": "node",
      "args": ["path/to/mcp-deployable/dist/server/index.js"],
      "env": {
        "GITHUB_TOKEN": "your_token_here"
      }
    }
  }
}

Integration with OpenAI

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { spawn } from 'child_process';
import OpenAI from 'openai';

// Start MCP server
const serverProcess = spawn('node', ['dist/server/index.js'], {
  env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN },
});

// Connect MCP client
const client = new Client({
  name: 'openai-github-client',
  version: '1.0.0',
}, { capabilities: {} });

const transport = new StdioClientTransport({ command: serverProcess });
await client.connect(transport);

// Get available tools
const tools = await client.listTools();

// Use with OpenAI
const openai = new OpenAI();
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [
    { role: 'user', content: 'List open PRs in owner/repo' }
  ],
  tools: tools.tools.map(tool => ({
    type: 'function',
    function: {
      name: tool.name,
      description: tool.description,
      parameters: tool.inputSchema,
    },
  })),
});

// Execute tool if requested
if (response.choices[0].message.tool_calls) {
  const toolCall = response.choices[0].message.tool_calls[0];
  const result = await client.callTool({
    name: toolCall.function.name,
    arguments: JSON.parse(toolCall.function.arguments),
  });
  console.log(result);
}

Cloudflare Workers Deployment

Prerequisites

  • Cloudflare account
  • Wrangler CLI installed (npm install -g wrangler)

Deploy

# Build worker bundle
npm run build:worker

# Set GitHub token as secret
wrangler secret put GITHUB_TOKEN

# Deploy to Cloudflare Workers
npm run deploy

HTTP API

Once deployed, the worker exposes these endpoints:

Health Check

curl https://your-worker.workers.dev/health

List Tools

curl https://your-worker.workers.dev/tools

Invoke Tool

curl -X POST https://your-worker.workers.dev/invoke \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "list_prs",
    "arguments": {
      "owner": "octocat",
      "repo": "hello-world",
      "state": "open"
    }
  }'

Development

Project Structure

mcp-deployable/
├── src/
│   ├── server/
│   │   ├── index.ts          # MCP server (stdio)
│   │   ├── tools/
│   │   │   └── github-tools.ts  # GitHub API operations
│   │   └── schemas/
│   │       └── tools.ts      # Zod schemas
│   ├── client/
│   │   └── test-client.ts    # Example client
│   ├── types/
│   │   └── github.ts         # TypeScript types
│   └── worker.ts             # Cloudflare Workers entry
├── tests/
│   └── golden/
│       ├── github-tools.test.ts  # Golden tests
│       └── fixtures/         # Mock responses
├── wrangler.toml             # Workers config
├── package.json
└── tsconfig.json

Running Tests

# Run all tests
npm test

# Run golden tests only
npm run test:golden

# Run tests in watch mode
npm test -- --watch

Scripts

  • npm run build - Build TypeScript and worker bundle
  • npm run dev - Run MCP server locally (stdio)
  • npm run client - Run test client
  • npm test - Run test suite
  • npm run deploy - Deploy to Cloudflare Workers

Tool Examples

List Pull Requests

{
  "tool": "list_prs",
  "arguments": {
    "owner": "modelcontextprotocol",
    "repo": "typescript-sdk",
    "state": "open",
    "per_page": 10
  }
}

Get Pull Request Details

{
  "tool": "get_pr",
  "arguments": {
    "owner": "modelcontextprotocol",
    "repo": "typescript-sdk",
    "pull_number": 42
  }
}

Create Pull Request

{
  "tool": "create_pr",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "title": "Add new feature",
    "body": "This PR adds feature X",
    "head": "feature-branch",
    "base": "main",
    "draft": false
  }
}

Update Pull Request

{
  "tool": "update_pr",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "pull_number": 42,
    "title": "Updated title",
    "body": "Updated description"
  }
}

Add Comment

{
  "tool": "add_pr_comment",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "pull_number": 42,
    "body": "Great work! LGTM 👍"
  }
}

Merge Pull Request

{
  "tool": "merge_pr",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "pull_number": 42,
    "merge_method": "squash",
    "commit_title": "feat: add new feature"
  }
}

Request Reviewers

{
  "tool": "request_pr_reviewers",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "pull_number": 42,
    "reviewers": ["user1", "user2"],
    "team_reviewers": ["team-alpha"]
  }
}

Manage Labels

{
  "tool": "add_pr_labels",
  "arguments": {
    "owner": "myorg",
    "repo": "myrepo",
    "pull_number": 42,
    "labels": ["bug", "high-priority"]
  }
}

Error Handling

All tools include comprehensive error handling:

  • Validation Errors: Input parameters are validated using Zod schemas
  • GitHub API Errors: HTTP errors from GitHub API are caught and formatted
  • Rate Limiting: GitHub API rate limit errors are properly surfaced
  • Authentication Errors: Missing or invalid tokens return clear error messages

Example error response:

{
  "error": "GitHub API error (404): Not Found",
  "code": "INTERNAL_ERROR"
}

Security

  • Authentication: Uses GitHub Personal Access Token (PAT)
  • Least Privilege: Configure tokens with only necessary scopes
  • Environment Variables: Secrets stored in env vars, never committed
  • Input Validation: All inputs validated before GitHub API calls

License

MIT

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Support

For issues or questions:

About

Model Context Protocol (MCP) server for GitHub operations - deployable to Cloudflare Workers

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published