mcp-server-return-to-dark-tower 1.0.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +729 -0
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +133 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/prompts/index.d.ts +3 -0
  9. package/dist/prompts/index.d.ts.map +1 -0
  10. package/dist/prompts/index.js +250 -0
  11. package/dist/prompts/index.js.map +1 -0
  12. package/dist/resources/index.d.ts +4 -0
  13. package/dist/resources/index.d.ts.map +1 -0
  14. package/dist/resources/index.js +228 -0
  15. package/dist/resources/index.js.map +1 -0
  16. package/dist/tools/audio.d.ts +4 -0
  17. package/dist/tools/audio.d.ts.map +1 -0
  18. package/dist/tools/audio.js +59 -0
  19. package/dist/tools/audio.js.map +1 -0
  20. package/dist/tools/connection.d.ts +4 -0
  21. package/dist/tools/connection.d.ts.map +1 -0
  22. package/dist/tools/connection.js +111 -0
  23. package/dist/tools/connection.js.map +1 -0
  24. package/dist/tools/drums.d.ts +4 -0
  25. package/dist/tools/drums.d.ts.map +1 -0
  26. package/dist/tools/drums.js +70 -0
  27. package/dist/tools/drums.js.map +1 -0
  28. package/dist/tools/lights.d.ts +4 -0
  29. package/dist/tools/lights.d.ts.map +1 -0
  30. package/dist/tools/lights.js +86 -0
  31. package/dist/tools/lights.js.map +1 -0
  32. package/dist/tools/seals.d.ts +4 -0
  33. package/dist/tools/seals.d.ts.map +1 -0
  34. package/dist/tools/seals.js +60 -0
  35. package/dist/tools/seals.js.map +1 -0
  36. package/dist/tools/state.d.ts +4 -0
  37. package/dist/tools/state.d.ts.map +1 -0
  38. package/dist/tools/state.js +64 -0
  39. package/dist/tools/state.js.map +1 -0
  40. package/dist/tower-controller.d.ts +87 -0
  41. package/dist/tower-controller.d.ts.map +1 -0
  42. package/dist/tower-controller.js +355 -0
  43. package/dist/tower-controller.js.map +1 -0
  44. package/dist/utils/logger.d.ts +11 -0
  45. package/dist/utils/logger.d.ts.map +1 -0
  46. package/dist/utils/logger.js +29 -0
  47. package/dist/utils/logger.js.map +1 -0
  48. package/dist/utils/lookups.d.ts +14 -0
  49. package/dist/utils/lookups.d.ts.map +1 -0
  50. package/dist/utils/lookups.js +33 -0
  51. package/dist/utils/lookups.js.map +1 -0
  52. package/dist/utils/schemas.d.ts +165 -0
  53. package/dist/utils/schemas.d.ts.map +1 -0
  54. package/dist/utils/schemas.js +70 -0
  55. package/dist/utils/schemas.js.map +1 -0
  56. package/package.json +69 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
