Emin MCP Server
by eminogrande
README.md
# emin-mcp
> **Use this? Here's everything you need. One URL, no auth, 30 seconds.**
```
URL: https://emin-mcp.emino.workers.dev/mcp
Auth: none
```
---
## Connect your agent
Pick your tool, copy the config. Done.
### Hermes Agent
```yaml
# ~/.hermes/config.yaml
mcp_servers:
emin:
type: http
url: https://emin-mcp.emino.workers.dev/mcp
transport: streamable-http
```
### opencode
```jsonc
// opencode.json
{
"mcp": {
"emin": {
"type": "http",
"url": "https://emin-mcp.emino.workers.dev/mcp",
"transport": "streamable-http"
}
}
}
```
### Claude Code
```json
// .claude/mcp.json or VS Code settings
{
"mcpServers": {
"emin": {
"type": "http",
"url": "https://emin-mcp.emino.workers.dev/mcp"
}
}
}
```
### Cursor
```json
// .cursor/mcp.json
{
"mcpServers": {
"emin": {
"transport": "sse",
"url": "https://emin-mcp.emino.workers.dev/mcp"
}
}
}
```
### Continue
```json
// config.json
{
"experimental": {
"mcpServers": {
"emin": {
"transport": "sse",
"url": "https://emin-mcp.emino.workers.dev/mcp"
}
}
}
}
```
### Generic SSE client
```
Endpoint: POST https://emin-mcp.emino.workers.dev/mcp
Headers: Accept: application/json, text/event-stream
```
### Run it locally instead
```bash
git clone https://github.com/eminogrande/emin-mcp.git
cd emin-mcp && npm install
```
Then point your tool at `node /path/to/emin-mcp/src/index.mjs` (stdio).
---
## What your agent gets
Three resources, read automatically on session start. Four tools for mechanical enforcement.
| Resource | Content |
|---|---|
| `rules://emin/global` | 16 working rules: TLDR first, never invent features, ask before irreversible actions, document every decision, … |
| `rules://emin/tooling` | Mandatory tools: ponytail (YAGNI), nuanced (call-graph), repowise (file health), task-master (PRD→tasks) |
| `rules://emin/coding` | 15 evidence-derived coding rules: zeroize buffers, no silent fallbacks, scope-drift = stop, hostile self-review, … |
| Tool | What it does |
|---|---|
| `scope_check` | Checks if a diff stayed within planned scope (files + LOC). Enforces rule #3. |
| `secrets_check` | Scans text for API keys, tokens, private keys, mnemonics. Enforces rule #14. |
| `rule_check` | Scans diff for unsafe casts, silent fallbacks, missing zeroize. Enforces rules #5, #6, #9, #10. |
| `handoff` | Validates structured subagent handoff context. Enforces tooling rule #6. |
Verify it's working:
```bash
curl -s -X POST https://emin-mcp.emino.workers.dev/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"resources/list"}'
```
---
## FAQ (using, not developing)
**Q: Do I need an API key?**
No. The rules are public. No auth, no token, no signup.
**Q: Can I use this for my own rules?**
Yes — fork the repo, replace `src/rules/*.mjs`, deploy your own Worker. The structure is generic; the rules are personal.
**Q: What if the Worker is down?**
Run it locally: `git clone`, `npm install`, point your tool at `src/index.mjs`. Same rules, no network dependency.
**Q: Which tools does this work with?**
Any MCP-compatible client. Tested: Hermes Agent, opencode, Claude Code, Cursor, Continue. If your tool speaks MCP over HTTP/SSE or stdio, it works.
---
---
# Everything below is for developers working ON emin-mcp, not just using it.
---
## Project structure
```
src/
├── index.mjs # Stdio entry point (local) — 8 lines
├── worker.mjs # HTTP entry point (Cloudflare Worker) — 12 lines
├── server.mjs # createServer() — shared resource + tool registration
├── version.mjs # Single VERSION constant
├── rules/
│ ├── global.mjs # Working rules
│ ├── tooling.mjs # Tool install + usage instructions
│ └── coding.mjs # Evidence-derived coding rules (capped at 15)
├── checks/ # Pure functions — zero deps (no MCP, no Zod)
│ ├── scope.mjs # checkScope()
│ ├── secrets.mjs # checkSecrets()
│ ├── rules.mjs # checkRules()
│ └── handoff.mjs # checkHandoff()
├── tools/ # MCP wrappers — Zod schemas, call checks/
│ ├── scope_check.mjs
│ ├── secrets_check.mjs
│ ├── rule_check.mjs
│ └── handoff.mjs
└── sdk/
└── index.mjs # Client library — imports from checks/, zero deps
scripts/
└── selfcheck.mjs # 95 assertions — boots server, reads resources, calls tools
.github/workflows/
├── ci.yml # Selfcheck on PRs
└── deploy.yml # Auto-deploy to Cloudflare on push to master
wrangler.toml # Cloudflare Worker config
package.json # Two dependencies: @modelcontextprotocol/sdk + zod
```
Two entry points, one source of truth. Both import from the same `src/rules/`
files. Selfcheck enforces they stay in sync.
## Selfcheck
```bash
npm run selfcheck # 34 assertions, all must pass
```
## Deploy
```bash
npx wrangler deploy
```
## How to add a new rule
1. Find a real bug in an agent's commit
2. Identify the failure class
3. Write a mechanical check that would have caught it
4. Add the commit SHA as evidence
5. If at 15 coding rules, merge or drop the weakest
6. Update `scripts/selfcheck.mjs`
7. `npm run selfcheck` — all must pass
8. `npx wrangler deploy`
9. Add entry to Development Journal below
---
## Development Journal
Every commit, every decision, every thought process. Read chronologically.
> **⚠️ This is a chronological log — not a reference manual.** Each entry
> describes the state of the product *at that point in time*. Later entries
> may override, undo, or break earlier ones. The current state is what the
> live server serves at `https://emin-mcp.emino.workers.dev/mcp`. If an old
> entry says "two resources" but the live server returns three, the live
> server wins. This is the **only** documentation file — there is no separate
> FAQ, CHANGELOG, or LOGBUCH. Everything lives here.
### 2026-07-05 · `939505d` — Initial commit
**What:** First working version. Two MCP resources (`rules://emin/global`,
`rules://emin/tooling`), stdio transport, selfcheck script.
**Why:** Emin was tired of maintaining the same rules in different formats for
different AI coding tools — `CLAUDE.md` for Claude Code, `AGENTS.md` for
opencode, `.cursorrules` for Cursor. Every tool needed its own copy, and they
drifted out of sync. An MCP server solves this: one source of truth, every
MCP-compatible client reads from the same place.
**Decision: MCP server, not a file.** CLAUDE.md ties you to one tool. MCP is
the standard — every major AI coding tool speaks it. Also: MCP gives room to
add enforcement tools later (like `scope_check` to verify a diff didn't drift
from the plan) without changing the transport.
**Decision: Resources, not tools.** YAGNI. The server instructs agents to use
ponytail and nuanced — it does not wrap them. Tools will be added when a real
enforcement need shows up, not before.
**Decision: Selfcheck, not a test framework.** A single script that boots the
server over stdio, sends JSON-RPC messages, and asserts the responses. No Jest,
no Vitest — just assertions. Keeps the dependency footprint at exactly one
package (the MCP SDK).
### 2026-07-05 · `605a65b` — Sharpen rules
**What:** Two new global rules, two sharpened existing rules, subagent
delegation rule in tooling, Firecrawl instruction in tooling.
**Why:** Emin caught the agent on specific loopholes in the existing rules:
re-arguing decisions he'd already made, skipping comprehension before editing,
and asking permission after doing something irreversible instead of before.
The rules needed to close those gaps explicitly.
**Decision: Subagent delegation rule.** Tasks that burn context (long docs,
browsing, exploring codebases) should be delegated to a subagent. The subagent
returns compressed signal — file paths, line numbers, relevant snippets,
decisions — not a brain dump. Default threshold: if a step reads more than ~3
files or fetches external content, delegate it.
**Mistake: Firecrawl was premature.** The commit also added a Firecrawl
instruction. Emin flagged it immediately — it was only an idea, not a decision.
The agent broke its own rule #1 (don't invent unrequested scope). Reverted in
the next commit.
### 2026-07-05 · `09f49a8` — Revert Firecrawl
**What:** Removed the Firecrawl instruction from tooling rules.
**Why:** Emin hadn't decided to use Firecrawl. The agent added it because it
seemed useful, but that's exactly what rule #1 forbids: "Not mentioned = not
built. Suggestions, not implementations."
**Lesson:** Even when an addition seems obviously useful, if Emin didn't ask
for it, it doesn't go in. The subagent delegation rule stayed because Emin
did approve that one.
### 2026-07-05 · `e5eb546` — .context/ folder convention
**What:** New tooling rule: persist distilled external knowledge in
`.context/<topic>.md` per project.
**Why:** Emin wanted digested SDK docs, API references, and repo explorations
to survive across sessions. Without this, every new session re-digests the same
external sources, burning tokens and time.
**Decision: Delegate the digest, store the result.** The agent delegates the
heavy reading to a subagent, which returns a compressed summary. That summary
goes into `.context/<topic>.md` with a standard structure: title, date, sources,
key findings, open questions, "approved by Emin?" status. If the source was
5000 lines, the context file is 50.
### 2026-07-05 · `c95bcd9` — Tooling: install + usage for ponytail and nuanced
**What:** Expanded the tooling resource from "use ponytail and nuanced" to
full install instructions per client and exact command/tool references.
**Why:** The original tooling resource named the tools but left install steps
implicit. Every new client had to re-derive how to install and configure them.
Emin decided the resource should be self-contained: install snippets for
opencode, Claude Code, Codex, Gemini; the ponytail ladder; the full nuanced
tool list; license activation; and the compose rule.
**Decision: Self-contained instructions.** The MCP server is the single source
of truth — agents shouldn't need to search the web to figure out how to use
the tools it mandates. Selfcheck extended to assert the new content is present.
### 2026-07-05 · `76df11a` — Tooling: add repowise
**What:** Repowise added as the third mandatory tool in the tooling resource.
**Why:** Emin decided repowise closes a gap neither ponytail nor nuanced covers:
WHICH FILE BREAKS NEXT. Ponytail tells you WHAT to build (YAGNI). Nuanced tells
you HOW to edit (call-graph-aware). Repowise tells you WHERE to edit — it gives
a defect-validated 1-10 health score per file (ROC AUC 0.74), hotspots, dead
code, architectural decisions, and agent provenance.
**Decision: Repowise stays its own MCP server.** Like nuanced, emin-mcp only
instructs agents to install and use it. It does not wrap it. Selfcheck extended
with 7 new assertions for repowise content.
### 2026-07-05 · `632ec23` — Cloudflare Worker + answer-format rule + task-master
**What:** Three changes in one commit:
1. Cloudflare Worker entry point (`src/worker.mjs`) for MCP-over-HTTP
2. Global rule 15: answers must be compact tables or bullets, never text walls
3. Task-master added as the fourth mandatory tool
**Why (Worker):** Emin wanted the rules publicly accessible without requiring
a local process. A Cloudflare Worker serves the same rules over HTTP for
browser-based tools, remote agents, or any client that can't spawn a local
Node process. No auth — the rules are public knowledge, not secrets.
**Why (answer-format rule):** Emin was getting text-wall answers from agents.
The rule enforces: compact tables or bullets, one glance to understand, what /
how to test / commit message in short scannable columns.
**Why (task-master):** Any feature bigger than 3 tasks needs structured planning.
Task-master takes a PRD and generates tasks.json with dependencies, status, and
priority. Stops the "huge plan, no overview" problem.
**Decision: Two entry points, same rules.** `src/index.mjs` for local stdio,
`src/worker.mjs` for Cloudflare HTTP. Both import from the same rule source
files. One truth, two transports.
**Mistake (discovered later):** The Worker only registered `global` and
`tooling` resources. When `coding` rules were added in the next commit, the
Worker was never updated. This divergence wasn't caught until 2026-07-08.
### 2026-07-05 · `31c49f3` — Coding rules
**What:** Third resource: `rules://emin/coding`. 15 evidence-derived rules for
code-writing agents, each with a failure class, mechanical check, and commit
SHA as evidence.
**Why:** The coding agent (GLM) kept repeating the same failure classes in
benchmark runs: truncated files causing syntax errors, missing buffer zeroize,
compliance-theater helpers that were never called, unsafe casts. Emin wanted
a strict, checkable ruleset that would stop these mechanically.
**Decision: Evidence-derived, not theoretical.** Every rule comes from a real
bug found in an agent's commit. The format is: failure class → mechanical check
→ one-line incident as evidence. No rule exists without a commit SHA proving
it was needed.
**Decision: Hard cap at 15 rules.** The cap forces curation. When a new failure
class is discovered, the weakest existing rule is merged or dropped. Repeat
offenses strengthen a rule's evidence line instead of adding rules. This
prevents rule-bloat where agents ignore a wall of text.
**Decision: Generalized failure classes, not incidents.** The rules describe
patterns ("check-then-create on shared state needs a mutex"), not specific bugs
("the keychain getOrCreateKey race in commit X"). This makes them applicable
across projects.
**Evidence sources:** GLM benchmark runs (truncated files, missing zeroize,
compliance-theater helpers, the 88.85→97.00 hostile-self-review delta) and two
nuri-expo commit reviews (`ed60764b`: constructor-registered listener leaked
per transient instance; `51d1306f`: comment described unimplemented code,
Promise.all let a secondary keychain read block unlock).
**Trade-off: DB-connection-caching rule dropped.** The original draft had a
rule about connection caching, but the 1→N failure-semantics rule (from
`51d1306f`) had stronger evidence. The weaker rule lost its slot per the cap
policy.
### 2026-07-05 · `4d5b921` — Fix Worker transport
**What:** Switched the Worker from `StreamableHTTPServerTransport` to
`WebStandardStreamableHTTPServerTransport`.
**Why:** The Node.js `StreamableHTTPServerTransport` depends on
`@hono/node-server` which requires Node `stream` and `crypto` builtins not
available in the Cloudflare Workers runtime. The MCP SDK ships
`WebStandardStreamableHTTPServerTransport` specifically for web-standard
environments (Workers, Deno, Bun). Switched to that in stateless mode (no
session ID). Worker is now live and serving rules over MCP-over-HTTP.
### 2026-07-08 — Documentation discipline rule + Worker bugfix
**What:** Three changes:
1. Global rule 16: every non-obvious decision, bug root-cause, or design
trade-off must be documented in README.md
2. Bugfix: Worker was missing `coding` rules — only served `global` and
`tooling`
3. Selfcheck extended to prevent Worker divergence mechanically
**Why (rule 16):** Emin wanted the README to be the product's memory. When work
is handed off to another developer or agent, they should read one file and
understand the entire development history — what was built, why, what
alternatives were considered, what mistakes were made and how they were fixed.
**Why (Worker bugfix):** The `coding` rules were added to `src/index.mjs` in
commit `632ec23` but the Worker (`src/worker.mjs`) was never updated. Agents
connecting via HTTP got incomplete instructions. Root cause: two entry points
with no automated sync check.
**Decision: README as single source of truth.** Previously the README was a
standard project readme and a separate FAQ.md held decisions. Emin decided to
merge everything into the README: development journal, architecture decisions,
mistakes, Q&A. One file. Anyone reading it gets the full picture.
**Decision: Mechanical prevention of Worker divergence.** Selfcheck now reads
`src/worker.mjs` and asserts it imports and registers every rule set. Add a
rule to `index.mjs` → selfcheck fails until you also add it to `worker.mjs`.
### 2026-07-16 — v0.2.0: Mechanical rule enforcement (4 tools + SDK)
**What:** Four MCP tools that mechanically enforce the rules, plus a client SDK.
Selfcheck extended from 34 to 65 assertions.
**Why:** The rules were instructions agents read but could ignore. Till Kolter's
`guck-mcp` showed the pattern: MCP tools that do real work, not just recite text.
The highest-leverage move was adding tools that verify rules were followed.
**New tools:**
| Tool | Enforces | What it checks |
|---|---|---|
| `scope_check` | Rule #3: scope drift = stop | Files/LOC planned vs. actual. 1.5x file threshold, 2x LOC threshold. |
| `secrets_check` | Rule #14: never commit secrets | 12 regex patterns: OpenAI keys, GitHub tokens, AWS keys, private keys, mnemonics, ETH keys, JWTs, passwords. Redacts findings. |
| `rule_check` | Rules #5, #6, #9, #10 | Unsafe casts (`as any`, `!`), silent fallbacks, missing zeroize, compliance-theater comments. |
| `handoff` | Tooling rule #6: subagent delegation | Validates handoff context: has done items? has next action? notes too long? |
**Decision: Compact syntax on every tool.** Following Till's pattern, every tool
accepts short-key aliases (`fp` for `files_planned`, `t` for `text`, `p` for
`path`). Saves ~30% tokens on tool call arguments.
**Decision: Zod schemas, not plain JSON.** The MCP SDK requires Zod schema
objects for `inputSchema`. Switched all four tools from plain JSON Schema to
`z.object({...})`.
**Decision: Client SDK (`src/sdk/index.mjs`).** Agents can import the check
functions directly without MCP transport. `checkAll({ diff, path, plan })` runs
scope + secrets + rules in one call. `validateHandoff(to, context)` validates
handoff structure. Same logic, no network dependency.
**Decision: Tool responses as JSON strings in `content[0].text`.** The MCP SDK
wraps tool output in `{ content: [{ type: "text", text: "..." }] }`. Selfcheck
parses this with a `parseResult()` helper.
**Mistake: Regex syntax errors.** First pass used `(?i)` inline flags which
aren't valid in JS regex literals. Switched to `/gi` suffix. Also the OpenAI
key regex `/sk-[A-Za-z0-9]{20,}/` didn't match `sk-proj-...` because of
hyphens — fixed to `/sk-[A-Za-z0-9\-]{20,}/`.
**Mistake: Plain JSON Schema rejected by MCP SDK.** The SDK's `getZodSchemaObject`
throws on non-Zod objects. Had to rewrite all schemas with `z.object()`.
**What's next:** Deploy to Cloudflare Worker. Add `scope_check` to the agent's
pre-commit flow. Consider a `secrets_check` git hook.
### 2026-07-16 — v0.2.0 cleanup: architecture, CI/CD, auto-deploy
**What:** Refactored to match Till Kolter's MCP design patterns. Added CI/CD.
Selfcheck: 65 → 95 assertions.
**Why:** The previous structure had three problems:
1. `index.mjs` + `worker.mjs` duplicated 50 lines of registration
2. SDK imported from `tools/` → pulled in Zod + MCP response format
3. No auto-deploy, no CI — every push needed manual `wrangler deploy`
**New architecture (Till's pattern):**
```
src/
├── index.mjs # Stdio entry — 8 lines
├── worker.mjs # HTTP entry — 12 lines
├── server.mjs # createServer() — shared registration
├── version.mjs # Single VERSION constant
├── rules/ # Static rule text (unchanged)
├── checks/ # Pure functions — zero deps
│ ├── scope.mjs # checkScope()
│ ├── secrets.mjs # checkSecrets()
│ ├── rules.mjs # checkRules()
│ └── handoff.mjs # checkHandoff()
├── tools/ # MCP wrappers — Zod schemas, call checks/
│ ├── scope_check.mjs
│ ├── secrets_check.mjs
│ ├── rule_check.mjs
│ └── handoff.mjs
└── sdk/
└── index.mjs # Imports from checks/ — zero deps
```
**Decision: Three-layer architecture.** `checks/` = pure logic (no MCP, no Zod).
`tools/` = MCP wrappers (Zod schemas, `content[0].text` format). `sdk/` = client
library (imports from `checks/`, zero deps). Add a check → add to `checks/`,
wrap in `tools/`, re-export in `sdk/`. Selfcheck enforces this mechanically.
**Decision: `createServer()` in `server.mjs`.** Single source of truth for
resource + tool registration. Both `index.mjs` (stdio) and `worker.mjs` (HTTP)
call `createServer()`. Add a resource or tool → add it to `server.mjs` once.
Selfcheck asserts neither entry point does direct registration.
**Decision: `version.mjs`.** Single `VERSION` constant imported by `server.mjs`.
No more duplicated version strings across files.
**Decision: Auto-deploy on push to master.** `.github/workflows/deploy.yml`:
checks out, installs, runs selfcheck, deploys via `cloudflare/wrangler-action`.
Needs `CLOUDFLARE_API_TOKEN` secret in GitHub repo settings.
**Decision: CI on PRs.** `.github/workflows/ci.yml`: runs selfcheck on every PR
and on pushes to non-master branches. Catches regressions before merge.
**What you need to do (one-time):**
1. Go to https://github.com/eminogrande/emin/settings/secrets/actions
2. Add `CLOUDFLARE_API_TOKEN` — get it from `npx wrangler whoami` or Cloudflare dashboard
3. That's it. Every push to master auto-deploys.
Maintenance
ActivityMaintained
ResponsivenessSyncing