Skip to content

refactor: modularize MCP server and CLI shared utilities#162

Open
galligan wants to merge 2 commits into
mainfrom
refactor/mcp-modularize
Open

refactor: modularize MCP server and CLI shared utilities#162
galligan wants to merge 2 commits into
mainfrom
refactor/mcp-modularize

Conversation

@galligan

@galligan galligan commented Feb 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • MCP extraction: Split the 2,348-line apps/mcp/src/index.ts monolith into 14 focused modules (~290 lines remaining)

    • types.ts: shared interfaces (FirewatchParams, McpToolResult, SchemaName)
    • handlers/: query, status, feedback, mutations, config, help
    • context/: repo, mutation, feedback context factories
    • utils/: formatting, parsing, sync, id-resolution
  • CLI deduplication: Extract shared auth-client helper and deduplicate resolveRepo

    • New auth-client.ts with tryCreateClient() replacing 6 identical createContext functions
    • New resolveRepo() in repo.ts replacing 4 inline copies across ack, close, freeze, unfreeze
    • Net -166 lines across 11 CLI files

Test plan

  • bun run check — 0 errors (1 pre-existing complexity warning on handleRm)
  • bun test — 200 tests pass, 518 assertions
  • Manual: fw status, fw list, fw query --type review --since 7d
  • Manual: MCP server starts and responds to tool calls

🤘🏻 In-collaboration-with: Claude Code

@galligan galligan changed the title refactor(mcp): extract monolith index.ts into modular handlers refactor: modularize MCP server and CLI shared utilities Feb 7, 2026

galligan commented Feb 7, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@galligan galligan marked this pull request as ready for review February 7, 2026 12:08
@greptile-apps

greptile-apps Bot commented Feb 7, 2026

Copy link
Copy Markdown

Greptile Overview

Greptile Summary

This PR modularizes the MCP server implementation by splitting the prior apps/mcp/src/index.ts monolith into focused handler/context/utility modules, and refactors the CLI to deduplicate repo resolution and authenticated client/context creation.

On the MCP side, tool registration is now centralized in FirewatchMCPServer (base tools always available; write tools registered only after successful auth check, with sendToolListChanged() notification). Query/status/doctor/help/config/mutation/feedback logic has been extracted into separate modules with shared parsing/formatting/sync helpers.

On the CLI side, repeated per-command context creation is replaced with a shared tryCreateClient() helper (load config, resolve repo, detect auth, instantiate GitHubClient, and decide JSONL vs human output), and repo detection is consolidated into resolveRepo() in apps/cli/src/repo.ts for commands that previously duplicated inline repo detection.

One functional regression was found in MCP help/schema output: requesting the query schema via fw_help will currently return the entry schema instead.

Confidence Score: 4/5

  • This PR is mostly safe to merge, with one user-visible MCP help/schema regression to fix first.
  • Changes are primarily structural refactors with preserved call paths and types, and the only verified behavioral issue is fw_help returning the wrong schema when schema="query" is requested. Once fixed, remaining risk is limited to refactor integration edges (tool registration/auth gating) that should be covered by the existing test suite plus manual MCP smoke test.
  • apps/mcp/src/handlers/help.ts

Important Files Changed

Filename Overview
apps/cli/src/auth-client.ts Adds shared tryCreateClient() helper to centralize config/auth/repo resolution and output-format selection.
apps/cli/src/repo.ts Adds resolveRepo() as a silent variant of resolveRepoOrThrow(); keeps repo format validation helpers.
apps/mcp/src/handlers/feedback.ts Extracts feedback tool handler with list/view/reply/ack/resolve flows; uses shared context + ID resolution helpers.
apps/mcp/src/handlers/help.ts Extracts MCP help/schema docs builder; currently returns entry schema for schema:"query" due to missing branch.
apps/mcp/src/handlers/mutations.ts Extracts mutation handlers (add/edit/rm) and shared parsing utilities; preserves prior behavior.
apps/mcp/src/handlers/query.ts Refactors query tool handling into phases (validate, detect, sync, query, filter, format) using extracted utils.
apps/mcp/src/index.ts Replaces monolithic server with FirewatchMCPServer class that registers base tools and auth-gated write tools.

Sequence Diagram

sequenceDiagram
  autonumber
  participant Client as MCP Client
  participant FW as FirewatchMCPServer
  participant Core as firewatch-core
  participant DB as SQLite Cache
  participant GH as GitHub API

  Client->>FW: connect() via stdio transport
  FW->>FW: registerBaseTools()
  FW->>Core: loadConfig()
  FW->>Core: detectAuth(config.github_token)
  alt auth token available
    FW->>FW: registerWriteTools()
    FW-->>Client: sendToolListChanged()
  else no auth
    FW-->>Client: base tools only
  end

  Client->>FW: tool call fw_query(params)
  FW->>Core: loadConfig()
  FW->>Core: detectRepo()
  FW->>FW: ensureRepoCacheIfNeeded(repoFilter,...)
  alt cache missing or stale + auto_sync
    FW->>Core: detectAuth(...)
    FW->>GH: syncRepo(...)
    GH-->>FW: PR activity
    FW->>DB: write entries/meta
  end
  FW->>DB: queryEntries(filters)
  FW-->>Client: JSONL text result

  Client->>FW: tool call fw_status({recheck_auth:true})
  FW->>Core: loadConfig()
  FW->>Core: detectAuth(...)
  alt token newly available
    FW->>FW: registerWriteTools()
    FW-->>Client: sendToolListChanged()
  end
  FW->>FW: handleStatus(params)
  FW-->>Client: status JSON text result
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread apps/mcp/src/handlers/help.ts Outdated
Comment on lines +9 to +11
export function schemaDoc(name: SchemaName | undefined): object {
if (name === "worklist") {
return WORKLIST_SCHEMA_DOC;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

schemaDoc ignores query

schemaDoc() only branches on worklist and config, and otherwise returns ENTRY_SCHEMA_DOC, so fw_help with {"schema":"query"} will return the entry schema instead of the query schema. This is user-visible and breaks the advertised help output for the query schema type.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/mcp/src/handlers/help.ts
Line: 9:11

Comment:
**`schemaDoc` ignores `query`**

`schemaDoc()` only branches on `worklist` and `config`, and otherwise returns `ENTRY_SCHEMA_DOC`, so `fw_help` with `{"schema":"query"}` will return the entry schema instead of the query schema. This is user-visible and breaks the advertised help output for the `query` schema type.

How can I resolve this? If you propose a fix, please make it concise.

Split the 2,348-line MCP server monolith into focused modules:
- types.ts: shared interfaces (FirewatchParams, McpToolResult)
- handlers/: query, status, feedback, mutations, config, help
- context/: repo, mutation, feedback context factories
- utils/: formatting, parsing, sync, id-resolution
- index.ts slimmed to ~290 lines (server class + tool registration)

🤘🏻 In-collaboration-with: [Claude Code](https://claude.com/claude-code)
schemaDoc() silently fell through to ENTRY_SCHEMA_DOC for "query" and
"entry" via the default case. Make all SchemaName variants explicit
in a switch so the mapping is intentional, not accidental.

🤘🏻 In-collaboration-with: [Claude Code](https://claude.com/claude-code)
@galligan galligan force-pushed the refactor/mcp-modularize branch from 0575763 to 08f79bf Compare February 8, 2026 12:22
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