run-dmcp 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 +22 -0
- package/README.md +79 -0
- package/dist/__tests__/engineVocabulary.test.d.ts +1 -0
- package/dist/__tests__/engineVocabulary.test.js +147 -0
- package/dist/db/__tests__/connection.test.d.ts +1 -0
- package/dist/db/__tests__/connection.test.js +72 -0
- package/dist/db/__tests__/testDb.d.ts +33 -0
- package/dist/db/__tests__/testDb.js +41 -0
- package/dist/db/connection.d.ts +22 -0
- package/dist/db/connection.js +107 -0
- package/dist/db/schema.d.ts +1 -0
- package/dist/db/schema.js +725 -0
- package/dist/events/emitter.d.ts +22 -0
- package/dist/events/emitter.js +71 -0
- package/dist/http/server.d.ts +3 -0
- package/dist/http/server.js +649 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +92 -0
- package/dist/register/abilities.d.ts +2 -0
- package/dist/register/abilities.js +165 -0
- package/dist/register/audio.d.ts +2 -0
- package/dist/register/audio.js +326 -0
- package/dist/register/batch.d.ts +2 -0
- package/dist/register/batch.js +343 -0
- package/dist/register/character.d.ts +2 -0
- package/dist/register/character.js +324 -0
- package/dist/register/combat.d.ts +2 -0
- package/dist/register/combat.js +207 -0
- package/dist/register/core.d.ts +2 -0
- package/dist/register/core.js +1040 -0
- package/dist/register/display.d.ts +2 -0
- package/dist/register/display.js +263 -0
- package/dist/register/factions.d.ts +2 -0
- package/dist/register/factions.js +186 -0
- package/dist/register/images.d.ts +2 -0
- package/dist/register/images.js +400 -0
- package/dist/register/inventory.d.ts +2 -0
- package/dist/register/inventory.js +115 -0
- package/dist/register/mcp-prompts.d.ts +2 -0
- package/dist/register/mcp-prompts.js +684 -0
- package/dist/register/mcp-resources.d.ts +2 -0
- package/dist/register/mcp-resources.js +335 -0
- package/dist/register/narrative.d.ts +2 -0
- package/dist/register/narrative.js +242 -0
- package/dist/register/notes.d.ts +2 -0
- package/dist/register/notes.js +170 -0
- package/dist/register/pause.d.ts +2 -0
- package/dist/register/pause.js +580 -0
- package/dist/register/quests.d.ts +2 -0
- package/dist/register/quests.js +118 -0
- package/dist/register/relationships.d.ts +2 -0
- package/dist/register/relationships.js +147 -0
- package/dist/register/resources.d.ts +2 -0
- package/dist/register/resources.js +277 -0
- package/dist/register/secrets.d.ts +2 -0
- package/dist/register/secrets.js +192 -0
- package/dist/register/status.d.ts +2 -0
- package/dist/register/status.js +130 -0
- package/dist/register/tables.d.ts +2 -0
- package/dist/register/tables.js +146 -0
- package/dist/register/tags.d.ts +2 -0
- package/dist/register/tags.js +114 -0
- package/dist/register/time.d.ts +2 -0
- package/dist/register/time.js +281 -0
- package/dist/register/world.d.ts +2 -0
- package/dist/register/world.js +127 -0
- package/dist/schemas/index.d.ts +921 -0
- package/dist/schemas/index.js +121 -0
- package/dist/test-setup.d.ts +1 -0
- package/dist/test-setup.js +13 -0
- package/dist/tools/__tests__/audio.test.d.ts +1 -0
- package/dist/tools/__tests__/audio.test.js +59 -0
- package/dist/tools/__tests__/conserved.test.d.ts +1 -0
- package/dist/tools/__tests__/conserved.test.js +488 -0
- package/dist/tools/__tests__/constraint.test.d.ts +1 -0
- package/dist/tools/__tests__/constraint.test.js +212 -0
- package/dist/tools/__tests__/expiry-consequences.test.d.ts +1 -0
- package/dist/tools/__tests__/expiry-consequences.test.js +110 -0
- package/dist/tools/__tests__/images.test.d.ts +1 -0
- package/dist/tools/__tests__/images.test.js +59 -0
- package/dist/tools/__tests__/relationship.test.d.ts +1 -0
- package/dist/tools/__tests__/relationship.test.js +132 -0
- package/dist/tools/__tests__/resource-constraints.test.d.ts +1 -0
- package/dist/tools/__tests__/resource-constraints.test.js +131 -0
- package/dist/tools/__tests__/resource.test.d.ts +1 -0
- package/dist/tools/__tests__/resource.test.js +190 -0
- package/dist/tools/__tests__/time.test.d.ts +1 -0
- package/dist/tools/__tests__/time.test.js +404 -0
- package/dist/tools/__tests__/timers.test.d.ts +1 -0
- package/dist/tools/__tests__/timers.test.js +426 -0
- package/dist/tools/__tests__/world.test.d.ts +1 -0
- package/dist/tools/__tests__/world.test.js +70 -0
- package/dist/tools/ability.d.ts +48 -0
- package/dist/tools/ability.js +238 -0
- package/dist/tools/audio.d.ts +24 -0
- package/dist/tools/audio.js +365 -0
- package/dist/tools/character.d.ts +70 -0
- package/dist/tools/character.js +309 -0
- package/dist/tools/combat.d.ts +13 -0
- package/dist/tools/combat.js +195 -0
- package/dist/tools/constraint.d.ts +132 -0
- package/dist/tools/constraint.js +269 -0
- package/dist/tools/dice.d.ts +23 -0
- package/dist/tools/dice.js +111 -0
- package/dist/tools/display.d.ts +120 -0
- package/dist/tools/display.js +528 -0
- package/dist/tools/faction.d.ts +61 -0
- package/dist/tools/faction.js +269 -0
- package/dist/tools/game.d.ts +96 -0
- package/dist/tools/game.js +526 -0
- package/dist/tools/image-prompt.d.ts +49 -0
- package/dist/tools/image-prompt.js +479 -0
- package/dist/tools/images.d.ts +47 -0
- package/dist/tools/images.js +449 -0
- package/dist/tools/inventory.d.ts +20 -0
- package/dist/tools/inventory.js +145 -0
- package/dist/tools/narrative.d.ts +58 -0
- package/dist/tools/narrative.js +237 -0
- package/dist/tools/notes.d.ts +41 -0
- package/dist/tools/notes.js +220 -0
- package/dist/tools/pause.d.ts +110 -0
- package/dist/tools/pause.js +1254 -0
- package/dist/tools/quest.d.ts +34 -0
- package/dist/tools/quest.js +164 -0
- package/dist/tools/relationship.d.ts +74 -0
- package/dist/tools/relationship.js +324 -0
- package/dist/tools/resource.d.ts +93 -0
- package/dist/tools/resource.js +374 -0
- package/dist/tools/rules.d.ts +4 -0
- package/dist/tools/rules.js +30 -0
- package/dist/tools/secrets.d.ts +49 -0
- package/dist/tools/secrets.js +195 -0
- package/dist/tools/status.d.ts +36 -0
- package/dist/tools/status.js +218 -0
- package/dist/tools/tables.d.ts +33 -0
- package/dist/tools/tables.js +209 -0
- package/dist/tools/tags.d.ts +52 -0
- package/dist/tools/tags.js +176 -0
- package/dist/tools/time.d.ts +33 -0
- package/dist/tools/time.js +276 -0
- package/dist/tools/timers.d.ts +41 -0
- package/dist/tools/timers.js +215 -0
- package/dist/tools/world.d.ts +78 -0
- package/dist/tools/world.js +331 -0
- package/dist/types/index.d.ts +969 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/__tests__/json.test.d.ts +1 -0
- package/dist/utils/__tests__/json.test.js +55 -0
- package/dist/utils/__tests__/validation.test.d.ts +1 -0
- package/dist/utils/__tests__/validation.test.js +90 -0
- package/dist/utils/errors.d.ts +44 -0
- package/dist/utils/errors.js +121 -0
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.js +23 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +50 -0
- package/dist/utils/output-schemas.d.ts +594 -0
- package/dist/utils/output-schemas.js +331 -0
- package/dist/utils/tool-annotations.d.ts +147 -0
- package/dist/utils/tool-annotations.js +98 -0
- package/dist/utils/validation.d.ts +34 -0
- package/dist/utils/validation.js +52 -0
- package/dist/utils/verbosity.d.ts +57 -0
- package/dist/utils/verbosity.js +67 -0
- package/dist/utils/webui.d.ts +20 -0
- package/dist/utils/webui.js +35 -0
- package/package.json +75 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getDisplayConfig, setDisplayConfig, resetDisplayConfig, applyThemePreset, listThemePresets, getGameDisplayConfig, setGameDisplayConfig, applyGameThemePreset, resetGameTheme, inferAndApplyTheme, } from "../tools/display.js";
|
|
3
|
+
import { ANNOTATIONS } from "../utils/tool-annotations.js";
|
|
4
|
+
// All available theme presets
|
|
5
|
+
const themePresetNames = [
|
|
6
|
+
"high-fantasy",
|
|
7
|
+
"dark-fantasy",
|
|
8
|
+
"sci-fi",
|
|
9
|
+
"cyberpunk",
|
|
10
|
+
"western",
|
|
11
|
+
"noir",
|
|
12
|
+
"cosmic-horror",
|
|
13
|
+
"steampunk",
|
|
14
|
+
"post-apocalyptic",
|
|
15
|
+
"pirate",
|
|
16
|
+
"modern",
|
|
17
|
+
"superhero",
|
|
18
|
+
];
|
|
19
|
+
export function registerDisplayTools(server) {
|
|
20
|
+
// Get display configuration
|
|
21
|
+
server.registerTool("get_display_config", {
|
|
22
|
+
description: "Get the current display configuration for the web viewer (colors, fonts, visibility options)",
|
|
23
|
+
inputSchema: {},
|
|
24
|
+
annotations: ANNOTATIONS.READ_ONLY,
|
|
25
|
+
}, async () => {
|
|
26
|
+
const config = getDisplayConfig();
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: "text",
|
|
31
|
+
text: JSON.stringify(config, null, 2),
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
// Set display configuration (full or partial)
|
|
37
|
+
server.registerTool("set_display_config", {
|
|
38
|
+
description: "Set display configuration for the web viewer. Can set any subset of options.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
bgColor: z.string().optional().describe("Background color (e.g., '#1a1a2e')"),
|
|
41
|
+
bgSecondary: z.string().optional().describe("Secondary background color"),
|
|
42
|
+
bgElevated: z.string().optional().describe("Elevated surface background"),
|
|
43
|
+
textColor: z.string().optional().describe("Main text color"),
|
|
44
|
+
textMuted: z.string().optional().describe("Muted text color"),
|
|
45
|
+
accentColor: z.string().optional().describe("Accent color for links and highlights"),
|
|
46
|
+
accentHover: z.string().optional().describe("Accent color on hover"),
|
|
47
|
+
borderColor: z.string().optional().describe("Border color"),
|
|
48
|
+
successColor: z.string().optional().describe("Success/positive color"),
|
|
49
|
+
warningColor: z.string().optional().describe("Warning/caution color"),
|
|
50
|
+
dangerColor: z.string().optional().describe("Danger/error color"),
|
|
51
|
+
codeBackground: z.string().optional().describe("Code/monospace block background"),
|
|
52
|
+
codeText: z.string().optional().describe("Code/monospace text color"),
|
|
53
|
+
borderRadius: z
|
|
54
|
+
.enum(["sharp", "rounded", "soft"])
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Border radius style: sharp (0px), rounded (12px), soft (24px)"),
|
|
57
|
+
cardStyle: z
|
|
58
|
+
.enum(["clean", "grungy", "tech", "parchment", "metallic", "wooden"])
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Card visual style"),
|
|
61
|
+
fontDisplay: z.string().optional().describe("Display/heading font (Google Font name)"),
|
|
62
|
+
fontBody: z.string().optional().describe("Body text font (Google Font name)"),
|
|
63
|
+
fontMono: z.string().optional().describe("Monospace font (Google Font name)"),
|
|
64
|
+
showHealthBars: z.boolean().optional().describe("Show health bars on character cards"),
|
|
65
|
+
showConditionTags: z.boolean().optional().describe("Show condition tags"),
|
|
66
|
+
showImages: z.boolean().optional().describe("Show images in the viewer"),
|
|
67
|
+
appTitle: z.string().optional().describe("Custom title for the web viewer"),
|
|
68
|
+
},
|
|
69
|
+
annotations: ANNOTATIONS.SET,
|
|
70
|
+
}, async (args) => {
|
|
71
|
+
const config = setDisplayConfig(args);
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: `Display configuration updated:\n${JSON.stringify(config, null, 2)}`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
// Reset display configuration
|
|
82
|
+
server.registerTool("reset_display_config", {
|
|
83
|
+
description: "Reset display configuration to defaults",
|
|
84
|
+
inputSchema: {},
|
|
85
|
+
annotations: ANNOTATIONS.SET,
|
|
86
|
+
}, async () => {
|
|
87
|
+
const config = resetDisplayConfig();
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `Display configuration reset to defaults:\n${JSON.stringify(config, null, 2)}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
// Apply theme preset (global)
|
|
98
|
+
server.registerTool("apply_theme_preset", {
|
|
99
|
+
description: "Apply a predefined theme preset globally. Available presets include genre-specific themes with appropriate colors, fonts, and styles.",
|
|
100
|
+
inputSchema: {
|
|
101
|
+
preset: z
|
|
102
|
+
.enum(themePresetNames)
|
|
103
|
+
.describe("Theme preset name"),
|
|
104
|
+
},
|
|
105
|
+
annotations: ANNOTATIONS.SET,
|
|
106
|
+
}, async ({ preset }) => {
|
|
107
|
+
const config = applyThemePreset(preset);
|
|
108
|
+
if (!config) {
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: "text", text: `Unknown preset: ${preset}` }],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: "text",
|
|
118
|
+
text: `Applied '${preset}' theme preset:\n${JSON.stringify(config, null, 2)}`,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
// List theme presets
|
|
124
|
+
server.registerTool("list_theme_presets", {
|
|
125
|
+
description: "List all available theme presets with their colors and styles",
|
|
126
|
+
inputSchema: {},
|
|
127
|
+
annotations: ANNOTATIONS.READ_ONLY,
|
|
128
|
+
}, async () => {
|
|
129
|
+
const presets = listThemePresets();
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: "text",
|
|
134
|
+
text: `Available theme presets:\n${JSON.stringify(presets, null, 2)}`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
// ============================================
|
|
140
|
+
// Per-Game Theme Tools
|
|
141
|
+
// ============================================
|
|
142
|
+
// Get game theme
|
|
143
|
+
server.registerTool("get_game_theme", {
|
|
144
|
+
description: "Get the display configuration for a specific game",
|
|
145
|
+
inputSchema: {
|
|
146
|
+
gameId: z.string().describe("The game ID"),
|
|
147
|
+
},
|
|
148
|
+
annotations: ANNOTATIONS.READ_ONLY,
|
|
149
|
+
}, async ({ gameId }) => {
|
|
150
|
+
const config = getGameDisplayConfig(gameId);
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: "text",
|
|
155
|
+
text: JSON.stringify(config, null, 2),
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
// Set game theme
|
|
161
|
+
server.registerTool("set_game_theme", {
|
|
162
|
+
description: "Set display configuration for a specific game. Each game can have its own visual theme.",
|
|
163
|
+
inputSchema: {
|
|
164
|
+
gameId: z.string().describe("The game ID"),
|
|
165
|
+
bgColor: z.string().optional().describe("Background color"),
|
|
166
|
+
bgSecondary: z.string().optional().describe("Secondary background"),
|
|
167
|
+
bgElevated: z.string().optional().describe("Elevated surface background"),
|
|
168
|
+
textColor: z.string().optional().describe("Text color"),
|
|
169
|
+
textMuted: z.string().optional().describe("Muted text"),
|
|
170
|
+
accentColor: z.string().optional().describe("Accent color"),
|
|
171
|
+
accentHover: z.string().optional().describe("Accent hover color"),
|
|
172
|
+
borderColor: z.string().optional().describe("Border color"),
|
|
173
|
+
successColor: z.string().optional().describe("Success color"),
|
|
174
|
+
warningColor: z.string().optional().describe("Warning color"),
|
|
175
|
+
dangerColor: z.string().optional().describe("Danger color"),
|
|
176
|
+
codeBackground: z.string().optional().describe("Code block background"),
|
|
177
|
+
codeText: z.string().optional().describe("Code text color"),
|
|
178
|
+
borderRadius: z.enum(["sharp", "rounded", "soft"]).optional().describe("Border radius style"),
|
|
179
|
+
cardStyle: z.enum(["clean", "grungy", "tech", "parchment", "metallic", "wooden"]).optional().describe("Card style"),
|
|
180
|
+
fontDisplay: z.string().optional().describe("Display font"),
|
|
181
|
+
fontBody: z.string().optional().describe("Body font"),
|
|
182
|
+
fontMono: z.string().optional().describe("Mono font"),
|
|
183
|
+
showHealthBars: z.boolean().optional().describe("Show health bars"),
|
|
184
|
+
showConditionTags: z.boolean().optional().describe("Show condition tags"),
|
|
185
|
+
showImages: z.boolean().optional().describe("Show images"),
|
|
186
|
+
appTitle: z.string().optional().describe("App title"),
|
|
187
|
+
},
|
|
188
|
+
annotations: ANNOTATIONS.SET,
|
|
189
|
+
}, async ({ gameId, ...config }) => {
|
|
190
|
+
const updated = setGameDisplayConfig(gameId, config);
|
|
191
|
+
return {
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: `Game theme updated for ${gameId}:\n${JSON.stringify(updated, null, 2)}`,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
// Apply preset to game
|
|
201
|
+
server.registerTool("apply_game_theme_preset", {
|
|
202
|
+
description: "Apply a predefined theme preset to a specific game. This allows different games to have completely different visual themes.",
|
|
203
|
+
inputSchema: {
|
|
204
|
+
gameId: z.string().describe("The game ID"),
|
|
205
|
+
preset: z.enum(themePresetNames).describe("Theme preset name"),
|
|
206
|
+
},
|
|
207
|
+
annotations: ANNOTATIONS.SET,
|
|
208
|
+
}, async ({ gameId, preset }) => {
|
|
209
|
+
const config = applyGameThemePreset(gameId, preset);
|
|
210
|
+
if (!config) {
|
|
211
|
+
return {
|
|
212
|
+
content: [{ type: "text", text: `Unknown preset: ${preset}` }],
|
|
213
|
+
isError: true,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
content: [
|
|
218
|
+
{
|
|
219
|
+
type: "text",
|
|
220
|
+
text: `Applied '${preset}' theme to game ${gameId}:\n${JSON.stringify(config, null, 2)}`,
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
// Reset game theme
|
|
226
|
+
server.registerTool("reset_game_theme", {
|
|
227
|
+
description: "Remove a game's custom theme, reverting to the global theme",
|
|
228
|
+
inputSchema: {
|
|
229
|
+
gameId: z.string().describe("The game ID"),
|
|
230
|
+
},
|
|
231
|
+
annotations: ANNOTATIONS.SET,
|
|
232
|
+
}, async ({ gameId }) => {
|
|
233
|
+
resetGameTheme(gameId);
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: `Game theme reset. Game ${gameId} will now use the global theme.`,
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
// Auto-apply theme based on genre
|
|
244
|
+
server.registerTool("auto_theme_game", {
|
|
245
|
+
description: "Automatically apply an appropriate theme to a game based on its genre and setting. Call this when creating a new game to set up the visual style.",
|
|
246
|
+
inputSchema: {
|
|
247
|
+
gameId: z.string().describe("The game ID"),
|
|
248
|
+
genre: z.string().describe("Game genre (e.g., 'fantasy', 'sci-fi', 'western', 'noir')"),
|
|
249
|
+
setting: z.string().optional().describe("Optional setting description for more accurate theme matching"),
|
|
250
|
+
},
|
|
251
|
+
annotations: ANNOTATIONS.SET,
|
|
252
|
+
}, async ({ gameId, genre, setting }) => {
|
|
253
|
+
const config = inferAndApplyTheme(gameId, genre, setting);
|
|
254
|
+
return {
|
|
255
|
+
content: [
|
|
256
|
+
{
|
|
257
|
+
type: "text",
|
|
258
|
+
text: `Auto-themed game ${gameId} based on genre "${genre}":\n${JSON.stringify(config, null, 2)}`,
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as factionTools from "../tools/faction.js";
|
|
3
|
+
import { LIMITS } from "../utils/validation.js";
|
|
4
|
+
import { ANNOTATIONS } from "../utils/tool-annotations.js";
|
|
5
|
+
export function registerFactionTools(server) {
|
|
6
|
+
server.registerTool("create_faction", {
|
|
7
|
+
description: "Create a new faction/organization",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
gameId: z.string().max(100).describe("The game ID"),
|
|
10
|
+
name: z.string().min(1).max(LIMITS.NAME_MAX).describe("Faction name"),
|
|
11
|
+
description: z.string().max(LIMITS.DESCRIPTION_MAX).optional().describe("Faction description"),
|
|
12
|
+
leaderId: z.string().max(100).optional().describe("Character ID of the leader"),
|
|
13
|
+
headquartersId: z.string().max(100).optional().describe("Location ID of headquarters"),
|
|
14
|
+
resources: z.record(z.number()).optional().describe("Initial resources (e.g., {gold: 1000, soldiers: 50})"),
|
|
15
|
+
goals: z.array(z.string().max(LIMITS.DESCRIPTION_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Faction goals"),
|
|
16
|
+
traits: z.array(z.string().max(LIMITS.NAME_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Faction traits (e.g., ['secretive', 'militant'])"),
|
|
17
|
+
status: z.enum(["active", "disbanded", "hidden"]).optional().describe("Faction status"),
|
|
18
|
+
},
|
|
19
|
+
annotations: ANNOTATIONS.CREATE,
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
const faction = factionTools.createFaction(params);
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: JSON.stringify(faction, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
server.registerTool("get_faction", {
|
|
27
|
+
description: "Get a faction by ID",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
30
|
+
},
|
|
31
|
+
annotations: ANNOTATIONS.READ_ONLY,
|
|
32
|
+
}, async ({ factionId }) => {
|
|
33
|
+
const faction = factionTools.getFaction(factionId);
|
|
34
|
+
if (!faction) {
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: "Faction not found" }],
|
|
37
|
+
isError: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text", text: JSON.stringify(faction, null, 2) }],
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
server.registerTool("update_faction", {
|
|
45
|
+
description: "Update a faction's details",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
48
|
+
name: z.string().max(LIMITS.NAME_MAX).optional().describe("New name"),
|
|
49
|
+
description: z.string().max(LIMITS.DESCRIPTION_MAX).optional().describe("New description"),
|
|
50
|
+
leaderId: z.string().max(100).nullable().optional().describe("New leader ID (null to remove)"),
|
|
51
|
+
headquartersId: z.string().max(100).nullable().optional().describe("New headquarters ID (null to remove)"),
|
|
52
|
+
traits: z.array(z.string().max(LIMITS.NAME_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Replace traits"),
|
|
53
|
+
status: z.enum(["active", "disbanded", "hidden"]).optional().describe("New status"),
|
|
54
|
+
},
|
|
55
|
+
annotations: ANNOTATIONS.UPDATE,
|
|
56
|
+
}, async ({ factionId, ...updates }) => {
|
|
57
|
+
const faction = factionTools.updateFaction(factionId, updates);
|
|
58
|
+
if (!faction) {
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: "Faction not found" }],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text: JSON.stringify(faction, null, 2) }],
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
server.registerTool("delete_faction", {
|
|
69
|
+
description: "Delete a faction",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
72
|
+
},
|
|
73
|
+
annotations: ANNOTATIONS.DESTRUCTIVE,
|
|
74
|
+
}, async ({ factionId }) => {
|
|
75
|
+
const success = factionTools.deleteFaction(factionId);
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: "text", text: success ? "Faction deleted" : "Faction not found" }],
|
|
78
|
+
isError: !success,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
server.registerTool("list_factions", {
|
|
82
|
+
description: "List factions in a game",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
gameId: z.string().max(100).describe("The game ID"),
|
|
85
|
+
status: z.enum(["active", "disbanded", "hidden"]).optional().describe("Filter by status"),
|
|
86
|
+
},
|
|
87
|
+
annotations: ANNOTATIONS.READ_ONLY,
|
|
88
|
+
}, async ({ gameId, status }) => {
|
|
89
|
+
const factions = factionTools.listFactions(gameId, status ? { status } : undefined);
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: JSON.stringify(factions, null, 2) }],
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// CONSOLIDATED: UPDATE FACTION RESOURCE (replaces modify_faction_resource + set_faction_resource)
|
|
96
|
+
// ============================================================================
|
|
97
|
+
server.registerTool("update_faction_resource", {
|
|
98
|
+
description: "Update a faction resource value. Use mode 'delta' to add/subtract, or 'set' to set an absolute value.",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
101
|
+
resource: z.string().max(LIMITS.NAME_MAX).describe("Resource name (e.g., 'gold', 'soldiers')"),
|
|
102
|
+
mode: z.enum(["delta", "set"]).describe("'delta' to add/subtract from current value, 'set' to set absolute value"),
|
|
103
|
+
value: z.number().describe("Amount to add/subtract (for delta) or absolute value (for set). Values <= 0 remove the resource."),
|
|
104
|
+
},
|
|
105
|
+
annotations: ANNOTATIONS.UPDATE,
|
|
106
|
+
}, async (params) => {
|
|
107
|
+
const faction = factionTools.updateFactionResource(params);
|
|
108
|
+
if (!faction) {
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: "text", text: "Faction not found" }],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: JSON.stringify(faction, null, 2) }],
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// CONSOLIDATED: MODIFY FACTION GOALS (replaces add_faction_goal + complete_faction_goal)
|
|
120
|
+
// ============================================================================
|
|
121
|
+
server.registerTool("modify_faction_goals", {
|
|
122
|
+
description: "Add and/or complete faction goals in a single call. More efficient than separate add/complete calls.",
|
|
123
|
+
inputSchema: {
|
|
124
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
125
|
+
add: z.array(z.string().max(LIMITS.DESCRIPTION_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Goals to add"),
|
|
126
|
+
complete: z.array(z.number()).max(LIMITS.ARRAY_MAX).optional().describe("Indices of goals to complete (0-based)"),
|
|
127
|
+
},
|
|
128
|
+
annotations: ANNOTATIONS.UPDATE,
|
|
129
|
+
}, async ({ factionId, add, complete }) => {
|
|
130
|
+
if (!add?.length && !complete?.length) {
|
|
131
|
+
return {
|
|
132
|
+
content: [{ type: "text", text: "No goals to add or complete" }],
|
|
133
|
+
isError: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const result = factionTools.modifyFactionGoals(factionId, { add, complete });
|
|
137
|
+
if (!result) {
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: "text", text: "Faction not found" }],
|
|
140
|
+
isError: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
145
|
+
factionId: result.faction.id,
|
|
146
|
+
goals: result.faction.goals,
|
|
147
|
+
added: result.added,
|
|
148
|
+
completed: result.completed,
|
|
149
|
+
}, null, 2) }],
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// CONSOLIDATED: MODIFY FACTION TRAITS (replaces add_faction_trait + remove_faction_trait)
|
|
154
|
+
// ============================================================================
|
|
155
|
+
server.registerTool("modify_faction_traits", {
|
|
156
|
+
description: "Add and/or remove faction traits in a single call. More efficient than separate add/remove calls.",
|
|
157
|
+
inputSchema: {
|
|
158
|
+
factionId: z.string().max(100).describe("The faction ID"),
|
|
159
|
+
add: z.array(z.string().max(LIMITS.NAME_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Traits to add"),
|
|
160
|
+
remove: z.array(z.string().max(LIMITS.NAME_MAX)).max(LIMITS.ARRAY_MAX).optional().describe("Traits to remove"),
|
|
161
|
+
},
|
|
162
|
+
annotations: ANNOTATIONS.UPDATE,
|
|
163
|
+
}, async ({ factionId, add, remove }) => {
|
|
164
|
+
if (!add?.length && !remove?.length) {
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: "text", text: "No traits to add or remove" }],
|
|
167
|
+
isError: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const result = factionTools.modifyFactionTraits(factionId, { add, remove });
|
|
171
|
+
if (!result) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: "text", text: "Faction not found" }],
|
|
174
|
+
isError: true,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
179
|
+
factionId: result.faction.id,
|
|
180
|
+
traits: result.faction.traits,
|
|
181
|
+
added: result.added,
|
|
182
|
+
removed: result.removed,
|
|
183
|
+
}, null, 2) }],
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|