@blockspool/mcp
v0.5.60
Published
BlockSpool MCP server - stateful tool provider for Claude Code
Maintainers
Readme
@blockspool/mcp — MCP Server
Stateful MCP server that powers BlockSpool's improvement loop. Exposes tools for session management, scouting, execution, and git operations.
Quick Start
# As stdio MCP server (for Claude Code plugin)
npx @blockspool/mcp
# Or via the DirectClient API (for any LLM)
import { DirectClient } from '@blockspool/mcp/direct-client';
const client = await DirectClient.create({ projectPath: '.' });
client.startSession({ scope: 'src/**', formula: 'security-audit' });
while (true) {
const resp = await client.advance();
if (resp.next_action === 'STOP') break;
// ... call your LLM with resp.prompt ...
await client.ingestEvent('SCOUT_OUTPUT', { proposals: [...] });
}
client.endSession();
await client.close();MCP Tool Reference
Session Management
| Tool | Description | Parameters |
|------|-------------|------------|
| blockspool_start_session | Initialize a session | hours?, formula?, deep?, scope?, categories?, min_confidence?, max_prs?, step_budget?, ticket_step_budget?, draft_prs? |
| blockspool_advance | Get next action (main loop driver) | — |
| blockspool_ingest_event | Report event, trigger state transitions | type, payload |
| blockspool_session_status | Current session state | — |
| blockspool_end_session | Finalize session | — |
| blockspool_nudge | Add hint for next scout cycle | hint |
| blockspool_list_formulas | List available formulas | — |
| blockspool_get_scope_policy | Get scope policy for current ticket | file_path? |
Execution
| Tool | Description | Parameters |
|------|-------------|------------|
| blockspool_next_ticket | Get next ticket to work on | — |
| blockspool_validate_scope | Check changed files against scope | ticketId, changedFiles[] |
| blockspool_complete_ticket | Mark ticket done, run QA | ticketId, runId, summary? |
| blockspool_fail_ticket | Mark ticket failed | ticketId, runId, reason |
Git
| Tool | Description | Parameters |
|------|-------------|------------|
| blockspool_git_setup | Create/checkout branch for ticket | ticketId, baseBranch? |
Canonical Loop Protocol
The core protocol is adapter-agnostic. Any client repeats:
advance() → get prompt + constraints
→ execute prompt (any LLM)
→ ingest_event(type, payload)
→ repeat until STOPEvent Types
| Event | When | Payload |
|-------|------|---------|
| SCOUT_OUTPUT | After scouting | { proposals: [...] } |
| PLAN_SUBMITTED | After planning | { ticket_id, files_to_touch, estimated_lines, risk_level } |
| TICKET_RESULT | After execution | { status, changed_files, lines_added, lines_removed } |
| QA_COMMAND_RESULT | Per QA command | { command, success, output } |
| QA_PASSED | All QA passes | { summary } |
| QA_FAILED | QA fails | { error } |
| PR_CREATED | PR created | { url, branch } |
| USER_OVERRIDE | Hint or cancel | { hint } or { cancel: true } |
Phase State Machine
SCOUT → NEXT_TICKET → PLAN → EXECUTE → QA → PR → NEXT_TICKET → DONE
Terminal states: DONE, BLOCKED_NEEDS_HUMAN, FAILED_BUDGET, FAILED_VALIDATION, FAILED_SPINDLEFormulas
Built-in formulas customize scout behavior:
| Formula | Description | Categories |
|---------|-------------|------------|
| security-audit | OWASP vulnerabilities | security |
| test-coverage | Missing unit tests | test |
| type-safety | Remove any/unknown | types |
| cleanup | Dead code, unused imports | refactor |
| deep | Architecture review | refactor, perf, security |
| docs | Missing JSDoc | docs |
Custom Formulas
Create .blockspool/formulas/<name>.yaml:
description: Find and fix error handling issues
categories: [refactor, security]
min_confidence: 75 # hint only — does not filter proposals
risk_tolerance: medium
prompt: |
Find functions with missing error handling.
Look for uncaught promises, empty catch blocks,
and functions that silently swallow errors.
tags: [quality]Run Folder Anatomy
Each session creates a run folder at .blockspool/runs/<run_id>/:
.blockspool/runs/run_abc123/
├── state.json # Current RunState (overwritten each step)
├── events.ndjson # Append-only event log (one JSON per line)
├── diffs/ # Patch files per step
│ └── 5-tkt_xyz.patch
└── artifacts/ # QA logs, scout proposals, etc.
├── 1-scout-proposals.json
├── 3-ticket-result.json
├── 4-qa-npm-test-pass.log
└── 5-pr-created.jsonDebugging a Failed Run
- Check phase:
cat .blockspool/runs/<id>/state.json | jq .phase - Read events:
cat .blockspool/runs/<id>/events.ndjson | jq . - Find the failure:
grep FAILED .blockspool/runs/<id>/events.ndjson - Check spindle:
cat .blockspool/runs/<id>/state.json | jq .spindle - Read QA logs:
cat .blockspool/runs/<id>/artifacts/*qa*
state.json Fields
| Field | Description |
|-------|-------------|
| phase | Current state machine phase |
| step_count / step_budget | Progress tracking |
| tickets_completed / tickets_failed | Work summary |
| spindle | Loop detection state (output_hashes, diff_hashes, iterations_since_change) |
| current_ticket_id | Active ticket being worked on |
| plan_approved | Whether commit plan was approved |
| hints | Pending hints from nudge |
Architecture
Claude Code / Any LLM
└─ MCP: @blockspool/mcp (stdio)
├─ advance() — deterministic state machine
├─ processEvent() — event-driven transitions
├─ checkSpindle() — loop detection
├─ deriveScopePolicy()— scope enforcement
├─ loadFormula() — formula system
├─ loadGuidelines() — CLAUDE.md context injection
└─ SQLite state — tickets, runs, proposalsProject Guidelines Context
The advance engine automatically loads project guidelines and prepends them to scout and execute prompts. This ensures agents follow project conventions without any configuration.
- Claude runs search for
CLAUDE.mdfirst, then fall back toAGENTS.md - Codex runs search for
AGENTS.mdfirst, then fall back toCLAUDE.md - Loaded fresh on every
advance()call (MCP sessions are stateless between calls) - Wrapped in
<project-guidelines>XML tags - Full file content injected (no truncation)
