@q-ching/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jean Llorca
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @q-ching/mcp
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server that exposes the **q-ching** I-Ching
4
+ oracle as a tool, so any MCP client — Claude Desktop, Claude Code, or another agent —
5
+ can cast a reading and be guided by it.
6
+
7
+ It runs the dependency-free `@q-ching/core` engine directly. Because it's a Node
8
+ process with no browser CORS in the way, it reaches the **live quantum sources** the
9
+ same way the terminal app does.
10
+
11
+ ## The tool
12
+
13
+ **`cast_reading`** — cast an I-Ching reading.
14
+
15
+ | Input | Type | Notes |
16
+ |---|---|---|
17
+ | `question` | string? | The querent's question, recorded for context. |
18
+ | `method` | `"coin"` \| `"yarrow"`? | `coin` (default) or the traditional `yarrow` (changing lines rarer). |
19
+ | `seed` | string? | Reproduce a prior reading exactly from its hex seed. |
20
+ | `quantum` | boolean? | Fold in live quantum entropy (default `true`). |
21
+ | `contextHash` | string? | The agent's "gesture" — a hash/digest of its current conversation context, folded into the entropy pool as the caller's own contribution. Hashed with every other source, so its form is free. Ignored when `seed` is set. |
22
+
23
+ Returns the primary hexagram (Judgment, Image, gloss), the changing lines and their
24
+ texts, the hexagram it transforms into, and the **reproducible seed**.
25
+
26
+ ## Run it
27
+
28
+ Install from npm:
29
+
30
+ ```bash
31
+ npm install -g @q-ching/mcp
32
+ q-ching-mcp # starts the server on stdio
33
+ ```
34
+
35
+ Or run from a clone of the repo:
36
+
37
+ ```bash
38
+ npm install
39
+ npm run build:core # the server imports @q-ching/core from its dist/
40
+ npm run mcp # starts the server on stdio
41
+ ```
42
+
43
+ ## Use it from Claude Desktop / Claude Code
44
+
45
+ With the package installed (or via `npx`), point your MCP client at it. For Claude
46
+ Desktop, add to `claude_desktop_config.json`:
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "q-ching": {
52
+ "command": "npx",
53
+ "args": ["-y", "@q-ching/mcp"]
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ For Claude Code: `claude mcp add q-ching -- npx -y @q-ching/mcp`.
60
+
61
+ Running from a clone instead? Build once (`npm run build:core && npm run build:mcp`)
62
+ and point the client at `node /absolute/path/to/q-ching/apps/mcp/dist/index.js`.
63
+
64
+ Then ask the assistant to consult the oracle — it will call `cast_reading` and let the
65
+ hexagram shape its answer.
@@ -0,0 +1,9 @@
1
+ import type { Reading } from '@q-ching/core';
2
+ /**
3
+ * Render a Reading as readable text for an LLM tool result: the primary
4
+ * hexagram with its Judgment and Image, the changing lines and their texts,
5
+ * the hexagram it transforms into, and the reproducible seed.
6
+ */
7
+ export declare function formatReading(reading: Reading, question?: string, opts?: {
8
+ contextFolded?: boolean;
9
+ }): string;
package/dist/format.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Render a Reading as readable text for an LLM tool result: the primary
3
+ * hexagram with its Judgment and Image, the changing lines and their texts,
4
+ * the hexagram it transforms into, and the reproducible seed.
5
+ */
6
+ export function formatReading(reading, question, opts) {
7
+ const p = reading.primary;
8
+ const out = [];
9
+ if (question)
10
+ out.push(`Question: ${question}`, '');
11
+ out.push(`${p.symbol} ${p.number}. ${p.name.chinese} (${p.name.pinyin}) — ${p.name.english}`);
12
+ out.push(`“${p.gloss}”`);
13
+ out.push('');
14
+ out.push(`Method: ${reading.method}`);
15
+ out.push(reading.changingPositions.length
16
+ ? `Changing lines: ${reading.changingPositions.join(', ')}`
17
+ : 'Changing lines: none (a static hexagram)');
18
+ out.push('');
19
+ out.push('JUDGMENT');
20
+ out.push(p.judgment);
21
+ out.push('');
22
+ out.push('IMAGE');
23
+ out.push(p.image);
24
+ if (reading.changingPositions.length) {
25
+ out.push('', 'CHANGING LINES');
26
+ for (const pos of reading.changingPositions) {
27
+ out.push(` Line ${pos}: ${p.lineTexts[pos - 1]}`);
28
+ }
29
+ }
30
+ if (reading.transformed) {
31
+ const t = reading.transformed;
32
+ out.push('');
33
+ out.push(`Becoming: ${t.symbol} ${t.number}. ${t.name.chinese} (${t.name.pinyin}) — ${t.name.english}`);
34
+ }
35
+ out.push('');
36
+ if (opts?.contextFolded) {
37
+ out.push('(Your conversation context was folded into this cast as the agent gesture.)');
38
+ }
39
+ out.push(`Seed: ${reading.seed}`);
40
+ return out.join('\n');
41
+ }
42
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAgB,EAChB,QAAiB,EACjB,IAAkC;IAElC,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAC1B,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,IAAI,QAAQ;QAAE,GAAG,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;IAEpD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9F,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;IACzB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,GAAG,CAAC,IAAI,CACN,OAAO,CAAC,iBAAiB,CAAC,MAAM;QAC9B,CAAC,CAAC,mBAAmB,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC3D,CAAC,CAAC,0CAA0C,CAC/C,CAAC;IACF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACrB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAElB,IAAI,OAAO,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC;QACrC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAC5C,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1G,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,IAAI,IAAI,EAAE,aAAa,EAAE,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;IAC1F,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * q-ching MCP server.
4
+ *
5
+ * Exposes the q-ching I-Ching oracle as a Model Context Protocol tool over
6
+ * stdio, so any MCP client (Claude Desktop, Claude Code, other agents) can cast
7
+ * a reading. Runs the dependency-free @q-ching/core engine directly — and,
8
+ * being a Node process with no browser CORS, it reaches the live quantum
9
+ * sources the same way the terminal app does.
10
+ */
11
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
+ import { z } from 'zod';
14
+ import { cast } from '@q-ching/core';
15
+ import { formatReading } from './format.js';
16
+ const server = new McpServer({ name: 'q-ching', version: '0.1.0' });
17
+ server.registerTool('cast_reading', {
18
+ title: 'Cast an I-Ching reading',
19
+ description: 'Cast an I-Ching (Book of Changes) reading from the q-ching oracle, which mixes ' +
20
+ 'true/quantum randomness (the NIST beacon, ANU, RANDOM.ORG) with a local cryptographic ' +
21
+ 'RNG. Returns the primary hexagram with its Judgment, Image, and one-line gloss; the ' +
22
+ 'changing lines and their texts; the hexagram it transforms into; and a reproducible hex ' +
23
+ 'seed (pass it back as `seed` to replay the exact same reading). Call this when the user ' +
24
+ 'poses a question to the oracle or wants a hexagram cast to reflect on a situation.',
25
+ inputSchema: {
26
+ question: z.string().optional().describe("The querent's question, recorded for context."),
27
+ method: z
28
+ .enum(['coin', 'yarrow'])
29
+ .optional()
30
+ .describe("Casting method: 'coin' (default) or the traditional 'yarrow' (changing lines rarer)."),
31
+ seed: z
32
+ .string()
33
+ .optional()
34
+ .describe('Reproduce a prior reading exactly from its hex seed (ignores the live entropy sources).'),
35
+ quantum: z
36
+ .boolean()
37
+ .optional()
38
+ .describe('Fold in live quantum entropy (default true). Set false to skip the network calls and use local entropy only.'),
39
+ contextHash: z
40
+ .string()
41
+ .optional()
42
+ .describe("Your 'gesture': a hash or digest of your current conversation context, folded into the " +
43
+ 'entropy pool as the calling agent’s own contribution to the cast — the analog of a human ' +
44
+ 'querent stirring with their hand while holding the question in mind. Send e.g. a hex digest of ' +
45
+ 'your recent context, a summary string, or a nonce; it is hashed together with every other source, ' +
46
+ 'so its form does not matter. Unlike a human gesture it carries little true randomness (the quantum ' +
47
+ 'and local CSPRNG sources do that), but a fresh agent context is genuinely hard to reproduce, and ' +
48
+ 'this is how you participate in the reading rather than merely observe it. Ignored when `seed` is set ' +
49
+ '(a replay is deterministic).'),
50
+ },
51
+ }, async ({ question, method, seed, quantum, contextHash }) => {
52
+ // A seed reproduces a cast deterministically, so the live sources (quantum,
53
+ // and the agent's own context gesture) are skipped when one is supplied.
54
+ const contextFolded = !seed && !!contextHash;
55
+ const reading = await cast({
56
+ method,
57
+ seed,
58
+ userEntropy: contextFolded ? new TextEncoder().encode(contextHash) : undefined,
59
+ qrng: seed ? undefined : quantum === false ? undefined : true,
60
+ });
61
+ return { content: [{ type: 'text', text: formatReading(reading, question, { contextFolded }) }] };
62
+ });
63
+ const transport = new StdioServerTransport();
64
+ await server.connect(transport);
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAEpE,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;IACE,KAAK,EAAE,yBAAyB;IAChC,WAAW,EACT,iFAAiF;QACjF,wFAAwF;QACxF,sFAAsF;QACtF,0FAA0F;QAC1F,0FAA0F;QAC1F,oFAAoF;IACtF,WAAW,EAAE;QACX,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACzF,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;aACxB,QAAQ,EAAE;aACV,QAAQ,CAAC,sFAAsF,CAAC;QACnG,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,yFAAyF,CAAC;QACtG,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,8GAA8G,CAAC;QAC3H,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,yFAAyF;YACvF,2FAA2F;YAC3F,iGAAiG;YACjG,oGAAoG;YACpG,qGAAqG;YACrG,mGAAmG;YACnG,uGAAuG;YACvG,8BAA8B,CACjC;KACJ;CACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;IACzD,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,aAAa,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC;QACzB,MAAM;QACN,IAAI;QACJ,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;QAC9E,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;KAC9D,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACpG,CAAC,CACF,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@q-ching/mcp",
3
+ "version": "0.1.0",
4
+ "description": "An MCP server that lets any AI assistant consult the q-ching I-Ching oracle as a tool.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Jean Llorca <jean@hylaean.com>",
8
+ "homepage": "https://github.com/Hylaean/q-ching#readme",
9
+ "bugs": "https://github.com/Hylaean/q-ching/issues",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/Hylaean/q-ching.git",
13
+ "directory": "apps/mcp"
14
+ },
15
+ "keywords": [
16
+ "i-ching",
17
+ "iching",
18
+ "oracle",
19
+ "hexagram",
20
+ "mcp",
21
+ "model-context-protocol",
22
+ "ai",
23
+ "divination"
24
+ ],
25
+ "bin": {
26
+ "q-ching-mcp": "./dist/index.js"
27
+ },
28
+ "files": ["dist", "src"],
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "scripts": {
36
+ "start": "tsx src/index.ts",
37
+ "dev": "tsx watch src/index.ts",
38
+ "build": "tsc",
39
+ "prepublishOnly": "npm run build"
40
+ },
41
+ "dependencies": {
42
+ "@q-ching/core": "^0.1.0",
43
+ "@modelcontextprotocol/sdk": "^1.29.0",
44
+ "zod": "^4.4.3"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.14.0",
48
+ "tsx": "^4.16.0",
49
+ "typescript": "^5.5.0"
50
+ }
51
+ }
package/src/format.ts ADDED
@@ -0,0 +1,53 @@
1
+ import type { Reading } from '@q-ching/core';
2
+
3
+ /**
4
+ * Render a Reading as readable text for an LLM tool result: the primary
5
+ * hexagram with its Judgment and Image, the changing lines and their texts,
6
+ * the hexagram it transforms into, and the reproducible seed.
7
+ */
8
+ export function formatReading(
9
+ reading: Reading,
10
+ question?: string,
11
+ opts?: { contextFolded?: boolean },
12
+ ): string {
13
+ const p = reading.primary;
14
+ const out: string[] = [];
15
+
16
+ if (question) out.push(`Question: ${question}`, '');
17
+
18
+ out.push(`${p.symbol} ${p.number}. ${p.name.chinese} (${p.name.pinyin}) — ${p.name.english}`);
19
+ out.push(`“${p.gloss}”`);
20
+ out.push('');
21
+ out.push(`Method: ${reading.method}`);
22
+ out.push(
23
+ reading.changingPositions.length
24
+ ? `Changing lines: ${reading.changingPositions.join(', ')}`
25
+ : 'Changing lines: none (a static hexagram)',
26
+ );
27
+ out.push('');
28
+ out.push('JUDGMENT');
29
+ out.push(p.judgment);
30
+ out.push('');
31
+ out.push('IMAGE');
32
+ out.push(p.image);
33
+
34
+ if (reading.changingPositions.length) {
35
+ out.push('', 'CHANGING LINES');
36
+ for (const pos of reading.changingPositions) {
37
+ out.push(` Line ${pos}: ${p.lineTexts[pos - 1]}`);
38
+ }
39
+ }
40
+
41
+ if (reading.transformed) {
42
+ const t = reading.transformed;
43
+ out.push('');
44
+ out.push(`Becoming: ${t.symbol} ${t.number}. ${t.name.chinese} (${t.name.pinyin}) — ${t.name.english}`);
45
+ }
46
+
47
+ out.push('');
48
+ if (opts?.contextFolded) {
49
+ out.push('(Your conversation context was folded into this cast as the agent gesture.)');
50
+ }
51
+ out.push(`Seed: ${reading.seed}`);
52
+ return out.join('\n');
53
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * q-ching MCP server.
4
+ *
5
+ * Exposes the q-ching I-Ching oracle as a Model Context Protocol tool over
6
+ * stdio, so any MCP client (Claude Desktop, Claude Code, other agents) can cast
7
+ * a reading. Runs the dependency-free @q-ching/core engine directly — and,
8
+ * being a Node process with no browser CORS, it reaches the live quantum
9
+ * sources the same way the terminal app does.
10
+ */
11
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
+ import { z } from 'zod';
14
+ import { cast } from '@q-ching/core';
15
+ import { formatReading } from './format.js';
16
+
17
+ const server = new McpServer({ name: 'q-ching', version: '0.1.0' });
18
+
19
+ server.registerTool(
20
+ 'cast_reading',
21
+ {
22
+ title: 'Cast an I-Ching reading',
23
+ description:
24
+ 'Cast an I-Ching (Book of Changes) reading from the q-ching oracle, which mixes ' +
25
+ 'true/quantum randomness (the NIST beacon, ANU, RANDOM.ORG) with a local cryptographic ' +
26
+ 'RNG. Returns the primary hexagram with its Judgment, Image, and one-line gloss; the ' +
27
+ 'changing lines and their texts; the hexagram it transforms into; and a reproducible hex ' +
28
+ 'seed (pass it back as `seed` to replay the exact same reading). Call this when the user ' +
29
+ 'poses a question to the oracle or wants a hexagram cast to reflect on a situation.',
30
+ inputSchema: {
31
+ question: z.string().optional().describe("The querent's question, recorded for context."),
32
+ method: z
33
+ .enum(['coin', 'yarrow'])
34
+ .optional()
35
+ .describe("Casting method: 'coin' (default) or the traditional 'yarrow' (changing lines rarer)."),
36
+ seed: z
37
+ .string()
38
+ .optional()
39
+ .describe('Reproduce a prior reading exactly from its hex seed (ignores the live entropy sources).'),
40
+ quantum: z
41
+ .boolean()
42
+ .optional()
43
+ .describe('Fold in live quantum entropy (default true). Set false to skip the network calls and use local entropy only.'),
44
+ contextHash: z
45
+ .string()
46
+ .optional()
47
+ .describe(
48
+ "Your 'gesture': a hash or digest of your current conversation context, folded into the " +
49
+ 'entropy pool as the calling agent’s own contribution to the cast — the analog of a human ' +
50
+ 'querent stirring with their hand while holding the question in mind. Send e.g. a hex digest of ' +
51
+ 'your recent context, a summary string, or a nonce; it is hashed together with every other source, ' +
52
+ 'so its form does not matter. Unlike a human gesture it carries little true randomness (the quantum ' +
53
+ 'and local CSPRNG sources do that), but a fresh agent context is genuinely hard to reproduce, and ' +
54
+ 'this is how you participate in the reading rather than merely observe it. Ignored when `seed` is set ' +
55
+ '(a replay is deterministic).',
56
+ ),
57
+ },
58
+ },
59
+ async ({ question, method, seed, quantum, contextHash }) => {
60
+ // A seed reproduces a cast deterministically, so the live sources (quantum,
61
+ // and the agent's own context gesture) are skipped when one is supplied.
62
+ const contextFolded = !seed && !!contextHash;
63
+ const reading = await cast({
64
+ method,
65
+ seed,
66
+ userEntropy: contextFolded ? new TextEncoder().encode(contextHash) : undefined,
67
+ qrng: seed ? undefined : quantum === false ? undefined : true,
68
+ });
69
+ return { content: [{ type: 'text', text: formatReading(reading, question, { contextFolded }) }] };
70
+ },
71
+ );
72
+
73
+ const transport = new StdioServerTransport();
74
+ await server.connect(transport);