5
+ import { localhostHostValidation } from "@modelcontextprotocol/sdk/server/middleware/hostHeaderValidation.js";
6
+ import express from "express";
7
+ import { randomUUID } from "node:crypto";
8
+ import { TowerController } from "./tower-controller.js";
9
+ import { McpLogOutput } from "./utils/logger.js";
10
+ import { registerConnectionTools } from "./tools/connection.js";
11
+ import { registerAudioTools } from "./tools/audio.js";
12
+ import { registerLightTools } from "./tools/lights.js";
13
+ import { registerDrumTools } from "./tools/drums.js";
14
+ import { registerSealTools } from "./tools/seals.js";
15
+ import { registerStateTools } from "./tools/state.js";
16
+ import { registerResources } from "./resources/index.js";
17
+ import { registerPrompts } from "./prompts/index.js";
18
+ const VERSION = "0.1.0";
19
+ function registerAll(server, tower) {
20
+ registerConnectionTools(server, tower);
21
+ registerAudioTools(server, tower);
22
+ registerLightTools(server, tower);
23
+ registerDrumTools(server, tower);
24
+ registerSealTools(server, tower);
25
+ registerStateTools(server, tower);
26
+ registerResources(server, tower);
27
+ registerPrompts(server);
28
+ }
29
+ // Parse CLI args
30
+ const args = process.argv.slice(2);
31
+ const stdioOnly = args.includes("--stdio-only");
32
+ const httpOnly = args.includes("--http-only");
33
+ const portIndex = args.indexOf("--port");
34
+ const httpPort = portIndex !== -1 ? parseInt(args[portIndex + 1], 10) : 3001;
35
+ // Shared tower controller singleton
36
+ const tower = TowerController.getInstance();
37
+ // Track transports for cleanup
38
+ const transports = new Map();
39
+ let stdioServer = null;
40
+ let httpServer = null;
41
+ async function startStdio() {
42
+ stdioServer = new McpServer({ name: "return-to-dark-tower", version: VERSION }, { capabilities: { logging: {} } });
43
+ registerAll(stdioServer, tower);
44
+ // Set up MCP log forwarding
45
+ tower.setLoggerOutputs([new McpLogOutput(stdioServer)]);
46
+ const transport = new StdioServerTransport();
47
+ await stdioServer.connect(transport);
48
+ }
49
+ async function startHttp() {
50
+ httpServer = new McpServer({ name: "return-to-dark-tower-http", version: VERSION }, { capabilities: { logging: {} } });
51
+ registerAll(httpServer, tower);
52
+ const app = express();
53
+ app.use(express.json());
54
+ app.use(localhostHostValidation());
55
+ // POST /mcp — main JSON-RPC endpoint
56
+ app.post("/mcp", async (req, res) => {
57
+ const transport = new StreamableHTTPServerTransport({
58
+ sessionIdGenerator: () => randomUUID(),
59
+ });
60
+ const sessionId = transport.sessionId;
61
+ if (sessionId) {
62
+ transports.set(sessionId, transport);
63
+ transport.onclose = () => {
64
+ transports.delete(sessionId);
65
+ };
66
+ }
67
+ await httpServer.connect(transport);
68
+ await transport.handleRequest(req, res, req.body);
69
+ });
70
+ // GET /mcp — SSE stream for server-initiated notifications
71
+ app.get("/mcp", async (req, res) => {
72
+ const sessionId = req.headers["mcp-session-id"];
73
+ if (!sessionId || !transports.has(sessionId)) {
74
+ res.status(400).json({ error: "Invalid or missing session ID" });
75
+ return;
76
+ }
77
+ const transport = transports.get(sessionId);
78
+ await transport.handleRequest(req, res);
79
+ });
80
+ // DELETE /mcp — session teardown
81
+ app.delete("/mcp", async (req, res) => {
82
+ const sessionId = req.headers["mcp-session-id"];
83
+ if (!sessionId || !transports.has(sessionId)) {
84
+ res.status(400).json({ error: "Invalid or missing session ID" });
85
+ return;
86
+ }
87
+ const transport = transports.get(sessionId);
88
+ await transport.handleRequest(req, res);
89
+ });
90
+ // Health check
91
+ app.get("/health", (_req, res) => {
92
+ res.json({
93
+ status: "ok",
94
+ towerConnected: tower.isConnected,
95
+ towerCalibrated: tower.isCalibrated,
96
+ });
97
+ });
98
+ app.listen(httpPort, () => {
99
+ console.error(`Dark Tower MCP HTTP server listening on http://localhost:${httpPort}/mcp`);
100
+ });
101
+ }
102
+ // Graceful shutdown
103
+ async function shutdown() {
104
+ console.error("Shutting down...");
105
+ await tower.cleanup();
106
+ for (const transport of transports.values()) {
107
+ await transport.close();
108
+ }
109
+ if (stdioServer)
110
+ await stdioServer.close();
111
+ if (httpServer)
112
+ await httpServer.close();
113
+ process.exit(0);
114
+ }
115
+ process.on("SIGINT", shutdown);
116
+ process.on("SIGTERM", shutdown);
117
+ // Start
118
+ async function main() {
119
+ if (!httpOnly) {
120
+ await startStdio();
121
+ if (!stdioOnly) {
122
+ console.error("Stdio transport started");
123
+ }
124
+ }
125
+ if (!stdioOnly) {
126
+ await startHttp();
127
+ }
128
+ }
129
+ main().catch((err) => {
130
+ console.error("Fatal error:", err);
131
+ process.exit(1);
132
+ });
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerPrompts(server: McpServer): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqSvD"}
@@ -0,0 +1,250 @@
1
+ import { z } from "zod";
2
+ import { TOWER_AUDIO_LIBRARY, TOWER_LIGHT_SEQUENCES } from "ultimatedarktower";
3
+ import { getSoundCategories, soundCategoryIndex } from "../utils/lookups.js";
4
+ export function registerPrompts(server) {
5
+ server.registerPrompt("dramatic_entrance", {
6
+ title: "Dramatic Entrance",
7
+ description: "A dramatic tower startup sequence: connect, calibrate, play adversary sound, strobe lights, random rotate drums",
8
+ argsSchema: {
9
+ adversary: z
10
+ .string()
11
+ .optional()
12
+ .describe("Adversary name to play spawn sound (e.g. 'Ashstrider')"),
13
+ },
14
+ }, (args) => {
15
+ const adversary = args.adversary ?? "Ashstrider";
16
+ const adversaryEntry = TOWER_AUDIO_LIBRARY[adversary.replace(/\s+/g, "")];
17
+ const soundNote = adversaryEntry
18
+ ? `Use tower_play_sound with index ${adversaryEntry.value} for the ${adversaryEntry.name} sound.`
19
+ : `Look up "${adversary}" in the audio library using tower_play_sound_by_name.`;
20
+ return {
21
+ messages: [
22
+ {
23
+ role: "user",
24
+ content: {
25
+ type: "text",
26
+ text: [
27
+ "Execute a dramatic tower entrance sequence:",
28
+ "1. Connect to the tower using tower_connect",
29
+ "2. Calibrate with tower_calibrate",
30
+ `3. ${soundNote}`,
31
+ `4. Run the angryStrobe01 light sequence using tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.angryStrobe01}`,
32
+ "5. Random rotate all drums with tower_random_rotate",
33
+ "",
34
+ "Execute each step in order, waiting for each to complete before proceeding.",
35
+ ].join("\n"),
36
+ },
37
+ },
38
+ ],
39
+ };
40
+ });
41
+ server.registerPrompt("victory_sequence", {
42
+ title: "Victory Sequence",
43
+ description: "Play a victory celebration: victory sound, victory lights, drum rotation",
44
+ argsSchema: {
45
+ soundIndex: z
46
+ .string()
47
+ .optional()
48
+ .describe("Custom victory sound index (default: uses Victory sound)"),
49
+ },
50
+ }, (args) => {
51
+ const victorySoundEntry = TOWER_AUDIO_LIBRARY["Victory"];
52
+ const soundIndex = args.soundIndex ?? String(victorySoundEntry?.value ?? 100);
53
+ return {
54
+ messages: [
55
+ {
56
+ role: "user",
57
+ content: {
58
+ type: "text",
59
+ text: [
60
+ "Execute a victory celebration sequence:",
61
+ `1. Play the victory sound: tower_play_sound with index ${soundIndex}`,
62
+ `2. Run the victory light sequence: tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.victory}`,
63
+ "3. Random rotate all drums: tower_random_rotate",
64
+ "",
65
+ "Execute each step in order for dramatic effect.",
66
+ ].join("\n"),
67
+ },
68
+ },
69
+ ],
70
+ };
71
+ });
72
+ server.registerPrompt("defeat_sequence", {
73
+ title: "Defeat Sequence",
74
+ description: "Play a defeat sequence: defeat sound and defeat lights",
75
+ }, () => {
76
+ const defeatEntry = TOWER_AUDIO_LIBRARY["Defeat"];
77
+ const defeatSound = defeatEntry?.value ?? 101;
78
+ return {
79
+ messages: [
80
+ {
81
+ role: "user",
82
+ content: {
83
+ type: "text",
84
+ text: [
85
+ "Execute a defeat sequence:",
86
+ `1. Play the defeat sound: tower_play_sound with index ${defeatSound}`,
87
+ `2. Run the defeat light sequence: tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.defeat}`,
88
+ ].join("\n"),
89
+ },
90
+ },
91
+ ],
92
+ };
93
+ });
94
+ server.registerPrompt("monthly_transition", {
95
+ title: "Monthly Transition",
96
+ description: "Transition between game months: end sound, rotate, start sound, month lights",
97
+ argsSchema: {
98
+ month: z.string().optional().describe("Month number being entered"),
99
+ },
100
+ }, (args) => {
101
+ const monthEndEntry = TOWER_AUDIO_LIBRARY["MonthEnded"];
102
+ const monthStartEntry = TOWER_AUDIO_LIBRARY["MonthStarted"];
103
+ return {
104
+ messages: [
105
+ {
106
+ role: "user",
107
+ content: {
108
+ type: "text",
109
+ text: [
110
+ `Execute a monthly transition${args.month ? ` to month ${args.month}` : ""}:`,
111
+ `1. Play the month ended sound: tower_play_sound with index ${monthEndEntry?.value ?? 104}`,
112
+ "2. Random rotate all drums: tower_random_rotate",
113
+ `3. Play the month started sound: tower_play_sound with index ${monthStartEntry?.value ?? 105}`,
114
+ `4. Run the monthStarted light sequence: tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.monthStarted}`,
115
+ ].join("\n"),
116
+ },
117
+ },
118
+ ],
119
+ };
120
+ });
121
+ server.registerPrompt("dungeon_run", {
122
+ title: "Dungeon Run",
123
+ description: "Set up a dungeon atmosphere: dungeon sound and idle lights",
124
+ argsSchema: {
125
+ type: z.string().optional().describe("Type of dungeon (for sound selection)"),
126
+ },
127
+ }, (args) => {
128
+ const dungeonNote = args.type
129
+ ? `Look up a "${args.type}" dungeon sound using tower_play_sound_by_name.`
130
+ : 'Play a dungeon sound using tower_play_sound_by_name with name "Dungeon Intro".';
131
+ return {
132
+ messages: [
133
+ {
134
+ role: "user",
135
+ content: {
136
+ type: "text",
137
+ text: [
138
+ "Set up a dungeon atmosphere:",
139
+ `1. ${dungeonNote}`,
140
+ `2. Run the dungeon idle light sequence: tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.dungeonIdle}`,
141
+ ].join("\n"),
142
+ },
143
+ },
144
+ ],
145
+ };
146
+ });
147
+ server.registerPrompt("battle_start", {
148
+ title: "Battle Start",
149
+ description: "Start a battle with sound and dramatic lighting",
150
+ }, () => {
151
+ const battleStartEntry = TOWER_AUDIO_LIBRARY["BattleStart"];
152
+ return {
153
+ messages: [
154
+ {
155
+ role: "user",
156
+ content: {
157
+ type: "text",
158
+ text: [
159
+ "Execute a battle start sequence:",
160
+ `1. Play the battle start sound: tower_play_sound with index ${battleStartEntry?.value ?? 19}`,
161
+ `2. Run the flareThenFlicker light sequence: tower_light_sequence with sequence ${TOWER_LIGHT_SEQUENCES.flareThenFlicker}`,
162
+ ].join("\n"),
163
+ },
164
+ },
165
+ ],
166
+ };
167
+ });
168
+ server.registerPrompt("game_master_setup", {
169
+ title: "Game Master Setup",
170
+ description: "Guide for the AI to manage a full game session — connect, calibrate, and learn available tools and resources",
171
+ }, () => ({
172
+ messages: [
173
+ {
174
+ role: "user",
175
+ content: {
176
+ type: "text",
177
+ text: [
178
+ "You are the Game Master for Return to Dark Tower. Set up and manage a game session.",
179
+ "",
180
+ "SETUP:",
181
+ "1. Connect to the tower: tower_connect",
182
+ "2. Calibrate drums: tower_calibrate",
183
+ "3. Check tower status: tower_status",
184
+ "",
185
+ "AVAILABLE TOOLS:",
186
+ "- Connection: tower_connect, tower_disconnect, tower_calibrate, tower_status, tower_device_info",
187
+ "- Audio: tower_play_sound, tower_play_sound_by_name, tower_list_sounds",
188
+ "- Lights: tower_set_lights, tower_set_led, tower_light_sequence, tower_light_sequence_by_name, tower_lights_off",
189
+ "- Drums: tower_rotate, tower_rotate_drum, tower_random_rotate, tower_get_drum_positions",
190
+ "- Seals: tower_break_seal, tower_is_seal_broken, tower_get_broken_seals, tower_reset_seals, tower_random_seal",
191
+ "- State: tower_get_state, tower_send_state, tower_get_glyphs, tower_get_glyph, tower_glyphs_facing, tower_skull_count, tower_reset_skull_count",
192
+ "",
193
+ "GAME KNOWLEDGE RESOURCES:",
194
+ "Read the game rules (tower://game/rules), adversaries, quests, items, heroes, buildings, lore, and glossary resources to understand the game.",
195
+ "",
196
+ "DRAMATIC SEQUENCES:",
197
+ "Use the prompt templates (dramatic_entrance, victory_sequence, defeat_sequence, monthly_transition, dungeon_run, battle_start) for cinematic game moments.",
198
+ "",
199
+ "Begin by connecting and calibrating the tower, then guide players through their game session.",
200
+ ].join("\n"),
201
+ },
202
+ },
203
+ ],
204
+ }));
205
+ server.registerPrompt("sound_browser", {
206
+ title: "Sound Browser",
207
+ description: "Browse the tower audio library, optionally filtered by category",
208
+ argsSchema: {
209
+ category: z.string().optional().describe("Filter by sound category"),
210
+ },
211
+ }, (args) => {
212
+ let soundList;
213
+ if (args.category) {
214
+ const sounds = soundCategoryIndex.get(args.category);
215
+ if (sounds) {
216
+ soundList = sounds.map((s) => `- ${s.name} (index: ${s.value})`).join("\n");
217
+ soundList = `**${args.category} sounds:**\n${soundList}`;
218
+ }
219
+ else {
220
+ soundList = `Category "${args.category}" not found. Available categories: ${getSoundCategories().join(", ")}`;
221
+ }
222
+ }
223
+ else {
224
+ const lines = [];
225
+ for (const [cat, sounds] of soundCategoryIndex.entries()) {
226
+ lines.push(`\n**${cat}:**`);
227
+ for (const s of sounds) {
228
+ lines.push(`- ${s.name} (index: ${s.value})`);
229
+ }
230
+ }
231
+ soundList = lines.join("\n");
232
+ }
233
+ return {
234
+ messages: [
235
+ {
236
+ role: "user",
237
+ content: {
238
+ type: "text",
239
+ text: [
240
+ "Here is the tower audio library. You can play any sound using tower_play_sound with the index, or tower_play_sound_by_name with the name.",
241
+ "",
242
+ soundList,
243
+ ].join("\n"),
244
+ },
245
+ },
246
+ ],
247
+ };
248
+ });
249
+ }
250
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { TowerController } from "../tower-controller.js";
3
+ export declare function registerResources(server: McpServer, tower: TowerController): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAYzD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CA+RjF"}
@@ -0,0 +1,228 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { TOWER_AUDIO_LIBRARY, TOWER_LIGHT_SEQUENCES, LIGHT_EFFECTS } from "ultimatedarktower";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ function loadAsset(relativePath) {
7
+ try {
8
+ return readFileSync(join(__dirname, "..", relativePath), "utf-8");
9
+ }
10
+ catch {
11
+ return `[File not found: ${relativePath}]`;
12
+ }
13
+ }
14
+ export function registerResources(server, tower) {
15
+ // --- Tower state resources ---
16
+ server.registerResource("tower-connection", "tower://connection", {
17
+ title: "Tower Connection Status",
18
+ description: "Current connection state, calibration, and command status",
19
+ mimeType: "application/json",
20
+ }, () => ({
21
+ contents: [
22
+ {
23
+ uri: "tower://connection",
24
+ mimeType: "application/json",
25
+ text: JSON.stringify({
26
+ connected: tower.isConnected,
27
+ calibrated: tower.isCalibrated,
28
+ performingLongCommand: tower.performingLongCommand,
29
+ performingCalibration: tower.performingCalibration,
30
+ connectionStatus: tower.getConnectionStatus(),
31
+ }, null, 2),
32
+ },
33
+ ],
34
+ }));
35
+ server.registerResource("tower-device-info", "tower://device-info", {
36
+ title: "Tower Device Information",
37
+ description: "Manufacturer, model, serial, firmware, hardware revisions",
38
+ mimeType: "application/json",
39
+ }, () => ({
40
+ contents: [
41
+ {
42
+ uri: "tower://device-info",
43
+ mimeType: "application/json",
44
+ text: JSON.stringify(tower.getDeviceInformation(), null, 2),
45
+ },
46
+ ],
47
+ }));
48
+ server.registerResource("tower-battery", "tower://battery", {
49
+ title: "Tower Battery Status",
50
+ description: "Battery voltage, percentage, and monitoring configuration",
51
+ mimeType: "application/json",
52
+ }, () => {
53
+ const snapshot = tower.getSnapshot();
54
+ return {
55
+ contents: [
56
+ {
57
+ uri: "tower://battery",
58
+ mimeType: "application/json",
59
+ text: JSON.stringify(snapshot.battery, null, 2),
60
+ },
61
+ ],
62
+ };
63
+ });
64
+ server.registerResource("tower-drums", "tower://drums", {
65
+ title: "Tower Drum Positions",
66
+ description: "Current position of all three drums",
67
+ mimeType: "application/json",
68
+ }, () => {
69
+ const snapshot = tower.getSnapshot();
70
+ return {
71
+ contents: [
72
+ {
73
+ uri: "tower://drums",
74
+ mimeType: "application/json",
75
+ text: JSON.stringify(snapshot.drumPositions, null, 2),
76
+ },
77
+ ],
78
+ };
79
+ });
80
+ server.registerResource("tower-glyphs", "tower://glyphs", {
81
+ title: "Tower Glyph Positions",
82
+ description: "All 5 glyph positions and facing directions",
83
+ mimeType: "application/json",
84
+ }, () => ({
85
+ contents: [
86
+ {
87
+ uri: "tower://glyphs",
88
+ mimeType: "application/json",
89
+ text: JSON.stringify(tower.getAllGlyphPositions(), null, 2),
90
+ },
91
+ ],
92
+ }));
93
+ server.registerResource("tower-seals", "tower://seals", {
94
+ title: "Tower Seals",
95
+ description: "Broken and unbroken seal status",
96
+ mimeType: "application/json",
97
+ }, () => {
98
+ const broken = tower.getBrokenSeals();
99
+ return {
100
+ contents: [
101
+ {
102
+ uri: "tower://seals",
103
+ mimeType: "application/json",
104
+ text: JSON.stringify({
105
+ brokenSeals: broken,
106
+ brokenCount: broken.length,
107
+ totalSeals: 12,
108
+ unbrokenCount: 12 - broken.length,
109
+ }, null, 2),
110
+ },
111
+ ],
112
+ };
113
+ });
114
+ server.registerResource("tower-state", "tower://state", {
115
+ title: "Tower State",
116
+ description: "Full tower state including drums, lights, audio, beam",
117
+ mimeType: "application/json",
118
+ }, () => ({
119
+ contents: [
120
+ {
121
+ uri: "tower://state",
122
+ mimeType: "application/json",
123
+ text: JSON.stringify(tower.getCurrentTowerState(), null, 2),
124
+ },
125
+ ],
126
+ }));
127
+ server.registerResource("tower-audio-library", "tower://audio-library", {
128
+ title: "Tower Audio Library",
129
+ description: "Complete list of all 113 sounds with names, indices, and categories",
130
+ mimeType: "application/json",
131
+ }, () => ({
132
+ contents: [
133
+ {
134
+ uri: "tower://audio-library",
135
+ mimeType: "application/json",
136
+ text: JSON.stringify(TOWER_AUDIO_LIBRARY, null, 2),
137
+ },
138
+ ],
139
+ }));
140
+ server.registerResource("tower-light-effects", "tower://light-effects", {
141
+ title: "Tower Light Effects & Sequences",
142
+ description: "Available light effects (6) and predefined light sequences (19)",
143
+ mimeType: "application/json",
144
+ }, () => ({
145
+ contents: [
146
+ {
147
+ uri: "tower://light-effects",
148
+ mimeType: "application/json",
149
+ text: JSON.stringify({ effects: LIGHT_EFFECTS, sequences: TOWER_LIGHT_SEQUENCES }, null, 2),
150
+ },
151
+ ],
152
+ }));
153
+ // --- Game content resources ---
154
+ const gameContent = [
155
+ {
156
+ name: "game-rules",
157
+ uri: "tower://game/rules",
158
+ file: "rules.md",
159
+ title: "Game Rules",
160
+ desc: "Core rules — setup, turn structure, quests, battle, win/loss",
161
+ },
162
+ {
163
+ name: "game-adversaries",
164
+ uri: "tower://game/adversaries",
165
+ file: "adversaries.md",
166
+ title: "Adversaries",
167
+ desc: "All adversaries — abilities, spawn mechanics, escalation",
168
+ },
169
+ {
170
+ name: "game-quests",
171
+ uri: "tower://game/quests",
172
+ file: "quests.md",
173
+ title: "Quests",
174
+ desc: "Quest types, completion conditions, rewards",
175
+ },
176
+ {
177
+ name: "game-items",
178
+ uri: "tower://game/items",
179
+ file: "items.md",
180
+ title: "Items",
181
+ desc: "Equipment, potions, relics — names, effects, costs",
182
+ },
183
+ {
184
+ name: "game-heroes",
185
+ uri: "tower://game/heroes",
186
+ file: "heroes.md",
187
+ title: "Heroes",
188
+ desc: "Hero classes, starting stats, special abilities",
189
+ },
190
+ {
191
+ name: "game-buildings",
192
+ uri: "tower://game/buildings",
193
+ file: "buildings.md",
194
+ title: "Buildings",
195
+ desc: "Kingdom buildings — citadel, sanctuary, village, bazaar",
196
+ },
197
+ {
198
+ name: "game-lore",
199
+ uri: "tower://game/lore",
200
+ file: "lore.md",
201
+ title: "Lore",
202
+ desc: "World lore, tower history, thematic flavor",
203
+ },
204
+ {
205
+ name: "game-glossary",
206
+ uri: "tower://game/glossary",
207
+ file: "glossary.md",
208
+ title: "Glossary",
209
+ desc: "Key terms — virtues, corruption, skulls, seals, glyphs",
210
+ },
211
+ ];
212
+ for (const gc of gameContent) {
213
+ server.registerResource(gc.name, gc.uri, {
214
+ title: gc.title,
215
+ description: gc.desc,
216
+ mimeType: "text/markdown",
217
+ }, () => ({
218
+ contents: [
219
+ {
220
+ uri: gc.uri,
221
+ mimeType: "text/markdown",
222
+ text: loadAsset(`game-content/${gc.file}`),
223
+ },
224
+ ],
225
+ }));
226
+ }
227
+ }
228
+ //# sourceMappingURL=index.js.map