feat: bounded responses for get_pull_request_diff + get_file_content (closes #124) #131

Merged
goern merged 0 commits from refs/pull/131/head into main 2026-05-12 08:41:53 +00:00
goern commented 2026-05-11 14:58:10 +00:00 (Migrated from codeberg.org)

Summary

Implements the add-bounded-text-responses OpenSpec change (proposal → design → spec deltas → tasks → impl).

Two MCP tools previously returned arbitrarily large text payloads with no caller-side bound. Both now honor the architectural rule in docs/design/output-bounding.md:

  • get_pull_request_diff gains optional file_path. When set, returns only that file's hunks (matched on the diff --git boundary, accepts pre- or post-rename path). Missing path is a tool error — no silent fallback.
  • get_file_content gains optional start_line + end_line (1-indexed inclusive). Omit-defaults, clamping, inverted-range error, with_metadata=true bypass — all documented in the spec.

Closes #124.

Implementation

  • New package pkg/diff/FileSlice(rawDiff, filePath) (string, bool). Splits the diff on diff --git boundaries; matches either a/<path> or b/<path> so renames Just Work.
  • operation/pull/pull.goGetPullRequestDiffFn adds the file_path branch.
  • operation/repo/file.goGetFileContentFn gains a sliceLines(content, start, end) helper. Plain-text path only; with_metadata=true returns the full ContentsResponse unchanged.

Tests

Suite Cases
pkg/diff multi-file, single, binary, rename (both sides), not-found, empty inputs, non-diff garbage
operation/pull full diff, sliced diff, missing file_path errors
operation/repo in-range, head, tail, clamp end, clamp start, inverted error, both omitted, with_metadata bypass

go test ./... + make build both green locally.

Docs

README tool table updated:

  • Added previously-missing entries: get_pull_request_diff, list_pull_request_files, merge_pull_request, create_pull_review
  • Existing get_file_content row mentions the new start_line/end_line

Test plan

  • go test ./... passes
  • make build passes
  • openspec validate add-bounded-text-responses --strict passes
  • Manual smoke against a Codeberg PR: get_pull_request_diff without file_path returns full diff; with file_path returns one file's hunks
  • Manual smoke: get_file_content with start_line=10, end_line=20 returns 11 lines

Closes #124.

## Summary Implements the `add-bounded-text-responses` OpenSpec change (proposal → design → spec deltas → tasks → impl). Two MCP tools previously returned arbitrarily large text payloads with no caller-side bound. Both now honor the architectural rule in [`docs/design/output-bounding.md`](docs/design/output-bounding.md): - **`get_pull_request_diff`** gains optional `file_path`. When set, returns only that file's hunks (matched on the `diff --git` boundary, accepts pre- or post-rename path). Missing path is a tool error — no silent fallback. - **`get_file_content`** gains optional `start_line` + `end_line` (1-indexed inclusive). Omit-defaults, clamping, inverted-range error, `with_metadata=true` bypass — all documented in the spec. Closes [#124](https://codeberg.org/goern/forgejo-mcp/issues/124). ## Implementation - **New package `pkg/diff/`** — `FileSlice(rawDiff, filePath) (string, bool)`. Splits the diff on `diff --git` boundaries; matches either `a/<path>` or `b/<path>` so renames Just Work. - **`operation/pull/pull.go`** — `GetPullRequestDiffFn` adds the `file_path` branch. - **`operation/repo/file.go`** — `GetFileContentFn` gains a `sliceLines(content, start, end)` helper. Plain-text path only; `with_metadata=true` returns the full `ContentsResponse` unchanged. ## Tests | Suite | Cases | |---|---| | `pkg/diff` | multi-file, single, binary, rename (both sides), not-found, empty inputs, non-diff garbage | | `operation/pull` | full diff, sliced diff, missing `file_path` errors | | `operation/repo` | in-range, head, tail, clamp end, clamp start, inverted error, both omitted, `with_metadata` bypass | `go test ./...` + `make build` both green locally. ## Docs README tool table updated: - Added previously-missing entries: `get_pull_request_diff`, `list_pull_request_files`, `merge_pull_request`, `create_pull_review` - Existing `get_file_content` row mentions the new `start_line`/`end_line` ## Test plan - [x] `go test ./...` passes - [x] `make build` passes - [x] `openspec validate add-bounded-text-responses --strict` passes - [ ] Manual smoke against a Codeberg PR: `get_pull_request_diff` without `file_path` returns full diff; with `file_path` returns one file's hunks - [ ] Manual smoke: `get_file_content` with `start_line=10`, `end_line=20` returns 11 lines Closes #124.
op1st-gitops commented 2026-05-12 07:59:00 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/on-pull-request-4p5pk is running.

Starting Pipelinerun on-pull-request-4p5pk in namespace op1st-pipelines

You can monitor the execution using the op1st Pipelines as Code PipelineRun viewer or through the command line by
using the tkn CLI with the following command:

tkn pr logs -n op1st-pipelines on-pull-request-4p5pk -f

op1st Pipelines as Code/on-pull-request-4p5pk is running. Starting Pipelinerun <b>[on-pull-request-4p5pk](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/on-pull-request-4p5pk)</b> in namespace <b>op1st-pipelines</b> You can monitor the execution using the [op1st Pipelines as Code](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/on-pull-request-4p5pk) PipelineRun viewer or through the command line by using the [tkn](https://tekton.dev/docs/cli/#installation) CLI with the following command: <code>tkn pr logs -n op1st-pipelines on-pull-request-4p5pk -f</code>
op1st-gitops commented 2026-05-12 07:59:00 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/openspec-validate-pr-t5khd is running.

Starting Pipelinerun openspec-validate-pr-t5khd in namespace op1st-pipelines

You can monitor the execution using the op1st Pipelines as Code PipelineRun viewer or through the command line by
using the tkn CLI with the following command:

tkn pr logs -n op1st-pipelines openspec-validate-pr-t5khd -f

op1st Pipelines as Code/openspec-validate-pr-t5khd is running. Starting Pipelinerun <b>[openspec-validate-pr-t5khd](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/openspec-validate-pr-t5khd)</b> in namespace <b>op1st-pipelines</b> You can monitor the execution using the [op1st Pipelines as Code](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/openspec-validate-pr-t5khd) PipelineRun viewer or through the command line by using the [tkn](https://tekton.dev/docs/cli/#installation) CLI with the following command: <code>tkn pr logs -n op1st-pipelines openspec-validate-pr-t5khd -f</code>
op1st-gitops commented 2026-05-12 07:59:28 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/openspec-validate-pr-t5khd has successfully validated your commit.


Task Statuses:

StatusDurationName
Succeeded 11 seconds

fetch-source

Succeeded 16 seconds

validate

op1st Pipelines as Code/openspec-validate-pr-t5khd has <b>successfully</b> validated your commit. <ul> <li><b>Namespace</b>: <a href="https://detailurl.setting.custom-console-url-namespace.is.not.configured">op1st-pipelines</a></li> <li><b>PipelineRun:</b> <a href="https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/openspec-validate-pr-t5khd">openspec-validate-pr-t5khd</a></li> </ul> <hr> <h4>Task Statuses:</h4> <table> <tr><th>Status</th><th>Duration</th><th>Name</th></tr> <tr> <td>Succeeded</td> <td>11 seconds</td><td> [fetch-source](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/openspec-validate-pr-t5khd/logs/fetch-source) </td></tr> <tr> <td>Succeeded</td> <td>16 seconds</td><td> [validate](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/openspec-validate-pr-t5khd/logs/validate) </td></tr> </table>
op1st-gitops commented 2026-05-12 07:59:59 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/on-pull-request-4p5pk has successfully validated your commit.


Task Statuses:

StatusDurationName
Succeeded 9 seconds

fetch-source

Succeeded 47 seconds

build-and-test

op1st Pipelines as Code/on-pull-request-4p5pk has <b>successfully</b> validated your commit. <ul> <li><b>Namespace</b>: <a href="https://detailurl.setting.custom-console-url-namespace.is.not.configured">op1st-pipelines</a></li> <li><b>PipelineRun:</b> <a href="https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/on-pull-request-4p5pk">on-pull-request-4p5pk</a></li> </ul> <hr> <h4>Task Statuses:</h4> <table> <tr><th>Status</th><th>Duration</th><th>Name</th></tr> <tr> <td>Succeeded</td> <td>9 seconds</td><td> [fetch-source](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/on-pull-request-4p5pk/logs/fetch-source) </td></tr> <tr> <td>Succeeded</td> <td>47 seconds</td><td> [build-and-test](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1beta1~PipelineRun/on-pull-request-4p5pk/logs/build-and-test) </td></tr> </table>
op1st-gitops commented 2026-05-12 08:15:18 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/openspec-validate-pr-rr2jd is running.

Starting Pipelinerun openspec-validate-pr-rr2jd in namespace op1st-pipelines

You can monitor the execution using the op1st Pipelines as Code PipelineRun viewer or through the command line by
using the tkn CLI with the following command:

tkn pr logs -n op1st-pipelines openspec-validate-pr-rr2jd -f

op1st Pipelines as Code/openspec-validate-pr-rr2jd is running. Starting Pipelinerun <b>[openspec-validate-pr-rr2jd](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/openspec-validate-pr-rr2jd)</b> in namespace <b>op1st-pipelines</b> You can monitor the execution using the [op1st Pipelines as Code](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/openspec-validate-pr-rr2jd) PipelineRun viewer or through the command line by using the [tkn](https://tekton.dev/docs/cli/#installation) CLI with the following command: <code>tkn pr logs -n op1st-pipelines openspec-validate-pr-rr2jd -f</code>
op1st-gitops commented 2026-05-12 08:15:18 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/on-pull-request-8p772 is running.

Starting Pipelinerun on-pull-request-8p772 in namespace op1st-pipelines

You can monitor the execution using the op1st Pipelines as Code PipelineRun viewer or through the command line by
using the tkn CLI with the following command:

tkn pr logs -n op1st-pipelines on-pull-request-8p772 -f

op1st Pipelines as Code/on-pull-request-8p772 is running. Starting Pipelinerun <b>[on-pull-request-8p772](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/on-pull-request-8p772)</b> in namespace <b>op1st-pipelines</b> You can monitor the execution using the [op1st Pipelines as Code](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/on-pull-request-8p772) PipelineRun viewer or through the command line by using the [tkn](https://tekton.dev/docs/cli/#installation) CLI with the following command: <code>tkn pr logs -n op1st-pipelines on-pull-request-8p772 -f</code>
op1st-gitops commented 2026-05-12 08:15:41 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/openspec-validate-pr-rr2jd has successfully validated your commit.


Task Statuses:

StatusDurationName
Succeeded 10 seconds

fetch-source

Succeeded 12 seconds

validate

op1st Pipelines as Code/openspec-validate-pr-rr2jd has <b>successfully</b> validated your commit. <ul> <li><b>Namespace</b>: <a href="https://detailurl.setting.custom-console-url-namespace.is.not.configured">op1st-pipelines</a></li> <li><b>PipelineRun:</b> <a href="https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/openspec-validate-pr-rr2jd">openspec-validate-pr-rr2jd</a></li> </ul> <hr> <h4>Task Statuses:</h4> <table> <tr><th>Status</th><th>Duration</th><th>Name</th></tr> <tr> <td>Succeeded</td> <td>10 seconds</td><td> [fetch-source](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/openspec-validate-pr-rr2jd/logs/fetch-source) </td></tr> <tr> <td>Succeeded</td> <td>12 seconds</td><td> [validate](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/openspec-validate-pr-rr2jd/logs/validate) </td></tr> </table>
op1st-gitops commented 2026-05-12 08:16:05 +00:00 (Migrated from codeberg.org)

op1st Pipelines as Code/on-pull-request-8p772 has successfully validated your commit.


Task Statuses:

StatusDurationName
Succeeded 10 seconds

fetch-source

Succeeded 37 seconds

build-and-test

op1st Pipelines as Code/on-pull-request-8p772 has <b>successfully</b> validated your commit. <ul> <li><b>Namespace</b>: <a href="https://detailurl.setting.custom-console-url-namespace.is.not.configured">op1st-pipelines</a></li> <li><b>PipelineRun:</b> <a href="https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/on-pull-request-8p772">on-pull-request-8p772</a></li> </ul> <hr> <h4>Task Statuses:</h4> <table> <tr><th>Status</th><th>Duration</th><th>Name</th></tr> <tr> <td>Succeeded</td> <td>10 seconds</td><td> [fetch-source](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/on-pull-request-8p772/logs/fetch-source) </td></tr> <tr> <td>Succeeded</td> <td>37 seconds</td><td> [build-and-test](https://console-openshift-console.apps.nostromo.erdgeschoss.b4mad.emea.operate-first.cloud/k8s/ns/op1st-pipelines/tekton.dev~v1~PipelineRun/on-pull-request-8p772/logs/build-and-test) </td></tr> </table>
fiesh commented 2026-05-18 06:00:53 +00:00 (Migrated from codeberg.org)

Sorry, I was traveling abroad last week with limited connectivity and time and thus didn't get around to looking at this yet. Thank you for the prompt implementation!

Sorry, I was traveling abroad last week with limited connectivity and time and thus didn't get around to looking at this yet. Thank you for the prompt implementation!
goern commented 2026-05-18 06:44:14 +00:00 (Migrated from codeberg.org)

@fiesh no worries — travel beats CI any day. landed in main last week. when you get a moment, give it a spin and let me know if file_path on get_pull_request_diff and start_line/end_line on get_file_content actually solve what you ran into in #124. happy to iterate if something feels off.

@fiesh no worries — travel beats CI any day. landed in main last week. when you get a moment, give it a spin and let me know if `file_path` on `get_pull_request_diff` and `start_line`/`end_line` on `get_file_content` actually solve what you ran into in #124. happy to iterate if something feels off.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
agentic-forges/forgejo-mcp!131
No description provided.