vader-mcp
# vader-mcp
A local stdio MCP server, written in TypeScript, that makes Claude answer as
Darth Vader whenever you mention Star Wars.
## How the trigger actually works
An MCP server cannot intercept your messages — it exposes tools, and the model
decides when to call them. So the persona fires from two things working
together:
1. **Server instructions.** On connect, the server sends an `instructions`
block that Claude Code injects into its system prompt. It tells Claude to
call `sense_disturbance` on any message that might mention Star Wars, and to
stay in voice while `engage` is true.
2. **The `sense_disturbance` tool.** Deterministic keyword matching over ~120
Star Wars terms, returning the matched keywords, an intensity level, and the
persona directive.
This is best-effort by design — the model chooses to call the tool. If you want
it guaranteed, use the `vader_mode` prompt (`/vader_mode`) to pin the persona on
for the whole conversation.
## Tools
| Tool | Purpose |
|---|---|
| `sense_disturbance` | Scan text for Star Wars keywords. Returns `engage`, matched `keywords`, `intensity`, and the persona `directive`. |
| `vader_speak` | Restyle a message in Vader's register — no contractions, formal phrasing, framed by an opening and closing line. Takes `intensity` of `low`/`medium`/`high`. |
| `vader_quote` | Return a canonical Vader line, optionally by topic (`power`, `father`, `failure`, `destiny`, ...). |
## Prompt
`vader_mode` — force the persona on for the rest of the conversation.
## Install
```bash
npm install # `prepare` builds dist/ automatically
```
Register with Claude Code (user scope, available in every project):
```bash
claude mcp add vader --scope user -- node /Users/gabrielestes/vader_mcp/dist/index.js
```
Remove it with `claude mcp remove vader --scope user`.
> The registered server runs compiled JavaScript from `dist/`, so it has no
> dependency on experimental Node features. **Re-run `npm run build` after
> editing `src/`** or the running server keeps serving the old build.
## Scripts
| Command | What it does |
|---|---|
| `npm run build` | `tsc -p tsconfig.build.json` → `dist/` (JS + `.d.ts` + sourcemaps) |
| `npm run typecheck` | Typechecks `src/`, `test/`, and `scripts/` with no emit |
| `npm test` | Unit tests for the voice engine, run straight from `.ts` |
| `npm run probe` | Builds, then drives every tool over real JSON-RPC against `dist/` |
| `npm run dev` | Runs the server straight from `src/index.ts` |
`npm test` and `npm run dev` rely on Node's native type stripping (Node ≥ 22.18),
which prints an experimental warning. The build path does not.
## TypeScript setup
- `tsconfig.json` — strict base config, `noEmit`, covers `src`/`test`/`scripts`.
- `tsconfig.build.json` — extends it, emits `src/` to `dist/`.
Relative imports are written with `.ts` extensions so Node can run the sources
directly; `rewriteRelativeImportExtensions` turns them into `.js` on build.
`erasableSyntaxOnly` keeps the source compatible with type stripping, so the
same files run both ways.
Strictness beyond `strict`: `noUncheckedIndexedAccess`,
`exactOptionalPropertyTypes`, `noImplicitOverride`, `noUnusedLocals`,
`noUnusedParameters`, `verbatimModuleSyntax`.
## Layout
- `src/vader.ts` — keyword detection, quotes, and text styling. Pure functions, no I/O.
- `src/index.ts` — MCP wiring: tool registration and stdio transport.
- `test/vader.test.ts` — unit tests for the voice engine.
- `scripts/probe.ts` — spawns the built server and exercises every tool over real JSON-RPC.
TDQS
Scored across 3 tools
Each tool has a clear, non-overlapping role: one detects whether Vader mode should activate, one restyles an arbitrary message, and one returns a canned quote. There is little chance an agent would confuse them.
The names are readable and all snake_case, but they follow different patterns: sense_disturbance is verb_noun, vader_speak is noun_verb, and vader_quote is noun_noun. Two share a vader_ prefix while the third does not, making the convention inconsistent.
Three tools is appropriate for a narrow Vader roleplay server. Each tool earns its place and there is no bloat or redundancy.
The server covers the full intended workflow: detect when Vader's voice should engage, restyle a message into that voice, and provide authentic quotes. No obvious gaps or dead ends exist for the stated domain.