|
| 1 | +#GitHub MCP Server - Copilot Instructions |
| 2 | + |
| 3 | +##Project Overview |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +**Key Details:** |
| 8 | +-**Language:** Go 1.24+ (~38k lines of code) |
| 9 | +-**Type:** MCP server application with CLI interface |
| 10 | +-**Primary Package:** github-mcp-server (stdio MCP server -**this is the main focus**) |
| 11 | +-**Secondary Package:** mcpcurl (testing utility - don't break it, but not the priority) |
| 12 | +-**Framework:** Uses mark3labs/mcp-go for MCP protocol, google/go-github for GitHub API |
| 13 | +-**Size:**~60MB repository, 70 Go files |
| 14 | + |
| 15 | +##Critical Build & Validation Steps |
| 16 | + |
| 17 | +###Required Commands (Run Before Committing) |
| 18 | + |
| 19 | +**ALWAYS run these commands in this exact order before using report_progress or finishing work:** |
| 20 | + |
| 21 | +1.**Format Code:**`script/lint` (this runs`gofmt -s -w .` then`golangci-lint`) |
| 22 | +2.**Run Tests:**`script/test` (runs`go test -race ./...`) |
| 23 | +3.**Update Documentation:**`script/generate-docs` (if you modified MCP tools/toolsets) |
| 24 | + |
| 25 | +**These commands are FAST:** Lint~1s, Tests~1s (cached), Build~1s |
| 26 | + |
| 27 | +###When Modifying MCP Tools/Endpoints |
| 28 | + |
| 29 | +If you change any MCP tool definitions or schemas: |
| 30 | +1. Run tests with`UPDATE_TOOLSNAPS=true go test ./...` to update toolsnaps |
| 31 | +2. Commit the updated`.snap` files in`pkg/github/__toolsnaps__/` |
| 32 | +3. Run`script/generate-docs` to update README.md |
| 33 | +4. Toolsnaps document API surface and ensure changes are intentional |
| 34 | + |
| 35 | +###Common Build Commands |
| 36 | + |
| 37 | +```bash |
| 38 | +# Download dependencies (rarely needed - usually cached) |
| 39 | +go mod download |
| 40 | + |
| 41 | +# Build the server binary |
| 42 | +go build -v ./cmd/github-mcp-server |
| 43 | + |
| 44 | +# Run the server |
| 45 | +./github-mcp-server stdio |
| 46 | + |
| 47 | +# Run specific package tests |
| 48 | +gotest ./pkg/github -v |
| 49 | + |
| 50 | +# Run specific test |
| 51 | +gotest ./pkg/github -run TestGetMe |
| 52 | +``` |
| 53 | + |
| 54 | +##Project Structure |
| 55 | + |
| 56 | +###Directory Layout |
| 57 | + |
| 58 | +``` |
| 59 | +. |
| 60 | +├── cmd/ |
| 61 | +│ ├── github-mcp-server/ # Main MCP server entry point (PRIMARY FOCUS) |
| 62 | +│ └── mcpcurl/ # MCP testing utility (secondary - don't break it) |
| 63 | +├── pkg/ # Public API packages |
| 64 | +│ ├── github/ # GitHub API MCP tools implementation |
| 65 | +│ │ └── __toolsnaps__/ # Tool schema snapshots (*.snap files) |
| 66 | +│ ├── toolsets/ # Toolset configuration & management |
| 67 | +│ ├── errors/ # Error handling utilities |
| 68 | +│ ├── sanitize/ # HTML/content sanitization |
| 69 | +│ ├── log/ # Logging utilities |
| 70 | +│ ├── raw/ # Raw data handling |
| 71 | +│ ├── buffer/ # Buffer utilities |
| 72 | +│ └── translations/ # i18n translation support |
| 73 | +├── internal/ # Internal implementation packages |
| 74 | +│ ├── ghmcp/ # GitHub MCP server core logic |
| 75 | +│ ├── githubv4mock/ # GraphQL API mocking for tests |
| 76 | +│ ├── toolsnaps/ # Toolsnap validation system |
| 77 | +│ └── profiler/ # Performance profiling |
| 78 | +├── e2e/ # End-to-end tests (require GitHub PAT) |
| 79 | +├── script/ # Build and maintenance scripts |
| 80 | +├── docs/ # Documentation |
| 81 | +├── .github/workflows/ # CI/CD workflows |
| 82 | +└── [config files] # See below |
| 83 | +``` |
| 84 | + |
| 85 | +###Key Configuration Files |
| 86 | + |
| 87 | +-**go.mod / go.sum:** Go module dependencies (Go 1.24.0+) |
| 88 | +-**.golangci.yml:** Linter configuration (v2 format,~15 linters enabled) |
| 89 | +-**Dockerfile:** Multi-stage build (golang:1.25.3-alpine → distroless) |
| 90 | +-**server.json:** MCP server metadata for registry |
| 91 | +-**.goreleaser.yaml:** Release automation config |
| 92 | +-**.gitignore:** Excludes bin/, dist/, vendor/,*.DS_Store, github-mcp-server binary |
| 93 | + |
| 94 | +###Important Scripts (script/ directory) |
| 95 | + |
| 96 | +-**script/lint** - Runs`gofmt` +`golangci-lint`.**MUST RUN** before committing |
| 97 | +-**script/test** - Runs`go test -race ./...` (full test suite) |
| 98 | +-**script/generate-docs** - Updates README.md tool documentation. Run after tool changes |
| 99 | +-**script/licenses** - Updates third-party license files when dependencies change |
| 100 | +-**script/licenses-check** - Validates license compliance (runs in CI) |
| 101 | +-**script/get-me** - Quick test script for get_me tool |
| 102 | +-**script/get-discussions** - Quick test for discussions |
| 103 | +-**script/tag-release** -**NEVER USE THIS** - releases are managed separately |
| 104 | + |
| 105 | +##GitHub Workflows (CI/CD) |
| 106 | + |
| 107 | +All workflows run on push/PR unless noted. Located in`.github/workflows/`: |
| 108 | + |
| 109 | +1.**go.yml** - Build and test on ubuntu/windows/macos. Runs`script/test` and builds binary |
| 110 | +2.**lint.yml** - Runs golangci-lint v2.5 with actions/setup-go stable |
| 111 | +3.**docs-check.yml** - Verifies README.md is up-to-date by running generate-docs and checking git diff |
| 112 | +4.**code-scanning.yml** - CodeQL security analysis for Go and GitHub Actions |
| 113 | +5.**license-check.yml** - Runs`script/licenses-check` to validate compliance |
| 114 | +6.**docker-publish.yml** - Publishes container image to ghcr.io |
| 115 | +7.**goreleaser.yml** - Creates releases (main branch only) |
| 116 | +8.**registry-releaser.yml** - Updates MCP registry |
| 117 | + |
| 118 | +**All of these must pass for PR merge.** If docs-check fails, run`script/generate-docs` and commit changes. |
| 119 | + |
| 120 | +##Testing Guidelines |
| 121 | + |
| 122 | +###Unit Tests |
| 123 | + |
| 124 | +- Use`testify` for assertions (`require` for critical checks,`assert` for non-blocking) |
| 125 | +- Tests are in`*_test.go` files alongside implementation (internal tests, not`_test` package) |
| 126 | +- Mock GitHub API with`go-github-mock` (REST) or`githubv4mock` (GraphQL) |
| 127 | +- Test structure for tools: |
| 128 | +1. Test tool snapshot |
| 129 | +2. Verify critical schema properties (e.g., ReadOnly annotation) |
| 130 | +3. Table-driven behavioral tests |
| 131 | + |
| 132 | +###Toolsnaps (Tool Schema Snapshots) |
| 133 | + |
| 134 | +- Every MCP tool has a JSON schema snapshot in`pkg/github/__toolsnaps__/*.snap` |
| 135 | +- Tests fail if current schema differs from snapshot (shows diff) |
| 136 | +- To update after intentional changes:`UPDATE_TOOLSNAPS=true go test ./...` |
| 137 | +-**MUST commit updated .snap files** - they document API changes |
| 138 | +- Missing snapshots cause CI failure |
| 139 | + |
| 140 | +###End-to-End Tests |
| 141 | + |
| 142 | +- Located in`e2e/` directory with`e2e_test.go` |
| 143 | +-**Require GitHub PAT token** - you usually cannot run these yourself |
| 144 | +- Run with:`GITHUB_MCP_SERVER_E2E_TOKEN=<token> go test -v --tags e2e ./e2e` |
| 145 | +- Tests interact with live GitHub API via Docker container |
| 146 | +-**Keep e2e tests updated when changing MCP tools** |
| 147 | +-**Use only the e2e test style** when modifying tests in this directory |
| 148 | +- For debugging:`GITHUB_MCP_SERVER_E2E_DEBUG=true` runs in-process (no Docker) |
| 149 | + |
| 150 | +##Code Style & Linting |
| 151 | + |
| 152 | +###Go Code Requirements |
| 153 | + |
| 154 | +-**gofmt with simplify flag (-s)** - Automatically run by`script/lint` |
| 155 | +-**golangci-lint v2.5.0** with these linters enabled: |
| 156 | +- bodyclose, gocritic, gosec, makezero, misspell, nakedret, revive |
| 157 | +- errcheck, staticcheck, govet, ineffassign, unused |
| 158 | +- Exclusions for: third_party/, builtin/, examples/, generated code |
| 159 | + |
| 160 | +###Go Naming Conventions |
| 161 | + |
| 162 | +-**Acronyms in identifiers:** Use`ID` not`Id`,`API` not`Api`,`URL` not`Url`,`HTTP` not`Http` |
| 163 | +- Examples:`userID`,`getAPI`,`parseURL`,`HTTPClient` |
| 164 | +- This applies to variable names, function names, struct fields, etc. |
| 165 | + |
| 166 | +###Code Patterns |
| 167 | + |
| 168 | +-**Keep changes minimal and focused** on the specific issue being addressed |
| 169 | +- Prefer explicit over clever code |
| 170 | +- Use table-driven tests for behavioral testing |
| 171 | +- Comment sparingly - code should be self-documenting |
| 172 | +- Follow standard Go conventions (Effective Go, Go proverbs) |
| 173 | +-**Test changes thoroughly** before committing |
| 174 | + |
| 175 | +##Common Development Workflows |
| 176 | + |
| 177 | +###Adding a New MCP Tool |
| 178 | + |
| 179 | +1. Add tool implementation in`pkg/github/` (e.g.,`foo_tools.go`) |
| 180 | +2. Register tool in appropriate toolset in`pkg/github/` or`pkg/toolsets/` |
| 181 | +3. Write unit tests following the tool test pattern |
| 182 | +4. Run`UPDATE_TOOLSNAPS=true go test ./...` to create snapshot |
| 183 | +5. Run`script/generate-docs` to update README |
| 184 | +6. Run`script/lint` and`script/test` before committing |
| 185 | +7. If e2e tests are relevant, update`e2e/e2e_test.go` using existing test style |
| 186 | +8. Commit code + snapshots + README changes together |
| 187 | + |
| 188 | +###Fixing a Bug |
| 189 | + |
| 190 | +1. Write a failing test that reproduces the bug |
| 191 | +2. Fix the bug with minimal changes |
| 192 | +3. Verify test passes and existing tests still pass |
| 193 | +4. Run`script/lint` and`script/test` |
| 194 | +5. If tool schema changed, update toolsnaps (see above) |
| 195 | + |
| 196 | +###Updating Dependencies |
| 197 | + |
| 198 | +1. Update`go.mod` (e.g.,`go get -u ./...` or manually) |
| 199 | +2. Run`go mod tidy` |
| 200 | +3. Run`script/licenses` to update license files |
| 201 | +4. Run`script/test` to verify nothing broke |
| 202 | +5. Commit go.mod, go.sum, and third-party-licenses* files |
| 203 | + |
| 204 | +##Common Errors & Solutions |
| 205 | + |
| 206 | +###"Documentation is out of date" in CI |
| 207 | + |
| 208 | +**Fix:** Run`script/generate-docs` and commit README.md changes |
| 209 | + |
| 210 | +###Toolsnap mismatch failures |
| 211 | + |
| 212 | +**Fix:** Run`UPDATE_TOOLSNAPS=true go test ./...` and commit updated .snap files |
| 213 | + |
| 214 | +###Lint failures |
| 215 | + |
| 216 | +**Fix:** Run`script/lint` locally - it will auto-format and show issues. Fix manually reported issues. |
| 217 | + |
| 218 | +###License check failures |
| 219 | + |
| 220 | +**Fix:** Run`script/licenses` to regenerate license files after dependency changes |
| 221 | + |
| 222 | +###Test failures after changing a tool |
| 223 | + |
| 224 | +**Likely causes:** |
| 225 | +1. Forgot to update toolsnaps - run with`UPDATE_TOOLSNAPS=true` |
| 226 | +2. Changed behavior broke existing tests - verify intent and fix tests |
| 227 | +3. Schema change not reflected in test - update test expectations |
| 228 | + |
| 229 | +##Environment Variables |
| 230 | + |
| 231 | +-**GITHUB_PERSONAL_ACCESS_TOKEN** - Required for server operation and e2e tests |
| 232 | +-**GITHUB_HOST** - For GitHub Enterprise Server (prefix with`https://`) |
| 233 | +-**GITHUB_TOOLSETS** - Comma-separated toolset list (overrides --toolsets flag) |
| 234 | +-**GITHUB_READ_ONLY** - Set to "1" for read-only mode |
| 235 | +-**GITHUB_DYNAMIC_TOOLSETS** - Set to "1" for dynamic toolset discovery |
| 236 | +-**UPDATE_TOOLSNAPS** - Set to "true" when running tests to update snapshots |
| 237 | +-**GITHUB_MCP_SERVER_E2E_TOKEN** - Token for e2e tests |
| 238 | +-**GITHUB_MCP_SERVER_E2E_DEBUG** - Set to "true" for in-process e2e debugging |
| 239 | + |
| 240 | +##Key Files Reference |
| 241 | + |
| 242 | +###Root Directory Files |
| 243 | +``` |
| 244 | +.dockerignore - Docker build exclusions |
| 245 | +.gitignore - Git exclusions (includes bin/, dist/, vendor/, binaries) |
| 246 | +.golangci.yml - Linter configuration |
| 247 | +.goreleaser.yaml - Release automation |
| 248 | +CODE_OF_CONDUCT.md - Community guidelines |
| 249 | +CONTRIBUTING.md - Contribution guide (fork, clone, test, lint workflow) |
| 250 | +Dockerfile - Multi-stage Go build |
| 251 | +LICENSE - MIT license |
| 252 | +README.md - Main documentation (auto-generated sections) |
| 253 | +SECURITY.md - Security policy |
| 254 | +SUPPORT.md - Support resources |
| 255 | +gemini-extension.json - Gemini CLI configuration |
| 256 | +go.mod / go.sum - Go dependencies |
| 257 | +server.json - MCP server registry metadata |
| 258 | +``` |
| 259 | + |
| 260 | +###Main Entry Point |
| 261 | + |
| 262 | +`cmd/github-mcp-server/main.go` - Uses cobra for CLI, viper for config, supports: |
| 263 | +-`stdio` command (default) - MCP stdio transport |
| 264 | +-`generate-docs` command - Documentation generation |
| 265 | +- Flags: --toolsets, --read-only, --dynamic-toolsets, --gh-host, --log-file |
| 266 | + |
| 267 | +##Important Reminders |
| 268 | + |
| 269 | +1.**PRIMARY FOCUS:** The local stdio MCP server (github-mcp-server) - this is what you should work on and test with |
| 270 | +2.**ALWAYS** trust these instructions first - only search if information is incomplete or incorrect |
| 271 | +3.**NEVER** use`script/tag-release` or push tags |
| 272 | +4.**NEVER** skip`script/lint` before committing Go code changes |
| 273 | +5.**ALWAYS** update toolsnaps when changing MCP tool schemas |
| 274 | +6.**ALWAYS** run`script/generate-docs` after modifying tools |
| 275 | +7. For specific test files, use`go test ./path -run TestName` not full suite |
| 276 | +8. E2E tests require PAT token - you likely cannot run them |
| 277 | +9. Toolsnaps are API documentation - treat changes seriously |
| 278 | +10. Build/test/lint are very fast (~1s each) - run frequently |
| 279 | +11. CI failures for docs-check or license-check have simple fixes (run the script) |
| 280 | +12. mcpcurl is secondary - don't break it, but it's not the priority |