hoi4-agent-tools 2.3.8 → 2.3.10

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 (34) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/hoi4_agent_tools/core/workspace.js +36 -0
  3. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +23 -0
  4. package/dist/hoi4_agent_tools/mcp/server/create.js +28 -7
  5. package/dist/hoi4_agent_tools/mcp/tools/chaosx.js +3 -2
  6. package/dist/hoi4_agent_tools/mcp/tools/event.js +4 -3
  7. package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -4
  8. package/dist/hoi4_agent_tools/mcp/tools/gui.js +4 -4
  9. package/dist/hoi4_agent_tools/mcp/tools/map.js +4 -4
  10. package/dist/hoi4_agent_tools/mcp/tools/probability.js +10 -9
  11. package/dist/hoi4_agent_tools/mcp/tools/technology.js +4 -3
  12. package/dist/hoi4_agent_tools/version.js +1 -1
  13. package/package.json +1 -1
  14. package/schemas/configuration.schema.json +1 -1
  15. package/schemas/continuous-focus-palette.schema.json +1 -1
  16. package/schemas/custom-weighted-pool.schema.json +1 -1
  17. package/schemas/event-feature-manifest.schema.json +1 -1
  18. package/schemas/focus-plan.schema.json +1 -1
  19. package/schemas/focus-planning-sidecar.schema.json +1 -1
  20. package/schemas/gui-animation-source.schema.json +1 -1
  21. package/schemas/gui-helper.schema.json +1 -1
  22. package/schemas/gui-scenario.schema.json +1 -1
  23. package/schemas/map-operation.schema.json +1 -1
  24. package/schemas/operation-result.schema.json +1 -1
  25. package/schemas/probability-analysis-result.schema.json +1 -1
  26. package/schemas/probability-compare-input.schema.json +1 -1
  27. package/schemas/probability-evaluate-input.schema.json +1 -1
  28. package/schemas/probability-inspect-input.schema.json +1 -1
  29. package/schemas/probability-render-input.schema.json +1 -1
  30. package/schemas/probability-scenario-set.schema.json +1 -1
  31. package/schemas/probability-sequence-input.schema.json +1 -1
  32. package/schemas/probability-simulate-input.schema.json +1 -1
  33. package/schemas/probability-sweep-input.schema.json +1 -1
  34. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.10 - 2026-08-04
4
+
5
+ - Routed focus operations to the unique discovered mod containing a requested source when a stale client root points at another mod.
6
+ - Added regression coverage for a stale client context requesting Ireland's focus source without a workspace selector.
7
+
8
+ ## 2.3.9 - 2026-08-04
9
+
10
+ - Bound omitted-workspace tool calls to the connected MCP client's active filesystem root instead of the server process's original working directory.
11
+ - Added cross-workspace regression coverage proving an Ireland client root cannot be misdirected to a Slop Redux server working directory.
12
+
3
13
  ## 2.3.8 - 2026-08-04
4
14
 
5
15
  - Regenerated the clean-install lockfile with the release-pinned npm so optional native runtime metadata is complete in CI.
@@ -249,6 +249,42 @@ export class WorkspaceResolver {
249
249
  return workspaces[0].id;
250
250
  throw new ServiceError('WORKSPACE_CONTEXT_REQUIRED', 'The MCP working directory does not identify one writable mod workspace', { currentDirectory, workspaceIds: workspaces.map(({ id }) => id) });
251
251
  }
