|
| 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 | +go test ./pkg/github -v |
| 49 | + |
| 50 | +# Run specific test |
| 51 | +go test ./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 |
0 commit comments