@timetick/mcp 0.2.0 → 0.2.1
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/dist/index.js +321 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -117,6 +117,7 @@ function registerContextTools(server) {
|
|
|
117
117
|
server.registerTool(
|
|
118
118
|
"get_context",
|
|
119
119
|
{
|
|
120
|
+
annotations: { readOnlyHint: true },
|
|
120
121
|
title: "Get active context",
|
|
121
122
|
description: "Show the project and sim world the MCP server is currently operating on. If no project is selected yet and you have only one project, it is auto-selected.",
|
|
122
123
|
inputSchema: {}
|
|
@@ -132,6 +133,7 @@ function registerContextTools(server) {
|
|
|
132
133
|
server.registerTool(
|
|
133
134
|
"use_project",
|
|
134
135
|
{
|
|
136
|
+
annotations: { readOnlyHint: true },
|
|
135
137
|
title: "Select project",
|
|
136
138
|
description: "Switch the active project by name or id. Only needed if you have more than one project. Caches the project's sim world for subsequent tools.",
|
|
137
139
|
inputSchema: {
|
|
@@ -148,6 +150,25 @@ function registerContextTools(server) {
|
|
|
148
150
|
// src/tools/data.ts
|
|
149
151
|
import { z as z3 } from "zod";
|
|
150
152
|
|
|
153
|
+
// src/links.ts
|
|
154
|
+
var SIMULATOR_PATH = /\/projects\/([^/?#&|>\s]+)\/simulators\/([^/?#&|>\s]+)/;
|
|
155
|
+
function looksLikeLink(text) {
|
|
156
|
+
return /^<?https?:\/\//i.test(text) || /(^|\.)timetick\.io\//i.test(text);
|
|
157
|
+
}
|
|
158
|
+
function parseSimulatorRef(input) {
|
|
159
|
+
const text = input.trim();
|
|
160
|
+
if (!looksLikeLink(text)) return { simulator: text };
|
|
161
|
+
const unescaped = text.replace(/&/g, "&");
|
|
162
|
+
const match = unescaped.match(SIMULATOR_PATH);
|
|
163
|
+
if (!match) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`"${input}" looks like a link but not to a simulator. Expected https://app.timetick.io/projects/<project id>/simulators/<simulator id>.`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return { project: decodeURIComponent(match[1]), simulator: decodeURIComponent(match[2]) };
|
|
169
|
+
}
|
|
170
|
+
var SIMULATOR_ARG_DESCRIPTION = "Simulator id, base name, or portal link (https://app.timetick.io/projects/<id>/simulators/<id>)";
|
|
171
|
+
|
|
151
172
|
// src/resolve.ts
|
|
152
173
|
async function resolveSimWorld(project) {
|
|
153
174
|
if (project) return lookupProject(project);
|
|
@@ -172,6 +193,20 @@ Candidates:
|
|
|
172
193
|
${candidates}` : " No simulators found in this sim world.")
|
|
173
194
|
);
|
|
174
195
|
}
|
|
196
|
+
async function resolveSimulatorTarget(simulator, project) {
|
|
197
|
+
const ref = parseSimulatorRef(simulator);
|
|
198
|
+
const ctx = await resolveSimWorld(ref.project ?? project);
|
|
199
|
+
const sim = ref.project !== void 0 ? await resolveSimulatorById(ref.simulator) : await resolveSimulator(ctx.simWorldId, ref.simulator);
|
|
200
|
+
return { ctx, sim };
|
|
201
|
+
}
|
|
202
|
+
async function resolveSimulatorById(id) {
|
|
203
|
+
const byId = await sdk().simulators.get(id).catch((err) => {
|
|
204
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
205
|
+
throw new Error(`No simulator with id ${id} from the portal link: ${reason}`);
|
|
206
|
+
});
|
|
207
|
+
if (!byId?.id) throw new Error(`No simulator with id ${id} from the portal link.`);
|
|
208
|
+
return { id: byId.id, baseName: byId.baseName ?? "", protocol: String(byId.protocol) };
|
|
209
|
+
}
|
|
175
210
|
async function resolveActionId(simWorldId, protocol, actionName) {
|
|
176
211
|
const page = await sdk().actions.list({
|
|
177
212
|
simWorldId,
|
|
@@ -228,6 +263,7 @@ function registerDataTools(server) {
|
|
|
228
263
|
server.registerTool(
|
|
229
264
|
"list_projects",
|
|
230
265
|
{
|
|
266
|
+
annotations: { readOnlyHint: true },
|
|
231
267
|
title: "List projects",
|
|
232
268
|
description: "List all projects available to your API key.",
|
|
233
269
|
inputSchema: {}
|
|
@@ -240,6 +276,7 @@ function registerDataTools(server) {
|
|
|
240
276
|
server.registerTool(
|
|
241
277
|
"list_simulators",
|
|
242
278
|
{
|
|
279
|
+
annotations: { readOnlyHint: true },
|
|
243
280
|
title: "List simulators",
|
|
244
281
|
description: "List simulators (virtual chargers) in the active project's sim world. Optionally filter by name search or protocol.",
|
|
245
282
|
inputSchema: {
|
|
@@ -266,16 +303,16 @@ function registerDataTools(server) {
|
|
|
266
303
|
server.registerTool(
|
|
267
304
|
"get_simulator",
|
|
268
305
|
{
|
|
306
|
+
annotations: { readOnlyHint: true },
|
|
269
307
|
title: "Get simulator",
|
|
270
308
|
description: "Get a simulator's details and live status (network status, launched/power status, connectors) by id or base name.",
|
|
271
309
|
inputSchema: {
|
|
272
|
-
simulator: z3.string().describe(
|
|
310
|
+
simulator: z3.string().describe(SIMULATOR_ARG_DESCRIPTION),
|
|
273
311
|
project: z3.string().optional().describe("Project name or id (defaults to active project)")
|
|
274
312
|
}
|
|
275
313
|
},
|
|
276
314
|
async ({ simulator, project }) => guard(async () => {
|
|
277
|
-
const
|
|
278
|
-
const resolved = await resolveSimulator(ctx.simWorldId, simulator);
|
|
315
|
+
const { sim: resolved } = await resolveSimulatorTarget(simulator, project);
|
|
279
316
|
const details = await sdk().simulators.get(resolved.id);
|
|
280
317
|
return ok(`Simulator ${resolved.baseName} (id: ${resolved.id}).`, details);
|
|
281
318
|
})
|
|
@@ -283,6 +320,7 @@ function registerDataTools(server) {
|
|
|
283
320
|
server.registerTool(
|
|
284
321
|
"list_hardware",
|
|
285
322
|
{
|
|
323
|
+
annotations: { readOnlyHint: true },
|
|
286
324
|
title: "List hardware",
|
|
287
325
|
description: "List physical OCPP hardware devices in the active project's sim world.",
|
|
288
326
|
inputSchema: {
|
|
@@ -307,6 +345,7 @@ function registerDataTools(server) {
|
|
|
307
345
|
server.registerTool(
|
|
308
346
|
"list_actions",
|
|
309
347
|
{
|
|
348
|
+
annotations: { readOnlyHint: true },
|
|
310
349
|
title: "List actions (test steps)",
|
|
311
350
|
description: "List available actions (steps) you can use to build a test \u2014 e.g. 'Power On Charger', 'Plug In Connector', 'Charge a Vehicle'. Filter by protocol. Each action lists its arguments: the name, whether it is required (allowNull false), and any default.",
|
|
312
351
|
inputSchema: {
|
|
@@ -337,8 +376,7 @@ function registerDataTools(server) {
|
|
|
337
376
|
// src/tools/simulators.ts
|
|
338
377
|
import { z as z4 } from "zod";
|
|
339
378
|
async function runOnSimulator(project, simulator, actionName, args = []) {
|
|
340
|
-
const ctx = await
|
|
341
|
-
const sim = await resolveSimulator(ctx.simWorldId, simulator);
|
|
379
|
+
const { ctx, sim } = await resolveSimulatorTarget(simulator, project);
|
|
342
380
|
const actionId = await resolveActionId(ctx.simWorldId, sim.protocol, actionName);
|
|
343
381
|
const status = await sdk().testRuns.runAction({
|
|
344
382
|
chargerId: sim.id,
|
|
@@ -351,10 +389,11 @@ function registerSimulatorTools(server) {
|
|
|
351
389
|
server.registerTool(
|
|
352
390
|
"power_on_simulator",
|
|
353
391
|
{
|
|
392
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
354
393
|
title: "Power on simulator",
|
|
355
394
|
description: "Power on a simulator (boots it and connects it to the OCPP server).",
|
|
356
395
|
inputSchema: {
|
|
357
|
-
simulator: z4.string().describe(
|
|
396
|
+
simulator: z4.string().describe(SIMULATOR_ARG_DESCRIPTION),
|
|
358
397
|
project: projectArg
|
|
359
398
|
}
|
|
360
399
|
},
|
|
@@ -366,10 +405,11 @@ function registerSimulatorTools(server) {
|
|
|
366
405
|
server.registerTool(
|
|
367
406
|
"power_off_simulator",
|
|
368
407
|
{
|
|
408
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
369
409
|
title: "Power off simulator",
|
|
370
410
|
description: "Power off a simulator.",
|
|
371
411
|
inputSchema: {
|
|
372
|
-
simulator: z4.string().describe(
|
|
412
|
+
simulator: z4.string().describe(SIMULATOR_ARG_DESCRIPTION),
|
|
373
413
|
project: projectArg
|
|
374
414
|
}
|
|
375
415
|
},
|
|
@@ -381,10 +421,11 @@ function registerSimulatorTools(server) {
|
|
|
381
421
|
server.registerTool(
|
|
382
422
|
"run_simulator_action",
|
|
383
423
|
{
|
|
424
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
384
425
|
title: "Run simulator action",
|
|
385
426
|
description: "Run a single named action against a simulator \u2014 e.g. 'Reset Charger', 'Plug In Connector', 'Plug Out Connector'. Use list_actions to discover names and required args. Args are passed as key/value pairs (e.g. connectorId=1).",
|
|
386
427
|
inputSchema: {
|
|
387
|
-
simulator: z4.string().describe(
|
|
428
|
+
simulator: z4.string().describe(SIMULATOR_ARG_DESCRIPTION),
|
|
388
429
|
actionName: z4.string().describe("Exact action name, e.g. 'Reset Charger'"),
|
|
389
430
|
args: z4.array(z4.object({ key: z4.string(), value: z4.string() })).optional().describe("Action arguments as key/value pairs"),
|
|
390
431
|
project: projectArg
|
|
@@ -405,6 +446,7 @@ function registerTestTools(server) {
|
|
|
405
446
|
server.registerTool(
|
|
406
447
|
"list_tests",
|
|
407
448
|
{
|
|
449
|
+
annotations: { readOnlyHint: true },
|
|
408
450
|
title: "List tests",
|
|
409
451
|
description: "List tests (scenarios) in the active project's sim world.",
|
|
410
452
|
inputSchema: {
|
|
@@ -428,6 +470,7 @@ function registerTestTools(server) {
|
|
|
428
470
|
server.registerTool(
|
|
429
471
|
"get_test",
|
|
430
472
|
{
|
|
473
|
+
annotations: { readOnlyHint: true },
|
|
431
474
|
title: "Get test",
|
|
432
475
|
description: "Get a test by id, including its device requirements.",
|
|
433
476
|
inputSchema: {
|
|
@@ -443,6 +486,7 @@ function registerTestTools(server) {
|
|
|
443
486
|
server.registerTool(
|
|
444
487
|
"create_test",
|
|
445
488
|
{
|
|
489
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
446
490
|
title: "Create test",
|
|
447
491
|
description: "Create a test from an ordered list of steps. Each step references an action by name (use list_actions to discover them) plus optional key/value args. The steps run in order against a single simulator. Example steps: 'Power On Charger', 'Plug In Connector', 'Use RFID Card', 'Charge a Vehicle', 'Plug Out Connector', 'Power Off Charger'.",
|
|
448
492
|
inputSchema: {
|
|
@@ -491,20 +535,20 @@ function registerTestRunTools(server) {
|
|
|
491
535
|
server.registerTool(
|
|
492
536
|
"run_test",
|
|
493
537
|
{
|
|
538
|
+
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
|
|
494
539
|
title: "Run test",
|
|
495
540
|
description: "Run a test (scenario) on a simulator, starting immediately. Returns the test run id and status \u2014 poll with get_test_run to follow it. A simulator runs one test at a time; if it is busy this says so and starts nothing.",
|
|
496
541
|
inputSchema: {
|
|
497
542
|
testId: z6.string().describe("Test (scenario) id to run"),
|
|
498
|
-
simulator: z6.string().describe(
|
|
543
|
+
simulator: z6.string().describe(`${SIMULATOR_ARG_DESCRIPTION} to run the test on`),
|
|
499
544
|
project: projectArg
|
|
500
545
|
}
|
|
501
546
|
},
|
|
502
547
|
async ({ testId, simulator, project }) => guard(async () => {
|
|
503
|
-
const ctx = await
|
|
548
|
+
const { ctx, sim } = await resolveSimulatorTarget(simulator, project);
|
|
504
549
|
const test = await sdk().tests.get(testId);
|
|
505
550
|
const requirementId = test?.requirements?.[0]?.id;
|
|
506
551
|
if (!requirementId) return fail(`Test ${testId} has no device requirement to assign.`);
|
|
507
|
-
const sim = await resolveSimulator(ctx.simWorldId, simulator);
|
|
508
552
|
const run = await sdk().testRuns.create({
|
|
509
553
|
scenarioId: testId,
|
|
510
554
|
simWorldId: ctx.simWorldId,
|
|
@@ -532,6 +576,7 @@ function registerTestRunTools(server) {
|
|
|
532
576
|
server.registerTool(
|
|
533
577
|
"get_test_run",
|
|
534
578
|
{
|
|
579
|
+
annotations: { readOnlyHint: true },
|
|
535
580
|
title: "Get test run",
|
|
536
581
|
description: "Get a test run's status by id.",
|
|
537
582
|
inputSchema: {
|
|
@@ -548,6 +593,7 @@ function registerTestRunTools(server) {
|
|
|
548
593
|
server.registerTool(
|
|
549
594
|
"list_test_runs",
|
|
550
595
|
{
|
|
596
|
+
annotations: { readOnlyHint: true },
|
|
551
597
|
title: "List test runs",
|
|
552
598
|
description: "List recent test runs in the active project's sim world.",
|
|
553
599
|
inputSchema: {
|
|
@@ -567,6 +613,7 @@ function registerTestRunTools(server) {
|
|
|
567
613
|
server.registerTool(
|
|
568
614
|
"stop_test_run",
|
|
569
615
|
{
|
|
616
|
+
annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
|
|
570
617
|
title: "Stop test run",
|
|
571
618
|
description: "Shut down (stop) a running or scheduled test run by id.",
|
|
572
619
|
inputSchema: {
|
|
@@ -586,6 +633,265 @@ function registerTestRunTools(server) {
|
|
|
586
633
|
);
|
|
587
634
|
}
|
|
588
635
|
|
|
636
|
+
// src/tools/support.ts
|
|
637
|
+
import { z as z7 } from "zod";
|
|
638
|
+
|
|
639
|
+
// src/logs-format.ts
|
|
640
|
+
var DEFAULT_LOGS_LAST = "1h";
|
|
641
|
+
var DEFAULT_LOGS_LIMIT = 200;
|
|
642
|
+
var MAX_LOGS_LIMIT = 1e3;
|
|
643
|
+
var PAYLOAD_MAX_CHARS = 500;
|
|
644
|
+
var UNIT_MS = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
645
|
+
function parseDuration(value) {
|
|
646
|
+
const match = value.trim().match(/^(\d+)\s*([smhd])$/i);
|
|
647
|
+
if (!match) throw new Error(`Invalid duration "${value}". Use a number and a unit: 30m, 6h, 2d.`);
|
|
648
|
+
return Number(match[1]) * UNIT_MS[match[2].toLowerCase()];
|
|
649
|
+
}
|
|
650
|
+
function parseInstant(value, name) {
|
|
651
|
+
const date = new Date(value);
|
|
652
|
+
if (Number.isNaN(date.getTime())) throw new Error(`Invalid ${name} "${value}". Use an ISO date-time.`);
|
|
653
|
+
return date;
|
|
654
|
+
}
|
|
655
|
+
function resolveWindow(input, now = /* @__PURE__ */ new Date()) {
|
|
656
|
+
const to = input.to ? parseInstant(input.to, "to") : now;
|
|
657
|
+
const from = input.from ? parseInstant(input.from, "from") : new Date(to.getTime() - parseDuration(input.last ?? DEFAULT_LOGS_LAST));
|
|
658
|
+
if (from.getTime() > to.getTime()) throw new Error(`"from" (${from.toISOString()}) is after "to" (${to.toISOString()}).`);
|
|
659
|
+
return { from, to };
|
|
660
|
+
}
|
|
661
|
+
function tryJson(text) {
|
|
662
|
+
if (text == null) return void 0;
|
|
663
|
+
try {
|
|
664
|
+
return JSON.parse(text);
|
|
665
|
+
} catch {
|
|
666
|
+
return void 0;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function stringify(value) {
|
|
670
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
671
|
+
}
|
|
672
|
+
function truncate(text, max = PAYLOAD_MAX_CHARS) {
|
|
673
|
+
return text.length > max ? `${text.slice(0, max)}\u2026(+${text.length - max} chars)` : text;
|
|
674
|
+
}
|
|
675
|
+
function direction(record, envelope) {
|
|
676
|
+
const dir = envelope?.payload?.direction;
|
|
677
|
+
if (dir === "client_to_server") return "CP\u2192CSMS";
|
|
678
|
+
if (dir === "server_to_client") return "CSMS\u2192CP";
|
|
679
|
+
if (record.sender || record.receiver) return `${record.sender ?? "?"}\u2192${record.receiver ?? "?"}`;
|
|
680
|
+
return "-";
|
|
681
|
+
}
|
|
682
|
+
function toLogLines(records) {
|
|
683
|
+
const parsed = records.map((r) => ({ record: r, message: tryJson(r.content), envelope: tryJson(r.rawContent) }));
|
|
684
|
+
const callActions = /* @__PURE__ */ new Map();
|
|
685
|
+
for (const { message } of parsed) {
|
|
686
|
+
if (Array.isArray(message) && message[0] === 2) callActions.set(String(message[1]), String(message[2]));
|
|
687
|
+
}
|
|
688
|
+
return parsed.map(({ record, message, envelope }) => {
|
|
689
|
+
let action;
|
|
690
|
+
let payload;
|
|
691
|
+
if (record.protocol === "OCPP" && Array.isArray(message) && [2, 3, 4].includes(message[0])) {
|
|
692
|
+
const call = callActions.get(String(message[1]));
|
|
693
|
+
if (message[0] === 2) {
|
|
694
|
+
action = String(message[2]);
|
|
695
|
+
payload = stringify(message[3] ?? {});
|
|
696
|
+
} else if (message[0] === 3) {
|
|
697
|
+
action = `${call ?? "?"}.result`;
|
|
698
|
+
payload = stringify(message[2] ?? {});
|
|
699
|
+
} else {
|
|
700
|
+
action = `${call ?? "?"}.error`;
|
|
701
|
+
payload = [message[2], message[3], message[4] ? stringify(message[4]) : ""].filter(Boolean).join(" ");
|
|
702
|
+
}
|
|
703
|
+
} else {
|
|
704
|
+
action = String(envelope?.type ?? record.protocol ?? "log");
|
|
705
|
+
payload = record.content ?? "";
|
|
706
|
+
}
|
|
707
|
+
if (record.error) payload = `${payload} [error: ${record.error}]`;
|
|
708
|
+
return {
|
|
709
|
+
time: record.timestamp ?? "?",
|
|
710
|
+
direction: direction(record, envelope),
|
|
711
|
+
action,
|
|
712
|
+
payload: truncate(payload.replace(/\s+/g, " ").trim())
|
|
713
|
+
};
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function matchesAction(line, action) {
|
|
717
|
+
const base = line.action.replace(/\.(result|error)$/, "").toLowerCase();
|
|
718
|
+
return base === action.trim().toLowerCase();
|
|
719
|
+
}
|
|
720
|
+
function formatLine(line) {
|
|
721
|
+
return `${line.time} ${line.direction} ${line.action} ${line.payload}`;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/tools/support.ts
|
|
725
|
+
var READ_ONLY = { readOnlyHint: true, openWorldHint: true };
|
|
726
|
+
var SECRET_KEY = /authorizationkey|password|secret|privatekey|passphrase/i;
|
|
727
|
+
function maskSecretItems(items) {
|
|
728
|
+
return (items ?? []).map(
|
|
729
|
+
(item) => SECRET_KEY.test(item.key ?? item.variableName ?? "") && item.value ? { ...item, value: "***" } : item
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
function summarizeSimulator(sim) {
|
|
733
|
+
const model = sim.chargerModel;
|
|
734
|
+
const config = sim.chargerConfig;
|
|
735
|
+
const connectors = (model?.connectorModels ?? sim.chargerConnectors ?? []).map((c) => `#${c.number ?? c.connectorId} ${c.type} (cable ${c.cableFixed ? "fixed" : "flexible"})`).join(", ");
|
|
736
|
+
const lines = [
|
|
737
|
+
`Simulator ${sim.baseName} (id: ${sim.id}), ${sim.protocol}; network ${sim.networkStatus}, power ${sim.launchedStatus}, OCPP status ${sim.chargerStatus}${sim.emergency ? ", EMERGENCY" : ""}.`,
|
|
738
|
+
`Model: ${model?.name ?? "?"} by ${model?.deviceManufacturer?.name ?? "?"}` + (connectors ? `; connectors: ${connectors}.` : "."),
|
|
739
|
+
`Behavior: ${config?.behavior ?? "?"}; remote templates ${config?.useRemoteTemplates ? "on" : "off"}; supported commands: ${(config?.supportedCommands ?? []).join(", ") || "\u2014"}.`,
|
|
740
|
+
`OCPP configuration keys: ${sim.chargerOcppConfigItems?.length ?? 0}.`
|
|
741
|
+
];
|
|
742
|
+
if (sim.lastRun) {
|
|
743
|
+
lines.push(
|
|
744
|
+
`Last run ${sim.lastRun.id}: ${sim.lastRun.status}` + (sim.lastRun.failReason ? ` \u2014 ${sim.lastRun.failReason}` : "") + "."
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
return lines.join("\n");
|
|
748
|
+
}
|
|
749
|
+
var RUN_SIMULATORS_PAGE_SIZE = 20;
|
|
750
|
+
function simulatorName(rc) {
|
|
751
|
+
return rc.charger?.baseName ?? rc.device?.serialNumber ?? rc.id;
|
|
752
|
+
}
|
|
753
|
+
function findRunSimulator(records, simulator) {
|
|
754
|
+
const needle = simulator.trim().toLowerCase();
|
|
755
|
+
return records.find((rc) => rc.id === simulator.trim()) ?? records.find((rc) => rc.charger?.id === simulator.trim() || rc.device?.id === simulator.trim()) ?? records.find(
|
|
756
|
+
(rc) => rc.charger?.baseName?.toLowerCase() === needle || rc.device?.serialNumber?.toLowerCase() === needle
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
function summarizeRun(run, simulators, page, steps) {
|
|
760
|
+
const records = (simulators?.records ?? []).filter(Boolean);
|
|
761
|
+
const lines = [
|
|
762
|
+
`Test run ${run.id} ("${run.scenario?.name ?? "?"}"): ${run.status}` + (run.failReason ? ` \u2014 ${run.failReason}` : "") + `. Started ${run.realStartTimestamp ?? run.startTimestamp ?? "\u2014"}, stopped ${run.realStopTimestamp ?? "\u2014"}.`,
|
|
763
|
+
pageSummary("simulator(s)", records.length, simulators?.pageInfo ?? { page })
|
|
764
|
+
];
|
|
765
|
+
for (const rc of records) {
|
|
766
|
+
lines.push(`- ${simulatorName(rc)} (simulator ${rc.charger?.id ?? rc.device?.id ?? "?"}, run entry ${rc.id}): ${rc.status}`);
|
|
767
|
+
}
|
|
768
|
+
if (steps) {
|
|
769
|
+
lines.push("", `Steps of ${simulatorName(steps)}:`);
|
|
770
|
+
for (const step of steps.chargerActions ?? []) {
|
|
771
|
+
lines.push(
|
|
772
|
+
` step ${step.order} ${step.scenarioAction?.action?.name ?? "?"}: ${step.status}` + (step.failReason ? ` \u2014 ${step.failReason}` : "")
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
} else if (records.length > 1 || simulators?.pageInfo?.hasNextPage) {
|
|
776
|
+
lines.push("", "Pass `simulator` with one of the names or ids above to see its steps.");
|
|
777
|
+
}
|
|
778
|
+
return lines.join("\n");
|
|
779
|
+
}
|
|
780
|
+
function registerSupportTools(server) {
|
|
781
|
+
const projectArg = z7.string().optional().describe("Project name or id (defaults to active project; a portal link sets its own)");
|
|
782
|
+
server.registerTool(
|
|
783
|
+
"get_simulator_config",
|
|
784
|
+
{
|
|
785
|
+
title: "Get simulator configuration",
|
|
786
|
+
description: "Read-only. Everything that explains why a simulator behaves the way it does: its OCPP configuration keys (e.g. FreevendEnabled, HeartbeatInterval), behavior settings (vendor behavior, remote start/stop templates, supported commands, timeouts), model and connector types (fixed or flexible cable), live connectors, authorizations, charging profiles, transactions, reservations, and the last test run with its fail reason. Credential values are masked.",
|
|
787
|
+
inputSchema: { simulator: z7.string().describe(SIMULATOR_ARG_DESCRIPTION), project: projectArg },
|
|
788
|
+
annotations: READ_ONLY
|
|
789
|
+
},
|
|
790
|
+
async ({ simulator, project }) => guard(async () => {
|
|
791
|
+
const { sim } = await resolveSimulatorTarget(simulator, project);
|
|
792
|
+
const details = await sdk().simulators.getDetails(sim.id);
|
|
793
|
+
if (!details) return ok(`No simulator found with id ${sim.id}.`);
|
|
794
|
+
const items = await sdk().simulators.getOcppConfigItems(sim.id);
|
|
795
|
+
const safe = { ...details, chargerOcppConfigItems: maskSecretItems(items) };
|
|
796
|
+
return ok(summarizeSimulator(safe), safe);
|
|
797
|
+
})
|
|
798
|
+
);
|
|
799
|
+
server.registerTool(
|
|
800
|
+
"get_simulator_logs",
|
|
801
|
+
{
|
|
802
|
+
title: "Get simulator logs",
|
|
803
|
+
description: "Read-only. The simulator's OCPP message log for a time window, one line per message: `time direction action payload` (payload cut at ~500 chars). Newest messages are kept when the limit cuts the window; lines are printed oldest first. Use `action` to keep one OCPP action, e.g. StatusNotification (its results and errors are kept too).",
|
|
804
|
+
inputSchema: {
|
|
805
|
+
simulator: z7.string().describe(SIMULATOR_ARG_DESCRIPTION),
|
|
806
|
+
from: z7.string().optional().describe("Window start, ISO date-time (wins over `last`)"),
|
|
807
|
+
to: z7.string().optional().describe("Window end, ISO date-time (default now)"),
|
|
808
|
+
last: z7.string().optional().describe(`Window length back from \`to\`, e.g. 30m, 6h, 2d (default ${DEFAULT_LOGS_LAST})`),
|
|
809
|
+
limit: z7.number().int().min(1).max(MAX_LOGS_LIMIT).optional().describe(`Max messages to show (default ${DEFAULT_LOGS_LIMIT}, max ${MAX_LOGS_LIMIT})`),
|
|
810
|
+
action: z7.string().optional().describe("Keep only this OCPP action, e.g. StatusNotification"),
|
|
811
|
+
project: projectArg
|
|
812
|
+
},
|
|
813
|
+
annotations: READ_ONLY
|
|
814
|
+
},
|
|
815
|
+
async ({ simulator, from, to, last, limit, action, project }) => guard(async () => {
|
|
816
|
+
const window = resolveWindow({ from, to, last });
|
|
817
|
+
const { sim } = await resolveSimulatorTarget(simulator, project);
|
|
818
|
+
const shown = Math.min(limit ?? DEFAULT_LOGS_LIMIT, MAX_LOGS_LIMIT);
|
|
819
|
+
const result = await sdk().logs.list({
|
|
820
|
+
simulatorId: sim.id,
|
|
821
|
+
from: window.from,
|
|
822
|
+
to: window.to,
|
|
823
|
+
limit: action ? MAX_LOGS_LIMIT : shown
|
|
824
|
+
});
|
|
825
|
+
const all = toLogLines(result.records);
|
|
826
|
+
const matched = action ? all.filter((line) => matchesAction(line, action)) : all;
|
|
827
|
+
const lines = matched.slice(0, shown).reverse();
|
|
828
|
+
const truncated = matched.length > shown || Boolean(result.pageInfo?.hasNextPage);
|
|
829
|
+
const head = `${sim.baseName} (id: ${sim.id}) ${window.from.toISOString()} \u2026 ${window.to.toISOString()}: ${lines.length} message(s) shown` + (action ? ` matching "${action}" of ${all.length} scanned` : "") + (result.pageInfo?.totalCount != null ? `; ${result.pageInfo.totalCount} in window` : "") + `; truncated: ${truncated ? "yes \u2014 narrow the window or raise the limit" : "no"}.`;
|
|
830
|
+
return ok([head, "", ...lines.map(formatLine)].join("\n"));
|
|
831
|
+
})
|
|
832
|
+
);
|
|
833
|
+
server.registerTool(
|
|
834
|
+
"get_test_run_details",
|
|
835
|
+
{
|
|
836
|
+
title: "Get test run details",
|
|
837
|
+
description: `Read-only. A test run's status and fail reason, plus one page of its simulators or devices with their status (${RUN_SIMULATORS_PAGE_SIZE} per page). Steps \u2014 status, fail reason, expected / actual result \u2014 are shown for one simulator at a time: pass \`simulator\` with a name or id from the page. A run with a single simulator shows its steps right away.`,
|
|
838
|
+
inputSchema: {
|
|
839
|
+
runId: z7.string().describe("Test run id"),
|
|
840
|
+
page: z7.number().int().min(1).optional().describe("Page of the run's simulators, starting at 1 (default 1)"),
|
|
841
|
+
simulator: z7.string().optional().describe("Show the steps of this simulator from the page: its name, simulator id or run entry id")
|
|
842
|
+
},
|
|
843
|
+
annotations: READ_ONLY
|
|
844
|
+
},
|
|
845
|
+
async ({ runId, page, simulator }) => guard(async () => {
|
|
846
|
+
const run = await sdk().testRuns.getDetails(runId);
|
|
847
|
+
if (!run) return ok(`No test run found with id ${runId}.`);
|
|
848
|
+
const current = page ?? 1;
|
|
849
|
+
const simulators = await sdk().testRuns.listSimulators(runId, {
|
|
850
|
+
pagination: { page: current, pageSize: RUN_SIMULATORS_PAGE_SIZE }
|
|
851
|
+
});
|
|
852
|
+
const records = (simulators?.records ?? []).filter(Boolean);
|
|
853
|
+
let target;
|
|
854
|
+
if (simulator) {
|
|
855
|
+
target = findRunSimulator(records, simulator);
|
|
856
|
+
if (!target) {
|
|
857
|
+
return fail(
|
|
858
|
+
`No simulator "${simulator}" on page ${current} of test run ${runId}. Pass a name or id listed on this page, or another page.`
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
} else if (simulators?.pageInfo?.totalCount === 1 || current === 1 && records.length === 1 && !simulators?.pageInfo?.hasNextPage) {
|
|
862
|
+
target = records[0];
|
|
863
|
+
}
|
|
864
|
+
const ref = target?.charger?.id ? { chargerId: target.charger.id } : target?.device?.id ? { deviceId: target.device.id } : null;
|
|
865
|
+
const steps = ref ? await sdk().testRuns.getSimulatorSteps(runId, ref) : null;
|
|
866
|
+
return ok(summarizeRun(run, simulators, current, steps), { run, simulators, steps });
|
|
867
|
+
})
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// src/tools/index.ts
|
|
872
|
+
var READONLY_ENV = "TIMETICK_MCP_READONLY";
|
|
873
|
+
function isReadOnlyMode(env = process.env) {
|
|
874
|
+
const value = env[READONLY_ENV]?.trim().toLowerCase();
|
|
875
|
+
return value === "1" || value === "true";
|
|
876
|
+
}
|
|
877
|
+
function readOnlyView(server) {
|
|
878
|
+
return new Proxy(server, {
|
|
879
|
+
get(target, prop, receiver) {
|
|
880
|
+
if (prop !== "registerTool") return Reflect.get(target, prop, receiver);
|
|
881
|
+
return (name, config, cb) => config.annotations?.readOnlyHint === true ? target.registerTool(name, config, cb) : void 0;
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
function registerTools(server, options) {
|
|
886
|
+
const target = options.readOnly ? readOnlyView(server) : server;
|
|
887
|
+
registerContextTools(target);
|
|
888
|
+
registerDataTools(target);
|
|
889
|
+
registerSimulatorTools(target);
|
|
890
|
+
registerTestTools(target);
|
|
891
|
+
registerTestRunTools(target);
|
|
892
|
+
registerSupportTools(target);
|
|
893
|
+
}
|
|
894
|
+
|
|
589
895
|
// src/index.ts
|
|
590
896
|
async function main() {
|
|
591
897
|
if (!process.env.TIMETICK_API_TOKEN) {
|
|
@@ -594,15 +900,12 @@ async function main() {
|
|
|
594
900
|
);
|
|
595
901
|
process.exit(1);
|
|
596
902
|
}
|
|
597
|
-
const server = new McpServer({ name: "timetick", version: "0.1
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
registerSimulatorTools(server);
|
|
601
|
-
registerTestTools(server);
|
|
602
|
-
registerTestRunTools(server);
|
|
903
|
+
const server = new McpServer({ name: "timetick", version: "0.2.1" });
|
|
904
|
+
const readOnly = isReadOnlyMode();
|
|
905
|
+
registerTools(server, { readOnly });
|
|
603
906
|
const transport = new StdioServerTransport();
|
|
604
907
|
await server.connect(transport);
|
|
605
|
-
console.error(
|
|
908
|
+
console.error(`Timetick MCP server running on stdio${readOnly ? " (read-only)" : ""}`);
|
|
606
909
|
}
|
|
607
910
|
main().catch((error) => {
|
|
608
911
|
console.error("Fatal error starting Timetick MCP server:", error);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/tools/context.ts","../src/sdk.ts","../src/context.ts","../src/result.ts","../src/tools/data.ts","../src/resolve.ts","../src/pagination.ts","../src/tools/simulators.ts","../src/tools/tests.ts","../src/tools/test-runs.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { registerContextTools } from \"./tools/context.js\";\nimport { registerDataTools } from \"./tools/data.js\";\nimport { registerSimulatorTools } from \"./tools/simulators.js\";\nimport { registerTestTools } from \"./tools/tests.js\";\nimport { registerTestRunTools } from \"./tools/test-runs.js\";\n\nasync function main() {\n if (!process.env.TIMETICK_API_TOKEN) {\n console.error(\n \"TIMETICK_API_TOKEN is not set. Generate an API key in the Timetick portal \" +\n \"(Account → API keys) and expose it to the MCP server as TIMETICK_API_TOKEN.\",\n );\n process.exit(1);\n }\n\n const server = new McpServer({ name: \"timetick\", version: \"0.1.0\" });\n\n registerContextTools(server);\n registerDataTools(server);\n registerSimulatorTools(server);\n registerTestTools(server);\n registerTestRunTools(server);\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(\"Timetick MCP server running on stdio\");\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error starting Timetick MCP server:\", error);\n process.exit(1);\n});\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getContext, useProject, peekContext } from \"../context.js\";\nimport { ok, guard } from \"../result.js\";\n\nexport function registerContextTools(server: McpServer) {\n server.registerTool(\n \"get_context\",\n {\n title: \"Get active context\",\n description:\n \"Show the project and sim world the MCP server is currently operating on. \" +\n \"If no project is selected yet and you have only one project, it is auto-selected.\",\n inputSchema: {},\n },\n async () =>\n guard(async () => {\n const ctx = peekContext() ?? (await getContext());\n return ok(\n `Active project: ${ctx.projectName} (id: ${ctx.projectId}); sim world: ${ctx.simWorldId} [${ctx.source}]`,\n ctx,\n );\n }),\n );\n\n server.registerTool(\n \"use_project\",\n {\n title: \"Select project\",\n description:\n \"Switch the active project by name or id. Only needed if you have more than one project. \" +\n \"Caches the project's sim world for subsequent tools.\",\n inputSchema: {\n project: z.string().describe(\"Project name or id to make active\"),\n },\n },\n async ({ project }) =>\n guard(async () => {\n const ctx = await useProject({ project });\n return ok(`Active project is now ${ctx.projectName} (id: ${ctx.projectId}).`, ctx);\n }),\n );\n}\n","import { createClient, type TimetickClient } from \"@timetick/sdk\";\n\nlet client: TimetickClient | null = null;\n\n/** Lazily-created singleton Timetick SDK client, authenticated from the environment. */\nexport function sdk(): TimetickClient {\n if (client) return client;\n\n const apiKey = process.env.TIMETICK_API_TOKEN;\n if (!apiKey) {\n throw new Error(\n \"TIMETICK_API_TOKEN is not set. Generate an API key in the Timetick portal \" +\n \"(Account → API keys) and expose it to the MCP server as TIMETICK_API_TOKEN.\",\n );\n }\n\n client = createClient({ apiKey, endpoint: process.env.TIMETICK_API_URL });\n return client;\n}\n","import { sdk } from \"./sdk.js\";\n\nexport interface Context {\n projectId: string;\n projectName: string;\n simWorldId: string;\n /** Scope id used by hardware/device queries — distinct from simWorldId. */\n deviceScopeId: string;\n /** How the project was chosen — surfaced to the user for transparency. */\n source: \"single-project\" | \"explicit\";\n}\n\n/** Thrown when the project/sim world can't be resolved without user input. */\nexport class ContextError extends Error {}\n\nlet cached: Context | null = null;\n\n/** Resolves a project's sim world (one sim world per project today). */\nasync function buildContext(\n projectId: string,\n projectName: string,\n source: Context[\"source\"],\n): Promise<Context> {\n const worlds = await sdk().simWorlds.list(projectId);\n const world = worlds?.[0];\n if (!world?.id) {\n throw new ContextError(`Project \"${projectName}\" has no sim world to operate on.`);\n }\n return {\n projectId,\n projectName,\n simWorldId: world.id,\n deviceScopeId: world.deviceScopeId ?? world.id,\n source,\n };\n}\n\nconst PROJECT_LIST_LIMIT = 15;\n\ntype ProjectSummary = { id?: string | null; name?: string | null } | null | undefined;\n\nfunction formatProjects(projects: readonly ProjectSummary[] | null | undefined): string {\n const all = projects ?? [];\n const lines = all\n .slice(0, PROJECT_LIST_LIMIT)\n .map((p) => ` - ${p?.name} (id: ${p?.id})`);\n if (all.length > PROJECT_LIST_LIMIT) {\n lines.push(` …and ${all.length - PROJECT_LIST_LIMIT} more — call list_projects to see them all.`);\n }\n return lines.join(\"\\n\");\n}\n\nasync function findProject(project: string): Promise<{ id: string; name: string }> {\n const projects = await sdk().projects.list();\n const needle = project.toLowerCase();\n const match = projects?.find(\n (p) => p?.id === project || p?.name?.toLowerCase() === needle,\n );\n if (!match?.id) {\n throw new ContextError(\n `No project matching \"${project}\". Available:\\n${formatProjects(projects)}`,\n );\n }\n return { id: match.id, name: match.name ?? \"(unnamed)\" };\n}\n\n/**\n * Returns the active context, auto-selecting the project when there is only one.\n * Throws ContextError (with the project list) when the choice is ambiguous.\n */\nexport async function getContext(): Promise<Context> {\n if (cached) return cached;\n\n const projects = await sdk().projects.list();\n if (!projects || projects.length === 0) {\n throw new ContextError(\"No projects are available for this API key.\");\n }\n if (projects.length > 1) {\n throw new ContextError(\n `You have ${projects.length} projects. Call \\`use_project\\` with a project name or id ` +\n `first:\\n${formatProjects(projects)}`,\n );\n }\n\n const only = projects[0]!;\n cached = await buildContext(only.id!, only.name ?? \"(unnamed)\", \"single-project\");\n return cached;\n}\n\n/** Explicitly switches the active project by name or id, and caches its sim world. */\nexport async function useProject(input: { project: string }): Promise<Context> {\n const match = await findProject(input.project);\n cached = await buildContext(match.id, match.name, \"explicit\");\n return cached;\n}\n\nexport async function lookupProject(project: string): Promise<Context> {\n const match = await findProject(project);\n return buildContext(match.id, match.name, \"explicit\");\n}\n\n/** Returns the cached context without resolving, if any. */\nexport function peekContext(): Context | null {\n return cached;\n}\n","import { TimetickError } from \"@timetick/sdk\";\n\ntype ToolResult = {\n content: { type: \"text\"; text: string }[];\n isError?: boolean;\n};\n\n/** Wraps a value into an MCP text result, pretty-printing objects as JSON. */\nexport function ok(text: string, data?: unknown): ToolResult {\n const body = data === undefined ? text : `${text}\\n\\n${JSON.stringify(data, null, 2)}`;\n return { content: [{ type: \"text\", text: body }] };\n}\n\nexport function fail(message: string): ToolResult {\n return { content: [{ type: \"text\", text: message }], isError: true };\n}\n\n/** Runs a tool handler, normalizing SDK/unknown errors into an isError result. */\nexport async function guard(fn: () => Promise<ToolResult>): Promise<ToolResult> {\n try {\n return await fn();\n } catch (err) {\n if (err instanceof TimetickError) return fail(`Timetick API error: ${err.message}`);\n return fail(err instanceof Error ? err.message : String(err));\n }\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveSimulator } from \"../resolve.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, guard } from \"../result.js\";\n\nconst protocolEnum = z.enum([\"OCPP_1_6\", \"OCPP_2_0_1\"]);\n\nfunction summarizeArgs(params: unknown): Record<string, string> | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n const summary: Record<string, string> = {};\n for (const [name, spec] of Object.entries(params as Record<string, unknown>)) {\n if (!spec || typeof spec !== \"object\") continue;\n const { type, allowNull, defaultValue, visible } = spec as Record<string, unknown>;\n if (visible === false) continue;\n const parts = [String(type ?? \"unknown\"), allowNull === false ? \"required\" : \"optional\"];\n if (defaultValue !== undefined) parts.push(`default ${JSON.stringify(defaultValue)}`);\n summary[name] = parts.join(\", \");\n }\n return Object.keys(summary).length > 0 ? summary : undefined;\n}\n\nexport function registerDataTools(server: McpServer) {\n server.registerTool(\n \"list_projects\",\n {\n title: \"List projects\",\n description: \"List all projects available to your API key.\",\n inputSchema: {},\n },\n async () =>\n guard(async () => {\n const projects = await sdk().projects.list();\n return ok(`Found ${projects?.length ?? 0} project(s).`, projects);\n }),\n );\n\n server.registerTool(\n \"list_simulators\",\n {\n title: \"List simulators\",\n description:\n \"List simulators (virtual chargers) in the active project's sim world. \" +\n \"Optionally filter by name search or protocol.\",\n inputSchema: {\n search: z.string().optional().describe(\"Filter by simulator base name\"),\n protocol: protocolEnum.optional(),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ search, protocol, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().simulators.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: protocol ? { protocol } : undefined,\n pagination: pagination(page, pageSize),\n });\n return ok(\n pageSummary(\"simulator(s)\", result?.records?.length ?? 0, result?.pageInfo),\n result,\n );\n }),\n );\n\n server.registerTool(\n \"get_simulator\",\n {\n title: \"Get simulator\",\n description:\n \"Get a simulator's details and live status (network status, launched/power status, connectors) \" +\n \"by id or base name.\",\n inputSchema: {\n simulator: z.string().describe(\"Simulator id or base name\"),\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const resolved = await resolveSimulator(ctx.simWorldId, simulator);\n const details = await sdk().simulators.get(resolved.id);\n return ok(`Simulator ${resolved.baseName} (id: ${resolved.id}).`, details);\n }),\n );\n\n server.registerTool(\n \"list_hardware\",\n {\n title: \"List hardware\",\n description: \"List physical OCPP hardware devices in the active project's sim world.\",\n inputSchema: {\n search: z.string().optional().describe(\"Filter by serial number / model\"),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().hardware.list({\n deviceScopeId: ctx.deviceScopeId,\n searchValue: search,\n pagination: pagination(page, pageSize),\n });\n return ok(\n pageSummary(\"hardware device(s)\", result?.records?.length ?? 0, result?.pageInfo),\n result,\n );\n }),\n );\n\n server.registerTool(\n \"list_actions\",\n {\n title: \"List actions (test steps)\",\n description:\n \"List available actions (steps) you can use to build a test — e.g. 'Power On Charger', \" +\n \"'Plug In Connector', 'Charge a Vehicle'. Filter by protocol. Each action lists its \" +\n \"arguments: the name, whether it is required (allowNull false), and any default.\",\n inputSchema: {\n protocol: protocolEnum.optional(),\n search: z.string().optional().describe(\"Filter by action name\"),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ protocol, search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().actions.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: { isSystem: true, deviceType: \"CHARGER\", ...(protocol ? { protocol } : {}) },\n pagination: pagination(page, pageSize, 100),\n });\n const actions = (result?.records ?? []).map((a) => ({\n name: a?.name,\n description: a?.description ?? undefined,\n args: summarizeArgs(a?.params),\n }));\n return ok(pageSummary(\"action(s)\", actions.length, result?.pageInfo), actions);\n }),\n );\n}\n","import { sdk } from \"./sdk.js\";\nimport { getContext, lookupProject, type Context } from \"./context.js\";\n\n/** Resolves the sim world to operate in: explicit project arg wins, else session context. */\nexport async function resolveSimWorld(project?: string): Promise<Context> {\n if (project) return lookupProject(project);\n return getContext();\n}\n\nexport interface ResolvedSimulator {\n id: string;\n baseName: string;\n protocol: string;\n}\n\n/** Resolves a simulator by id or by (case-insensitive) base name within a sim world. */\nexport async function resolveSimulator(\n simWorldId: string,\n simulator: string,\n): Promise<ResolvedSimulator> {\n const needle = simulator.toLowerCase();\n const page = await sdk().simulators.list({ simWorldId, searchValue: simulator });\n const records = page?.records ?? [];\n\n const exact =\n records.find((r) => r?.id === simulator) ??\n records.find((r) => r?.baseName?.toLowerCase() === needle) ??\n (records.length === 1 ? records[0] : undefined);\n\n if (exact?.id) {\n return { id: exact.id, baseName: exact.baseName ?? \"\", protocol: String(exact.protocol) };\n }\n\n // Fall back to treating the input as a raw id.\n const byId = await sdk().simulators.get(simulator).catch(() => null);\n if (byId?.id) {\n return { id: byId.id, baseName: byId.baseName ?? \"\", protocol: String(byId.protocol) };\n }\n\n const candidates = records.map((r) => ` - ${r?.baseName} (id: ${r?.id})`).join(\"\\n\");\n throw new Error(\n `No simulator matching \"${simulator}\".` +\n (candidates ? `\\nCandidates:\\n${candidates}` : \" No simulators found in this sim world.\"),\n );\n}\n\n/** Finds a system action by exact name for a given protocol; returns its id. */\nexport async function resolveActionId(\n simWorldId: string,\n protocol: string,\n actionName: string,\n): Promise<string> {\n const page = await sdk().actions.list({\n simWorldId,\n searchValue: actionName,\n filters: { isSystem: true, protocol: protocol as any, deviceType: \"CHARGER\" },\n pagination: { page: 1, pageSize: 50 },\n });\n const records = page?.records ?? [];\n const needle = actionName.toLowerCase();\n const match =\n records.find((a) => a?.name?.toLowerCase() === needle) ??\n records.find((a) => a?.name?.toLowerCase().includes(needle));\n\n if (!match?.id) {\n const available = records.map((a) => ` - ${a?.name}`).join(\"\\n\");\n throw new Error(\n `Action \"${actionName}\" not found for ${protocol}.` +\n (available ? `\\nAvailable system actions matching your search:\\n${available}` : \"\"),\n );\n }\n return match.id;\n}\n","import { z } from \"zod\";\n\nexport const DEFAULT_PAGE_SIZE = 20;\n\nexport const paginationArgs = {\n page: z.number().int().min(1).optional().describe(\"Page number, starting at 1 (default 1)\"),\n pageSize: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(`Results per page (default ${DEFAULT_PAGE_SIZE})`),\n};\n\nexport function pagination(page?: number, pageSize?: number, defaultPageSize = DEFAULT_PAGE_SIZE) {\n return { page: page ?? 1, pageSize: pageSize ?? defaultPageSize };\n}\n\ninterface PageInfoLike {\n page?: number | null;\n pageSize?: number | null;\n hasNextPage?: boolean | null;\n totalCount?: number | null;\n}\n\nexport function pageSummary(noun: string, count: number, pageInfo?: PageInfoLike | null): string {\n const total = pageInfo?.totalCount;\n const head =\n total != null && total !== count\n ? `Showing ${count} of ${total} ${noun} (page ${pageInfo?.page ?? 1}).`\n : `Found ${count} ${noun}.`;\n return pageInfo?.hasNextPage ? `${head} More results available — request the next page.` : head;\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveSimulator, resolveActionId } from \"../resolve.js\";\nimport { ok, guard } from \"../result.js\";\n\n/** Runs a single named action against a simulator via the SDK's runAction. */\nasync function runOnSimulator(\n project: string | undefined,\n simulator: string,\n actionName: string,\n args: { key: string; value: string }[] = [],\n) {\n const ctx = await resolveSimWorld(project);\n const sim = await resolveSimulator(ctx.simWorldId, simulator);\n const actionId = await resolveActionId(ctx.simWorldId, sim.protocol, actionName);\n\n const status = await sdk().testRuns.runAction({\n chargerId: sim.id,\n action: { requirementKey: \"1\", stream: 1, order: 1, actionId, args },\n });\n return { sim, actionName, status };\n}\n\nexport function registerSimulatorTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"power_on_simulator\",\n {\n title: \"Power on simulator\",\n description: \"Power on a simulator (boots it and connects it to the OCPP server).\",\n inputSchema: {\n simulator: z.string().describe(\"Simulator id or base name\"),\n project: projectArg,\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, \"Power On Charger\");\n return ok(`Powered on ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n\n server.registerTool(\n \"power_off_simulator\",\n {\n title: \"Power off simulator\",\n description: \"Power off a simulator.\",\n inputSchema: {\n simulator: z.string().describe(\"Simulator id or base name\"),\n project: projectArg,\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, \"Power Off Charger\");\n return ok(`Powered off ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n\n server.registerTool(\n \"run_simulator_action\",\n {\n title: \"Run simulator action\",\n description:\n \"Run a single named action against a simulator — e.g. 'Reset Charger', 'Plug In Connector', \" +\n \"'Plug Out Connector'. Use list_actions to discover names and required args. \" +\n \"Args are passed as key/value pairs (e.g. connectorId=1).\",\n inputSchema: {\n simulator: z.string().describe(\"Simulator id or base name\"),\n actionName: z.string().describe(\"Exact action name, e.g. 'Reset Charger'\"),\n args: z\n .array(z.object({ key: z.string(), value: z.string() }))\n .optional()\n .describe(\"Action arguments as key/value pairs\"),\n project: projectArg,\n },\n },\n async ({ simulator, actionName, args, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, actionName, args ?? []);\n return ok(`Ran \"${actionName}\" on ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveActionId } from \"../resolve.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, guard } from \"../result.js\";\n\nconst protocolEnum = z.enum([\"OCPP_1_6\", \"OCPP_2_0_1\"]);\n\nexport function registerTestTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"list_tests\",\n {\n title: \"List tests\",\n description: \"List tests (scenarios) in the active project's sim world.\",\n inputSchema: {\n protocol: protocolEnum.optional(),\n search: z.string().optional().describe(\"Filter by test name\"),\n ...paginationArgs,\n project: projectArg,\n },\n },\n async ({ protocol, search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().tests.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: protocol ? { protocol } : undefined,\n pagination: pagination(page, pageSize),\n });\n return ok(pageSummary(\"test(s)\", result?.records?.length ?? 0, result?.pageInfo), result);\n }),\n );\n\n server.registerTool(\n \"get_test\",\n {\n title: \"Get test\",\n description: \"Get a test by id, including its device requirements.\",\n inputSchema: {\n testId: z.string().describe(\"Test (scenario) id\"),\n },\n },\n async ({ testId }) =>\n guard(async () => {\n const test = await sdk().tests.get(testId);\n if (!test) return ok(`No test found with id ${testId}.`);\n return ok(`Test ${test.name} (id: ${testId}).`, test);\n }),\n );\n\n server.registerTool(\n \"create_test\",\n {\n title: \"Create test\",\n description:\n \"Create a test from an ordered list of steps. Each step references an action by name \" +\n \"(use list_actions to discover them) plus optional key/value args. The steps run in order \" +\n \"against a single simulator. Example steps: 'Power On Charger', 'Plug In Connector', \" +\n \"'Use RFID Card', 'Charge a Vehicle', 'Plug Out Connector', 'Power Off Charger'.\",\n inputSchema: {\n name: z.string().describe(\"Test name\"),\n protocol: protocolEnum,\n steps: z\n .array(\n z.object({\n actionName: z.string().describe(\"Exact action name, e.g. 'Power On Charger'\"),\n args: z\n .array(z.object({ key: z.string(), value: z.string() }))\n .optional()\n .describe(\"Action arguments as key/value pairs\"),\n }),\n )\n .min(1)\n .describe(\"Ordered list of steps\"),\n project: projectArg,\n },\n },\n async ({ name, protocol, steps, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n\n const actions = [];\n for (let i = 0; i < steps.length; i++) {\n const actionId = await resolveActionId(ctx.simWorldId, protocol, steps[i].actionName);\n actions.push({\n order: i + 1,\n stream: 1,\n actionId,\n requirementKey: \"charger\",\n args: steps[i].args ?? [],\n });\n }\n\n const test = await sdk().tests.create({\n simWorldId: ctx.simWorldId,\n name,\n deviceType: \"CHARGER\",\n requirements: [\n { key: \"charger\", type: \"CHARGER\", params: [{ key: \"protocol\", value: protocol }] },\n ],\n actions,\n });\n return ok(`Created test \"${name}\" (id: ${test?.id}).`, test);\n }),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveSimulator } from \"../resolve.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, fail, guard } from \"../result.js\";\n\nexport function registerTestRunTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"run_test\",\n {\n title: \"Run test\",\n description:\n \"Run a test (scenario) on a simulator, starting immediately. \" +\n \"Returns the test run id and status — poll with get_test_run to follow it. \" +\n \"A simulator runs one test at a time; if it is busy this says so and starts nothing.\",\n inputSchema: {\n testId: z.string().describe(\"Test (scenario) id to run\"),\n simulator: z.string().describe(\"Simulator id or base name to run the test on\"),\n project: projectArg,\n },\n },\n async ({ testId, simulator, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const test = await sdk().tests.get(testId);\n const requirementId = test?.requirements?.[0]?.id;\n if (!requirementId) return fail(`Test ${testId} has no device requirement to assign.`);\n\n const sim = await resolveSimulator(ctx.simWorldId, simulator);\n const run = await sdk()\n .testRuns.create({\n scenarioId: testId,\n simWorldId: ctx.simWorldId,\n scheduleMode: \"NOW\",\n speedup: 1,\n forceDelete: false,\n requirementDevices: [\n { requirementId, deviceId: sim.id, deviceMode: \"SIMULATOR\" },\n ],\n })\n .catch(async (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n if (!/conflict/i.test(message)) throw err;\n\n const details = await sdk().simulators.get(sim.id).catch(() => null);\n const blocking = details?.lastRun;\n throw new Error(\n `${sim.baseName} (id: ${sim.id}) is busy` +\n (blocking?.id ? ` with test run ${blocking.id} (${blocking.status})` : \"\") +\n `, so nothing was started. Stop that run with stop_test_run — the simulator is ` +\n `free once it stops — then run this test again.`,\n );\n });\n return ok(\n `Started test \"${test?.name}\" on ${sim.baseName} — run id ${run?.id}, status ${run?.status}.`,\n run,\n );\n }),\n );\n\n server.registerTool(\n \"get_test_run\",\n {\n title: \"Get test run\",\n description: \"Get a test run's status by id.\",\n inputSchema: {\n runId: z.string().describe(\"Test run id\"),\n },\n },\n async ({ runId }) =>\n guard(async () => {\n const run = await sdk().testRuns.get(runId);\n if (!run) return ok(`No test run found with id ${runId}.`);\n const reason = run.failReason ? ` — ${run.failReason}` : \"\";\n return ok(`Test run ${runId} (\"${run.scenario?.name}\"): ${run.status}${reason}.`, run);\n }),\n );\n\n server.registerTool(\n \"list_test_runs\",\n {\n title: \"List test runs\",\n description: \"List recent test runs in the active project's sim world.\",\n inputSchema: {\n ...paginationArgs,\n project: projectArg,\n },\n },\n async ({ page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().testRuns.list({\n simWorldId: ctx.simWorldId,\n pagination: pagination(page, pageSize),\n });\n return ok(pageSummary(\"test run(s)\", result?.records?.length ?? 0, result?.pageInfo), result);\n }),\n );\n\n server.registerTool(\n \"stop_test_run\",\n {\n title: \"Stop test run\",\n description: \"Shut down (stop) a running or scheduled test run by id.\",\n inputSchema: {\n runId: z.string().describe(\"Test run id\"),\n },\n },\n async ({ runId }) =>\n guard(async () => {\n const existing = await sdk().testRuns.get(runId);\n if (!existing) return fail(`No test run found with id ${runId}.`);\n\n await sdk().testRuns.shutDown(runId);\n const after = await sdk().testRuns.get(runId);\n return ok(\n `Shut down test run ${runId} (was ${existing.status}, now ${after?.status ?? \"unknown\"}).`,\n after,\n );\n }),\n );\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","protocolEnum","z","z","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/tools/context.ts","../src/sdk.ts","../src/context.ts","../src/result.ts","../src/tools/data.ts","../src/links.ts","../src/resolve.ts","../src/pagination.ts","../src/tools/simulators.ts","../src/tools/tests.ts","../src/tools/test-runs.ts","../src/tools/support.ts","../src/logs-format.ts","../src/tools/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { isReadOnlyMode, registerTools } from \"./tools/index.js\";\n\nasync function main() {\n if (!process.env.TIMETICK_API_TOKEN) {\n console.error(\n \"TIMETICK_API_TOKEN is not set. Generate an API key in the Timetick portal \" +\n \"(Account → API keys) and expose it to the MCP server as TIMETICK_API_TOKEN.\",\n );\n process.exit(1);\n }\n\n const server = new McpServer({ name: \"timetick\", version: \"0.2.1\" });\n\n const readOnly = isReadOnlyMode();\n registerTools(server, { readOnly });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(`Timetick MCP server running on stdio${readOnly ? \" (read-only)\" : \"\"}`);\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error starting Timetick MCP server:\", error);\n process.exit(1);\n});\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getContext, useProject, peekContext } from \"../context.js\";\nimport { ok, guard } from \"../result.js\";\n\nexport function registerContextTools(server: McpServer) {\n server.registerTool(\n \"get_context\",\n {\n annotations: { readOnlyHint: true },\n title: \"Get active context\",\n description:\n \"Show the project and sim world the MCP server is currently operating on. \" +\n \"If no project is selected yet and you have only one project, it is auto-selected.\",\n inputSchema: {},\n },\n async () =>\n guard(async () => {\n const ctx = peekContext() ?? (await getContext());\n return ok(\n `Active project: ${ctx.projectName} (id: ${ctx.projectId}); sim world: ${ctx.simWorldId} [${ctx.source}]`,\n ctx,\n );\n }),\n );\n\n server.registerTool(\n \"use_project\",\n {\n annotations: { readOnlyHint: true },\n title: \"Select project\",\n description:\n \"Switch the active project by name or id. Only needed if you have more than one project. \" +\n \"Caches the project's sim world for subsequent tools.\",\n inputSchema: {\n project: z.string().describe(\"Project name or id to make active\"),\n },\n },\n async ({ project }) =>\n guard(async () => {\n const ctx = await useProject({ project });\n return ok(`Active project is now ${ctx.projectName} (id: ${ctx.projectId}).`, ctx);\n }),\n );\n}\n","import { createClient, type TimetickClient } from \"@timetick/sdk\";\n\nlet client: TimetickClient | null = null;\n\n/** Lazily-created singleton Timetick SDK client, authenticated from the environment. */\nexport function sdk(): TimetickClient {\n if (client) return client;\n\n const apiKey = process.env.TIMETICK_API_TOKEN;\n if (!apiKey) {\n throw new Error(\n \"TIMETICK_API_TOKEN is not set. Generate an API key in the Timetick portal \" +\n \"(Account → API keys) and expose it to the MCP server as TIMETICK_API_TOKEN.\",\n );\n }\n\n client = createClient({ apiKey, endpoint: process.env.TIMETICK_API_URL });\n return client;\n}\n","import { sdk } from \"./sdk.js\";\n\nexport interface Context {\n projectId: string;\n projectName: string;\n simWorldId: string;\n /** Scope id used by hardware/device queries — distinct from simWorldId. */\n deviceScopeId: string;\n /** How the project was chosen — surfaced to the user for transparency. */\n source: \"single-project\" | \"explicit\";\n}\n\n/** Thrown when the project/sim world can't be resolved without user input. */\nexport class ContextError extends Error {}\n\nlet cached: Context | null = null;\n\n/** Resolves a project's sim world (one sim world per project today). */\nasync function buildContext(\n projectId: string,\n projectName: string,\n source: Context[\"source\"],\n): Promise<Context> {\n const worlds = await sdk().simWorlds.list(projectId);\n const world = worlds?.[0];\n if (!world?.id) {\n throw new ContextError(`Project \"${projectName}\" has no sim world to operate on.`);\n }\n return {\n projectId,\n projectName,\n simWorldId: world.id,\n deviceScopeId: world.deviceScopeId ?? world.id,\n source,\n };\n}\n\nconst PROJECT_LIST_LIMIT = 15;\n\ntype ProjectSummary = { id?: string | null; name?: string | null } | null | undefined;\n\nfunction formatProjects(projects: readonly ProjectSummary[] | null | undefined): string {\n const all = projects ?? [];\n const lines = all\n .slice(0, PROJECT_LIST_LIMIT)\n .map((p) => ` - ${p?.name} (id: ${p?.id})`);\n if (all.length > PROJECT_LIST_LIMIT) {\n lines.push(` …and ${all.length - PROJECT_LIST_LIMIT} more — call list_projects to see them all.`);\n }\n return lines.join(\"\\n\");\n}\n\nasync function findProject(project: string): Promise<{ id: string; name: string }> {\n const projects = await sdk().projects.list();\n const needle = project.toLowerCase();\n const match = projects?.find(\n (p) => p?.id === project || p?.name?.toLowerCase() === needle,\n );\n if (!match?.id) {\n throw new ContextError(\n `No project matching \"${project}\". Available:\\n${formatProjects(projects)}`,\n );\n }\n return { id: match.id, name: match.name ?? \"(unnamed)\" };\n}\n\n/**\n * Returns the active context, auto-selecting the project when there is only one.\n * Throws ContextError (with the project list) when the choice is ambiguous.\n */\nexport async function getContext(): Promise<Context> {\n if (cached) return cached;\n\n const projects = await sdk().projects.list();\n if (!projects || projects.length === 0) {\n throw new ContextError(\"No projects are available for this API key.\");\n }\n if (projects.length > 1) {\n throw new ContextError(\n `You have ${projects.length} projects. Call \\`use_project\\` with a project name or id ` +\n `first:\\n${formatProjects(projects)}`,\n );\n }\n\n const only = projects[0]!;\n cached = await buildContext(only.id!, only.name ?? \"(unnamed)\", \"single-project\");\n return cached;\n}\n\n/** Explicitly switches the active project by name or id, and caches its sim world. */\nexport async function useProject(input: { project: string }): Promise<Context> {\n const match = await findProject(input.project);\n cached = await buildContext(match.id, match.name, \"explicit\");\n return cached;\n}\n\nexport async function lookupProject(project: string): Promise<Context> {\n const match = await findProject(project);\n return buildContext(match.id, match.name, \"explicit\");\n}\n\n/** Returns the cached context without resolving, if any. */\nexport function peekContext(): Context | null {\n return cached;\n}\n","import { TimetickError } from \"@timetick/sdk\";\n\ntype ToolResult = {\n content: { type: \"text\"; text: string }[];\n isError?: boolean;\n};\n\n/** Wraps a value into an MCP text result, pretty-printing objects as JSON. */\nexport function ok(text: string, data?: unknown): ToolResult {\n const body = data === undefined ? text : `${text}\\n\\n${JSON.stringify(data, null, 2)}`;\n return { content: [{ type: \"text\", text: body }] };\n}\n\nexport function fail(message: string): ToolResult {\n return { content: [{ type: \"text\", text: message }], isError: true };\n}\n\n/** Runs a tool handler, normalizing SDK/unknown errors into an isError result. */\nexport async function guard(fn: () => Promise<ToolResult>): Promise<ToolResult> {\n try {\n return await fn();\n } catch (err) {\n if (err instanceof TimetickError) return fail(`Timetick API error: ${err.message}`);\n return fail(err instanceof Error ? err.message : String(err));\n }\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveSimulatorTarget } from \"../resolve.js\";\nimport { SIMULATOR_ARG_DESCRIPTION } from \"../links.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, guard } from \"../result.js\";\n\nconst protocolEnum = z.enum([\"OCPP_1_6\", \"OCPP_2_0_1\"]);\n\nfunction summarizeArgs(params: unknown): Record<string, string> | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n const summary: Record<string, string> = {};\n for (const [name, spec] of Object.entries(params as Record<string, unknown>)) {\n if (!spec || typeof spec !== \"object\") continue;\n const { type, allowNull, defaultValue, visible } = spec as Record<string, unknown>;\n if (visible === false) continue;\n const parts = [String(type ?? \"unknown\"), allowNull === false ? \"required\" : \"optional\"];\n if (defaultValue !== undefined) parts.push(`default ${JSON.stringify(defaultValue)}`);\n summary[name] = parts.join(\", \");\n }\n return Object.keys(summary).length > 0 ? summary : undefined;\n}\n\nexport function registerDataTools(server: McpServer) {\n server.registerTool(\n \"list_projects\",\n {\n annotations: { readOnlyHint: true },\n title: \"List projects\",\n description: \"List all projects available to your API key.\",\n inputSchema: {},\n },\n async () =>\n guard(async () => {\n const projects = await sdk().projects.list();\n return ok(`Found ${projects?.length ?? 0} project(s).`, projects);\n }),\n );\n\n server.registerTool(\n \"list_simulators\",\n {\n annotations: { readOnlyHint: true },\n title: \"List simulators\",\n description:\n \"List simulators (virtual chargers) in the active project's sim world. \" +\n \"Optionally filter by name search or protocol.\",\n inputSchema: {\n search: z.string().optional().describe(\"Filter by simulator base name\"),\n protocol: protocolEnum.optional(),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ search, protocol, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().simulators.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: protocol ? { protocol } : undefined,\n pagination: pagination(page, pageSize),\n });\n return ok(\n pageSummary(\"simulator(s)\", result?.records?.length ?? 0, result?.pageInfo),\n result,\n );\n }),\n );\n\n server.registerTool(\n \"get_simulator\",\n {\n annotations: { readOnlyHint: true },\n title: \"Get simulator\",\n description:\n \"Get a simulator's details and live status (network status, launched/power status, connectors) \" +\n \"by id or base name.\",\n inputSchema: {\n simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION),\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim: resolved } = await resolveSimulatorTarget(simulator, project);\n const details = await sdk().simulators.get(resolved.id);\n return ok(`Simulator ${resolved.baseName} (id: ${resolved.id}).`, details);\n }),\n );\n\n server.registerTool(\n \"list_hardware\",\n {\n annotations: { readOnlyHint: true },\n title: \"List hardware\",\n description: \"List physical OCPP hardware devices in the active project's sim world.\",\n inputSchema: {\n search: z.string().optional().describe(\"Filter by serial number / model\"),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().hardware.list({\n deviceScopeId: ctx.deviceScopeId,\n searchValue: search,\n pagination: pagination(page, pageSize),\n });\n return ok(\n pageSummary(\"hardware device(s)\", result?.records?.length ?? 0, result?.pageInfo),\n result,\n );\n }),\n );\n\n server.registerTool(\n \"list_actions\",\n {\n annotations: { readOnlyHint: true },\n title: \"List actions (test steps)\",\n description:\n \"List available actions (steps) you can use to build a test — e.g. 'Power On Charger', \" +\n \"'Plug In Connector', 'Charge a Vehicle'. Filter by protocol. Each action lists its \" +\n \"arguments: the name, whether it is required (allowNull false), and any default.\",\n inputSchema: {\n protocol: protocolEnum.optional(),\n search: z.string().optional().describe(\"Filter by action name\"),\n ...paginationArgs,\n project: z.string().optional().describe(\"Project name or id (defaults to active project)\"),\n },\n },\n async ({ protocol, search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().actions.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: { isSystem: true, deviceType: \"CHARGER\", ...(protocol ? { protocol } : {}) },\n pagination: pagination(page, pageSize, 100),\n });\n const actions = (result?.records ?? []).map((a) => ({\n name: a?.name,\n description: a?.description ?? undefined,\n args: summarizeArgs(a?.params),\n }));\n return ok(pageSummary(\"action(s)\", actions.length, result?.pageInfo), actions);\n }),\n );\n}\n","export interface SimulatorRef {\n simulator: string;\n project?: string;\n}\n\nconst SIMULATOR_PATH = /\\/projects\\/([^/?#&|>\\s]+)\\/simulators\\/([^/?#&|>\\s]+)/;\n\nfunction looksLikeLink(text: string): boolean {\n return /^<?https?:\\/\\//i.test(text) || /(^|\\.)timetick\\.io\\//i.test(text);\n}\n\nexport function parseSimulatorRef(input: string): SimulatorRef {\n const text = input.trim();\n if (!looksLikeLink(text)) return { simulator: text };\n\n // Slack escapes & as & in links.\n const unescaped = text.replace(/&/g, \"&\");\n const match = unescaped.match(SIMULATOR_PATH);\n if (!match) {\n throw new Error(\n `\"${input}\" looks like a link but not to a simulator. Expected ` +\n \"https://app.timetick.io/projects/<project id>/simulators/<simulator id>.\",\n );\n }\n return { project: decodeURIComponent(match[1]!), simulator: decodeURIComponent(match[2]!) };\n}\n\nexport const SIMULATOR_ARG_DESCRIPTION =\n \"Simulator id, base name, or portal link (https://app.timetick.io/projects/<id>/simulators/<id>)\";\n","import { sdk } from \"./sdk.js\";\nimport { getContext, lookupProject, type Context } from \"./context.js\";\nimport { parseSimulatorRef } from \"./links.js\";\n\n/** Resolves the sim world to operate in: explicit project arg wins, else session context. */\nexport async function resolveSimWorld(project?: string): Promise<Context> {\n if (project) return lookupProject(project);\n return getContext();\n}\n\nexport interface ResolvedSimulator {\n id: string;\n baseName: string;\n protocol: string;\n}\n\n/** Resolves a simulator by id or by (case-insensitive) base name within a sim world. */\nexport async function resolveSimulator(\n simWorldId: string,\n simulator: string,\n): Promise<ResolvedSimulator> {\n const needle = simulator.toLowerCase();\n const page = await sdk().simulators.list({ simWorldId, searchValue: simulator });\n const records = page?.records ?? [];\n\n const exact =\n records.find((r) => r?.id === simulator) ??\n records.find((r) => r?.baseName?.toLowerCase() === needle) ??\n (records.length === 1 ? records[0] : undefined);\n\n if (exact?.id) {\n return { id: exact.id, baseName: exact.baseName ?? \"\", protocol: String(exact.protocol) };\n }\n\n // Fall back to treating the input as a raw id.\n const byId = await sdk().simulators.get(simulator).catch(() => null);\n if (byId?.id) {\n return { id: byId.id, baseName: byId.baseName ?? \"\", protocol: String(byId.protocol) };\n }\n\n const candidates = records.map((r) => ` - ${r?.baseName} (id: ${r?.id})`).join(\"\\n\");\n throw new Error(\n `No simulator matching \"${simulator}\".` +\n (candidates ? `\\nCandidates:\\n${candidates}` : \" No simulators found in this sim world.\"),\n );\n}\n\nexport async function resolveSimulatorTarget(\n simulator: string,\n project?: string,\n): Promise<{ ctx: Context; sim: ResolvedSimulator }> {\n const ref = parseSimulatorRef(simulator);\n const ctx = await resolveSimWorld(ref.project ?? project);\n const sim = ref.project !== undefined\n ? await resolveSimulatorById(ref.simulator)\n : await resolveSimulator(ctx.simWorldId, ref.simulator);\n return { ctx, sim };\n}\n\nasync function resolveSimulatorById(id: string): Promise<ResolvedSimulator> {\n const byId = await sdk().simulators.get(id).catch((err: unknown) => {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`No simulator with id ${id} from the portal link: ${reason}`);\n });\n if (!byId?.id) throw new Error(`No simulator with id ${id} from the portal link.`);\n return { id: byId.id, baseName: byId.baseName ?? \"\", protocol: String(byId.protocol) };\n}\n\n/** Finds a system action by exact name for a given protocol; returns its id. */\nexport async function resolveActionId(\n simWorldId: string,\n protocol: string,\n actionName: string,\n): Promise<string> {\n const page = await sdk().actions.list({\n simWorldId,\n searchValue: actionName,\n filters: { isSystem: true, protocol: protocol as any, deviceType: \"CHARGER\" },\n pagination: { page: 1, pageSize: 50 },\n });\n const records = page?.records ?? [];\n const needle = actionName.toLowerCase();\n const match =\n records.find((a) => a?.name?.toLowerCase() === needle) ??\n records.find((a) => a?.name?.toLowerCase().includes(needle));\n\n if (!match?.id) {\n const available = records.map((a) => ` - ${a?.name}`).join(\"\\n\");\n throw new Error(\n `Action \"${actionName}\" not found for ${protocol}.` +\n (available ? `\\nAvailable system actions matching your search:\\n${available}` : \"\"),\n );\n }\n return match.id;\n}\n","import { z } from \"zod\";\n\nexport const DEFAULT_PAGE_SIZE = 20;\n\nexport const paginationArgs = {\n page: z.number().int().min(1).optional().describe(\"Page number, starting at 1 (default 1)\"),\n pageSize: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(`Results per page (default ${DEFAULT_PAGE_SIZE})`),\n};\n\nexport function pagination(page?: number, pageSize?: number, defaultPageSize = DEFAULT_PAGE_SIZE) {\n return { page: page ?? 1, pageSize: pageSize ?? defaultPageSize };\n}\n\ninterface PageInfoLike {\n page?: number | null;\n pageSize?: number | null;\n hasNextPage?: boolean | null;\n totalCount?: number | null;\n}\n\nexport function pageSummary(noun: string, count: number, pageInfo?: PageInfoLike | null): string {\n const total = pageInfo?.totalCount;\n const head =\n total != null && total !== count\n ? `Showing ${count} of ${total} ${noun} (page ${pageInfo?.page ?? 1}).`\n : `Found ${count} ${noun}.`;\n return pageInfo?.hasNextPage ? `${head} More results available — request the next page.` : head;\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimulatorTarget, resolveActionId } from \"../resolve.js\";\nimport { SIMULATOR_ARG_DESCRIPTION } from \"../links.js\";\nimport { ok, guard } from \"../result.js\";\n\n/** Runs a single named action against a simulator via the SDK's runAction. */\nasync function runOnSimulator(\n project: string | undefined,\n simulator: string,\n actionName: string,\n args: { key: string; value: string }[] = [],\n) {\n const { ctx, sim } = await resolveSimulatorTarget(simulator, project);\n const actionId = await resolveActionId(ctx.simWorldId, sim.protocol, actionName);\n\n const status = await sdk().testRuns.runAction({\n chargerId: sim.id,\n action: { requirementKey: \"1\", stream: 1, order: 1, actionId, args },\n });\n return { sim, actionName, status };\n}\n\nexport function registerSimulatorTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"power_on_simulator\",\n {\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n title: \"Power on simulator\",\n description: \"Power on a simulator (boots it and connects it to the OCPP server).\",\n inputSchema: {\n simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION),\n project: projectArg,\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, \"Power On Charger\");\n return ok(`Powered on ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n\n server.registerTool(\n \"power_off_simulator\",\n {\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n title: \"Power off simulator\",\n description: \"Power off a simulator.\",\n inputSchema: {\n simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION),\n project: projectArg,\n },\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, \"Power Off Charger\");\n return ok(`Powered off ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n\n server.registerTool(\n \"run_simulator_action\",\n {\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n title: \"Run simulator action\",\n description:\n \"Run a single named action against a simulator — e.g. 'Reset Charger', 'Plug In Connector', \" +\n \"'Plug Out Connector'. Use list_actions to discover names and required args. \" +\n \"Args are passed as key/value pairs (e.g. connectorId=1).\",\n inputSchema: {\n simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION),\n actionName: z.string().describe(\"Exact action name, e.g. 'Reset Charger'\"),\n args: z\n .array(z.object({ key: z.string(), value: z.string() }))\n .optional()\n .describe(\"Action arguments as key/value pairs\"),\n project: projectArg,\n },\n },\n async ({ simulator, actionName, args, project }) =>\n guard(async () => {\n const { sim, status } = await runOnSimulator(project, simulator, actionName, args ?? []);\n return ok(`Ran \"${actionName}\" on ${sim.baseName} (id: ${sim.id}).`, { status });\n }),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveActionId } from \"../resolve.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, guard } from \"../result.js\";\n\nconst protocolEnum = z.enum([\"OCPP_1_6\", \"OCPP_2_0_1\"]);\n\nexport function registerTestTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"list_tests\",\n {\n annotations: { readOnlyHint: true },\n title: \"List tests\",\n description: \"List tests (scenarios) in the active project's sim world.\",\n inputSchema: {\n protocol: protocolEnum.optional(),\n search: z.string().optional().describe(\"Filter by test name\"),\n ...paginationArgs,\n project: projectArg,\n },\n },\n async ({ protocol, search, page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().tests.list({\n simWorldId: ctx.simWorldId,\n searchValue: search,\n filters: protocol ? { protocol } : undefined,\n pagination: pagination(page, pageSize),\n });\n return ok(pageSummary(\"test(s)\", result?.records?.length ?? 0, result?.pageInfo), result);\n }),\n );\n\n server.registerTool(\n \"get_test\",\n {\n annotations: { readOnlyHint: true },\n title: \"Get test\",\n description: \"Get a test by id, including its device requirements.\",\n inputSchema: {\n testId: z.string().describe(\"Test (scenario) id\"),\n },\n },\n async ({ testId }) =>\n guard(async () => {\n const test = await sdk().tests.get(testId);\n if (!test) return ok(`No test found with id ${testId}.`);\n return ok(`Test ${test.name} (id: ${testId}).`, test);\n }),\n );\n\n server.registerTool(\n \"create_test\",\n {\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n title: \"Create test\",\n description:\n \"Create a test from an ordered list of steps. Each step references an action by name \" +\n \"(use list_actions to discover them) plus optional key/value args. The steps run in order \" +\n \"against a single simulator. Example steps: 'Power On Charger', 'Plug In Connector', \" +\n \"'Use RFID Card', 'Charge a Vehicle', 'Plug Out Connector', 'Power Off Charger'.\",\n inputSchema: {\n name: z.string().describe(\"Test name\"),\n protocol: protocolEnum,\n steps: z\n .array(\n z.object({\n actionName: z.string().describe(\"Exact action name, e.g. 'Power On Charger'\"),\n args: z\n .array(z.object({ key: z.string(), value: z.string() }))\n .optional()\n .describe(\"Action arguments as key/value pairs\"),\n }),\n )\n .min(1)\n .describe(\"Ordered list of steps\"),\n project: projectArg,\n },\n },\n async ({ name, protocol, steps, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n\n const actions = [];\n for (let i = 0; i < steps.length; i++) {\n const actionId = await resolveActionId(ctx.simWorldId, protocol, steps[i].actionName);\n actions.push({\n order: i + 1,\n stream: 1,\n actionId,\n requirementKey: \"charger\",\n args: steps[i].args ?? [],\n });\n }\n\n const test = await sdk().tests.create({\n simWorldId: ctx.simWorldId,\n name,\n deviceType: \"CHARGER\",\n requirements: [\n { key: \"charger\", type: \"CHARGER\", params: [{ key: \"protocol\", value: protocol }] },\n ],\n actions,\n });\n return ok(`Created test \"${name}\" (id: ${test?.id}).`, test);\n }),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimWorld, resolveSimulatorTarget } from \"../resolve.js\";\nimport { SIMULATOR_ARG_DESCRIPTION } from \"../links.js\";\nimport { paginationArgs, pagination, pageSummary } from \"../pagination.js\";\nimport { ok, fail, guard } from \"../result.js\";\n\nexport function registerTestRunTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project)\");\n\n server.registerTool(\n \"run_test\",\n {\n annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },\n title: \"Run test\",\n description:\n \"Run a test (scenario) on a simulator, starting immediately. \" +\n \"Returns the test run id and status — poll with get_test_run to follow it. \" +\n \"A simulator runs one test at a time; if it is busy this says so and starts nothing.\",\n inputSchema: {\n testId: z.string().describe(\"Test (scenario) id to run\"),\n simulator: z.string().describe(`${SIMULATOR_ARG_DESCRIPTION} to run the test on`),\n project: projectArg,\n },\n },\n async ({ testId, simulator, project }) =>\n guard(async () => {\n const { ctx, sim } = await resolveSimulatorTarget(simulator, project);\n const test = await sdk().tests.get(testId);\n const requirementId = test?.requirements?.[0]?.id;\n if (!requirementId) return fail(`Test ${testId} has no device requirement to assign.`);\n\n const run = await sdk()\n .testRuns.create({\n scenarioId: testId,\n simWorldId: ctx.simWorldId,\n scheduleMode: \"NOW\",\n speedup: 1,\n forceDelete: false,\n requirementDevices: [\n { requirementId, deviceId: sim.id, deviceMode: \"SIMULATOR\" },\n ],\n })\n .catch(async (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n if (!/conflict/i.test(message)) throw err;\n\n const details = await sdk().simulators.get(sim.id).catch(() => null);\n const blocking = details?.lastRun;\n throw new Error(\n `${sim.baseName} (id: ${sim.id}) is busy` +\n (blocking?.id ? ` with test run ${blocking.id} (${blocking.status})` : \"\") +\n `, so nothing was started. Stop that run with stop_test_run — the simulator is ` +\n `free once it stops — then run this test again.`,\n );\n });\n return ok(\n `Started test \"${test?.name}\" on ${sim.baseName} — run id ${run?.id}, status ${run?.status}.`,\n run,\n );\n }),\n );\n\n server.registerTool(\n \"get_test_run\",\n {\n annotations: { readOnlyHint: true },\n title: \"Get test run\",\n description: \"Get a test run's status by id.\",\n inputSchema: {\n runId: z.string().describe(\"Test run id\"),\n },\n },\n async ({ runId }) =>\n guard(async () => {\n const run = await sdk().testRuns.get(runId);\n if (!run) return ok(`No test run found with id ${runId}.`);\n const reason = run.failReason ? ` — ${run.failReason}` : \"\";\n return ok(`Test run ${runId} (\"${run.scenario?.name}\"): ${run.status}${reason}.`, run);\n }),\n );\n\n server.registerTool(\n \"list_test_runs\",\n {\n annotations: { readOnlyHint: true },\n title: \"List test runs\",\n description: \"List recent test runs in the active project's sim world.\",\n inputSchema: {\n ...paginationArgs,\n project: projectArg,\n },\n },\n async ({ page, pageSize, project }) =>\n guard(async () => {\n const ctx = await resolveSimWorld(project);\n const result = await sdk().testRuns.list({\n simWorldId: ctx.simWorldId,\n pagination: pagination(page, pageSize),\n });\n return ok(pageSummary(\"test run(s)\", result?.records?.length ?? 0, result?.pageInfo), result);\n }),\n );\n\n server.registerTool(\n \"stop_test_run\",\n {\n annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },\n title: \"Stop test run\",\n description: \"Shut down (stop) a running or scheduled test run by id.\",\n inputSchema: {\n runId: z.string().describe(\"Test run id\"),\n },\n },\n async ({ runId }) =>\n guard(async () => {\n const existing = await sdk().testRuns.get(runId);\n if (!existing) return fail(`No test run found with id ${runId}.`);\n\n await sdk().testRuns.shutDown(runId);\n const after = await sdk().testRuns.get(runId);\n return ok(\n `Shut down test run ${runId} (was ${existing.status}, now ${after?.status ?? \"unknown\"}).`,\n after,\n );\n }),\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { sdk } from \"../sdk.js\";\nimport { resolveSimulatorTarget } from \"../resolve.js\";\nimport { SIMULATOR_ARG_DESCRIPTION } from \"../links.js\";\nimport {\n DEFAULT_LOGS_LAST,\n DEFAULT_LOGS_LIMIT,\n MAX_LOGS_LIMIT,\n formatLine,\n matchesAction,\n resolveWindow,\n toLogLines,\n} from \"../logs-format.js\";\nimport { ok, fail, guard } from \"../result.js\";\nimport { pageSummary } from \"../pagination.js\";\n\nconst READ_ONLY = { readOnlyHint: true, openWorldHint: true } as const;\n\nconst SECRET_KEY = /authorizationkey|password|secret|privatekey|passphrase/i;\n\ntype ConfigItem = { key?: string | null; variableName?: string | null; value?: string | null };\n\nexport function maskSecretItems<T extends ConfigItem>(items: readonly T[] | null | undefined): T[] {\n return (items ?? []).map((item) =>\n SECRET_KEY.test(item.key ?? item.variableName ?? \"\") && item.value ? { ...item, value: \"***\" } : item,\n );\n}\n\nfunction summarizeSimulator(sim: any): string {\n const model = sim.chargerModel;\n const config = sim.chargerConfig;\n const connectors = (model?.connectorModels ?? sim.chargerConnectors ?? [])\n .map((c: any) => `#${c.number ?? c.connectorId} ${c.type} (cable ${c.cableFixed ? \"fixed\" : \"flexible\"})`)\n .join(\", \");\n const lines = [\n `Simulator ${sim.baseName} (id: ${sim.id}), ${sim.protocol}; network ${sim.networkStatus}, ` +\n `power ${sim.launchedStatus}, OCPP status ${sim.chargerStatus}${sim.emergency ? \", EMERGENCY\" : \"\"}.`,\n `Model: ${model?.name ?? \"?\"} by ${model?.deviceManufacturer?.name ?? \"?\"}` +\n (connectors ? `; connectors: ${connectors}.` : \".\"),\n `Behavior: ${config?.behavior ?? \"?\"}; remote templates ${config?.useRemoteTemplates ? \"on\" : \"off\"}; ` +\n `supported commands: ${(config?.supportedCommands ?? []).join(\", \") || \"—\"}.`,\n `OCPP configuration keys: ${sim.chargerOcppConfigItems?.length ?? 0}.`,\n ];\n if (sim.lastRun) {\n lines.push(\n `Last run ${sim.lastRun.id}: ${sim.lastRun.status}` +\n (sim.lastRun.failReason ? ` — ${sim.lastRun.failReason}` : \"\") + \".\",\n );\n }\n return lines.join(\"\\n\");\n}\n\nconst RUN_SIMULATORS_PAGE_SIZE = 20;\n\nfunction simulatorName(rc: any): string {\n return rc.charger?.baseName ?? rc.device?.serialNumber ?? rc.id;\n}\n\nfunction findRunSimulator(records: any[], simulator: string): any {\n const needle = simulator.trim().toLowerCase();\n return (\n records.find((rc) => rc.id === simulator.trim()) ??\n records.find((rc) => rc.charger?.id === simulator.trim() || rc.device?.id === simulator.trim()) ??\n records.find((rc) =>\n rc.charger?.baseName?.toLowerCase() === needle || rc.device?.serialNumber?.toLowerCase() === needle,\n )\n );\n}\n\nfunction summarizeRun(run: any, simulators: any, page: number, steps: any): string {\n const records = (simulators?.records ?? []).filter(Boolean);\n const lines = [\n `Test run ${run.id} (\"${run.scenario?.name ?? \"?\"}\"): ${run.status}` +\n (run.failReason ? ` — ${run.failReason}` : \"\") +\n `. Started ${run.realStartTimestamp ?? run.startTimestamp ?? \"—\"}, stopped ${run.realStopTimestamp ?? \"—\"}.`,\n pageSummary(\"simulator(s)\", records.length, simulators?.pageInfo ?? { page }),\n ];\n for (const rc of records) {\n lines.push(`- ${simulatorName(rc)} (simulator ${rc.charger?.id ?? rc.device?.id ?? \"?\"}, run entry ${rc.id}): ${rc.status}`);\n }\n if (steps) {\n lines.push(\"\", `Steps of ${simulatorName(steps)}:`);\n for (const step of steps.chargerActions ?? []) {\n lines.push(\n ` step ${step.order} ${step.scenarioAction?.action?.name ?? \"?\"}: ${step.status}` +\n (step.failReason ? ` — ${step.failReason}` : \"\"),\n );\n }\n } else if (records.length > 1 || simulators?.pageInfo?.hasNextPage) {\n lines.push(\"\", \"Pass `simulator` with one of the names or ids above to see its steps.\");\n }\n return lines.join(\"\\n\");\n}\n\nexport function registerSupportTools(server: McpServer) {\n const projectArg = z\n .string()\n .optional()\n .describe(\"Project name or id (defaults to active project; a portal link sets its own)\");\n\n server.registerTool(\n \"get_simulator_config\",\n {\n title: \"Get simulator configuration\",\n description:\n \"Read-only. Everything that explains why a simulator behaves the way it does: its OCPP \" +\n \"configuration keys (e.g. FreevendEnabled, HeartbeatInterval), behavior settings (vendor \" +\n \"behavior, remote start/stop templates, supported commands, timeouts), model and connector \" +\n \"types (fixed or flexible cable), live connectors, authorizations, charging profiles, \" +\n \"transactions, reservations, and the last test run with its fail reason. Credential values \" +\n \"are masked.\",\n inputSchema: { simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION), project: projectArg },\n annotations: READ_ONLY,\n },\n async ({ simulator, project }) =>\n guard(async () => {\n const { sim } = await resolveSimulatorTarget(simulator, project);\n const details = await sdk().simulators.getDetails(sim.id);\n if (!details) return ok(`No simulator found with id ${sim.id}.`);\n const items = await sdk().simulators.getOcppConfigItems(sim.id);\n const safe = { ...details, chargerOcppConfigItems: maskSecretItems(items as ConfigItem[] | null) };\n return ok(summarizeSimulator(safe), safe);\n }),\n );\n\n server.registerTool(\n \"get_simulator_logs\",\n {\n title: \"Get simulator logs\",\n description:\n \"Read-only. The simulator's OCPP message log for a time window, one line per message: \" +\n \"`time direction action payload` (payload cut at ~500 chars). Newest messages are kept \" +\n \"when the limit cuts the window; lines are printed oldest first. Use `action` to keep one \" +\n \"OCPP action, e.g. StatusNotification (its results and errors are kept too).\",\n inputSchema: {\n simulator: z.string().describe(SIMULATOR_ARG_DESCRIPTION),\n from: z.string().optional().describe(\"Window start, ISO date-time (wins over `last`)\"),\n to: z.string().optional().describe(\"Window end, ISO date-time (default now)\"),\n last: z.string().optional().describe(`Window length back from \\`to\\`, e.g. 30m, 6h, 2d (default ${DEFAULT_LOGS_LAST})`),\n limit: z.number().int().min(1).max(MAX_LOGS_LIMIT).optional()\n .describe(`Max messages to show (default ${DEFAULT_LOGS_LIMIT}, max ${MAX_LOGS_LIMIT})`),\n action: z.string().optional().describe(\"Keep only this OCPP action, e.g. StatusNotification\"),\n project: projectArg,\n },\n annotations: READ_ONLY,\n },\n async ({ simulator, from, to, last, limit, action, project }) =>\n guard(async () => {\n const window = resolveWindow({ from, to, last });\n const { sim } = await resolveSimulatorTarget(simulator, project);\n // With a filter, scan a full page and cut to the limit afterwards.\n const shown = Math.min(limit ?? DEFAULT_LOGS_LIMIT, MAX_LOGS_LIMIT);\n const result = await sdk().logs.list({\n simulatorId: sim.id,\n from: window.from,\n to: window.to,\n limit: action ? MAX_LOGS_LIMIT : shown,\n });\n\n const all = toLogLines(result.records);\n const matched = action ? all.filter((line) => matchesAction(line, action)) : all;\n const lines = matched.slice(0, shown).reverse();\n const truncated = matched.length > shown || Boolean(result.pageInfo?.hasNextPage);\n\n const head =\n `${sim.baseName} (id: ${sim.id}) ${window.from.toISOString()} … ${window.to.toISOString()}: ` +\n `${lines.length} message(s) shown` +\n (action ? ` matching \"${action}\" of ${all.length} scanned` : \"\") +\n (result.pageInfo?.totalCount != null ? `; ${result.pageInfo.totalCount} in window` : \"\") +\n `; truncated: ${truncated ? \"yes — narrow the window or raise the limit\" : \"no\"}.`;\n return ok([head, \"\", ...lines.map(formatLine)].join(\"\\n\"));\n }),\n );\n\n server.registerTool(\n \"get_test_run_details\",\n {\n title: \"Get test run details\",\n description:\n \"Read-only. A test run's status and fail reason, plus one page of its simulators or devices \" +\n `with their status (${RUN_SIMULATORS_PAGE_SIZE} per page). Steps — status, fail reason, ` +\n \"expected / actual result — are shown for one simulator at a time: pass `simulator` with a \" +\n \"name or id from the page. A run with a single simulator shows its steps right away.\",\n inputSchema: {\n runId: z.string().describe(\"Test run id\"),\n page: z.number().int().min(1).optional().describe(\"Page of the run's simulators, starting at 1 (default 1)\"),\n simulator: z.string().optional()\n .describe(\"Show the steps of this simulator from the page: its name, simulator id or run entry id\"),\n },\n annotations: READ_ONLY,\n },\n async ({ runId, page, simulator }) =>\n guard(async () => {\n const run = await sdk().testRuns.getDetails(runId);\n if (!run) return ok(`No test run found with id ${runId}.`);\n const current = page ?? 1;\n const simulators = await sdk().testRuns.listSimulators(runId, {\n pagination: { page: current, pageSize: RUN_SIMULATORS_PAGE_SIZE },\n });\n const records = (simulators?.records ?? []).filter(Boolean);\n\n let target: any;\n if (simulator) {\n target = findRunSimulator(records, simulator);\n if (!target) {\n return fail(\n `No simulator \"${simulator}\" on page ${current} of test run ${runId}. ` +\n \"Pass a name or id listed on this page, or another page.\",\n );\n }\n } else if (simulators?.pageInfo?.totalCount === 1 || (current === 1 && records.length === 1 && !simulators?.pageInfo?.hasNextPage)) {\n target = records[0];\n }\n\n const ref = target?.charger?.id\n ? { chargerId: target.charger.id as string }\n : target?.device?.id ? { deviceId: target.device.id as string } : null;\n const steps = ref ? await sdk().testRuns.getSimulatorSteps(runId, ref) : null;\n return ok(summarizeRun(run, simulators, current, steps), { run, simulators, steps });\n }),\n );\n}\n","\nexport const DEFAULT_LOGS_LAST = \"1h\";\nexport const DEFAULT_LOGS_LIMIT = 200;\nexport const MAX_LOGS_LIMIT = 1000;\nexport const PAYLOAD_MAX_CHARS = 500;\n\nconst UNIT_MS: Record<string, number> = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 };\n\nexport function parseDuration(value: string): number {\n const match = value.trim().match(/^(\\d+)\\s*([smhd])$/i);\n if (!match) throw new Error(`Invalid duration \"${value}\". Use a number and a unit: 30m, 6h, 2d.`);\n return Number(match[1]) * UNIT_MS[match[2]!.toLowerCase()]!;\n}\n\nfunction parseInstant(value: string, name: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) throw new Error(`Invalid ${name} \"${value}\". Use an ISO date-time.`);\n return date;\n}\n\nexport function resolveWindow(\n input: { from?: string; to?: string; last?: string },\n now: Date = new Date(),\n): { from: Date; to: Date } {\n const to = input.to ? parseInstant(input.to, \"to\") : now;\n const from = input.from\n ? parseInstant(input.from, \"from\")\n : new Date(to.getTime() - parseDuration(input.last ?? DEFAULT_LOGS_LAST));\n if (from.getTime() > to.getTime()) throw new Error(`\"from\" (${from.toISOString()}) is after \"to\" (${to.toISOString()}).`);\n return { from, to };\n}\n\nexport interface LogRecordLike {\n id: string;\n timestamp: string | null;\n sender: string | null;\n receiver: string | null;\n protocol: string | null;\n content: string | null;\n rawContent: string | null;\n error: string | null;\n}\n\nexport interface LogLine {\n time: string;\n direction: string;\n action: string;\n payload: string;\n}\n\nfunction tryJson(text: string | null): unknown {\n if (text == null) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\nfunction stringify(value: unknown): string {\n return typeof value === \"string\" ? value : JSON.stringify(value);\n}\n\nexport function truncate(text: string, max = PAYLOAD_MAX_CHARS): string {\n return text.length > max ? `${text.slice(0, max)}…(+${text.length - max} chars)` : text;\n}\n\nfunction direction(record: LogRecordLike, envelope: any): string {\n const dir = envelope?.payload?.direction;\n if (dir === \"client_to_server\") return \"CP→CSMS\";\n if (dir === \"server_to_client\") return \"CSMS→CP\";\n if (record.sender || record.receiver) return `${record.sender ?? \"?\"}→${record.receiver ?? \"?\"}`;\n return \"-\";\n}\n\nexport function toLogLines(records: LogRecordLike[]): LogLine[] {\n const parsed = records.map((r) => ({ record: r, message: tryJson(r.content), envelope: tryJson(r.rawContent) }));\n\n const callActions = new Map<string, string>();\n for (const { message } of parsed) {\n if (Array.isArray(message) && message[0] === 2) callActions.set(String(message[1]), String(message[2]));\n }\n\n return parsed.map(({ record, message, envelope }) => {\n let action: string;\n let payload: string;\n if (record.protocol === \"OCPP\" && Array.isArray(message) && [2, 3, 4].includes(message[0])) {\n const call = callActions.get(String(message[1]));\n if (message[0] === 2) {\n action = String(message[2]);\n payload = stringify(message[3] ?? {});\n } else if (message[0] === 3) {\n action = `${call ?? \"?\"}.result`;\n payload = stringify(message[2] ?? {});\n } else {\n action = `${call ?? \"?\"}.error`;\n payload = [message[2], message[3], message[4] ? stringify(message[4]) : \"\"].filter(Boolean).join(\" \");\n }\n } else {\n action = String((envelope as any)?.type ?? record.protocol ?? \"log\");\n payload = record.content ?? \"\";\n }\n if (record.error) payload = `${payload} [error: ${record.error}]`;\n return {\n time: record.timestamp ?? \"?\",\n direction: direction(record, envelope),\n action,\n payload: truncate(payload.replace(/\\s+/g, \" \").trim()),\n };\n });\n}\n\nexport function matchesAction(line: LogLine, action: string): boolean {\n const base = line.action.replace(/\\.(result|error)$/, \"\").toLowerCase();\n return base === action.trim().toLowerCase();\n}\n\nexport function formatLine(line: LogLine): string {\n return `${line.time} ${line.direction} ${line.action} ${line.payload}`;\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { registerContextTools } from \"./context.js\";\nimport { registerDataTools } from \"./data.js\";\nimport { registerSimulatorTools } from \"./simulators.js\";\nimport { registerTestTools } from \"./tests.js\";\nimport { registerTestRunTools } from \"./test-runs.js\";\nimport { registerSupportTools } from \"./support.js\";\n\nexport const READONLY_ENV = \"TIMETICK_MCP_READONLY\";\n\nexport function isReadOnlyMode(env: NodeJS.ProcessEnv = process.env): boolean {\n const value = env[READONLY_ENV]?.trim().toLowerCase();\n return value === \"1\" || value === \"true\";\n}\n\nfunction readOnlyView(server: McpServer): McpServer {\n return new Proxy(server, {\n get(target, prop, receiver) {\n if (prop !== \"registerTool\") return Reflect.get(target, prop, receiver);\n return (name: string, config: { annotations?: { readOnlyHint?: boolean } }, cb: unknown) =>\n config.annotations?.readOnlyHint === true\n ? (target.registerTool as (...args: unknown[]) => unknown)(name, config, cb)\n : undefined;\n },\n });\n}\n\nexport function registerTools(server: McpServer, options: { readOnly: boolean }) {\n const target = options.readOnly ? readOnlyView(server) : server;\n registerContextTools(target);\n registerDataTools(target);\n registerSimulatorTools(target);\n registerTestTools(target);\n registerTestRunTools(target);\n registerSupportTools(target);\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","protocolEnum","z","z","z","z","z"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timetick/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server for Timetick (https://app.timetick.io) platform",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"author": "Timetick <support@timetick.io>",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"type": "module",
|
|
21
21
|
"bin": {
|
|
22
|
-
"timetick-mcp": "
|
|
22
|
+
"timetick-mcp": "dist/index.js"
|
|
23
23
|
},
|
|
24
24
|
"main": "./dist/index.js",
|
|
25
25
|
"files": [
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsup",
|
|
38
|
+
"prepublishOnly": "yarn build",
|
|
38
39
|
"dev": "tsup --watch",
|
|
39
40
|
"typecheck": "tsc --noEmit",
|
|
40
41
|
"start": "node dist/index.js",
|