Skip to content

feat(github-repo-reports): initial implementation#227

Merged
viktormarinho merged 2 commits intomainfrom
feat/github-repo-reports
Feb 13, 2026
Merged

feat(github-repo-reports): initial implementation#227
viktormarinho merged 2 commits intomainfrom
feat/github-repo-reports

Conversation

@viktormarinho
Copy link
Contributor

@viktormarinho viktormarinho commented Feb 13, 2026

Summary

  • New MCP server github-repo-reports implementing the Reports Binding (REPORTS_LIST, REPORTS_GET, REPORTS_UPDATE_STATUS)
  • Reports are stored as Markdown files with YAML frontmatter in a configurable GitHub repository, branch, and directory
  • Uses GitHub App OAuth (PKCE) for per-repo authentication — users grant access during installation
  • Directory nesting becomes tags automatically (e.g., reports/security/audit.md → tag ["security"])
  • Zero server-side persistence — all data fetched from GitHub API on every call; lifecycle status stored in .reports-status.json committed to the repo
  • Includes REPORT_FORMAT.md as a prompt/reference for LLM agents to generate correctly formatted reports

Architecture

Component Description
server/main.ts Runtime + GitHub App OAuth config
server/types/env.ts StateSchema — REPO, PATH (default reports), BRANCH (default reports)
server/lib/github-client.ts GitHub API client (Git Trees, Blobs, Contents) + OAuth token exchange
server/lib/report-parser.ts YAML frontmatter parser, directory→tags derivation, section validation
server/lib/config.ts Env config extraction helpers
server/tools/reports-list.ts REPORTS_LIST — tree walk, parallel blob fetch, filter, sort
server/tools/reports-get.ts REPORTS_GET — single file fetch + full parse
server/tools/reports-update-status.ts REPORTS_UPDATE_STATUS — read/write .reports-status.json via Contents API

Test plan

  • 43 unit tests for report parser (frontmatter parsing, ID derivation, tag derivation, section validation, lifecycle status parsing, edge cases)
  • Manual: configure with a real GitHub repo, verify REPORTS_LIST returns reports
  • Manual: verify REPORTS_GET returns full sections including markdown body
  • Manual: verify REPORTS_UPDATE_STATUS commits status changes to repo
  • Manual: verify directory nesting produces correct tags
  • Manual: verify OAuth flow grants access to selected repos

Made 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

    • Reports Binding MCP with REPORTS_LIST, REPORTS_GET, and REPORTS_UPDATE_STATUS.
    • Reads Markdown + YAML frontmatter from a configurable repo/branch/path; directory nesting becomes tags.
    • Zero server persistence; lifecycle stored in .reports-status.json in the repo.
    • GitHub App OAuth (PKCE) for per-repo access.
    • Includes a report parser, GitHub API client, 43 unit tests, REPORT_FORMAT.md, and the Reports Binding spec at docs/REPORTS_BINDING.md.
  • Migration

    • Create or use a repo with a reports branch and directory (defaults: BRANCH=reports, PATH=reports).
    • Install the GitHub App, grant repo access, and set GITHUB_CLIENT_ID/SECRET (and optional GITHUB_APP_NAME).
    • Configure state: REPO="owner/repo", optional PATH/BRANCH; deploy the new service.

Written for commit 24cd556. Summary will update on new commits.

viktormarinho and others added 2 commits February 13, 2026 11:07
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>
@viktormarinho viktormarinho merged commit baf88f3 into main Feb 13, 2026
4 of 5 checks passed
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic

const treeSha = commitResponse.data.tree.sha;

// Fetch the full tree recursively
const treeResponse = await this.octokit.git.getTree({
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic

}

// Fetch all file contents in parallel via the Blob API
const contentPromises = treeEntries.map(async (entry) => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic

}

const yamlBlock = trimmed.slice(3, closingIndex).trim();
const body = trimmed.slice(closingIndex + 4).trim();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant