agentleFS
nickytonlinenickytonline/beads-mcp/AGENTS.md

beads-mcp

AGENTS.md3 starsChanged 34 days agoMITView on GitHub

Beads adapter based on the TypeScript template for building Model Context Protocol (MCP) servers over HTTP. Always run these and fix any failures before opening a PR: Config files (vite.config.ts, tsconfig.json, eslint.config.js, Dockerfile) live at the repo root.

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository3 other files it gives its agents.

The file

Show its rules and text

We split this AGENTS.md into the rules it gives an agent

16 rules. About 0 are common, 5 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Always run these and fix any failures before opening a PR:

    line 30
  2. Distinctive:

    If a tool needs state across calls, mint an explicit handle and have the model pass it back as an argument on the next call — there is no …

    line 81
  3. Very specific:

    Use Effect.all with explicit concurrency for independent parallel effects.

    line 112
  4. Very specific:

    Use logger from src/logger.ts — yield the returned Effect inside an Effect workflow or run it with runMcpEffect() at a callback boundary.

    line 116
  5. Very specific:

    Add the server.registerTool() call inside registerTools() in src/tools.ts

    line 130
  6. Very specific:

    If the tool needs user input mid-call, return inputRequired({ inputRequests: {...} }) (see elicit_echo in src/tools.ts) — the older …

    line 138
  7. Very specific:

    Add integration tests to src/tools.test.ts (import registerTools, wire an in-memory client/server)

    line 139
  8. Very specific:

    Test files: *.test.ts, colocated beside the source (see src/lib/utils.test.ts)

    line 144
  9. Very specific:

    Use async/await for all async tests

    line 146
  10. Distinctive:

    Write a failing test that reproduces a bug before fixing it

    line 147
  11. Very specific:

    Update package.json (name, description, version).

    line 153
  12. Very specific:

    Add/replace env vars in src/config.ts

    line 154
  13. Very specific:

    Add business logic under src/

    line 156
  14. Distinctive:

    Update README.md and this AGENTS.md to reflect your project

    line 157
  15. Very specific:

    Use Conventional Commits: feat:, fix:, chore:, docs:.

    line 161
  16. Distinctive:

    Keep one process and one replica for embedded mode.

    line 169

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Repository Guidelines

Beads adapter based on the TypeScript template for building Model Context Protocol (MCP) servers over HTTP.

Key Commands

# Development (hot reload via native Node.js type stripping)
npm run dev

# Build (Vite → ES modules in dist/)
npm run build

# Production
npm start

# Lint & format
npm run lint
npm run lint:fix
npm run format
npm run format:check

# Tests
npm run test       # interactive Vitest
npm run test:ci    # outputs test-results.json

Before Submitting

Always run these and fix any failures before opening a PR:

npm run lint && npm run format:check && npm run build && npm run test:ci

Project Structure

src/
  app.ts         # Express app and MCP Node adapter wiring
  app.test.ts    # HTTP boundary integration tests
  index.ts       # Effect startup and shutdown; runs the app on PORT
  tools.ts       # registerTools() wiring + per-tool logic functions
  tools.test.ts  # colocated integration tests (in-memory client/server)
  hardening.test.ts # concurrency, ownership, change-detection and error-contract tests
  beads.ts       # process-wide bd queue and subprocess execution
  bench-latency.ts # latency benchmark harness for MCP tool calls (npm run bench)
  errors.ts      # typed error codes and bd stderr classification
  revision.ts    # state_revision / activity_revision and lease-field stripping
  config.ts      # Env var loading and validation via Effect Config
  logger.ts      # Effect structured logging
  skills.ts      # bundled Agent Skill and MCP Skills extension handlers
  skills.test.ts # skill discovery, manifest integrity, and resource tests
  lib/
    utils.ts       # MCP response helpers (createTextResult, createErrorResult)
    mcp-schema.ts  # Effect Schema adapter for MCP Standard Schema
    utils.test.ts  # colocated unit tests
    mcp-schema.test.ts # adapter and JSON Schema dialect tests
  test-support/
    fake-bd.ts     # stateful in-memory bd stand-in for tests
