mcp-github-crunchtools 1.0.1__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. mcp_github_crunchtools-1.2.0/.github/workflows/ashigaru.yml +98 -0
  2. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/ci.yml +1 -1
  3. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/constitution.yml +1 -1
  4. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/dependabot-automerge.yml +1 -1
  5. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/gatehouse-retriage.yml +1 -1
  6. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/gatehouse.yml +2 -2
  7. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.pre-commit-config.yaml +6 -8
  8. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.specify/memory/constitution.md +18 -7
  9. mcp_github_crunchtools-1.2.0/.specify/specs/001-pr-merge-logs-release/spec.md +141 -0
  10. mcp_github_crunchtools-1.2.0/CHANGELOG.md +83 -0
  11. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/CLAUDE.md +21 -7
  12. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/Containerfile +3 -3
  13. mcp_github_crunchtools-1.2.0/PKG-INFO +374 -0
  14. mcp_github_crunchtools-1.2.0/README.md +348 -0
  15. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/SECURITY.md +105 -15
  16. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/pyproject.toml +2 -2
  17. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/server.json +3 -3
  18. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/__init__.py +1 -1
  19. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/client.py +160 -28
  20. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/models.py +80 -14
  21. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/server.py +255 -12
  22. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/tools/__init__.py +14 -0
  23. mcp_github_crunchtools-1.2.0/src/mcp_github_crunchtools/tools/actions.py +389 -0
  24. mcp_github_crunchtools-1.2.0/src/mcp_github_crunchtools/tools/pull_requests.py +526 -0
  25. mcp_github_crunchtools-1.2.0/src/mcp_github_crunchtools/tools/releases.py +82 -0
  26. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/tests/conftest.py +30 -3
  27. mcp_github_crunchtools-1.2.0/tests/test_tools.py +2010 -0
  28. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/tests/test_validation.py +89 -0
  29. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/uv.lock +2 -2
  30. mcp_github_crunchtools-1.0.1/CHANGELOG.md +0 -28
  31. mcp_github_crunchtools-1.0.1/PKG-INFO +0 -263
  32. mcp_github_crunchtools-1.0.1/README.md +0 -237
  33. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/actions.py +0 -187
  34. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/pull_requests.py +0 -287
  35. mcp_github_crunchtools-1.0.1/tests/test_tools.py +0 -861
  36. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.gatehouse-ignore +0 -0
  37. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  38. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  39. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  40. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/dependabot.yml +0 -0
  41. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/container.yml +0 -0
  42. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/publish.yml +0 -0
  43. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.github/workflows/security.yml +0 -0
  44. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.gitignore +0 -0
  45. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.specify/specs/000-baseline/spec.md +0 -0
  46. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.specify/templates/plan-template.md +0 -0
  47. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/.specify/templates/spec-template.md +0 -0
  48. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/LICENSE +0 -0
  49. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/gourmand-exceptions.toml +0 -0
  50. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/gourmand.toml +0 -0
  51. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/__main__.py +0 -0
  52. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/config.py +0 -0
  53. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/errors.py +0 -0
  54. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/tools/files.py +0 -0
  55. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/tools/issues.py +0 -0
  56. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/src/mcp_github_crunchtools/tools/search.py +0 -0
  57. {mcp_github_crunchtools-1.0.1 → mcp_github_crunchtools-1.2.0}/tests/__init__.py +0 -0