252
+ /** Resolve the active mod from filesystem roots advertised by the connected MCP client. */
253
+ async resolveClientWorkspaceId(rootPaths, principal) {
254
+ const canonicalRoots = await Promise.all(rootPaths.map((rootPath) => canonicalPath(rootPath)));
255
+ const matches = this.list(principal).filter((workspace) => workspace.registration.kind === 'mod' &&
256
+ canonicalRoots.some((rootPath) => isWithin(workspace.modRoot, rootPath) || isWithin(rootPath, workspace.modRoot)));
257
+ if (matches.length === 1)
258
+ return matches[0].id;
259
+ if (matches.length === 0) {
260
+ throw new ServiceError('WORKSPACE_CONTEXT_NOT_FOUND', 'The active MCP client roots do not identify a registered HOI4 mod workspace');
261
+ }
262
+ throw new ServiceError('WORKSPACE_CONTEXT_AMBIGUOUS', 'The active MCP client roots identify more than one HOI4 mod workspace', { workspaceIds: matches.map(({ id }) => id) });
263
+ }
264
+ /** Find one mod containing an existing source path when a stale client root selected another mod. */
265
+ async resolveUniqueModSourceWorkspaceId(relativePath, principal, signal) {
266
+ const matches = [];
267
+ for (const workspace of this.list(principal)) {
268
+ signal?.throwIfAborted();
269
+ if (workspace.registration.kind !== 'mod')
270
+ continue;
271
+ try {
272
+ const resolved = await this.resolvePath(workspace.id, relativePath, 'read', ['mod'], principal);
273
+ signal?.throwIfAborted();
274
+ if ((await lstat(resolved.path)).isFile())
275
+ matches.push(workspace.id);
276
+ }
277
+ catch (error) {
278
+ if (error.name === 'AbortError')
279
+ throw error;
280
+ }
281
+ }
282
+ if (matches.length === 0)
283
+ return undefined;
284
+ if (matches.length === 1)
285
+ return matches[0];
286
+ throw new ServiceError('WORKSPACE_SOURCE_AMBIGUOUS', `The requested source exists in more than one mod workspace: ${relativePath}`, { relativePath, workspaceIds: matches });
287
+ }
252
288
  resolveWorkspaceId(workspaceId, principal) {
253
289
  if (workspaceId === CURRENT_WORKSPACE_ID)
254
290
  return this.resolveCurrentWorkspaceId(principal);
@@ -1,4 +1,5 @@
1
1
  import { boundedSourceHashEvidence, publicArtifactLink } from '../../core/artifacts.js';
2
+ import { lstat } from 'node:fs/promises';
2
3
  import { canonicalJson } from '../../core/canonical.js';
3
4
  import { exactChangedFilePatterns, focusDomainScanPatterns, } from '../../core/domain-scan-patterns.js';
4
5
  import { ServiceError } from '../../core/result.js';
@@ -8,6 +9,28 @@ import { importContinuousFocusPalettes, importFocusTrees, layoutFocusTreeAsync,
8
9
  import { ScriptedGuiStudio } from '../../gui/index.js';
9
10
  import { AgentNudger, attributeMapValidationDiagnostics } from '../../map/index.js';
10
11
  import { PACKAGE_VERSION } from '../../version.js';
12
+ export async function resolveServerWorkspaceId(engine, context, workspaceId, signal) {
13
+ if (workspaceId === 'current' && context.resolveCurrentWorkspaceId !== undefined) {
14
+ return context.resolveCurrentWorkspaceId(signal);
15
+ }
16
+ return engine.resolver.resolveWorkspaceId(workspaceId, context.principal);
17
+ }
18
+ export async function resolveServerWorkspaceForSource(engine, context, workspaceId, relativePath, signal) {
19
+ const resolvedWorkspaceId = await resolveServerWorkspaceId(engine, context, workspaceId, signal);
20
+ if (workspaceId !== 'current' || relativePath === undefined)
21
+ return resolvedWorkspaceId;
22
+ try {
23
+ const resolved = await engine.resolver.resolvePath(resolvedWorkspaceId, relativePath, 'read', ['mod'], context.principal);
24
+ signal?.throwIfAborted();
25
+ if ((await lstat(resolved.path)).isFile())
26
+ return resolvedWorkspaceId;
27
+ }
28
+ catch (error) {
29
+ if (error.name === 'AbortError')
30
+ throw error;
31
+ }
32
+ return ((await engine.resolver.resolveUniqueModSourceWorkspaceId(relativePath, context.principal, signal)) ?? resolvedWorkspaceId);
33
+ }
11
34
  export function requireServerScope(context, scope) {
12
35
  if (context.scopes !== undefined && !context.scopes.includes(scope)) {
13
36
  throw new ServiceError('AUTH_SCOPE_REQUIRED', `This operation requires the ${scope} scope`, {
@@ -1,4 +1,5 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { fileURLToPath } from 'node:url';
2
3
  import { PACKAGE_NAME, PACKAGE_VERSION } from '../../version.js';
3
4
  import { registerFocusTools } from '../tools/focus.js';
4
5
  import { registerGuiTools } from '../tools/gui.js';
@@ -17,12 +18,32 @@ export function createMcpServer(engine, context = {}) {
17
18
  capabilities: { logging: {} },
18
19
  instructions: SERVER_INSTRUCTIONS,
19
20
  });
20
- registerFocusTools(server, engine, context);
21
- registerGuiTools(server, engine, context);
22
- registerMapTools(server, engine, context);
23
- registerEventTools(server, engine, context);
24
- registerTechnologyTools(server, engine, context);
25
- registerProbabilityTools(server, engine, context);
26
- registerMcpResources(server, engine, context);
21
+ const serverContext = {
22
+ ...context,
23
+ resolveCurrentWorkspaceId: async (signal) => {
24
+ const capabilities = server.server.getClientCapabilities();
25
+ if (capabilities?.roots === undefined) {
26
+ return engine.resolver.resolveCurrentWorkspaceId(context.principal);
27
+ }
28
+ const listed = await server.server.listRoots(undefined, signal === undefined ? undefined : { signal });
29
+ const rootPaths = listed.roots.flatMap(({ uri }) => {
30
+ try {
31
+ const parsed = new URL(uri);
32
+ return parsed.protocol === 'file:' ? [fileURLToPath(parsed)] : [];
33
+ }
34
+ catch {
35
+ return [];
36
+ }
37
+ });
38
+ return engine.resolver.resolveClientWorkspaceId(rootPaths, context.principal);
39
+ },
40
+ };
41
+ registerFocusTools(server, engine, serverContext);
42
+ registerGuiTools(server, engine, serverContext);
43
+ registerMapTools(server, engine, serverContext);
44
+ registerEventTools(server, engine, serverContext);
45
+ registerTechnologyTools(server, engine, serverContext);
46
+ registerProbabilityTools(server, engine, serverContext);
47
+ registerMcpResources(server, engine, serverContext);
27
48
  return server;
28
49
  }
@@ -11,6 +11,7 @@ import { GuiAssetCatalog } from '../../gui/assets.js';
11
11
  import { ScriptedGuiStudio } from '../../gui/index.js';
12
12
  import { buildGuiSourceGraph } from '../../gui/source-graph.js';
13
13
  import { PACKAGE_VERSION } from '../../version.js';
14
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
14
15
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
15
16
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
16
17
  import { progressReporter } from '../server/progress.js';
@@ -341,7 +342,7 @@ export function registerChaosxTools(server, engine, context) {
341
342
  outputSchema: chaosxVisualRevisionOutput,
342
343
  annotations: readOnly,
343
344
  }, async (input, extra) => {
344
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
345
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
345
346
  try {
346
347
  const progress = progressReporter(extra);
347
348
  await progress.report(0, 2, 'Checking ChaosX scripted-GUI sources');
@@ -379,7 +380,7 @@ export function registerChaosxTools(server, engine, context) {
379
380
  outputSchema: chaosxCountryAssetsOutput,
380
381
  annotations: artifactProducing,
381
382
  }, async (input, extra) => {
382
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
383
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
383
384
  try {
384
385
  const progress = progressReporter(extra);
385
386
  await progress.report(0, 3, 'Resolving ChaosX country assets');
@@ -9,6 +9,7 @@ import { compactValidatedInputSchema } from '../server/context-schemas.js';
9
9
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
10
10
  import { progressReporter } from '../server/progress.js';
11
11
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
12
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
12
13
  const nestedSelectorSchema = compactValidatedInputSchema(eventSelectorSchema, 'Event selector; see docs/events.md.');
13
14
  const nestedStateSubjectSchema = compactValidatedInputSchema(eventStateSubjectSchema, 'State kind and name.');
14
15
  const nestedImpactSubjectSchema = compactValidatedInputSchema(eventImpactSubjectSchema, 'Impact kind and name.');
@@ -311,7 +312,7 @@ export function registerEventTools(server, engine, context) {
311
312
  outputSchema: eventInspectOutputSchema,
312
313
  annotations: readOnlyEventTool,
313
314
  }, async (input, extra) => {
314
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
315
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
315
316
  try {
316
317
  const progress = progressReporter(extra);
317
318
  await progress.report(0, 3, 'Analyzing event chain');
@@ -350,7 +351,7 @@ export function registerEventTools(server, engine, context) {
350
351
  outputSchema: eventRenderOutputSchema,
351
352
  annotations: readOnlyEventTool,
352
353
  }, async (input, extra) => {
353
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
354
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
354
355
  try {
355
356
  const progress = progressReporter(extra);
356
357
  await progress.report(0, 3, 'Rendering event-chain view');
@@ -396,7 +397,7 @@ export function registerEventTools(server, engine, context) {
396
397
  outputSchema: eventCompareOutputSchema,
397
398
  annotations: readOnlyEventTool,
398
399
  }, async (input, extra) => {
399
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
400
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
400
401
  try {
401
402
  const progress = progressReporter(extra);
402
403
  await progress.report(0, 3, 'Comparing event-chain graphs');
@@ -13,7 +13,7 @@ import { PACKAGE_VERSION } from '../../version.js';
13
13
  import { nonNegativeIntegerSchema, renderHashesSchema, sha256Schema, } from '../server/output-schemas.js';
14
14
  import { progressReporter } from '../server/progress.js';
15
15
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
16
- import { requireServerScope } from '../server/base-tools.js';
16
+ import { requireServerScope, resolveServerWorkspaceForSource, } from '../server/base-tools.js';
17
17
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
18
18
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
19
19
  const focusInspectOutputSchema = strictOperationResultSchema(z
@@ -347,7 +347,7 @@ export async function computeFocusVisualRevisions(engine, context, workspaceId,
347
347
  }
348
348
  async function executeFocusVisualTool(engine, workbench, context, input, extra, rasterize) {
349
349
  const { workspaceId: requestedWorkspaceId, relativePath } = input;
350
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
350
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
351
351
  const outputName = rasterize ? 'raster' : 'render';
352
352
  try {
353
353
  const progress = progressReporter(extra);
@@ -607,7 +607,7 @@ export function registerFocusTools(server, engine, context) {
607
607
  annotations: artifactProducing,
608
608
  }, async (input, extra) => {
609
609
  const { workspaceId: requestedWorkspaceId, relativePath } = input;
610
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
610
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
611
611
  try {
612
612
  const progress = progressReporter(extra);
613
613
  await progress.report(0, 3, 'Building shared workspace index');
@@ -845,7 +845,7 @@ export function registerFocusTools(server, engine, context) {
845
845
  },
846
846
  }, async (input, extra) => {
847
847
  const { workspaceId: requestedWorkspaceId, relativePath, createIfMissing, horizontalSpacing, verticalSpacing, padding, reviewScale, } = input;
848
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
848
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
849
849
  try {
850
850
  requireServerScope(context, 'hoi4:write');
851
851
  const progress = progressReporter(extra);
@@ -8,7 +8,7 @@ import { GuiHelperDocumentSchema, GuiPreviewScenarioSchema, GUI_TEXT_PACKAGE_MAX
8
8
  import { encodeGuiInspectionArtifact, projectGuiGraphForArtifact, } from '../../gui/inspection-artifact.js';
9
9
  import { workspaceIdSchema, workspaceRelativePathSchema } from '../../schemas/common.js';
10
10
  import { PACKAGE_VERSION } from '../../version.js';
11
- import { requireServerScope } from '../server/base-tools.js';
11
+ import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
12
12
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
13
13
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
14
14
  import { indexSkippedSourceSchema, nonNegativeIntegerSchema, sha256Schema, } from '../server/output-schemas.js';
@@ -151,7 +151,7 @@ export function registerGuiTools(server, engine, context) {
151
151
  outputSchema: guiScanOutputSchema,
152
152
  annotations: artifactProducing,
153
153
  }, async ({ workspaceId: requestedWorkspaceId, windowName, scenario, relatedScenarios }, extra) => {
154
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
154
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
155
155
  try {
156
156
  const progress = progressReporter(extra);
157
157
  await progress.report(0, 3, 'Building GUI source graph');
@@ -262,7 +262,7 @@ export function registerGuiTools(server, engine, context) {
262
262
  }
263
263
  });
264
264
  const render = async (input, extra, code) => {
265
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
265
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
266
266
  const { windowName } = input;
267
267
  try {
268
268
  const progress = progressReporter(extra);
@@ -453,7 +453,7 @@ export function registerGuiTools(server, engine, context) {
453
453
  openWorldHint: false,
454
454
  },
455
455
  }, async (input, extra) => {
456
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
456
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
457
457
  const { relativePath, windowName, scenario } = input;
458
458
  try {
459
459
  requireServerScope(context, 'hoi4:write');
@@ -6,7 +6,7 @@ import { AgentNudger, allocateMapIdentifiersAsync, exportProvinceGeometryRowRuns
6
6
  import { workspaceIdSchema } from '../../schemas/common.js';
7
7
  import { mapAllocationRequestSchema, mapOperationSchema } from '../../schemas/map.js';
8
8
  import { PACKAGE_VERSION } from '../../version.js';
9
- import { requireServerScope } from '../server/base-tools.js';
9
+ import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
10
10
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
11
11
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
12
12
  import { allocationEvidenceSchema, bitmapRenderHashesSchema, nonNegativeIntegerSchema, operationBlockerDataSchema, sha256Schema, } from '../server/output-schemas.js';
@@ -365,7 +365,7 @@ export function registerMapTools(server, engine, context) {
365
365
  outputSchema: mapWorkspaceInspectOutputSchema,
366
366
  annotations: artifactProducing,
367
367
  }, async ({ workspaceId: requestedWorkspaceId, provinceIds, stateIds, regionIds, allocationRequests }, extra) => {
368
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
368
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
369
369
  try {
370
370
  const progress = progressReporter(extra);
371
371
  await progress.report(0, 3, 'Inspecting and validating the map');
@@ -512,7 +512,7 @@ export function registerMapTools(server, engine, context) {
512
512
  outputSchema: mapRenderOutputSchema,
513
513
  annotations: artifactProducing,
514
514
  }, async ({ workspaceId: requestedWorkspaceId, layer, overlays, scale }, extra) => {
515
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
515
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
516
516
  try {
517
517
  const progress = progressReporter(extra);
518
518
  await progress.report(0, 3, 'Rendering offline map layer');
@@ -558,7 +558,7 @@ export function registerMapTools(server, engine, context) {
558
558
  openWorldHint: false,
559
559
  },
560
560
  }, async ({ workspaceId: requestedWorkspaceId, operations, diffScale }, extra) => {
561
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
561
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
562
562
  try {
563
563
  requireServerScope(context, 'hoi4:write');
564
564
  const progress = progressReporter(extra);
@@ -3,6 +3,7 @@ import { emptyServiceResult } from '../../core/result.js';
3
3
  import { ProbabilityAnalyzer, } from '../../probability/service.js';
4
4
  import { customWeightedPoolManifestSchema, probabilityAcceptanceBandSchema, probabilityAdapterIdSchema, probabilityDiagnosticThresholdsSchema, probabilityMetricSchema, probabilityOutputSchema, probabilityRenderFilterSchema, probabilityScenarioSetSchema, probabilitySamplingMethodSchema, probabilitySourceSchema, } from '../../schemas/probability.js';
5
5
  import { workspaceIdSchema } from '../../schemas/common.js';
6
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
6
7
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
7
8
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
8
9
  import { progressReporter } from '../server/progress.js';
@@ -150,9 +151,9 @@ const readOnly = {
150
151
  idempotentHint: true,
151
152
  openWorldHint: false,
152
153
  };
153
- function requestContext(engine, context, workspaceId, refresh, signal) {
154
+ async function requestContext(engine, context, workspaceId, refresh, signal) {
154
155
  return {
155
- workspaceId: engine.resolver.resolveWorkspaceId(workspaceId, context.principal),
156
+ workspaceId: await resolveServerWorkspaceId(engine, context, workspaceId, signal),
156
157
  ...(context.principal === undefined ? {} : { principal: context.principal }),
157
158
  ...(refresh === undefined ? {} : { refresh }),
158
159
  signal,
@@ -216,7 +217,7 @@ export function registerProbabilityTools(server, engine, context) {
216
217
  annotations: readOnly,
217
218
  }, async (input, extra) => {
218
219
  const progress = progressReporter(extra);
219
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
220
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
220
221
  try {
221
222
  await progress.report(0, 2, 'Inspecting weighted source');
222
223
  const inspected = await analyzer.inspect(base, input.adapter, input.source, input.candidatePool);
@@ -255,7 +256,7 @@ export function registerProbabilityTools(server, engine, context) {
255
256
  annotations: readOnly,
256
257
  }, async (input, extra) => {
257
258
  const progress = progressReporter(extra);
258
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
259
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
259
260
  try {
260
261
  await progress.report(0, 3, 'Scanning and evaluating weighted source');
261
262
  const request = {
@@ -279,7 +280,7 @@ export function registerProbabilityTools(server, engine, context) {
279
280
  annotations: readOnly,
280
281
  }, async (input, extra) => {
281
282
  const progress = progressReporter(extra);
282
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
283
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
283
284
  try {
284
285
  await progress.report(0, 3, 'Evaluating parameter sweep');
285
286
  const request = {
@@ -303,7 +304,7 @@ export function registerProbabilityTools(server, engine, context) {
303
304
  annotations: readOnly,
304
305
  }, async (input, extra) => {
305
306
  const progress = progressReporter(extra);
306
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
307
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
307
308
  try {
308
309
  await progress.report(0, input.samples, 'Sampling uncertain scenarios');
309
310
  const request = {
@@ -327,7 +328,7 @@ export function registerProbabilityTools(server, engine, context) {
327
328
  annotations: readOnly,
328
329
  }, async (input, extra) => {
329
330
  const progress = progressReporter(extra);
330
- const base = requestContext(engine, context, input.workspaceId, undefined, progress.signal);
331
+ const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
331
332
  try {
332
333
  await progress.report(0, input.maxSteps, 'Analyzing declared sequence');
333
334
  const request = {
@@ -351,7 +352,7 @@ export function registerProbabilityTools(server, engine, context) {
351
352
  annotations: readOnly,
352
353
  }, async (input, extra) => {
353
354
  const progress = progressReporter(extra);
354
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
355
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
355
356
  try {
356
357
  await progress.report(0, 4, 'Comparing weighted source');
357
358
  const request = {
@@ -375,7 +376,7 @@ export function registerProbabilityTools(server, engine, context) {
375
376
  annotations: readOnly,
376
377
  }, async (input, extra) => {
377
378
  const progress = progressReporter(extra);
378
- const base = requestContext(engine, context, input.workspaceId, undefined, progress.signal);
379
+ const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
379
380
  try {
380
381
  await progress.report(0, input.outputs.length, 'Rendering analysis resources');
381
382
  const request = {
@@ -9,6 +9,7 @@ import { compactValidatedInputSchema } from '../server/context-schemas.js';
9
9
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
10
10
  import { progressReporter } from '../server/progress.js';
11
11
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
12
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
12
13
  const technologyMode = z.enum([
13
14
  'scan',
14
15
  'folders',
@@ -244,7 +245,7 @@ export function registerTechnologyTools(server, engine, context) {
244
245
  outputSchema: analysisOutput,
245
246
  annotations: readOnly,
246
247
  }, async (input, extra) => {
247
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
248
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
248
249
  try {
249
250
  const progress = progressReporter(extra);
250
251
  await progress.report(0, 2, 'Analyzing technologies');
@@ -273,7 +274,7 @@ export function registerTechnologyTools(server, engine, context) {
273
274
  outputSchema: renderOutput,
274
275
  annotations: readOnly,
275
276
  }, async (input, extra) => {
276
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
277
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
277
278
  try {
278
279
  const progress = progressReporter(extra);
279
280
  const request = {
@@ -317,7 +318,7 @@ export function registerTechnologyTools(server, engine, context) {
317
318
  outputSchema: compareOutput,
318
319
  annotations: readOnly,
319
320
  }, async (input, extra) => {
320
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
321
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
321
322
  try {
322
323
  const progress = progressReporter(extra);
323
324
  const request = {
@@ -1,6 +1,6 @@
1
1
  import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
2
2
  export const PACKAGE_NAME = 'hoi4-agent-tools';
3
- export const PACKAGE_VERSION = '2.3.8';
3
+ export const PACKAGE_VERSION = '2.3.10';
4
4
  export const MCP_PROTOCOL_VERSION = LATEST_PROTOCOL_VERSION;
5
5
  export const CONFIG_VERSION = 1;
6
6
  export const TRANSACTION_VERSION = 1;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hoi4-agent-tools",
3
3
  "mcpName": "io.github.klimPaskov/hoi4-agent-tools",
4
- "version": "2.3.8",
4
+ "version": "2.3.10",
5
5
  "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
6
  "type": "module",
7
7
  "license": "Apache-2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/configuration.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/continuous-focus-palette.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/custom-weighted-pool.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/event-feature-manifest.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/focus-plan.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/focus-planning-sidecar.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/gui-animation-source.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/gui-helper.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/gui-scenario.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/map-operation.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "oneOf": [
5
5
  {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/operation-result.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-analysis-result.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-compare-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-evaluate-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-inspect-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-render-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-scenario-set.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-sequence-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-simulate-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.8/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/schemas/probability-sweep-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.klimPaskov/hoi4-agent-tools",
4
4
  "title": "HOI4 Agent Tools",
5
5
  "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
- "version": "2.3.8",
6
+ "version": "2.3.10",
7
7
  "repository": {
8
8
  "url": "https://github.com/klimPaskov/hoi4-agent-tools",
9
9
  "source": "github"
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "hoi4-agent-tools",
16
- "version": "2.3.8",
16
+ "version": "2.3.10",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }