Skip to content

Latest commit

 

History

History
327 lines (248 loc) · 14.1 KB

File metadata and controls

327 lines (248 loc) · 14.1 KB

GitHub MCP Server - Agent Instructions

This file follows the agents.md convention for AI agent instructions.

AI Disclosure Requirement

If you are using AI assistance to contribute to this repository, you must disclose it in the pull request or issue body.

Include a brief statement like:

  • "This PR was written with assistance from [agent name]."
  • "I used [tool] to help generate this code."

This helps maintainers understand the context and apply appropriate review scrutiny.

Project Overview

This is the GitHub MCP Server, a Model Context Protocol (MCP) server that connects AI tools to GitHub's platform. It enables AI agents to manage repositories, issues, pull requests, workflows, and more through natural language.

Key Details:

  • Language: Go 1.24+ (~38k lines of code)
  • Type: MCP server application with CLI interface
  • Primary Package: github-mcp-server (stdio MCP server - this is the main focus)
  • Secondary Package: mcpcurl (testing utility - don't break it, but not the priority)
  • Framework: Uses modelcontextprotocol/go-sdk for MCP protocol, google/go-github for GitHub API
  • Size: ~60MB repository, 70 Go files
  • Library Usage: This repository is also used as a library by the remote server. Functions that could be called by other repositories should be exported (capitalized), even if not required internally. Preserve existing export patterns.

Code Quality Standards:

  • Popular Open Source Repository - High bar for code quality and clarity
  • Comprehension First - Code must be clear to a wide audience
  • Clean Commits - Atomic, focused changes with clear messages
  • Structure - Always maintain or improve, never degrade
  • Code over Comments - Prefer self-documenting code; comment only when necessary

Critical Build & Validation Steps

Required Commands (Run Before Committing)

ALWAYS run these commands in this exact order before using report_progress or finishing work:

  1. Format Code: script/lint (runs gofmt -s -w . then golangci-lint)
  2. Run Tests: script/test (runs go test -race ./...)
  3. Update Documentation: script/generate-docs (if you modified MCP tools/toolsets)

These commands are FAST: Lint ~1s, Tests ~1s (cached), Build ~1s

When Modifying MCP Tools/Endpoints

If you change any MCP tool definitions or schemas:

  1. Run tests with UPDATE_TOOLSNAPS=true go test ./... to update toolsnaps
  2. Commit the updated .snap files in pkg/github/__toolsnaps__/
  3. Run script/generate-docs to update README.md
  4. Toolsnaps document API surface and ensure changes are intentional

Common Build Commands

# Download dependencies (rarely needed - usually cached)
go mod download

# Build the server binary
go build -v ./cmd/github-mcp-server

# Run the server
./github-mcp-server stdio

# Run specific package tests
go test ./pkg/github -v

# Run specific test
go test ./pkg/github -run TestGetMe

Testing with MCP Inspector

Use the MCP Inspector CLI to test the server:

# Build the server first
go build -v ./cmd/github-mcp-server

# List available tools
npx @modelcontextprotocol/inspector@0.7.0 --cli \
  --config '{"mcpServers":{"github":{"command":"./github-mcp-server","args":["stdio"],"env":{"GITHUB_PERSONAL_ACCESS_TOKEN":"your-token"}}}}' \
  --server github \
  --method tools/list

# Call a specific tool (e.g., get authenticated user)
npx @modelcontextprotocol/inspector@0.7.0 --cli \
  --config '{"mcpServers":{"github":{"command":"./github-mcp-server","args":["stdio"],"env":{"GITHUB_PERSONAL_ACCESS_TOKEN":"your-token"}}}}' \
  --server github \
  --method tools/call --tool-name get_me

Note: Replace your-token with a valid GitHub Personal Access Token.

Project Structure

Directory Layout

.
├── cmd/
│   ├── github-mcp-server/    # Main MCP server entry point (PRIMARY FOCUS)
│   └── mcpcurl/              # MCP testing utility (secondary - don't break it)
├── pkg/                      # Public API packages
│   ├── github/               # GitHub API MCP tools implementation
│   │   └── __toolsnaps__/    # Tool schema snapshots (*.snap files)
│   ├── toolsets/             # Toolset configuration & management
│   ├── errors/               # Error handling utilities
│   ├── sanitize/             # HTML/content sanitization
│   ├── log/                  # Logging utilities
│   ├── raw/                  # Raw data handling
│   ├── buffer/               # Buffer utilities
│   └── translations/         # i18n translation support
├── internal/                 # Internal implementation packages
│   ├── ghmcp/                # GitHub MCP server core logic
│   ├── githubv4mock/         # GraphQL API mocking for tests
│   ├── toolsnaps/            # Toolsnap validation system
│   └── profiler/             # Performance profiling
├── e2e/                      # End-to-end tests (require GitHub PAT)
├── script/                   # Build and maintenance scripts
├── docs/                     # Documentation
├── .github/workflows/        # CI/CD workflows
└── [config files]            # See below

Key Configuration Files

  • go.mod / go.sum: Go module dependencies (Go 1.24.0+)
  • .golangci.yml: Linter configuration (v2 format, ~15 linters enabled)
  • Dockerfile: Multi-stage build (golang:1.25.3-alpine → distroless)
  • server.json: MCP server metadata for registry
  • .goreleaser.yaml: Release automation config
  • .gitignore: Excludes bin/, dist/, vendor/, *.DS_Store, github-mcp-server binary

Important Scripts (script/ directory)

  • script/lint - Runs gofmt + golangci-lint. MUST RUN before committing
  • script/test - Runs go test -race ./... (full test suite)
  • script/generate-docs - Updates README.md tool documentation. Run after tool changes
  • script/licenses - Updates third-party license files when dependencies change
  • script/licenses-check - Validates license compliance (runs in CI)
  • script/get-me - Quick test script for get_me tool
  • script/get-discussions - Quick test for discussions
  • script/tag-release - NEVER USE THIS - releases are managed separately

GitHub Workflows (CI/CD)

All workflows run on push/PR unless noted. Located in .github/workflows/:

  1. go.yml - Build and test on ubuntu/windows/macos. Runs script/test and builds binary
  2. lint.yml - Runs golangci-lint-action v2.5 (GitHub Action) with actions/setup-go stable
  3. docs-check.yml - Verifies README.md is up-to-date by running generate-docs and checking git diff
  4. code-scanning.yml - CodeQL security analysis for Go and GitHub Actions
  5. license-check.yml - Runs script/licenses-check to validate compliance
  6. docker-publish.yml - Publishes container image to ghcr.io
  7. goreleaser.yml - Creates releases (main branch only)
  8. registry-releaser.yml - Updates MCP registry

All of these must pass for PR merge. If docs-check fails, run script/generate-docs and commit changes.

Testing Guidelines

Unit Tests

  • Use testify for assertions (require for critical checks, assert for non-blocking)
  • Tests are in *_test.go files alongside implementation (internal tests, not _test package)
  • Mock GitHub API with go-github-mock (REST) or githubv4mock (GraphQL)
  • Test structure for tools:
    1. Test tool snapshot
    2. Verify critical schema properties (e.g., ReadOnly annotation)
    3. Table-driven behavioral tests

Toolsnaps (Tool Schema Snapshots)

  • Every MCP tool has a JSON schema snapshot in pkg/github/__toolsnaps__/*.snap
  • Tests fail if current schema differs from snapshot (shows diff)
  • To update after intentional changes: UPDATE_TOOLSNAPS=true go test ./...
  • MUST commit updated .snap files - they document API changes
  • Missing snapshots cause CI failure

End-to-End Tests

  • Located in e2e/ directory with e2e_test.go
  • Require GitHub PAT token - you usually cannot run these yourself
  • Run with: GITHUB_MCP_SERVER_E2E_TOKEN=<token> go test -v --tags e2e ./e2e
  • Tests interact with live GitHub API via Docker container
  • Keep e2e tests updated when changing MCP tools
  • Use only the e2e test style when modifying tests in this directory
  • For debugging: GITHUB_MCP_SERVER_E2E_DEBUG=true runs in-process (no Docker)

Code Style & Linting

Go Code Requirements

  • gofmt with simplify flag (-s) - Automatically run by script/lint
  • golangci-lint with these linters enabled:
    • bodyclose, gocritic, gosec, makezero, misspell, nakedret, revive
    • errcheck, staticcheck, govet, ineffassign, unused
  • Exclusions for: third_party/, builtin/, examples/, generated code

Go Naming Conventions

  • Acronyms in identifiers: Use ID not Id, API not Api, URL not Url, HTTP not Http
  • Examples: userID, getAPI, parseURL, HTTPClient
  • This applies to variable names, function names, struct fields, etc.

Code Patterns

  • Keep changes minimal and focused on the specific issue being addressed
  • Prefer clarity over cleverness - code must be understandable by a wide audience
  • Atomic commits - each commit should be a complete, logical change
  • Maintain or improve structure - never degrade code organization
  • Use table-driven tests for behavioral testing
  • Comment sparingly - code should be self-documenting
  • Follow standard Go conventions (Effective Go, Go proverbs)
  • Test changes thoroughly before committing
  • Export functions (capitalize) if they could be used by other repos as a library

Common Development Workflows

Adding a New MCP Tool

  1. Add tool implementation in pkg/github/ (e.g., foo_tools.go)
  2. Register tool in appropriate toolset in pkg/github/ or pkg/toolsets/
  3. Write unit tests following the tool test pattern
  4. Run UPDATE_TOOLSNAPS=true go test ./... to create snapshot
  5. Run script/generate-docs to update README
  6. Run script/lint and script/test before committing
  7. If e2e tests are relevant, update e2e/e2e_test.go using existing test style
  8. Commit code + snapshots + README changes together

Fixing a Bug

  1. Write a failing test that reproduces the bug
  2. Fix the bug with minimal changes
  3. Verify test passes and existing tests still pass
  4. Run script/lint and script/test
  5. If tool schema changed, update toolsnaps (see above)

Updating Dependencies

  1. Update go.mod (e.g., go get -u ./... or manually)
  2. Run go mod tidy
  3. Run script/licenses to update license files
  4. Run script/test to verify nothing broke
  5. Commit go.mod, go.sum, and third-party-licenses* files

Common Errors & Solutions

"Documentation is out of date" in CI

Fix: Run script/generate-docs and commit README.md changes

Toolsnap mismatch failures

Fix: Run UPDATE_TOOLSNAPS=true go test ./... and commit updated .snap files

Lint failures

Fix: Run script/lint locally - it will auto-format and show issues. Fix manually reported issues.

License check failures

Fix: Run script/licenses to regenerate license files after dependency changes

Test failures after changing a tool

Likely causes:

  1. Forgot to update toolsnaps - run with UPDATE_TOOLSNAPS=true
  2. Changed behavior broke existing tests - verify intent and fix tests
  3. Schema change not reflected in test - update test expectations

Environment Variables

  • GITHUB_PERSONAL_ACCESS_TOKEN - Required for server operation and e2e tests
  • GITHUB_HOST - For GitHub Enterprise Server (prefix with https://)
  • GITHUB_TOOLSETS - Comma-separated toolset list (overrides --toolsets flag)
  • GITHUB_READ_ONLY - Set to "1" for read-only mode
  • GITHUB_DYNAMIC_TOOLSETS - Set to "1" for dynamic toolset discovery
  • UPDATE_TOOLSNAPS - Set to "true" when running tests to update snapshots
  • GITHUB_MCP_SERVER_E2E_TOKEN - Token for e2e tests
  • GITHUB_MCP_SERVER_E2E_DEBUG - Set to "true" for in-process e2e debugging

Key Files Reference

Root Directory Files

.dockerignore        - Docker build exclusions
.gitignore          - Git exclusions (includes bin/, dist/, vendor/, binaries)
.golangci.yml       - Linter configuration
.goreleaser.yaml    - Release automation
CODE_OF_CONDUCT.md  - Community guidelines
CONTRIBUTING.md     - Contribution guide (fork, clone, test, lint workflow)
Dockerfile          - Multi-stage Go build
LICENSE             - MIT license
README.md           - Main documentation (auto-generated sections)
SECURITY.md         - Security policy
SUPPORT.md          - Support resources
gemini-extension.json - Gemini CLI configuration
go.mod / go.sum     - Go dependencies
server.json         - MCP server registry metadata

Main Entry Point

cmd/github-mcp-server/main.go - Uses cobra for CLI, viper for config, supports:

  • stdio command (default) - MCP stdio transport
  • generate-docs command - Documentation generation
  • Flags: --toolsets, --read-only, --dynamic-toolsets, --gh-host, --log-file

Important Reminders

  1. PRIMARY FOCUS: The local stdio MCP server (github-mcp-server) - this is what you should work on and test with
  2. REMOTE SERVER: Ignore remote server instructions when making code changes (unless specifically asked). This repo is used as a library by the remote server, so keep functions exported (capitalized) if they could be called by other repos, even if not needed internally.
  3. ALWAYS trust these instructions first - only search if information is incomplete or incorrect
  4. NEVER use script/tag-release or push tags
  5. NEVER skip script/lint before committing Go code changes
  6. ALWAYS update toolsnaps when changing MCP tool schemas
  7. ALWAYS run script/generate-docs after modifying tools
  8. For specific test files, use go test ./path -run TestName not full suite
  9. E2E tests require PAT token - you likely cannot run them
  10. Toolsnaps are API documentation - treat changes seriously
  11. Build/test/lint are very fast (~1s each) - run frequently
  12. CI failures for docs-check or license-check have simple fixes (run the script)
  13. mcpcurl is secondary - don't break it, but it's not the priority