@@ -0,0 +1,98 @@
1
+ # Ashigaru — issues in, fixed bugs out. ONE file enrolls a repo.
2
+ #
3
+ # Drop this in at .github/workflows/ashigaru.yml. The organization supplies the
4
+ # secrets (CLAUDE_CODE_OAUTH_TOKEN, ASHIGARU_APP_ID, ASHIGARU_APP_KEY,
5
+ # OPENROUTER_API_KEY) and the switch (variable ASHIGARU_ENABLED = true).
6
+ #
7
+ # What happens:
8
+ # • a new issue is triaged: bug, documentation and performance issues are
9
+ # labeled ready-to-code and fixed; features are labeled triaged and left
10
+ # for you; unclear ones get needs-info
11
+ # • an issue from someone without write access is triaged too, but is never
12
+ # fixed until a maintainer adds ready-to-code
13
+ # • the fix arrives as a pull request from ashigaru/issue-N with auto-merge on
14
+ # • Gatehouse reviews it like any other; Ashigaru answers each finding
15
+ # (`fixed in <sha>` or `not a bug: <reason>`) for up to five rounds, then
16
+ # labels the pull request needs-human and stops
17
+ # • GitHub merges when the required checks pass. No job here can merge.
18
+ #
19
+ # To steer it by hand: add `ready-to-code` to have an issue fixed,
20
+ # `ready-for-triage` to have it looked at again.
21
+ #
22
+ # Where the checks are. This file only routes events. The workflows it calls
23
+ # do the checking, at the pinned release, before any agent runs:
24
+ # • the switch: every called workflow stops at its first job unless the
25
+ # organization variable ASHIGARU_ENABLED is true
26
+ # • who may reach an agent: scripts/guard.py asks the API for the write
27
+ # access of the issue's author and of whoever triggered the event
28
+ # • which pull requests are touched: fix.yml acts only on ashigaru/ branches
29
+ # in this repository, opened by the Ashigaru app
30
+ # • what the secrets can do: the job that runs the model gets a read-only
31
+ # token; the app key is used only by jobs that run no model
32
+ #
33
+ # Copy unchanged apart from the pins, which Dependabot keeps current.
34
+
35
+ name: Ashigaru
36
+
37
+ on:
38
+ issues:
39
+ types: [opened, labeled]
40
+ workflow_run:
41
+ workflows: [Gatehouse]
42
+ types: [completed]
43
+
44
+ permissions: {}
45
+
46
+ # One run at a time per issue or per pull request branch; a second event waits.
47
+ concurrency:
48
+ group: ashigaru-${{ github.event.issue.number || github.event.workflow_run.head_branch }}
49
+ cancel-in-progress: false
50
+
51
+ jobs:
52
+ triage:
53
+ name: Triage
54
+ if: >-
55
+ github.event_name == 'issues' &&
56
+ (github.event.action == 'opened' || github.event.label.name == 'ready-for-triage')
57
+ permissions:
58
+ contents: read
59
+ issues: write
60
+ uses: crunchtools/ashigaru/.github/workflows/triage.yml@v2
61
+ secrets:
62
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
63
+
64
+ code:
65
+ name: Code
66
+ needs: triage
67
+ # After a triage that said ready-to-code, or when a maintainer adds the label.
68
+ if: >-
69
+ always() && github.event_name == 'issues' &&
70
+ (needs.triage.outputs.auto_code == 'true' ||
71
+ (github.event.action == 'labeled' && github.event.label.name == 'ready-to-code'))
72
+ permissions:
73
+ contents: read
74
+ issues: read
75
+ uses: crunchtools/ashigaru/.github/workflows/code.yml@v2
76
+ secrets:
77
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
78
+ ASHIGARU_APP_ID: ${{ secrets.ASHIGARU_APP_ID }}
79
+ ASHIGARU_APP_KEY: ${{ secrets.ASHIGARU_APP_KEY }}
80
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
81
+
82
+ fix:
83
+ name: Fix
84
+ if: >-
85
+ github.event_name == 'workflow_run' &&
86
+ github.event.workflow_run.event == 'pull_request_target' &&
87
+ github.event.workflow_run.head_repository.full_name == github.repository &&
88
+ startsWith(github.event.workflow_run.head_branch, 'ashigaru/')
89
+ permissions:
90
+ contents: read
91
+ pull-requests: read
92
+ checks: read
93
+ actions: read
94
+ uses: crunchtools/ashigaru/.github/workflows/fix.yml@v2
95
+ secrets:
96
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
97
+ ASHIGARU_APP_ID: ${{ secrets.ASHIGARU_APP_ID }}
98
+ ASHIGARU_APP_KEY: ${{ secrets.ASHIGARU_APP_KEY }}
@@ -40,7 +40,7 @@ jobs:
40
40
 
