Skip to content

feat(mcp+generator): Phase 2a — MCP server, Markdown renderer, tree reconstruction#24

Merged
thewrz merged 21 commits into
mainfrom
feat/parser-docx-1c-ii
May 13, 2026
Merged

feat(mcp+generator): Phase 2a — MCP server, Markdown renderer, tree reconstruction#24
thewrz merged 21 commits into
mainfrom
feat/parser-docx-1c-ii

Conversation

@thewrz
Copy link
Copy Markdown
Contributor

@thewrz thewrz commented May 12, 2026

Summary

  • MCP server (stateless Streamable HTTP on Express at POST /mcp): 3 read-only tools (search_library, get_spec, list_sections) + 2 resources (specr://specs/{id} as Markdown, specr://sections as Markdown table). Configure in Claude Code via .mcp.json.
  • Markdown renderer (src/generator/markdown.ts): pure renderMarkdown(CsiTree) + getLabel() helper. Used by MCP resources; shared with future DOCX generator. Vanish/note nodes render as > **[NOTE]** blockquotes for LLM context.
  • getSpecTree (src/db/queries/specs.ts): reconstructs full CsiNode hierarchy from flat paragraphs table + cross-reference resolution status (isResolved, isBroken). Feeds the get_spec tool.
  • searchParagraphs + listCsiSections (src/db/queries/search.ts): ILIKE text search with optional division filter; CSI section index with inDatabase flag.
  • Docs updated: ARCHITECTURE.md, README.md, ADR-010 reflect stateless Streamable HTTP decision (supersedes ADR-010's original stdio/SSE stance).

Architecture note

MCP server is integrated into the existing Express process (not a separate process). Transport: StreamableHTTPServerTransport with sessionIdGenerator: undefined (stateless). Upgrade to stateful sessions (Phase 5+) = one parameter change + session Map in route handler; tool/resource definitions unchanged. Auth hook comment in src/mcp/server.ts marks the insertion point for future auth.

Test plan

  • pnpm test — 303 unit tests pass
  • DATABASE_URL=postgres://specr:specr@localhost:5432/specr pnpm test:integration — 120/121 integration tests pass (1 pre-existing CPI_BUSBAR failure, unrelated)
  • pnpm lint — clean
  • pnpm build — compiles
  • Smoke: pnpm devcurl -s -X POST http://localhost:3000/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}' | jq '.result.serverInfo'{"name":"specr","version":"0.1.0"}
  • Verify .mcp.json loads in Claude Code with pnpm dev running

Out of scope (deferred)

  • get_paragraph, parse_document tools (Phase 2b follow-up)
  • Write tools, stateful sessions (Phase 5)
  • MCP prompts review_spec, suggest_paragraphs (Phase 6)
  • get_spec_diff tool / diff resource (Phase 3, needs merge engine)
  • DOCX generator (Phase 2b)

Summary by CodeRabbit

  • New Features

    • HTTP MCP server at POST /mcp with read-only tools and resources (search, spec retrieval, section listing) and Markdown resource outputs.
  • Improvements

    • Stricter upload validation and .sec UTF‑8/control-char/line-length safety.
    • Improved error handling for upload errors.
    • Markdown renderer for spec trees and labeled headings.
  • Documentation

    • Phase 2a spec, architecture, ADR, roadmap and implementation plans added/updated.
  • Tests

    • New unit and integration tests for DB queries, MCP, parsing, and markdown.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16b95e41-b635-47c2-95db-0d48a08e1655

📥 Commits

Reviewing files that changed from the base of the PR and between e530be1 and c903a7d.

📒 Files selected for processing (1)
  • docs/superpowers/specs/2026-05-11-mcp-server-design.md
✅ Files skipped from review due to trivial changes (1)
  • docs/superpowers/specs/2026-05-11-mcp-server-design.md

📝 Walkthrough

Walkthrough

This PR implements Phase 2a of the MCP server roadmap: a stateless, read-only MCP server integrated into Express using Streamable HTTP transport, backed by new database query functions and a Markdown renderer for CSI trees. It also hardens the DOCX/SEC file upload path with pre-job validation. The implementation includes comprehensive documentation, specification, tests, and a local MCP client configuration.

Changes

MCP Server Phase 2a Implementation

Layer / File(s) Summary
Documentation, architecture, and design specifications
ARCHITECTURE.md, README.md, docs/adr/010-mcp-server.md, docs/superpowers/specs/2026-05-11-mcp-server-design.md, docs/superpowers/plans/2026-05-11-mcp-server-phase-2a.md
Updated architecture diagrams and MVP API table to reflect Streamable HTTP MCP routes; ADR-010 supersedes prior stdio/SSE approach with new decision update for Phase 2a; comprehensive Phase 2a specification documents stateless transport model, tool/resource definitions, Markdown rendering approach, and error handling; detailed implementation plan breaks down MCP server, database queries, markdown renderer, and integration test tasks with definitions of done.
Markdown rendering from CSI trees
src/generator/markdown.ts, src/generator/markdown.test.ts
getLabel(type, index, partNumber) generates hierarchical labels for part/article/pr1–pr5 variants; renderMarkdown(tree) outputs section heading, part/article hierarchy as Markdown with special handling for note blockquotes and vanish-suppressed nodes; unit tests verify label formatting, full fixture rendering, and edge cases.
Database query layer for specs and search
src/db/queries/specs.ts, src/db/queries/specs.integration.test.ts, src/db/queries/search.ts, src/db/queries/search.integration.test.ts, src/db/index.ts
getSpecTree(id) reconstructs spec hierarchies with resolved/broken reference metadata; searchParagraphs(query, division?, limit) provides ILIKE search; listCsiSections(division?) enumerates CSI sections with in-database flags; integration tests cover tree reconstruction, search matching, division filtering, result limits; exports expanded via src/db/index.ts.
MCP server routes, tools, and resources
src/mcp/server.ts, src/mcp/tools.ts, src/mcp/resources.ts, src/mcp/server.integration.test.ts, src/index.ts, .mcp.json
registerMcpRoutes(app) wires POST /mcp to create per-request stateless StreamableHTTPServerTransport, with GET/DELETE /mcp 405 stubs; search_library, get_spec, list_sections tools call database functions with Zod input schemas; spec-tree and csi-sections resources render Markdown or section tables; integration tests validate MCP initialize, tool calls with edge cases, resource reads, and stateless behavior; app wiring registers MCP routes before error handler; .mcp.json defines specr HTTP MCP server at http://localhost:3000/mcp.
SEC file safety validation and parse handler refactoring
src/parser/sec/safety.ts, src/parser/sec/safety.test.ts, src/api/parse.ts, src/api/middleware/error.ts, .github/workflows/ci.yml
assertSecSafe(buf) validates SEC encoding (fatal UTF-8 decode, rejects null bytes/control chars, 4096-char line limit); parseHandler refactored to async, validates upload before job creation via validateUpload() helper, tightens multer limits, passes buffer+extension to processParseJob; error middleware catches multer.MulterError and returns HTTP 400; CI seeds CSI section reference data before tests.

Sequence Diagram

sequenceDiagram
  participant Client as MCP Client
  participant Express as POST /mcp
  participant Transport as StreamableHTTPServerTransport
  participant McpServer as McpServer
  participant Tools as MCP Tools
  participant DB as Database
  Client->>Express: POST JSON-RPC request (tool/resource)
  Express->>Transport: instantiate per-request transport
  Transport->>McpServer: connect new McpServer instance
  McpServer->>Tools: invoke tool handler (search/get_spec/list_sections)
  Tools->>DB: query (searchParagraphs / getSpecTree / listCsiSections)
  DB-->>Tools: typed rows/result
  Tools-->>McpServer: tool result (JSON content)
  McpServer-->>Transport: JSON-RPC response
  Transport-->>Client: streamed response
  Express->>Transport: close transport on response finish
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Poem

🐰 Whiskers twitching with delight,
Express and MCP unite in flight,
Search and specs now sing in line,
Markdown blooms from tree to sign,
Stateless streams and safety shine.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main changes: adding an MCP server, Markdown renderer, and tree reconstruction for Phase 2a. The three core components align with the primary deliverables in the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/parser-docx-1c-ii

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (6)
src/api/middleware/error.ts (1)

6-10: ⚡ Quick win

Lower log severity for expected client-side validation failures.

Right now these 4xx paths are logged as unhandled error before the branch, which can inflate error-level noise.

Proposed adjustment
 export const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {
-  logger.error({ err }, 'unhandled error');
   if (err instanceof multer.MulterError) {
+    logger.warn({ err }, 'request rejected by upload validation');
     res.status(400).json({ success: false, error: err.message });
     return;
   }
+  logger.error({ err }, 'unhandled error');
   const status = (err as { status?: number }).status ?? 500;
   res.status(status).json({ success: false, error: 'internal server error' });
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/middleware/error.ts` around lines 6 - 10, The middleware currently
logs every error as logger.error before checking for client-side Multer
validation, inflating error-level noise; update the error handling in the
middleware so you first detect client/4xx errors (e.g., using the
multer.MulterError check and any other expected validation errors), and then: a)
do not call logger.error for these expected 4xx cases (use logger.warn or
logger.info instead or omit logging), b) return the 4xx response
(res.status(400).json(...)), and only call logger.error({ err }, 'unhandled
error') for unexpected/non-4xx errors; modify the code around the existing
logger.error and the multer.MulterError branch to implement this control flow
(referencing logger.error and multer.MulterError).
src/parser/sec/safety.test.ts (1)

4-26: ⚡ Quick win

Add a direct invalid UTF-8 test case

Please add one test that feeds malformed UTF-8 bytes to lock in the decoder-failure branch.

Suggested test addition
 describe('assertSecSafe', () => {
+  it('rejects invalid UTF-8 byte sequence', () => {
+    const buf = Buffer.from([0xc3, 0x28]); // malformed UTF-8
+    expect(() => assertSecSafe(buf)).toThrow('invalid UTF-8');
+  });
+
   it('accepts valid UTF-8 SEC content', () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parser/sec/safety.test.ts` around lines 4 - 26, Add a new test in
safety.test.ts that calls assertSecSafe with a Buffer containing malformed UTF-8
bytes to exercise the decoder-failure branch; for example construct a buffer
with an invalid sequence (e.g. truncated multi‑byte like 0xC3 followed by 0x28
or lone 0xFF bytes) and assert that assertSecSafe(Buffer(...)) throws (matching
the decoder/invalid UTF‑8 error).
src/db/queries/specs.ts (1)

88-108: ⚖️ Poor tradeoff

Consider immutable Map construction pattern.

The current implementation mutates childrenByParent within the loop (line 91). As per coding guidelines, immutable patterns should be preferred over mutation.

A functional approach would rebuild the Map on each iteration:

♻️ Immutable alternative
 function buildNodeTree(rows: readonly ParaRow[]): readonly CsiNode[] {
-  const childrenByParent = new Map<string | null, ParaRow[]>();
-  for (const row of rows) {
-    childrenByParent.set(row.parent_id, [...(childrenByParent.get(row.parent_id) ?? []), row]);
-  }
+  const childrenByParent = rows.reduce((acc, row) => {
+    const siblings = acc.get(row.parent_id) ?? [];
+    const updated = new Map(acc);
+    updated.set(row.parent_id, [...siblings, row]);
+    return updated;
+  }, new Map<string | null, ParaRow[]>());

Note: This has a performance cost (O(n²) instead of O(n)). Since the Map is local and never exposed, the current mutation is pragmatically acceptable for tree-building. Consider this a stylistic preference per the immutability guideline rather than a functional defect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/queries/specs.ts` around lines 88 - 108, The code mutates
childrenByParent inside buildNodeTree; to follow the immutability guideline,
replace the in-loop mutation with an immutable Map build (e.g., use rows.reduce
to produce a new Map< string | null, ParaRow[] > without mutating: for each row
create a new Map based on the prior map, update the entry for row.parent_id to a
new array [...(old ?? []), row], and return the new Map), then keep the existing
buildNode function and final return unchanged; update the declaration of
childrenByParent to be produced by that reduce instead of being mutated in the
for-loop.
src/mcp/server.integration.test.ts (1)

94-94: ⚡ Quick win

Avoid global state for test data.

Storing testSection in the global object is fragile. Since beforeAll guarantees run before tests in the same suite, use a module-scoped variable instead.

♻️ Refactor to module-scoped variable
 let server: Server;
 let baseUrl: string;
 let mcpSpecId: string;
+let mcpTestSection: string;

 // ... in beforeAll:
-  // Store for tests
-  (global as Record<string, unknown>)['mcpTestSection'] = testSection;
+  mcpTestSection = testSection;

 // ... in test:
-    const testSection = (global as Record<string, unknown>)['mcpTestSection'] as string;
+    const testSection = mcpTestSection;

Also applies to: 173-173

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp/server.integration.test.ts` at line 94, The test stores testSection
on the global object which is fragile; instead declare a module-scoped variable
(e.g., let testSection: YourType | undefined) at the top of the test file and
assign to it inside the beforeAll block; replace all reads/writes of (global as
Record<string, unknown>)['mcpTestSection'] with the module variable, and do the
same for the other occurrence around line 173 so tests access the module-scoped
testSection rather than global state.
src/parser/docx/safety.ts (2)

111-162: 💤 Low value

Minor: Local array mutation in promise scope.

Line 117 mutates relEntries with push. While this is local to the promise and never exposed (preserving practical immutability), a strict immutability approach would collect entries functionally.

Given ESLint's skipBlankLines: true configuration, manual line counting isn't reliable for the 50-line limit—defer to pnpm lint output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parser/docx/safety.ts` around lines 111 - 162, The handler in
scanZipEntries mutates the local relEntries array with relEntries.push(entry);
change this to a functional update to avoid in-place mutation: declare
relEntries with let (e.g., let relEntries: yauzl.Entry[] = [];) and replace push
with an assignment that creates a new array (e.g., relEntries = [...relEntries,
entry] or relEntries = relEntries.concat(entry)); keep all other logic
(processEntry usage, fail, zip event handlers, and final resolve(relEntries))
the same.

193-196: 💤 Low value

RegEx from template literal is safe but flagged by static analysis.

The static analyzer warns about ReDoS because the regex is constructed from a variable. However, DANGEROUS_EXTERNAL_REL_TYPES is a const array of safe literals (not user input), and the pattern [^>]* is bounded by XML structure, making this practically safe.

If this warning becomes a blocker, consider pre-compiling the patterns.

💡 Optional: Pre-compile regex patterns
+const DANGEROUS_REL_PATTERNS = DANGEROUS_EXTERNAL_REL_TYPES.map(
+  (relType) => new RegExp(
+    `relationships/${relType}[^>]*TargetMode\\s*=\\s*["']External["']`,
+    'i'
+  )
+);
+
 function isDangerousExternalRel(xml: string): boolean {
-  return DANGEROUS_EXTERNAL_REL_TYPES.some((relType) => {
-    const pattern = new RegExp(
-      `relationships/${relType}[^>]*TargetMode\\s*=\\s*["']External["']`,
-      'i'
-    );
-    return pattern.test(xml);
-  });
+  return DANGEROUS_REL_PATTERNS.some((pattern) => pattern.test(xml));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/parser/docx/safety.ts` around lines 193 - 196, The dynamic RegExp
construction using `relType` (the `pattern` variable) is triggering ReDoS
warnings; replace runtime construction with pre-compiled safe regexes: at module
init, map each entry of `DANGEROUS_EXTERNAL_REL_TYPES` to a compiled RegExp
(e.g., build a Dictionary/Map of patterns) and then look up and use that
precompiled regex instead of creating `new RegExp(...)` inside the code that
checks `TargetMode="External"`; ensure you reference the same pattern structure
(`relationships/${relType}[^>]*TargetMode\\s*=\\s*["']External["']`) when
building the precompiled regexes so callers that use `pattern`/`relType` can
simply fetch the compiled RegExp from the map.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/adr/010-mcp-server.md`:
- Around line 97-101: The fenced code block that shows the MCP routes currently
has no language tag; update the opening fence from ``` to ```text so the block
starts with ```text and retains the same content (the three lines "POST /mcp
...", "GET /mcp ...", "DELETE /mcp ...") to satisfy markdown linting in the ADR
document.

In `@src/generator/markdown.ts`:
- Around line 3-21: The alphabetic label logic in getLabel (NodeType cases
'pr1', 'pr3', 'pr5') currently uses String.fromCharCode(65/97 + index) which
breaks after 26 items; replace that with a base-26 alphabetic converter used by
those three cases so indices map to A..Z, AA..AB... (or a..z, aa..ab... for
lowercase), then append the existing punctuation ('.' for 'pr1'/'pr3', ')' for
'pr5'); implement the converter as a helper (e.g., toAlpha(index, uppercase:
boolean)) and call it from getLabel for 'pr1', 'pr3', and 'pr5' to preserve
formatting while supporting >26 labels.

In `@src/mcp/server.ts`:
- Line 36: The error handler in src/mcp/server.ts currently returns
res.status(500).json({ error: 'internal server error' }) which violates the
ApiResponse<T> contract; update the response to match other endpoints by
returning res.status(500).json({ success: false, error: 'internal server error'
}) (ensure any code paths using the same handler or variable names like res or
the surrounding middleware keep the same semantics).
- Line 27: Remove the type assertion in the call to server.connect (i.e., stop
using "as Transport" on the StreamableHTTPServerTransport instance) and instead
add the recommended tsconfig workaround: set "skipLibCheck": true under
compilerOptions in tsconfig.json to resolve the optional-property mismatch
caused by exactOptionalPropertyTypes; update tsconfig.json accordingly, remove
the assertion in the server.connect call (referencing server.connect and
Transport/StreamableHTTPServerTransport), and run the TypeScript build to verify
the error is gone.

In `@src/parser/sec/safety.ts`:
- Around line 11-13: The catch block in src/parser/sec/safety.ts currently
swallows the original decode error; update the catch to capture the exception
(e.g., catch (err)) and rethrow a ParserError that preserves the original as its
cause (e.g., throw new ParserError('invalid UTF-8 in .sec file', { cause: err
})), so the original decode failure context is retained when using ParserError.

---

Nitpick comments:
In `@src/api/middleware/error.ts`:
- Around line 6-10: The middleware currently logs every error as logger.error
before checking for client-side Multer validation, inflating error-level noise;
update the error handling in the middleware so you first detect client/4xx
errors (e.g., using the multer.MulterError check and any other expected
validation errors), and then: a) do not call logger.error for these expected 4xx
cases (use logger.warn or logger.info instead or omit logging), b) return the
4xx response (res.status(400).json(...)), and only call logger.error({ err },
'unhandled error') for unexpected/non-4xx errors; modify the code around the
existing logger.error and the multer.MulterError branch to implement this
control flow (referencing logger.error and multer.MulterError).

In `@src/db/queries/specs.ts`:
- Around line 88-108: The code mutates childrenByParent inside buildNodeTree; to
follow the immutability guideline, replace the in-loop mutation with an
immutable Map build (e.g., use rows.reduce to produce a new Map< string | null,
ParaRow[] > without mutating: for each row create a new Map based on the prior
map, update the entry for row.parent_id to a new array [...(old ?? []), row],
and return the new Map), then keep the existing buildNode function and final
return unchanged; update the declaration of childrenByParent to be produced by
that reduce instead of being mutated in the for-loop.

In `@src/mcp/server.integration.test.ts`:
- Line 94: The test stores testSection on the global object which is fragile;
instead declare a module-scoped variable (e.g., let testSection: YourType |
undefined) at the top of the test file and assign to it inside the beforeAll
block; replace all reads/writes of (global as Record<string,
unknown>)['mcpTestSection'] with the module variable, and do the same for the
other occurrence around line 173 so tests access the module-scoped testSection
rather than global state.

In `@src/parser/docx/safety.ts`:
- Around line 111-162: The handler in scanZipEntries mutates the local
relEntries array with relEntries.push(entry); change this to a functional update
to avoid in-place mutation: declare relEntries with let (e.g., let relEntries:
yauzl.Entry[] = [];) and replace push with an assignment that creates a new
array (e.g., relEntries = [...relEntries, entry] or relEntries =
relEntries.concat(entry)); keep all other logic (processEntry usage, fail, zip
event handlers, and final resolve(relEntries)) the same.
- Around line 193-196: The dynamic RegExp construction using `relType` (the
`pattern` variable) is triggering ReDoS warnings; replace runtime construction
with pre-compiled safe regexes: at module init, map each entry of
`DANGEROUS_EXTERNAL_REL_TYPES` to a compiled RegExp (e.g., build a
Dictionary/Map of patterns) and then look up and use that precompiled regex
instead of creating `new RegExp(...)` inside the code that checks
`TargetMode="External"`; ensure you reference the same pattern structure
(`relationships/${relType}[^>]*TargetMode\\s*=\\s*["']External["']`) when
building the precompiled regexes so callers that use `pattern`/`relType` can
simply fetch the compiled RegExp from the map.

In `@src/parser/sec/safety.test.ts`:
- Around line 4-26: Add a new test in safety.test.ts that calls assertSecSafe
with a Buffer containing malformed UTF-8 bytes to exercise the decoder-failure
branch; for example construct a buffer with an invalid sequence (e.g. truncated
multi‑byte like 0xC3 followed by 0x28 or lone 0xFF bytes) and assert that
assertSecSafe(Buffer(...)) throws (matching the decoder/invalid UTF‑8 error).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dfb8f2fb-4d19-406d-8988-299bbca3e598

📥 Commits

Reviewing files that changed from the base of the PR and between 736808f and 11940f2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (39)
  • .mcp.json
  • ARCHITECTURE.md
  • README.md
  • docs/adr/010-mcp-server.md
  • docs/superpowers/plans/2026-05-11-mcp-server-phase-2a.md
  • docs/superpowers/plans/2026-05-11-security-upload-hardening.md
  • docs/superpowers/specs/2026-05-11-mcp-server-design.md
  • eslint.config.js
  • package.json
  • src/api/middleware/error.test.ts
  • src/api/middleware/error.ts
  • src/api/parse.integration.test.ts
  • src/api/parse.test.ts
  • src/api/parse.ts
  • src/api/router.ts
  • src/db/index.ts
  • src/db/queries/search.integration.test.ts
  • src/db/queries/search.ts
  • src/db/queries/specs.integration.test.ts
  • src/db/queries/specs.ts
  • src/generator/markdown.test.ts
  • src/generator/markdown.ts
  • src/index.ts
  • src/mcp/resources.ts
  • src/mcp/server.integration.test.ts
  • src/mcp/server.ts
  • src/mcp/tools.ts
  • src/parser/docx/document.ts
  • src/parser/docx/index.ts
  • src/parser/docx/numbering.ts
  • src/parser/docx/safety.integration.test.ts
  • src/parser/docx/safety.test.ts
  • src/parser/docx/safety.ts
  • src/parser/docx/styles.ts
  • src/parser/docx/xml-audit.test.ts
  • src/parser/index.ts
  • src/parser/sec/index.ts
  • src/parser/sec/safety.test.ts
  • src/parser/sec/safety.ts

Comment thread docs/adr/010-mcp-server.md Outdated
Comment thread src/api/parse.ts Outdated
Comment thread src/generator/markdown.ts
Comment thread src/mcp/server.ts
Comment thread src/mcp/server.ts Outdated
Comment thread src/parser/sec/safety.ts Outdated
thewrz added a commit that referenced this pull request May 12, 2026
…r format, log severity, parse.ts fileFilter, UTF-8 test, ADR fence tag
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/adr/010-mcp-server.md`:
- Around line 122-123: Update the sentence in docs/adr/010-mcp-server.md that
currently states "Tool and resource definitions in `tools.ts` / `resources.ts`
are unchanged by this upgrade" to explicitly indicate that the lists shown
earlier are the future/target scope and not the current Phase 2a implementation;
mention that Phase 2a ships a smaller read-only subset (rather than the full
set), and reference `tools.ts` / `resources.ts` as the target files for the
future expansion so readers understand current vs planned surface area.

In `@src/mcp/server.ts`:
- Around line 28-31: Subscribe the response cleanup handler before calling
transport.handleRequest and don't swallow promise rejections from close calls:
move the res.on/once('finish', ...) registration to before await
transport.handleRequest(req, res, req.body), and in that handler call
transport.close() and server.close() and handle their promise results (e.g.,
await or Promise.allSettled and log errors) instead of using void so failures
aren't dropped; reference transport.handleRequest,
res.on('finish')/res.once('finish'), transport.close, and server.close when
locating the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e0bd998a-8b66-4f58-ad14-c90a25f66fa0

📥 Commits

Reviewing files that changed from the base of the PR and between 11940f2 and f1b69b1.

📒 Files selected for processing (7)
  • docs/adr/010-mcp-server.md
  • src/api/middleware/error.ts
  • src/api/parse.ts
  • src/generator/markdown.ts
  • src/mcp/server.ts
  • src/parser/sec/safety.test.ts
  • src/parser/sec/safety.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/parser/sec/safety.test.ts
  • src/parser/sec/safety.ts
  • src/api/middleware/error.ts
  • src/generator/markdown.ts
  • src/api/parse.ts

Comment thread docs/adr/010-mcp-server.md
Comment thread src/mcp/server.ts Outdated
thewrz added 18 commits May 12, 2026 15:34
…cisions

- ARCHITECTURE.md: Phase 2a rewritten — MCP Streamable HTTP integrated into
  Express (POST /mcp), not a separate process. Adds stateless/stateful upgrade
  path note, Phase 2b/2c renumbering, updated API table with /mcp routes, and
  corrected src/mcp/ file structure comments.
- README.md: Phase 2 row split into 2a (In Progress) / 2b / 2c; "Not Yet Built"
  section distinguishes in-progress MCP scope from remaining planned work.
- docs/adr/010-mcp-server.md: adds Decision Update section superseding the
  original stdio/SSE stance — rationale, route layout, stateful upgrade path,
  and auth hook point documented.
…function; use z.uuid() over deprecated z.string().uuid()
- POST /mcp initialize, tools/call (search_library, get_spec,
  list_sections), resources/read (specr://specs/{id}, specr://sections),
  GET /mcp 405 stateless check
- mcpCall helper adds Accept: application/json, text/event-stream and
  handles SSE vs plain-JSON response from StreamableHTTPServerTransport
- fix(infra): remap docker-compose postgres to 5433 to avoid conflict
  with wrzdj-db-1 which holds 127.0.0.1:5432
- refactor(generator): reformat switch cases in markdown.ts (no logic change)
5433 was a local workaround committed accidentally. The DATABASE_URL
in .env (gitignored) handles local port overrides; docker-compose.yml
should expose the standard 5432 for other developers and CI parity.
…r format, log severity, parse.ts fileFilter, UTF-8 test, ADR fence tag
@thewrz thewrz force-pushed the feat/parser-docx-1c-ii branch from f1b69b1 to 92d0c3e Compare May 12, 2026 22:34
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/specs/2026-05-11-mcp-server-design.md`:
- Around line 27-31: The markdown in
docs/superpowers/specs/2026-05-11-mcp-server-design.md contains unlabeled fenced
code blocks; update each triple-backtick fence around the examples (the HTTP
endpoint list block and the src/ tree block further down) to include a language
token (e.g., ```text) so they satisfy MD040; ensure both occurrences referenced
in the comment (the block showing POST/GET/DELETE /mcp and the subsequent src/
tree block) are changed to use the same language tag.
- Around line 159-162: The inline code spans for table rows `pr2`, `pr3`, `pr4`,
and `pr5` contain leading internal spaces (e.g. "`   1. text`") which triggers
MD038; remove those internal leading spaces inside the backticks (or convert the
indented examples to regular paragraph/text outside code spans) so the code
spans contain only the literal content without leading spaces, ensuring the
table cells use `pr2`, `pr3`, `pr4`, `pr5` labels with clean inline code like
`"1. text"` or plain text instead of backticked values with internal
indentation.

In `@src/api/middleware/error.ts`:
- Around line 11-13: The middleware currently asserts (err as { status?: number
}).status and passes it directly to res.status; instead, inspect and normalize
err.status without a type assertion: read err?.status, if it's a string or
number convert using Number(), ensure it's an integer and in the valid HTTP
range (e.g., 100–599 or at least 400–599 for error responses), otherwise fall
back to 500, then call res.status(normalizedStatus).json(...). Update the code
around logger.error, the status extraction, and the res.status call to perform
these runtime checks (use Number.isInteger and range checks) and remove the
TypeScript type assertion.

In `@src/mcp/server.ts`:
- Around line 18-28: Add a Zod validation step for the incoming MCP envelope
before calling transport.handleRequest: define a minimal Zod schema for the
expected envelope shape and run it against req.body, returning 400 on failure;
only pass the parsed/validated value to
StreamableHTTPServerTransport.handleRequest. Locate this change around the POST
handler where StreamableHTTPServerTransport is instantiated and
createMcpServer() is connected (references: req.body, transport.handleRequest,
StreamableHTTPServerTransport, createMcpServer) and ensure invalid input
short-circuits with res.status(400).json(...) while valid input is the sanitized
object handed to handleRequest.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cd911076-1633-40a6-a194-940590d8181e

📥 Commits

Reviewing files that changed from the base of the PR and between f1b69b1 and 92d0c3e.

📒 Files selected for processing (22)
  • .mcp.json
  • ARCHITECTURE.md
  • README.md
  • docs/adr/010-mcp-server.md
  • docs/superpowers/plans/2026-05-11-mcp-server-phase-2a.md
  • docs/superpowers/specs/2026-05-11-mcp-server-design.md
  • src/api/middleware/error.ts
  • src/api/parse.ts
  • src/db/index.ts
  • src/db/queries/search.integration.test.ts
  • src/db/queries/search.ts
  • src/db/queries/specs.integration.test.ts
  • src/db/queries/specs.ts
  • src/generator/markdown.test.ts
  • src/generator/markdown.ts
  • src/index.ts
  • src/mcp/resources.ts
  • src/mcp/server.integration.test.ts
  • src/mcp/server.ts
  • src/mcp/tools.ts
  • src/parser/sec/safety.test.ts
  • src/parser/sec/safety.ts
💤 Files with no reviewable changes (1)
  • src/api/parse.ts
✅ Files skipped from review due to trivial changes (3)
  • .mcp.json
  • README.md
  • docs/superpowers/plans/2026-05-11-mcp-server-phase-2a.md
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/index.ts
  • src/db/queries/search.integration.test.ts
  • src/parser/sec/safety.test.ts
  • src/mcp/tools.ts
  • src/db/queries/specs.ts
  • src/db/queries/specs.integration.test.ts
  • src/generator/markdown.ts
  • src/generator/markdown.test.ts
  • src/mcp/resources.ts
  • ARCHITECTURE.md
  • src/mcp/server.integration.test.ts
  • src/db/queries/search.ts

Comment thread docs/superpowers/specs/2026-05-11-mcp-server-design.md Outdated
Comment thread docs/superpowers/specs/2026-05-11-mcp-server-design.md Outdated
Comment thread src/api/middleware/error.ts
Comment thread src/mcp/server.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp/server.ts`:
- Around line 19-21: The /mcp endpoint is unprotected; add authentication that
validates the Authorization: Bearer <token> header before accepting a transport
connection (same validation logic as the existing REST auth middleware) and
return 401 on failure. Implement this by applying the REST auth middleware (or
extracting its validation function) to the /mcp route/connection handler (the
transport connection acceptor) so that token parsing, verification and rejection
happen prior to any tool/write access. Ensure the middleware/validation function
is reused (not duplicated) and that failure paths send a 401 response and abort
the transport handshake.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ddeeaec-6a03-4892-b79b-b08c6fa15dcf

📥 Commits

Reviewing files that changed from the base of the PR and between 92d0c3e and e530be1.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • src/mcp/server.ts
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/ci.yml

Comment thread src/mcp/server.ts
@thewrz thewrz merged commit 897a54d into main May 13, 2026
6 checks passed
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