npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eng-discipline-mcp

v1.0.0

Published

MCP server that enforces a structured, senior-engineer workflow on AI coding assistants: requirements, architecture, data model, and security review must all pass before any code is written.

Downloads

162

Readme

🛡️ eng-discipline-mcp

The MCP server that makes AI assistants behave like senior engineers — before a single line of code is written.

License: MIT Node Built with TypeScript Transport Phases

Turn "vibe coding" into engineered coding.


An MCP (Model Context Protocol) server that forces AI coding assistants through a structured, senior-engineer workflow before they are allowed to touch your codebase.

Instead of letting an assistant jump straight from "build me an app" to a wall of code, eng-discipline-mcp manages a per-project session with sequential, gated phases. Each phase must be completed and accepted before the next one unlocks — and the ordering is enforced in TypeScript logic, not prompt text. Call a tool out of order and it returns an explicit error naming exactly what's missing and which tool to call first.

The original Master Software Engineering Prompt is embedded verbatim and injected into every phase tool response, so the model always operates from the canonical instructions — never a paraphrase.

🗺️ The pipeline

   ┌────────┐      ┌──────────────┐      ┌───────────────┐      ┌────────────┐      ┌────────────────┐      ┌─────────────┐
   │ INTAKE │ ───▶ │ REQUIREMENTS │ ───▶ │  ARCHITECTURE │ ───▶ │ DATA_MODEL │ ───▶ │ SECURITY_REVIEW │ ───▶ │ READY_FOR_CODE │
   └────────┘      └──────────────┘      └───────────────┘      └────────────┘      └────────────────┘      └─────────────┘
    start_project    submit_req.           propose_arch.         design_data_model    review_security        get_full_spec

| Phase | Completing tool | What must be provided | | --- | --- | --- | | INTAKE | start_project | name, description, target users, problem, expected scale, deployment target, preferred stack | | REQUIREMENTS | submit_requirements | functional + non-functional requirements (10 categories), constraints, explicit assumptions | | ARCHITECTURE | propose_architecture | components with purpose / rationale / dependencies / failure modes; complexity-justification rule enforced | | DATA_MODEL | design_data_model | entities with fields, types, keys, relationships, constraints, indexes, audit fields | | SECURITY_REVIEW | review_security | trust boundaries, server-side validation, what is exposed to untrusted clients | | READY_FOR_CODE | get_full_spec | final gate — emits the assembled spec as structured markdown |

Only when the last gate passes is the assistant allowed to write code — and the spec it returns becomes the source of truth for the implementation.

🚦 The enforced rules (code, not vibes)

🧱 Phase gating. submit_requirements, propose_architecture, design_data_model, review_security, and get_full_spec each require the project to be in the matching phase. Calling one early returns an isError result structured like:

Tool call rejected: 'propose_architecture'.
Project: 'invoices-cli' (id=9f0a…)
Phase gating: 'propose_architecture' requires the project to be in phase 'ARCHITECTURE',
but it is in phase 'REQUIREMENTS'.
Missing:
  - Functional requirements have not been recorded.
  - Non-functional requirements have not been recorded.
  - Constraints have not been recorded.
  - Assumptions have not been recorded.
Call this tool first: submit_requirements

📋 Completeness. submit_requirements rejects any submission where functional requirements, non-functional requirements, constraints, or assumptions are empty.

⚖️ Over-engineering / complexity justification. During propose_architecture, any component that adds high operational complexity (queues, message brokers, Redis, Kubernetes, microservices, event-driven infrastructure, serverless, …) must include a complexity_justification. Missing justification → hard reject. A justification that contradicts a small stated scale → warning flag, stored on the project and surfaced in status and the final spec. Dangling component dependencies and unaddressed architecture concerns (auth, database, monitoring, deployment, …) are also flagged as warnings.

🧬 Data model integrity. design_data_model rejects primary keys, unique keys, indexes, or relationships that reference fields/entities that do not exist in the model.

🧰 Tools

| Tool | Purpose | | --- | --- | | start_project | Create a project session and record intake. Returns project_id. | | submit_requirements | Record requirements; advances to ARCHITECTURE. | | propose_architecture | Record architecture; advances to DATA_MODEL. | | design_data_model | Record data model; advances to SECURITY_REVIEW. | | review_security | Record trust boundaries; advances to READY_FOR_CODE. | | get_project_status | Current phase, completed phases, missing items, next tool to call. | | get_full_spec | Assembles requirements + architecture + data model + security review as markdown. Only when READY_FOR_CODE. |

Each phase tool also appends the original corresponding section(s) of the Master Engineering Prompt to its response, so the calling model always sees the canonical instructions:

| Phase tool | Original prompt sections embedded | | --- | --- | | start_project | §1 PROJECT CONTEXT | | submit_requirements | §3 REQUIREMENTS ANALYSIS | | propose_architecture | §2 YOUR FIRST RULE + §4 ARCHITECTURE FIRST | | design_data_model | §6 DATA MODEL | | review_security | §5 SYSTEM BOUNDARIES + §8 AUTH & AUTHORIZATION + §9 SECURITY ENGINEERING + §10 INPUT VALIDATION |