41
41
  gourmand:
42
42
  name: Code Quality (Gourmand)
43
- uses: crunchtools/gatehouse/.github/workflows/gourmand.yml@v0.15.2
43
+ uses: crunchtools/gatehouse/.github/workflows/gourmand.yml@v0
44
44
 
45
45
  build-container:
46
46
  runs-on: ubuntu-latest
@@ -18,4 +18,4 @@ permissions:
18
18
  jobs:
19
19
  constitution:
20
20
  name: Constitution
21
- uses: crunchtools/constitution/.github/workflows/validate.yml@v1.18.0
21
+ uses: crunchtools/constitution/.github/workflows/validate.yml@v1.24.0
@@ -15,4 +15,4 @@ permissions:
15
15
  jobs:
16
16
  automerge:
17
17
  name: Dependabot
18
- uses: crunchtools/constitution/.github/workflows/dependabot-automerge.yml@v1.18.0
18
+ uses: crunchtools/constitution/.github/workflows/dependabot-automerge.yml@v1.24.0
@@ -20,4 +20,4 @@ jobs:
20
20
  if: github.event.workflow_run.event == 'pull_request_review_comment'
21
21
  permissions:
22
22
  actions: write # re-run the triage job; nothing else
23
- uses: crunchtools/gatehouse/.github/workflows/retriage.yml@v0.15.2
23
+ uses: crunchtools/gatehouse/.github/workflows/retriage.yml@v0
@@ -90,7 +90,7 @@ jobs:
90
90
  permissions:
91
91
  contents: read
92
92
  pull-requests: write
93
- uses: crunchtools/gatehouse/.github/workflows/review.yml@v0.15.2
93
+ uses: crunchtools/gatehouse/.github/workflows/review.yml@v0
94
94
  # Advisory by default — findings post as comments, the check always passes.
95
95
  # Uncomment to let critical/high findings fail the check (still not required):
96
96
  # with:
@@ -107,4 +107,4 @@ jobs:
107
107
  if: always()
108
108
  permissions:
109
109
  pull-requests: read
110
- uses: crunchtools/gatehouse/.github/workflows/triage.yml@v0.15.2
110
+ uses: crunchtools/gatehouse/.github/workflows/triage.yml@v0
@@ -1,20 +1,18 @@
1
1
  repos:
2
- - repo: local
2
+ # ruff runs from its own pre-commit environment, not a host install
3
+ # (constitution XII, host contract). Keep rev at the ruff version in uv.lock.
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.16.9
3
6
  hooks:
4
7
  - id: ruff-check
5
- name: ruff check
6
- entry: uv run ruff check --fix
7
- language: system
8
+ args: [--fix]
8
9
  types: [python]
9
10
  stages: [pre-commit, pre-merge-commit]
10
11
  - id: ruff-format
11
- name: ruff format
12
- entry: uv run ruff format
13
- language: system
14
12
  types: [python]
15
13
  stages: [pre-commit, pre-merge-commit]
16
14
  - repo: https://github.com/crunchtools/constitution
17
- rev: v1.0.0
15
+ rev: v1.24.0
18
16
  hooks:
19
17
  - id: validate-constitution
20
18
 
@@ -1,10 +1,10 @@
1
1
  # mcp-github-crunchtools Constitution
2
2
 
3
- > **Version:** 1.1.0
3
+ > **Version:** 1.2.0
4
4
  > **Ratified:** 2026-06-14
5
- > **Amended:** 2026-10-02
5
+ > **Amended:** 2026-10-12
6
6
  > **Status:** Active