docs/
  GUARANTEES.md  # what is guaranteed, tested, and still unverified
skills/
  beads-engineering-backlog/SKILL.md # canonical Agent Skill for Beads workflows
dist/            # compiled output (ES modules)

Config files (vite.config.ts, tsconfig.json, eslint.config.js, Dockerfile) live at the repo root.

Architecture

  • HTTP transport via Express on PORT (default 3000) — not stdio; app wiring lives in src/app.ts, startup and shutdown in src/index.ts
  • Tools registered via registerTools(server) in src/tools.ts, the single source of truth for tool wiring — called from getServer() in src/app.ts and reused by the tests
  • The canonical beads-engineering-backlog Agent Skill is registered by registerSkills(server) in src/skills.ts; it is served through normal MCP resources and the io.modelcontextprotocol/skills extension
  • Tool responses use createTextResult / createErrorResult from src/lib/utils.ts: a text content block plus structuredContent (for clients that declare an outputSchema)
  • Tool workflows use Effect and cross the MCP callback boundary with runMcpEffect()
  • Effect Schemas cross the MCP boundary through toMcpSchema(), which supports the MCP SDK's draft-07 and draft-2020-12 JSON Schema targets
  • Genuine execution failures return isError: true (via createErrorResult), not thrown; valid outcomes (e.g. a user declining an elicitation) are normal results
  • Stateless per the MCP 2026-07-28 spec: no session handshake or Mcp-Session-Id; createMcpHandler creates a fresh server per request and supports older clients through its fallback.
  • GET /health is a plain liveness endpoint (used by the Docker healthcheck) — GET /mcp itself is routed to the MCP handler and no longer doubles as one
  • If a tool needs state across calls, mint an explicit handle and have the model pass it back as an argument on the next call — there is no transport-level session to hang state off anymore
  • Graceful shutdown on SIGTERM/SIGINT (closes the handler and HTTP server in parallel with Effect.all, then exits)

Build System

  • Vite bundles to ES modules; @modelcontextprotocol/server and @modelcontextprotocol/node are external (not bundled)
  • TypeScript 7 provides the tsc compiler; the typescript dependency is an npm alias for @typescript/typescript6 so typescript-eslint can use its legacy compiler API, and exposes tsc6 for compatibility checks
  • @ path alias maps to src/
  • Node.js 24+ required (native TypeScript type stripping used in dev)

Environment Variables

Defined and validated in src/config.ts:

VariableDefaultDescription
PORT3000HTTP server port
NODE_ENV—development / production / test
SERVER_NAMEname in package.jsonMCP server name
SERVER_VERSIONversion in package.jsonMCP server version
LOG_LEVELinfoerror / warn / info / debug

Coding Conventions

  • TypeScript with ES module syntax (import/export)
  • Prettier defaults: 2-space indent, double quotes, trailing commas
  • ESLint with @typescript-eslint — any is discouraged (warn)
  • Private class methods use # prefix
  • Intentionally unused params/vars: prefix with _
  • camelCase for functions/variables, PascalCase for types
  • Descriptive filenames: logger.ts, utils.ts
  • Use Effect.all with explicit concurrency for independent parallel effects; use Effect.tryPromise only at Promise-based integration boundaries

Logging

Use logger from src/logger.ts — yield the returned Effect inside an Effect workflow or run it with runMcpEffect() at a callback boundary. Never use console.log.

// Structured data first, message second
yield* logger.info({ requestId, toolName }, "Tool executed");
yield* logger.error({ requestId, toolName, error: error.message }, "Tool execution failed");

