feat(github-repo-reports): initial implementation#227
Conversation
Implements the Reports Binding (REPORTS_LIST, REPORTS_GET, REPORTS_UPDATE_STATUS) backed by Markdown files with YAML frontmatter stored in a configurable GitHub repository. - GitHub App OAuth (PKCE) for per-repo authentication - Configurable repo, branch (default: "reports"), and directory path - Directory nesting automatically becomes report tags - Lifecycle status persisted in .reports-status.json (no server state) - All data fetched from GitHub API on every call (zero persistence) - 43 unit tests for the report parser - REPORT_FORMAT.md prompt for LLM agents Co-authored-by: Cursor <cursoragent@cursor.com>
Defines the binding contract (tools, schemas, detection) and documents the github-repo-reports implementation details. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
4 issues found across 20 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="github-repo-reports/server/lib/github-client.ts">
<violation number="1" location="github-repo-reports/server/lib/github-client.ts:88">
P2: The Git Tree API response may be truncated for large repositories, but `treeResponse.data.truncated` is never checked. This could silently return an incomplete list of reports. Consider logging a warning or throwing an error when the tree is truncated so callers know the results are incomplete.</violation>
</file>
<file name="github-repo-reports/server/tools/reports-get.ts">
<violation number="1" location="github-repo-reports/server/tools/reports-get.ts:57">
P1: Validate the report id to prevent path traversal. As written, a caller can inject `..` or absolute paths and read arbitrary repo files outside the reports directory.</violation>
</file>
<file name="github-repo-reports/server/tools/reports-list.ts">
<violation number="1" location="github-repo-reports/server/tools/reports-list.ts:77">
P2: Unbounded parallel blob fetches can trigger GitHub API rate limits on large repos. Add a concurrency limit (or fetch sequentially) to avoid request storms.</violation>
</file>
<file name="github-repo-reports/server/lib/report-parser.ts">
<violation number="1" location="github-repo-reports/server/lib/report-parser.ts:137">
P2: Avoid trimming the markdown body’s leading whitespace; it can change markdown semantics (e.g., indented code blocks). Consider trimming only the end or leaving the body untouched.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| description: | ||
| "Get a specific report with full content including all sections.", | ||
| inputSchema: z.object({ | ||
| id: z |
There was a problem hiding this comment.
P1: Validate the report id to prevent path traversal. As written, a caller can inject .. or absolute paths and read arbitrary repo files outside the reports directory.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At github-repo-reports/server/tools/reports-get.ts, line 57:
<comment>Validate the report id to prevent path traversal. As written, a caller can inject `..` or absolute paths and read arbitrary repo files outside the reports directory.</comment>
<file context>
@@ -0,0 +1,133 @@
+ description:
+ "Get a specific report with full content including all sections.",
+ inputSchema: z.object({
+ id: z
+ .string()
+ .describe("Report identifier (relative path without .md extension)"),
</file context>
| const treeSha = commitResponse.data.tree.sha; | ||
|
|
||
| // Fetch the full tree recursively | ||
| const treeResponse = await this.octokit.git.getTree({ |
There was a problem hiding this comment.
P2: The Git Tree API response may be truncated for large repositories, but treeResponse.data.truncated is never checked. This could silently return an incomplete list of reports. Consider logging a warning or throwing an error when the tree is truncated so callers know the results are incomplete.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At github-repo-reports/server/lib/github-client.ts, line 88:
<comment>The Git Tree API response may be truncated for large repositories, but `treeResponse.data.truncated` is never checked. This could silently return an incomplete list of reports. Consider logging a warning or throwing an error when the tree is truncated so callers know the results are incomplete.</comment>
<file context>
@@ -0,0 +1,269 @@
+ const treeSha = commitResponse.data.tree.sha;
+
+ // Fetch the full tree recursively
+ const treeResponse = await this.octokit.git.getTree({
+ owner,
+ repo,
</file context>
| } | ||
|
|
||
| // Fetch all file contents in parallel via the Blob API | ||
| const contentPromises = treeEntries.map(async (entry) => { |
There was a problem hiding this comment.
P2: Unbounded parallel blob fetches can trigger GitHub API rate limits on large repos. Add a concurrency limit (or fetch sequentially) to avoid request storms.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At github-repo-reports/server/tools/reports-list.ts, line 77:
<comment>Unbounded parallel blob fetches can trigger GitHub API rate limits on large repos. Add a concurrency limit (or fetch sequentially) to avoid request storms.</comment>
<file context>
@@ -0,0 +1,154 @@
+ }
+
+ // Fetch all file contents in parallel via the Blob API
+ const contentPromises = treeEntries.map(async (entry) => {
+ try {
+ const content = await client.getBlobContent(
</file context>
| } | ||
|
|
||
| const yamlBlock = trimmed.slice(3, closingIndex).trim(); | ||
| const body = trimmed.slice(closingIndex + 4).trim(); |
There was a problem hiding this comment.
P2: Avoid trimming the markdown body’s leading whitespace; it can change markdown semantics (e.g., indented code blocks). Consider trimming only the end or leaving the body untouched.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At github-repo-reports/server/lib/report-parser.ts, line 137:
<comment>Avoid trimming the markdown body’s leading whitespace; it can change markdown semantics (e.g., indented code blocks). Consider trimming only the end or leaving the body untouched.</comment>
<file context>
@@ -0,0 +1,342 @@
+ }
+
+ const yamlBlock = trimmed.slice(3, closingIndex).trim();
+ const body = trimmed.slice(closingIndex + 4).trim();
+
+ let frontmatter: ReportFrontmatter = {};
</file context>
Summary
github-repo-reportsimplementing the Reports Binding (REPORTS_LIST,REPORTS_GET,REPORTS_UPDATE_STATUS)reports/security/audit.md→ tag["security"]).reports-status.jsoncommitted to the repoREPORT_FORMAT.mdas a prompt/reference for LLM agents to generate correctly formatted reportsArchitecture
server/main.tsserver/types/env.tsStateSchema— REPO, PATH (defaultreports), BRANCH (defaultreports)server/lib/github-client.tsserver/lib/report-parser.tsserver/lib/config.tsserver/tools/reports-list.tsREPORTS_LIST— tree walk, parallel blob fetch, filter, sortserver/tools/reports-get.tsREPORTS_GET— single file fetch + full parseserver/tools/reports-update-status.tsREPORTS_UPDATE_STATUS— read/write.reports-status.jsonvia Contents APITest plan
REPORTS_LISTreturns reportsREPORTS_GETreturns full sections including markdown bodyREPORTS_UPDATE_STATUScommits status changes to repoMade with Cursor
Summary by cubic
Add a new MCP server, github-repo-reports, that reads and manages Markdown-based reports in a GitHub repo via the Reports Binding. It lists and fetches reports and updates lifecycle status using per-repo GitHub App OAuth.
New Features
Migration
Written for commit 24cd556. Summary will update on new commits.