Roll dice expressions (NdS notation with modifiers, multipliers, multi-term) and parse components via @mukundakatta/dice-mcp
@mukundakatta/dice-mcp v0.1.0 — 2 tools, stdio, credential-free. Tested 28 calls (22 OK + 6 correct rejections), p50=0ms.
Install: npm install @mukundakatta/dice-mcp @modelcontextprotocol/sdk Entry: dist/server.js
TOOLS:
- roll({expression}) — Roll dice, returns individual results + total
- parse({expression}) — Parse without rolling, returns components
EXPRESSION SYNTAX: NdS[+modifier][*multiplier]
- N = dice count [1, 1000]
- S = sides per die [2, 10000]
- +N/-N = additive modifier (applied after sum)
- N = multiplier (applied to total: (sum+modifier)multiplier... actually (sum)*multiplier+modifier? Let me verify)
VERIFIED: total = (sum of all dice) multiplier + modifier? No — test 5: 3d82 = (7+2+6)2 = 30, modifier=0. Test 4: 4d6+2 = (4+3+2+3)+2 = 14, multiplier=1. So total = sum multiplier + modifier? Wait: test 7: 2d6+1d8+5 = (3+5)+(8)+5 = 21, multiplier=1, modifier=5. That's (sumalldice + modifier) multiplier. With test 5: (15+0)2=30. Yes: total = (sum + modifier) * multiplier.
MULTI-TERM EXPRESSIONS WORK: "2d6+1d8+5" correctly parsed as two dice terms [{2,6},{1,8}] + modifier 5. Rolls array has separate sub-arrays per term: [[3,5],[8]].
ROLL RESPONSE: {expression, rolls: [[die1,die2,...], [die1,...]], modifier, multiplier, total} PARSE RESPONSE: {expression, terms: [{count, sides},...], modifier, multiplier}
KEY GOTCHAS:
- Leading "d" without count NOT supported — "d20" fails with "no XdY term found"
- Count range [1, 1000], sides range [2, 10000] — enforced with clear errors
- Non-deterministic (crypto-random) — no seed parameter
- Errors are text messages not MCP errors ("dice failed: ...")
- Empty expression correctly rejected
- 1d1 rejected (sides min is 2)
- Sub-millisecond after 2ms JIT first call
- Multi-term sums all dice across terms into one total
{ "server": "@mukundakatta/dice-mcp", "version": "0.1.0", "transport": "stdio", "entry": "dist/server.js", "tools": ["roll", "parse"], "calls": [ { "tool": "roll", "args": { "expression": "1d6" }, "ok": true, "ms": 2, "result": { "rolls": [ [3] ], "total": 3 } }, { "tool": "roll", "args": { "expression": "2d6" }, "ok": true, "ms": 0, "result": { "rolls": [ [5, 4] ], "total": 9 } }, { "tool": "roll", "args": { "expression": "1d20" }, "ok": true, "ms": 1, "result": { "rolls": [ [2] ], "total": 2 } }, { "tool": "roll", "args": { "expression": "4d6+2" }, "ok": true, "ms": 0, "result": { "rolls": [ [4, 3, 2, 3] ], "modifier": 2, "total": 14 } }, { "tool": "roll", "args": { "expression": "3d8*2" }, "ok": true, "ms": 0, "result": { "rolls": [ [7, 2, 6] ], "multiplier": 2, "total": 30 } }, { "tool": "roll", "args": { "expression": "1d100" }, "ok": true, "ms": 1, "result": { "rolls": [ [16] ], "total": 16 } }, { "tool": "roll", "args": { "expression": "2d6-1" }, "ok": true, "ms": 0, "result": { "rolls": [ [4, 6] ], "modifier": -1, "total": 9 } }, { "tool": "roll", "args": { "expression": "10d10" }, "ok": true, "ms": 1, "result": { "rolls": [ [5, 9, 2, 4, 1, 10, 5, 3, 8, 7] ], "total": 54 } }, { "tool": "roll", "args": { "expression": "1d4" }, "ok": true, "ms": 0, "result": { "rolls": [ [4] ], "total": 4 } }, { "tool": "roll", "args": { "expression": "2d6+1d8" }, "ok": true, "ms": 2, "result": { "rolls": [ [4, 4], [8] ], "total": 16, "note": "multi-term" } }, { "tool": "roll", "args": { "expression": "2d6+1d8+5" }, "ok": true, "ms": 0, "result": { "rolls": [ [3, 5], [8] ], "modifier": 5, "total": 21 } }, { "tool": "roll", "args": { "expression": "1d1000" }, "ok": true, "ms": 0, "result": { "rolls": [ [641] ], "total": 641 } }, { "tool": "roll", "args": { "expression": "1000d6" }, "ok": true, "ms": 1, "note": "max count, 1000 individual results" }, { "tool": "roll", "args": { "expression": "1d20" }, "ok": true, "ms": 0, "result": { "rolls": [ [12] ], "total": 12 } }, { "tool": "roll", "args": { "expression": "1d20" }, "ok": true, "ms": 1, "result": { "rolls": [ [18] ], "total": 18, "note": "non-deterministic" } }, { "tool": "parse", "args": { "expression": "4d6+2" }, "ok": true, "ms": 0, "result": { "terms": [ { "count": 4, "sides": 6 } ], "modifier": 2 } }, { "tool": "parse", "args": { "expression": "3d8*2" }, "ok": true, "ms": 0, "result": { "terms": [ { "count": 3, "sides": 8 } ], "multiplier": 2 } }, { "tool": "parse", "args": { "expression": "2d6-1" }, "ok": true, "ms": 0, "result": { "terms": [ { "count": 2, "sides": 6 } ], "modifier": -1 } }, { "tool": "parse", "args": { "expression": "1d20" }, "ok": true, "ms": 0, "result": { "terms": [ { "count": 1, "sides": 20 } ] } }, { "tool": "parse", "args": { "expression": "2d6+1d8" }, "ok": true, "ms": 0, "result": { "terms": [ { "count": 2, "sides": 6 }, { "count": 1, "sides": 8 } ] } }, { "tool": "parse", "args": { "expression": "abc" }, "ok": false, "error": "no XdY term found in: abc" }, { "tool": "roll", "args": { "expression": "0d6" }, "ok": false, "error": "dice count must be in [1, 1000]" }, { "tool": "roll", "args": { "expression": "1d0" }, "ok": false, "error": "dice sides must be in [2, 10000]" }, { "tool": "roll", "args": { "expression": "d20" }, "ok": false, "error": "no XdY term found in: d20" }, { "tool": "roll", "args": { "expression": "abc" }, "ok": false, "error": "no XdY term found in: abc" }, { "tool": "roll", "args": { "expression": "" }, "ok": false, "error": "empty expression" }, { "tool": "roll", "args": { "expression": "1001d6" }, "ok": false, "error": "dice count must be in [1, 1000]" }, { "tool": "roll", "args": { "expression": "1d1" }, "ok": false, "error": "dice sides must be in [2, 10000]" } ], "summary": { "total": 28, "ok": 22, "rejected": 6, "p50_ms": 0 } }