src/master-prompt.ts is generated from MASTER SOFTWARE ENGINEERING PROMPT.md (repo root) by npm run generate:master-prompt. It holds the prompt verbatim as named constants — MASTER_PROMPT_FULL, SECTION_PREAMBLE, one SECTION_* per numbered section (1–41), SECTION_FINAL_INSTRUCTION, and the SECTION_FOR_PHASE mapping above. The generator asserts a byte-exact round-trip before writing; regenerate it whenever you edit the source .md.

📦 Resources

| Resource | Description | | --- | --- | | eng-discipline://master-prompt | The full Master Software Engineering Prompt, verbatim. | | eng-discipline://project/{projectId}/status | Live project phase/status as JSON — read without a tool call. |

🚀 Quick start

git clone <this-repo> && cd eng-discipline-mcp
npm install
npm run build        # regenerates src/master-prompt.ts, then compiles to dist/
npm run smoke        # end-to-end test: drives a full project through all 6 phases over real stdio

Data is persisted as one JSON file per project under data/ (created automatically). Set ENG_DISCIPLINE_DATA_DIR to store projects elsewhere. Writes are atomic (tmp-file + rename) so a crash never leaves a half-written project file.

Run directly:

npx . --help           # from the repo
npx eng-discipline-mcp # after publishing to npm

🔌 Connect from your AI client

eng-discipline-mcp speaks stdio MCP (it launches as a local subprocess and talks over stdin/stdout). That's the shape nearly every AI coding client supports out of the box — no remote URL, tokens, or hosting needed. Just register it with your client's standard local server config and point it at npx -y eng-discipline-mcp.

Not published yet? Swap the command below for a local checkout: use node /absolute/path/to/eng-discipline-mcp/dist/index.js instead of npx -y eng-discipline-mcp (adjust the array/args shape per client). On Windows, escape backslashes (C:\\path\\to\\...) in JSON configs.

Quick reference

| Client | Config file | Top-level key | Transport field | | --- | --- | --- | --- | | Claude Code | .mcp.json or claude mcp add | mcpServers | inferred from command | | Claude Desktop | claude_desktop_config.json | mcpServers | inferred from command | | OpenCode | opencode.json | mcp | explicit type: "local" | | Cursor | .cursor/mcp.json | mcpServers | inferred from command | | Windsurf | ~/.codeium/windsurf/mcp_config.json | mcpServers | inferred from command | | VS Code (Copilot) | .vscode/mcp.json | servers | explicit type: "stdio" | | Zed | settings.json | context_servers | inferred from command |

🤖 Claude Code

Add to .mcp.json (project scope) or your user config:

{
  "mcpServers": {
    "eng-discipline": {
      "command": "npx",
      "args": ["-y", "eng-discipline-mcp"],
      "env": {
        "ENG_DISCIPLINE_DATA_DIR": "/absolute/path/to/eng-discipline-data"
      }
    }
  }
}

Or via the CLI (local is the default scope; use --scope user for all projects):

claude mcp add eng-discipline -- npx -y eng-discipline-mcp

Restart Claude Code and confirm with claude mcp list.

💬 Claude Desktop

Edit claude_desktop_config.json (Claude → Settings → Developer → Edit Config):

{
  "mcpServers": {
    "eng-discipline": {
      "command": "npx",
      "args": ["-y", "eng-discipline-mcp"]
    }
  }
}

Windows: %APPDATA%\Claude\claude_desktop_config.json · macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

⚡ OpenCode

Add to opencode.json (or opencode.jsonc):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "eng-discipline": {
      "type": "local",
      "command": ["npx", "-y", "eng-discipline-mcp"],
      "enabled": true,
      "environment": {
        "ENG_DISCIPLINE_DATA_DIR": "/absolute/path/to/eng-discipline-data"
      }
    }
  }
}

OpenCode is the one client that requires an explicit type: "local" and an array-form command. cwd and environment are supported if you need to pin the working directory or env vars.

🖱️ Cursor

Add to .cursor/mcp.json (per-project) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "eng-discipline": {
      "command": "npx",
      "args": ["-y", "eng-discipline-mcp"]
    }
  }
}

🌊 Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "eng-discipline": {
      "command": "npx",
      "args": ["-y", "eng-discipline-mcp"],
      "env": {
        "ENG_DISCIPLINE_DATA_DIR": "/absolute/path/to/eng-discipline-data"
      }
    }
  }
}

📝 VS Code (via Copilot / MCP extension)

Add to .vscode/mcp.json — note the top-level key is servers, not mcpServers:

{
  "servers": {
    "eng-discipline": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "eng-discipline-mcp"]
    }
  }
}

🧑‍💻 Zed

Add to your settings.json — Zed nests the command under a command object:

{
  "context_servers": {
    "eng-discipline": {
      "command": {
        "path": "npx",
        "args": ["-y", "eng-discipline-mcp"]
      }
    }
  }
}

⚠️ The differences to watch for

  • Top-level key: mcpServers (Claude Code, Claude Desktop, Cursor, Windsurf) vs mcp (OpenCode) vs servers (VS Code) vs context_servers (Zed).
  • Transport field: most clients infer stdio from a command; OpenCode and VS Code demand an explicit type ("local" / "stdio").
  • Command shape: OpenCode wants an array (["npx", "-y", "…"]); everyone else wants command + args.
  • Env vars: Claude Code, Claude Desktop, Windsurf, and OpenCode pass them via env/environment so you can pin ENG_DISCIPLINE_DATA_DIR.

💾 Persistence & environment

| Variable | Default | Description | | --- | --- | --- | | ENG_DISCIPLINE_DATA_DIR | <cwd>/data | Where project sessions are stored (one JSON file per project). Point this at a stable path so sessions survive across tools and machines. |

Project files are written atomically (tmp-file + rename), so a crash never leaves a half-written session. A corrupt file surfaces a descriptive CorruptProjectError telling you exactly which file to inspect.

🎬 End-to-end walkthrough

A full session proving every phase gate, from intake to the final spec:

1. Intake

start_project(name="Invoices CLI", description="...", target_users="...",
  problem="...", scale="single operator, tens of invoices", deployment_target="local laptop",
  preferred_stack="Node.js, SQLite")
→ INTAKE RECORDED … Phase advanced: INTAKE → REQUIREMENTS

2. Requirements

submit_requirements(project_id, functional=[...], non_functional={performance: "..."},
  constraints={budget: "..."}, assumptions=[...])
→ REQUIREMENTS RECORDED … Phase advanced: REQUIREMENTS → ARCHITECTURE

3. Trying to skip ahead is rejected

design_data_model(project_id, entities=[...])
→ Phase gating: 'design_data_model' requires phase 'DATA_MODEL', but it is in phase 'ARCHITECTURE'.
  Missing: The architecture has not been proposed. Call this tool first: propose_architecture

4. Architecture (with the complexity rule in action)

propose_architecture(project_id, components={
  backend: { purpose: "...", rationale: "...", dependencies: [], failure_modes: ["..."], complexity_justification: "..." },
  redis_cache: { purpose: "...", rationale: "...", dependencies: ["backend"], failure_modes: ["..."],
                 complexity_justification: "single operator — not justified" }
})
→ ARCHITECTURE RECORDED … warning flag raised: component 'redis_cache' adds complexity
  (redis) but the stated scale reads as small. Review before writing code.
  Phase advanced: ARCHITECTURE → DATA_MODEL

Omitting complexity_justification on redis_cache would instead reject the whole submission with an OverengineeringError until it is justified or removed.

5. Data model

design_data_model(project_id, entities=[{ name: "Invoice", fields: [...], keys: {primary_key: "id"},
  relationships: [], constraints: ["total >= 0"], audit_fields: ["created_at", "updated_at", "deleted_at"] }])
→ DATA MODEL RECORDED … Phase advanced: DATA_MODEL → SECURITY_REVIEW

6. Security review

review_security(project_id, trust_boundaries={ summary: "...", client_side: {...},
  server_side: { validated: ["..."] }, exposed_to_clients: [...], trust_assumptions: [...] })
→ ALL PHASES COMPLETE — project is now READY_FOR_CODE.

7. Final gate

get_project_status(project_id)
→ phase: READY_FOR_CODE, ready_for_code: true, next_tool: get_full_spec

get_full_spec(project_id)
→ # Engineering Specification: Invoices CLI … full markdown spec.

Only now is the assistant allowed to write code — and the spec it returns is the source of truth for the implementation.

🗂️ Project layout

MASTER SOFTWARE ENGINEERING PROMPT.md  # the source prompt; src/master-prompt.ts is generated from it
src/
  index.ts                 # MCP server wiring + stdio entry point
  master-prompt.ts         # GENERATED — Master Engineering Prompt, verbatim, as named string constants
  constants.ts             # phases, tool↔phase mapping, complexity keywords
  schemas/toolSchemas.ts   # zod schemas + inferred input types for every tool
  storage/types.ts         # Project, phase-section record types
  storage/store.ts         # JSON file store, atomic writes
  domain/phases.ts         # phase machine + hard gate enforcement
  domain/completeness.ts   # requirements completeness gate
  domain/complexity.ts     # over-engineering / scale-justification gate
  domain/dataModel.ts      # data-model integrity gate
  domain/status.ts         # status assembly + rendering
  domain/spec.ts           # get_full_spec markdown assembly
  tools/                   # one file per MCP tool + registry
  resources/               # master-prompt + live project-status resources
scripts/
  generate-master-prompt.mjs  # splits the .md into SECTION_* constants (verbatim, round-trip checked)
  smoke-test.mjs              # end-to-end proof: full project through all 6 phases over stdio

📄 License

MIT