XcodeBuildMCP is an MCP server exposing Xcode / Swift workflows as tools and resources.
Stack: TypeScript · Node.js · plugin-based auto-discovery (src/mcp/tools, src/mcp/resources).
For full details see README.md and docs/ARCHITECTURE.md.
- No hard-coded secrets, tokens or DSNs.
- MCP tool logic functions that orchestrate long-running processes with sub-processes (e.g.,
xcodebuild) must flow throughCommandExecutorwith validated arguments. Standalone utility modules that invoke simple, short-lived commands may use directchild_process/fsimports and standard vitest mocking. - Paths must be sanitised via helpers in
src/utils/validation.ts. - Sentry breadcrumbs / logs must NOT include user PII.
| Rule | Quick diff heuristic |
|---|---|
| Dependency injection for tool logic | New child_process | fs import in MCP tool logic ⇒ warning (check if process is complex/long-running) |
| Handler / Logic split | handler > 20 LOC or contains branching ⇒ critical |
| Plugin auto-registration | Manual registerTool(...) / registerResource(...) ⇒ critical |
Positive pattern skeleton:
// src/mcp/tools/foo-bar.ts
export async function fooBarLogic(
params: FooBarParams,
exec: CommandExecutor = getDefaultCommandExecutor(),
fs: FileSystemExecutor = getDefaultFileSystemExecutor(),
) {
// ...
}
export const handler = (p: FooBarParams) => fooBarLogic(p);- External-boundary rule for tool logic: Use
createMockExecutor/createMockFileSystemExecutorfor complex process orchestration (xcodebuild, multi-step pipelines) in MCP tool logic functions. - Simple utilities: Standalone utility modules with simple command calls can use direct imports and standard vitest mocking.
- Internal mocking is allowed:
vi.mock,vi.fn,vi.spyOn, and.mock*are acceptable for internal modules/collaborators. - Each tool must have tests covering happy-path and at least one failure path.
- Avoid the
anytype unless justified with an inline comment.
docs/TOOLS.mdmust exactly mirror the structure ofsrc/mcp/tools/**(exclude__tests__and*-shared). Diff heuristic: if a PR adds/removes a tool but does not changedocs/TOOLS.md⇒ warning.- Update public docs when CLI parameters or tool names change.
| Anti-pattern | Preferred approach |
|---|---|
Complex logic in handler |
Move to *Logic function |
| Re-implementing logging | Use src/utils/logger.ts |
Direct fs / child_process in tool logic orchestrating complex processes |
Inject FileSystemExecutor / CommandExecutor |
| Chained re-exports | Export directly from source |
- External-boundary violations: confirm tests use injected executors/filesystem for external side effects.
- DI compliance: check direct
child_process/fsimports in MCP tool logic; standalone utilities with simple commands are acceptable. - Docs accuracy: compare
docs/TOOLS.mdagainstsrc/mcp/tools/**. - Style: ensure ESLint and Prettier pass (
npm run lint,npm run format:check).
Happy reviewing 🚀