Log levels: error > warn > info > debug. For tool-call logs, include requestId and toolName so entries can be correlated back to a single call. Lifecycle and shutdown logs should include the context available to them. Add other scalar fields relevant to the outcome (e.g. action, kind). Never log the raw args object — tool inputs may carry user-provided or sensitive data — log individual fields only when they're known to be safe to record. Effect logging carries structured annotations and integrates with Effect's tracing context.

Adding a New Tool

See the create-mcp-tool skill (.agents/skills/create-mcp-tool) for the full walkthrough. For projects created from the pre-Effect version of this template, use migrate-mcp-template-to-effect (.agents/skills/migrate-mcp-template-to-effect) first. In short:

  1. Add the server.registerTool() call inside registerTools() in src/tools.ts
  2. Provide a title, description, inputSchema/outputSchema created with toMcpSchema(Schema.Struct({...})), and annotations (e.g. readOnlyHint)
  3. The handler receives (args, ctx) (or just (ctx) with no inputSchema) — ctx.mcpReq.id is the request id; there is no sessionId to rely on
  4. Compose the implementation as an Effect and return runMcpEffect(effect) from the MCP callback
  5. Return createTextResult(result) on success (it also emits structuredContent)
  6. On genuine failure return createErrorResult({ error }) (sets isError: true); don't throw
  7. Log with yield* logger.info({ toolName, requestId }, "Tool executed") on success
  8. Log with yield* logger.error({ toolName, requestId, error: error.message }, "Tool execution failed") on failure — omit the raw args object (see Logging)
  9. If the tool needs user input mid-call, return inputRequired({ inputRequests: {...} }) (see elicit_echo in src/tools.ts) — the older synchronous elicitInput() push request throws on a 2026-07-28-era connection
  10. Add integration tests to src/tools.test.ts (import registerTools, wire an in-memory client/server)

Testing

  • Framework: Vitest
  • Test files: *.test.ts, colocated beside the source (see src/lib/utils.test.ts)
  • Cover new tools, transports, config logic, schema adapters, and the HTTP app with focused tests
  • Use async/await for all async tests
  • Write a failing test that reproduces a bug before fixing it

Using This Template

To build your own MCP server from this template:

  1. Update package.json (name, description, version). name and version are the MCP server identity unless SERVER_NAME or SERVER_VERSION is set
  2. Add/replace env vars in src/config.ts
  3. Replace the echo / elicit_echo tools in src/tools.ts with Beads tools
  4. Add business logic under src/
  5. Update README.md and this AGENTS.md to reflect your project

Commit & PR Guidelines

  • Use Conventional Commits: feat:, fix:, chore:, docs:; use feat!: for breaking template migrations
  • PR description: summarize user-facing impact, link issues, list any new env vars
  • Include verification evidence: npm run lint, npm run test:ci

Beads adapter invariants

  • src/beads.ts owns the process-wide queue, shared across stateless requests. Queue all CLI access, including reads and compound operations.
  • Execute bd with argument arrays and no shell; never accept arbitrary commands or filesystem paths from tool inputs.
  • Keep one process and one replica for embedded mode. Do not run direct CLI/backup access concurrently. See README.md, "Running multiple MCP replicas", before changing storage mode or replica count; local queues do not coordinate ownership checks across pods.
  • Require a verified signed JWT for /mcp in every environment. Derive the Beads actor from the configured JWT claim; actor inputs are compatibility fields, not authenticated identity.
  • Claims never expire and there are no leases; do not advertise lease behavior. lease_expires_at and heartbeat_at from bd are stripped from responses.
  • Optimistic concurrency is opt-in: update, release, handoff and complete take expected_revision (the state_revision from get). Without it writes are last-writer-wins. Keep docs/GUARANTEES.md and the tool descriptions in sync with the code, and do not claim guarantees that no test covers.
  • Live verification: BD_BIN=/path/to/bd npm run test:beads; default tests skip it.
  • Container pins Beads 1.3.1.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.