7
- > **Inherits:** [crunchtools/constitution](https://github.com/crunchtools/constitution) v1.18.0
7
+ > **Inherits:** [crunchtools/constitution](https://github.com/crunchtools/constitution) v1.24.0
8
8
  > **Profile:** MCP Server
9
9
 
10
10
  This file holds what is specific to mcp-github. The fleet rules and the MCP
@@ -19,13 +19,22 @@ restated here.
19
19
  the environment only. `GitHubApiError` scrubs it from messages, and
20
20
  `Config.__repr__()`/`__str__()` never expose it.
21
21
  - **Input limits:** Pydantic models with `extra="forbid"`; issue and PR
22
- states are allowlisted (`open`, `closed`, `all`); owner and repo names are
22
+ states are allowlisted (`open`, `closed`, `all`), as are merge methods
23
+ (`merge`, `squash`, `rebase`); owner and repo names are
23
24
  checked for injection characters; git refs follow check-ref-format
24
- rules (no `..`, `//` or leading/trailing `.` or `/`). `NotFoundError`
25
+ rules (no `..`, `//` or leading/trailing `.` or `/`); an expected head SHA
26
+ is a full 40 or 64 character hex SHA. `NotFoundError`
25
27
  truncates long identifiers.
26
28
  - **API:** `Authorization: Bearer` header, never the URL; the
27
29
  `X-GitHub-Api-Version` header is pinned to `2022-11-28`; path parameters
28
30
  are URL-encoded; requests time out after 30s; responses are capped at 10MB.
31
+ - **Redirects:** the API client follows none. A job log, which GitHub serves
32
+ as a redirect to a pre-signed storage URL, is fetched by a separate client
33
+ that has no token, over HTTPS to a named host only, streamed, with only its
34
+ tail kept. The signed URL is never logged or put in an error message.
35
+ - **Result caps:** tools that gather several pages say when they cut:
36
+ 300 items per kind for pull request comments, 300 jobs per run, and for
37
+ failed-job logs 1000 lines per job, 5 jobs and 256 KiB per result.
29
38
  - **Surface:** pure API wrappers. No filesystem access, shell execution or
30
39
  code evaluation.
31
40
 
@@ -42,8 +51,9 @@ The server works with github.com and GitHub Enterprise Server:
42
51
 
43
52
  ## Tool Groups
44
53
 
45
- Issues, pull requests, Actions, files and search. Client error handling is
46
- tested for 401, 404, 429 and 204 responses in `TestClientErrorHandling`.
54
+ Issues, pull requests, Actions, releases, files and search: 25 tools, of which
55
+ 14 only read. Client error handling is tested for 401, 404, 429 and 204
56
+ responses in `TestClientErrorHandling`.
47
57
 
48
58
  ## Instance
49
59
 
@@ -62,3 +72,4 @@ tested for 401, 404, 429 and 204 responses in `TestClientErrorHandling`.
62
72
  | 1.0.0 | 2026-06-14 | Initial constitution (ported from mcp-gitlab-crunchtools) |
63
73
  | 1.0.1 | 2026-09-25 | Inherit constitution v1.17.0 (Gatehouse gates) |
64
74
  | 1.1.0 | 2026-10-02 | Manifest under constitution v1.18.0: profile restatement removed, mcp-github specifics kept; `..` rule moved from file paths to git refs to match the code |
75
+ | 1.2.0 | 2026-10-12 | Seven tools for pull requests, Actions runs and logs, and releases (spec 001): redirect handling, result caps, merge-method and SHA validation, releases tool group |
@@ -0,0 +1,141 @@
1
+ # Specification: Pull Request, Run Log and Release Tools
2
+
3
+ > **Spec ID:** 001-pr-merge-logs-release
4
+ > **Status:** Implemented
5
+ > **Version:** 1.2.0
6
+ > **Author:** crunchtools.com
7
+ > **Date:** 2026-10-12
8
+
9
+ ## Overview
10
+
11
+ An agent that takes a change from a branch to a release needs to open the pull
12
+ request, read what reviewers and CI said about it, answer them, merge, and
13
+ publish. Until now it did the missing steps with the `gh` CLI, which hands it
14
+ other people's text with no gateway in between. These seven tools close that
15
+ gap so the whole loop runs through the MCP server.
16
+
17
+ ---
18
+
19
+ ## New Tools
20
+
21
+ | Tool | Method | Endpoint | Description |
22
+ |------|--------|----------|-------------|
23
+ | `create_pull_request_tool` | POST | `/repos/{owner}/{repo}/pulls` | Open a pull request (write) |
24
+ | `merge_pull_request_tool` | PUT | `/repos/{owner}/{repo}/pulls/{pull_number}/merge` | Merge, squash or rebase; optional expected head SHA (write) |
25
+ | `list_pull_request_comments_tool` | GET | `.../issues/{n}/comments` + `.../pulls/{n}/comments` + `.../pulls/{n}/reviews` | One list of everything said on a PR |
26
+ | `reply_to_review_comment_tool` | POST | `/repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies` | Reply in a review thread (write) |
27
+ | `get_workflow_run_tool` | GET | `/repos/{owner}/{repo}/actions/runs/{run_id}` + `.../jobs` | Run status and jobs, no logs |
28
+ | `get_failed_job_logs_tool` | GET | `.../actions/runs/{run_id}/jobs` + `.../actions/jobs/{job_id}/logs` | Tail of each failed job's log |
29
+ | `create_release_tool` | POST | `/repos/{owner}/{repo}/releases` | Create a release and its tag (write) |
30
+
31
+ The three GET tools publish `readOnlyHint`. Not in scope: creating or forking
32
+ repositories, deleting packages, further search tools.
33
+
34
+ ### Result shapes and caps
35
+
36
+ | Tool | Cap | How the result reports it |
37
+ |------|-----|---------------------------|
38
+ | `list_pull_request_comments_tool` | 300 items per kind, read oldest first (at most 9 requests) | `truncated`, `truncated_kinds` |
39
+ | `get_workflow_run_tool` | 300 jobs | `jobs_truncated` |
40
+ | `get_failed_job_logs_tool` | `tail_lines` at most 1000 (default 200); 5 failed jobs; 256 KiB of log text per result, split evenly between jobs; 20 MB per download | `tail_lines` (value used), `failed_jobs_omitted`, per-job and overall `truncated` |
41
+
42
+ A job is failed when its conclusion is `failure` or `timed_out`. Cancelled
43
+ jobs are left out: in a failed run they are mostly siblings stopped by
44
+ fail-fast, and their logs say nothing about the cause.
45
+
46
+ ---
47
+
48
+ ## Security Considerations
49
+
50
+ ### Layer 1 — Token Protection
51
+
52
+ - GitHub serves a job log as a 302 to a pre-signed URL on a storage host. The
53
+ API client is created with `follow_redirects=False`; the redirect target is
54
+ fetched by a second client that has no default headers, so the token is not
55
+ sent there.
56
+ - The signed URL is a short-lived credential. It is not logged, not put in an
57
+ error message, and not kept in an exception chain.
58
+
59
+ ### Layer 2 — Input Validation
60
+
61
+ - `MERGE_METHODS` allowlist; `validate_commit_sha` for the expected head;
62
+ `validate_head` for `branch` or `owner:branch`; `validate_ref` for base,
63
+ tag and target.
64
+ - `CreateReleaseInput` for the release title and notes. Pull request title
65
+ and body reuse `CreateIssueInput`, and a review reply reuses
66
+ `CreateIssueCommentInput`: the limits are the same.
67
+ - Blank optional values (`sha`, `target_commitish`, `name`) mean "not given".
68
+
69
+ ### Layer 3 — API Hardening
70
+
71
+ - The redirect target must be HTTPS, name a host rather than an IP address,
72
+ and carry no embedded credentials. It is not redirected further and must
73
+ answer 200. The host is not held to a list of names: GitHub documents no
74
+ stable set of log-storage hosts, and GHES storage is the operator's.
75
+ - The download is streamed with a rolling 256 KiB tail and abandoned past
76
+ 20 MB. Paging loops are bounded by a page count, not by what the server
77
+ says.
78
+
79
+ ### Layer 4 — Dangerous Operation Prevention
80
+
81
+ - No filesystem, shell or code evaluation. Logs are held in memory only.
82
+ - Comments, reviews and logs are text written by others. The server returns
83
+ them as data and bounds their size; it does not interpret them.
84
+
85
+ ---
86
+
87
+ ## Module Changes
88
+
89
+ ### New Files
90
+
91
+ | File | Purpose |
92
+ |------|---------|
93
+ | `tools/releases.py` | `create_release` |
94
+
95
+ ### Modified Files
96
+
97
+ | File | Changes |
98
+ |------|---------|
99
+ | `client.py` | `_send` split out of `_request`; `get_redirected_tail`; `follow_redirects=False` |
100
+ | `models.py` | `MERGE_METHODS`, `validate_head`, `validate_commit_sha`, `CreateReleaseInput` |
101
+ | `tools/pull_requests.py` | `create_pull_request`, `merge_pull_request`, `list_pull_request_comments`, `reply_to_review_comment` |
102
+ | `tools/actions.py` | `get_workflow_run`, `get_failed_job_logs` |
103
+ | `tools/__init__.py` | Exports |
104
+ | `server.py` | Seven `@mcp.tool` wrappers |
105
+
106
+ ---
107
+
108
+ ## Testing Requirements
109
+
110
+ ### Mocked API Tests
111
+
112
+ - [x] Happy path, validation refusal and GitHub error path for each tool
113
+ - [x] Caps: comments per kind, jobs per run, `tail_lines`, bytes, failed jobs
114
+ - [x] The storage request carries no `Authorization` header (real httpx
115
+ client over a mock transport, so the assertion is on the request as sent)
116
+ - [x] Redirects that are not HTTPS, carry credentials or address an IP are
117
+ refused; storage errors and transport failures do not expose the
118
+ signed URL
119
+
120
+ ### Input Validation Tests
121
+
122
+ - [x] `validate_head`, `validate_commit_sha`, `CreateReleaseInput`
123
+
124
+ ### Tool Count Update
125
+
126
+ - [x] `test_tool_count` is 25; `READ_ONLY` and `WRITES` updated
127
+
128
+ ---
129
+
130
+ ## Dependencies
131
+
132
+ - Depends on: 000-baseline
133
+ - Blocks: none
134
+
135
+ ---
136
+
137
+ ## Changelog
138
+
139
+ | Version | Date | Changes |
140
+ |---------|------|---------|
141
+ | 1.2.0 | 2026-10-12 | Implemented |
@@ -0,0 +1,83 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/) and this project adheres to
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.2.0] - 2026-10-12
10
+
11
+ ### Added
12
+
13
+ - `create_pull_request_tool`: open a pull request, optionally as a draft; the
14
+ head may be `owner:branch` for a fork.
15
+ - `merge_pull_request_tool`: merge, squash or rebase a pull request. `sha` is
16
+ the expected head commit; GitHub refuses the merge if the branch has moved.
17
+ - `list_pull_request_comments_tool`: conversation comments, diff comments and
18
+ reviews in one chronological list, each tagged with its kind, author and id.
19
+ Each kind is capped at 300 items and the result says when one was cut.
20
+ - `reply_to_review_comment_tool`: reply in the thread of a diff comment.
21
+ - `get_workflow_run_tool`: one run's status, conclusion, head SHA and branch,
22
+ event and jobs, without logs.
23
+ - `get_failed_job_logs_tool`: the last lines of the log of each failed job in
24
+ a run, with ANSI escapes and timestamps removed. Bounded to 1000 lines per
25
+ job, 5 jobs and 256 KiB per result; the result says when something was cut.
26
+ - `create_release_tool`: create a release and, if needed, its tag.
27
+ - README and SECURITY.md list the fine-grained token permission each tool
28
+ needs.
29
+
30
+ ### Security
31
+
32
+ - The API client is created with `follow_redirects=False`. GitHub redirects a
33
+ job log to a pre-signed storage URL; that URL is fetched by a separate
34
+ client that has no token, over HTTPS only, and is never logged or put in an
35
+ error message.
36
+
37
+ ### Changed
38
+
39
+ - README lists all 25 tools; it had stopped at the first eleven.
40
+
41
+ ## [1.1.0] - 2026-10-10
42
+
43
+ ### Added
44
+
45
+ - The eleven tools that only read (`list_issues`, `get_issue`,
46
+ `list_pull_requests`, `get_pull_request`, `get_pull_request_diff`,
47
+ `get_pull_request_checks`, `get_file_content`, `list_repo_tree`,
48
+ `search_code`, `search_issues`, `list_workflow_runs`) publish
49
+ `readOnlyHint: true`. A gateway uses it to decide whether an invalid optional
50
+ argument may be dropped or must refuse the call (crunchtools/constitution#35).
51
+ - Tests pin every registered tool into `READ_ONLY` or `WRITES`, and check that
52
+ each read-only tool sends GitHub nothing but GET requests.
53
+
54
+ ### Changed
55
+
56
+ - Inherits constitution v1.22.0; the workflow pins and the pre-commit hook rev
57
+ move with it.
58
+
59
+ ### Fixed
60
+
61
+ - `server.json` said 0.1.0 and the Containerfile label said 0.3.0; both carry
62
+ the release version again.
63
+
64
+ ## [1.0.1] - 2026-10-02
65
+
66
+ ### Fixed
67
+
68
+ - The package, `__version__` and the MCP server reported 0.4.0 while the
69
+ v1.0.0 release and image said 1.0.0; all three now carry the release version.
70
+
71
+ ### Changed
72
+
73
+ - Constitution is now a v1.18.0 manifest: it holds only what is specific to
74
+ this repo; fleet and profile rules apply by reference.
75
+ - Constitution validation is pinned to the inherited release via
76
+ `.github/workflows/constitution.yml`.
77
+ - Dependabot auto-merges GitHub Actions minor and patch updates.
78
+
79
+ ## [1.0.0] - 2026-09-20
80
+
81
+ First tagged release. This image has been running in production since before
82
+ it had version control. No changes are recorded prior to this point --
83
+ RT #1484 added this file on 2026-09-19, before this repo's first tag.
@@ -1,6 +1,6 @@
1
1
  # Claude Code Instructions
2
2
 
3
- Secure MCP server for the GitHub REST API with 11 MVP tools across issues, pull requests, files, and search. Works with github.com and GitHub Enterprise Server.
3
+ Secure MCP server for the GitHub REST API with 25 tools across issues, pull requests, Actions, releases, files, and search. Works with github.com and GitHub Enterprise Server.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -32,8 +32,12 @@ claude mcp add mcp-github-crunchtools \
32
32
 
33
33
  1. Go to https://github.com/settings/tokens
34
34
  2. Create a fine-grained or classic PAT named `mcp-github-crunchtools`
35
- 3. Grant read access to repository contents, issues, and pull requests
36
- (add write to issues/PRs only if you need `create_issue_comment_tool`)
35
+ 3. Grant read access to repository contents, issues, pull requests, and
36
+ Actions. Add write only for the write tools you use: Issues and Pull
37
+ requests for commenting, opening and updating; Contents for
38
+ `merge_pull_request_tool` and `create_release_tool`; Actions for
39
+ `trigger_workflow_tool` and `rerun_*`. The per-tool table is in README.md
40
+ under "Token permissions".
37
41
  4. Copy the token immediately (shown only once)
38
42
 
39
43
  ## Environment Variables
@@ -46,28 +50,38 @@ claude mcp add mcp-github-crunchtools \
46
50
  | `SSL_CERT_FILE` | No | — | Custom CA bundle for self-hosted instances |
47
51
  | `GITHUB_SSL_VERIFY` | No | `true` | Set `false` to disable SSL verification |
48
52
 
49
- ## Available Tools (18)
53
+ ## Available Tools (25)
50
54
 
51
55
  | Category | Tools |
52
56
  |----------|-------|
53
57
  | Issues | `list_issues_tool`, `get_issue_tool`, `create_issue_tool`, `create_issue_comment_tool`, `update_issue_tool` |
54
- | Pull Requests | `list_pull_requests_tool`, `get_pull_request_tool`, `get_pull_request_diff_tool`, `get_pull_request_checks_tool`, `update_pull_request_tool` |
58
+ | Pull Requests | `list_pull_requests_tool`, `get_pull_request_tool`, `get_pull_request_diff_tool`, `get_pull_request_checks_tool`, `list_pull_request_comments_tool`, `create_pull_request_tool`, `update_pull_request_tool`, `reply_to_review_comment_tool`, `merge_pull_request_tool` |
55
59
  | Files | `get_file_content_tool`, `list_repo_tree_tool` |
56
60
  | Search | `search_code_tool`, `search_issues_tool` |
57
- | Actions | `list_workflow_runs_tool`, `trigger_workflow_tool`, `rerun_workflow_run_tool`, `rerun_failed_jobs_tool` |
61
+ | Actions | `list_workflow_runs_tool`, `get_workflow_run_tool`, `get_failed_job_logs_tool`, `trigger_workflow_tool`, `rerun_workflow_run_tool`, `rerun_failed_jobs_tool` |
62
+ | Releases | `create_release_tool` |
58
63
 
59
- Write tools (`create_issue*`, `update_*`, `trigger_workflow_tool`, `rerun_*`)
64
+ Write tools (`create_*`, `update_*`, `merge_pull_request_tool`,
65
+ `reply_to_review_comment_tool`, `trigger_workflow_tool`, `rerun_*`)
60
66
  are scoped per-profile by the gateway. `trigger_workflow_tool` dispatches a
61
67
  fresh run (via `workflow_dispatch`) and is the way to *force* a build —
62
68
  `rerun_*` only re-run an existing run and GitHub rejects runs older than 30
63
69
  days.
64
70
 
71
+ `get_failed_job_logs_tool` is the one tool that talks to a host other than the
72
+ API: GitHub redirects a job log to a storage URL. `GitHubClient.get_redirected_tail`
73
+ follows it with a separate client that has no token. Keep it that way.
74
+
65
75
  ## Example Usage
66
76
 
67
77
  ```
68
78
  List open issues for crunchtools/mcp-github
69
79
  Get the diff for PR #5 in crunchtools/mcp-github
70
80
  Show CI checks for pull request 5
81
+ Show the failed job logs for run 123456
82
+ List the review comments on PR 5 and reply to the first one
83
+ Squash-merge PR 5 in crunchtools/mcp-github
84
+ Create release v1.2.0 for crunchtools/mcp-github
71
85
  Read src/server.py from crunchtools/mcp-github
72
86
  Search code for "FastMCP" in repo:crunchtools/mcp-github
73
87
  Search issues for "is:open label:bug org:crunchtools"
@@ -27,15 +27,15 @@ FROM quay.io/hummingbird/python:latest
27
27
 
28
28
  # Labels for container metadata
29
29
  LABEL name="mcp-github-crunchtools" \
30
- version="0.3.0" \
31
- summary="Secure MCP server for GitHub issues, pull requests, files, and search" \
30
+ version="1.2.0" \
31
+ summary="Secure MCP server for GitHub issues, pull requests, Actions, releases, files, and search" \
32
32
  description="A security-focused MCP server for GitHub built on Red Hat UBI" \
33
33
  maintainer="crunchtools.com" \
34
34
  url="https://github.com/crunchtools/mcp-github" \
35
35
  io.k8s.display-name="MCP GitHub CrunchTools" \
36
36
  io.openshift.tags="mcp,github,devops" \
37
37
  org.opencontainers.image.source="https://github.com/crunchtools/mcp-github" \
38
- org.opencontainers.image.description="Secure MCP server for GitHub issues, pull requests, files, and search" \
38
+ org.opencontainers.image.description="Secure MCP server for GitHub issues, pull requests, Actions, releases, files, and search" \
39
39
  org.opencontainers.image.licenses="AGPL-3.0-or-later"
40
40
 
41
41
  WORKDIR /app