mmt-mcp 1.42.2-pre → 1.42.4
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/guides/offline-agent.md +1 -1
- package/dist/server.cjs +171 -95
- package/dist/server.js +171 -95
- package/package.json +1 -1
|
@@ -42,5 +42,5 @@ testlight docs api --pack full
|
|
|
42
42
|
`testlight docs` reads from, in order:
|
|
43
43
|
|
|
44
44
|
1. `MMT_GUIDES_DIR`
|
|
45
|
-
2. Guides bundled next to the CLI (`guides/` beside `cli.js`)
|
|
45
|
+
2. Guides bundled next to the CLI (`guides/` beside `cli.js` or inside the standalone binary)
|
|
46
46
|
3. Repo `docs/AI` when developing from source
|
package/dist/server.cjs
CHANGED
|
@@ -8299,8 +8299,41 @@ var init_grpcCore = __esm({
|
|
|
8299
8299
|
});
|
|
8300
8300
|
|
|
8301
8301
|
// src/index.ts
|
|
8302
|
+
var import_module = require("module");
|
|
8302
8303
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8303
8304
|
|
|
8305
|
+
// ../core/src/testlightHelp.ts
|
|
8306
|
+
var TESTLIGHT_NAME = "testlight";
|
|
8307
|
+
var TESTLIGHT_DESCRIPTION = "Multimeter CLI \u2014 run .mmt API tests, suites, and docs";
|
|
8308
|
+
var TESTLIGHT_HELP_AFTER = [
|
|
8309
|
+
"",
|
|
8310
|
+
"Run options:",
|
|
8311
|
+
" -q, --quiet Minimal output",
|
|
8312
|
+
" -o, --out <file> Write result JSON to file",
|
|
8313
|
+
" -i, --input <k=v...> Input variables (repeatable)",
|
|
8314
|
+
" -e, --env <k=v...> Environment variables (repeatable)",
|
|
8315
|
+
" -F, --env-file <path> Environment file (.mmt/.yaml)",
|
|
8316
|
+
" -P, --preset <name> Preset from env file (repeatable)",
|
|
8317
|
+
" -x, --example <name|#n> Named example or index (#1 is first)",
|
|
8318
|
+
" -p, --print-js Print generated JS before executing",
|
|
8319
|
+
" -r, --report <format> junit | mmt | html | md | md-detailed",
|
|
8320
|
+
" -R, --report-file <path> Report output path",
|
|
8321
|
+
"",
|
|
8322
|
+
"Examples:",
|
|
8323
|
+
" testlight run path/to/test.mmt",
|
|
8324
|
+
" testlight run path/to/test.mmt -F env.mmt -P runner.dev -P custom.prod",
|
|
8325
|
+
" testlight run path/to/suite.mmt --report html",
|
|
8326
|
+
" testlight scaffold test --from path/to/api.mmt",
|
|
8327
|
+
" testlight scaffold test --from path/to/api.mmt -o tests/api-smoke.mmt",
|
|
8328
|
+
" testlight docs test",
|
|
8329
|
+
" testlight validate path/to/test.mmt",
|
|
8330
|
+
" testlight suggest asserts --from path/to/api.mmt",
|
|
8331
|
+
" testlight update",
|
|
8332
|
+
" testlight update --check",
|
|
8333
|
+
"",
|
|
8334
|
+
"Run `testlight <command> --help` for command-specific options."
|
|
8335
|
+
].join("\n");
|
|
8336
|
+
|
|
8304
8337
|
// src/server.ts
|
|
8305
8338
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
8306
8339
|
var import_zod = require("zod");
|
|
@@ -20707,9 +20740,6 @@ function matchesSource(filePath, src) {
|
|
|
20707
20740
|
if (!fp || !s) {
|
|
20708
20741
|
return false;
|
|
20709
20742
|
}
|
|
20710
|
-
if (s === ".") {
|
|
20711
|
-
return true;
|
|
20712
|
-
}
|
|
20713
20743
|
if (/\.mmt$/i.test(s)) {
|
|
20714
20744
|
return fp.endsWith(s) || fp === s;
|
|
20715
20745
|
}
|
|
@@ -21102,9 +21132,6 @@ function matchesSource2(filePath, src) {
|
|
|
21102
21132
|
if (!fp || !s) {
|
|
21103
21133
|
return false;
|
|
21104
21134
|
}
|
|
21105
|
-
if (s === ".") {
|
|
21106
|
-
return true;
|
|
21107
|
-
}
|
|
21108
21135
|
if (/\.mmt$/i.test(s)) {
|
|
21109
21136
|
return fp.endsWith(s) || fp === s;
|
|
21110
21137
|
}
|
|
@@ -24327,6 +24354,88 @@ function parseDurationMs(duration) {
|
|
|
24327
24354
|
return void 0;
|
|
24328
24355
|
}
|
|
24329
24356
|
|
|
24357
|
+
// ../core/src/agentDocs.ts
|
|
24358
|
+
var FULL_TOPIC_FILES = {
|
|
24359
|
+
overview: ["agent-workflow.md", "general.md", "generate.md"],
|
|
24360
|
+
workflow: ["agent-workflow.md"],
|
|
24361
|
+
test: ["generate-test.md"],
|
|
24362
|
+
api: ["generate-api.md"],
|
|
24363
|
+
loadtest: ["generate-loadtest.md"],
|
|
24364
|
+
suite: ["generate-suite.md"],
|
|
24365
|
+
env: ["generate-env.md"],
|
|
24366
|
+
doc: ["generate-doc.md"],
|
|
24367
|
+
constraints: ["generate-test-skill.md"]
|
|
24368
|
+
};
|
|
24369
|
+
var MIN_TOPIC_FILES = {
|
|
24370
|
+
overview: ["min/overview.md"],
|
|
24371
|
+
workflow: ["min/workflow.md"],
|
|
24372
|
+
test: ["min/test.md"],
|
|
24373
|
+
api: ["min/api.md"],
|
|
24374
|
+
loadtest: ["min/loadtest.md"],
|
|
24375
|
+
suite: ["min/suite.md"],
|
|
24376
|
+
env: ["min/env.md"],
|
|
24377
|
+
doc: ["min/doc.md"],
|
|
24378
|
+
constraints: ["min/constraints.md"]
|
|
24379
|
+
};
|
|
24380
|
+
var AGENT_DOC_FILE_TOPICS = Object.keys(MIN_TOPIC_FILES);
|
|
24381
|
+
function filesForAgentDocTopic(topic, pack = "min") {
|
|
24382
|
+
if (topic === "offline") {
|
|
24383
|
+
return ["offline-agent.md"];
|
|
24384
|
+
}
|
|
24385
|
+
const table = pack === "full" ? FULL_TOPIC_FILES : MIN_TOPIC_FILES;
|
|
24386
|
+
if (topic === "all") {
|
|
24387
|
+
return Array.from(new Set(Object.values(table).flat()));
|
|
24388
|
+
}
|
|
24389
|
+
return table[topic];
|
|
24390
|
+
}
|
|
24391
|
+
function loadAgentDocSections(opts) {
|
|
24392
|
+
const topic = opts.topic || "overview";
|
|
24393
|
+
const pack = opts.pack || "min";
|
|
24394
|
+
const files = filesForAgentDocTopic(topic, pack);
|
|
24395
|
+
return {
|
|
24396
|
+
topic,
|
|
24397
|
+
pack,
|
|
24398
|
+
sections: files.map((fileName) => ({
|
|
24399
|
+
fileName,
|
|
24400
|
+
content: opts.readText(fileName)
|
|
24401
|
+
}))
|
|
24402
|
+
};
|
|
24403
|
+
}
|
|
24404
|
+
|
|
24405
|
+
// ../core/src/validateMmt.ts
|
|
24406
|
+
function validateMmtContent(content, filePath, expectedType) {
|
|
24407
|
+
const detectedType = fileType(filePath || "", content);
|
|
24408
|
+
if (expectedType && detectedType && detectedType !== expectedType) {
|
|
24409
|
+
return {
|
|
24410
|
+
valid: false,
|
|
24411
|
+
detectedType,
|
|
24412
|
+
errors: [`Expected type "${expectedType}" but detected "${detectedType}"`]
|
|
24413
|
+
};
|
|
24414
|
+
}
|
|
24415
|
+
const type = expectedType || detectedType;
|
|
24416
|
+
try {
|
|
24417
|
+
if (type === "api") {
|
|
24418
|
+
yamlToAPIStrict(content);
|
|
24419
|
+
} else if (type === "test" || !type) {
|
|
24420
|
+
yamlToTestStrict(content);
|
|
24421
|
+
} else {
|
|
24422
|
+
return {
|
|
24423
|
+
valid: false,
|
|
24424
|
+
detectedType,
|
|
24425
|
+
errors: [`Validation for type "${type}" is not implemented yet`]
|
|
24426
|
+
};
|
|
24427
|
+
}
|
|
24428
|
+
return { valid: true, detectedType: type || detectedType, errors: [] };
|
|
24429
|
+
} catch (error) {
|
|
24430
|
+
const message = error?.message || String(error);
|
|
24431
|
+
return {
|
|
24432
|
+
valid: false,
|
|
24433
|
+
detectedType,
|
|
24434
|
+
errors: message.split("\n").filter(Boolean)
|
|
24435
|
+
};
|
|
24436
|
+
}
|
|
24437
|
+
}
|
|
24438
|
+
|
|
24330
24439
|
// ../core/src/mmtFormatAst.ts
|
|
24331
24440
|
var import_yaml3 = __toESM(require("yaml"));
|
|
24332
24441
|
var ROOT_KEY_ORDER = {
|
|
@@ -26634,42 +26743,23 @@ function toWorkspaceRelative(workspaceRoot, fullPath) {
|
|
|
26634
26743
|
// src/resources/documentation.ts
|
|
26635
26744
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
26636
26745
|
var import_path3 = __toESM(require("path"), 1);
|
|
26637
|
-
var FULL_TOPIC_FILES = {
|
|
26638
|
-
overview: ["agent-workflow.md", "general.md", "generate.md"],
|
|
26639
|
-
workflow: ["agent-workflow.md"],
|
|
26640
|
-
test: ["generate-test.md"],
|
|
26641
|
-
api: ["generate-api.md"],
|
|
26642
|
-
loadtest: ["generate-loadtest.md"],
|
|
26643
|
-
suite: ["generate-suite.md"],
|
|
26644
|
-
env: ["generate-env.md"],
|
|
26645
|
-
doc: ["generate-doc.md"],
|
|
26646
|
-
constraints: ["generate-test-skill.md"]
|
|
26647
|
-
};
|
|
26648
|
-
var MIN_TOPIC_FILES = {
|
|
26649
|
-
overview: ["min/overview.md"],
|
|
26650
|
-
workflow: ["min/workflow.md"],
|
|
26651
|
-
test: ["min/test.md"],
|
|
26652
|
-
api: ["min/api.md"],
|
|
26653
|
-
loadtest: ["min/loadtest.md"],
|
|
26654
|
-
suite: ["min/suite.md"],
|
|
26655
|
-
env: ["min/env.md"],
|
|
26656
|
-
doc: ["min/doc.md"],
|
|
26657
|
-
constraints: ["min/constraints.md"]
|
|
26658
|
-
};
|
|
26659
26746
|
function readDocumentation(topic = "overview", pack = "min") {
|
|
26660
|
-
const
|
|
26661
|
-
|
|
26662
|
-
|
|
26663
|
-
|
|
26747
|
+
const loaded = loadAgentDocSections({
|
|
26748
|
+
topic,
|
|
26749
|
+
pack,
|
|
26750
|
+
readText: readGuideContent
|
|
26751
|
+
});
|
|
26752
|
+
const sections = loaded.sections.map((section) => {
|
|
26753
|
+
const resource = GUIDE_RESOURCES.find((item) => item.fileName === section.fileName);
|
|
26664
26754
|
return {
|
|
26665
|
-
name: resource?.name || fileName.replace(/\.md$/, "").replace(/^min\//, ""),
|
|
26666
|
-
fileName,
|
|
26667
|
-
content:
|
|
26755
|
+
name: resource?.name || section.fileName.replace(/\.md$/, "").replace(/^min\//, ""),
|
|
26756
|
+
fileName: section.fileName,
|
|
26757
|
+
content: section.content
|
|
26668
26758
|
};
|
|
26669
26759
|
});
|
|
26670
26760
|
return {
|
|
26671
|
-
topic,
|
|
26672
|
-
pack,
|
|
26761
|
+
topic: loaded.topic,
|
|
26762
|
+
pack: loaded.pack,
|
|
26673
26763
|
sections,
|
|
26674
26764
|
usage: pack === "min" ? 'Default min pack. Request pack: "full" only when you need rare syntax.' : 'Full documentation pack. Prefer pack: "min" for routine generate/modify.'
|
|
26675
26765
|
};
|
|
@@ -26769,33 +26859,6 @@ function listExamples(options) {
|
|
|
26769
26859
|
}
|
|
26770
26860
|
|
|
26771
26861
|
// src/tools/handlers.ts
|
|
26772
|
-
function detectType(content, filePath) {
|
|
26773
|
-
if (filePath) {
|
|
26774
|
-
return JSer_exports.fileType(filePath, content);
|
|
26775
|
-
}
|
|
26776
|
-
if (content.includes("type: api")) {
|
|
26777
|
-
return "api";
|
|
26778
|
-
}
|
|
26779
|
-
if (content.includes("type: test")) {
|
|
26780
|
-
return "test";
|
|
26781
|
-
}
|
|
26782
|
-
if (content.includes("type: env")) {
|
|
26783
|
-
return "env";
|
|
26784
|
-
}
|
|
26785
|
-
if (content.includes("type: suite")) {
|
|
26786
|
-
return "suite";
|
|
26787
|
-
}
|
|
26788
|
-
if (content.includes("type: doc")) {
|
|
26789
|
-
return "doc";
|
|
26790
|
-
}
|
|
26791
|
-
if (content.includes("type: server")) {
|
|
26792
|
-
return "server";
|
|
26793
|
-
}
|
|
26794
|
-
if (content.includes("type: loadtest")) {
|
|
26795
|
-
return "loadtest";
|
|
26796
|
-
}
|
|
26797
|
-
return null;
|
|
26798
|
-
}
|
|
26799
26862
|
function buildValidationSuggestions(errors) {
|
|
26800
26863
|
const suggestions = /* @__PURE__ */ new Set();
|
|
26801
26864
|
for (const error of errors) {
|
|
@@ -26824,37 +26887,11 @@ function buildValidationSuggestions(errors) {
|
|
|
26824
26887
|
return Array.from(suggestions);
|
|
26825
26888
|
}
|
|
26826
26889
|
function validateContent(content, filePath, expectedType) {
|
|
26827
|
-
const
|
|
26828
|
-
|
|
26829
|
-
|
|
26830
|
-
|
|
26831
|
-
|
|
26832
|
-
detectedType,
|
|
26833
|
-
errors,
|
|
26834
|
-
suggestions: buildValidationSuggestions(errors)
|
|
26835
|
-
};
|
|
26836
|
-
}
|
|
26837
|
-
try {
|
|
26838
|
-
const type = expectedType || detectedType;
|
|
26839
|
-
if (type === "api") {
|
|
26840
|
-
apiParsePack_exports.yamlToAPIStrict(content);
|
|
26841
|
-
} else if (type === "test" || !type) {
|
|
26842
|
-
testParsePack_exports.yamlToTestStrict(content);
|
|
26843
|
-
} else {
|
|
26844
|
-
const errors = [`Validation for type "${type}" is not implemented yet`];
|
|
26845
|
-
return { valid: false, detectedType, errors, suggestions: buildValidationSuggestions(errors) };
|
|
26846
|
-
}
|
|
26847
|
-
return { valid: true, detectedType: type || detectedType, errors: [], suggestions: [] };
|
|
26848
|
-
} catch (error) {
|
|
26849
|
-
const message = error?.message || String(error);
|
|
26850
|
-
const errors = message.split("\n").filter(Boolean);
|
|
26851
|
-
return {
|
|
26852
|
-
valid: false,
|
|
26853
|
-
detectedType,
|
|
26854
|
-
errors,
|
|
26855
|
-
suggestions: buildValidationSuggestions(errors)
|
|
26856
|
-
};
|
|
26857
|
-
}
|
|
26890
|
+
const result = validateMmtContent(content, filePath, expectedType);
|
|
26891
|
+
return {
|
|
26892
|
+
...result,
|
|
26893
|
+
suggestions: result.valid ? [] : buildValidationSuggestions(result.errors)
|
|
26894
|
+
};
|
|
26858
26895
|
}
|
|
26859
26896
|
async function handleReadDocumentation(args) {
|
|
26860
26897
|
try {
|
|
@@ -27484,7 +27521,46 @@ function createMmtMcpServer() {
|
|
|
27484
27521
|
}
|
|
27485
27522
|
|
|
27486
27523
|
// src/index.ts
|
|
27524
|
+
var requireFromHere = (0, import_module.createRequire)(__filename);
|
|
27525
|
+
function resolveMcpVersion() {
|
|
27526
|
+
try {
|
|
27527
|
+
const version = requireFromHere("../package.json").version;
|
|
27528
|
+
if (typeof version === "string" && version) {
|
|
27529
|
+
return version;
|
|
27530
|
+
}
|
|
27531
|
+
} catch {
|
|
27532
|
+
}
|
|
27533
|
+
return "0.0.0";
|
|
27534
|
+
}
|
|
27535
|
+
function printHelp() {
|
|
27536
|
+
const version = resolveMcpVersion();
|
|
27537
|
+
process.stdout.write([
|
|
27538
|
+
`mmt-mcp ${version}`,
|
|
27539
|
+
"",
|
|
27540
|
+
"Multimeter MCP server over stdio.",
|
|
27541
|
+
"Tools: read_documentation, list_examples, discover_api, api_card,",
|
|
27542
|
+
" scaffold_test, suggest_assertions, validate, format, run",
|
|
27543
|
+
"",
|
|
27544
|
+
"Usage: npx -y mmt-mcp",
|
|
27545
|
+
"Docs: https://mmt.dev/docs/features/mcp",
|
|
27546
|
+
"",
|
|
27547
|
+
`${TESTLIGHT_NAME} \u2014 ${TESTLIGHT_DESCRIPTION}`,
|
|
27548
|
+
"npm (mmt-testlight) and GitHub/Homebrew binaries share this CLI:",
|
|
27549
|
+
TESTLIGHT_HELP_AFTER,
|
|
27550
|
+
""
|
|
27551
|
+
].join("\n"));
|
|
27552
|
+
}
|
|
27487
27553
|
async function main() {
|
|
27554
|
+
const args = process.argv.slice(2);
|
|
27555
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
27556
|
+
printHelp();
|
|
27557
|
+
return;
|
|
27558
|
+
}
|
|
27559
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
27560
|
+
process.stdout.write(`${resolveMcpVersion()}
|
|
27561
|
+
`);
|
|
27562
|
+
return;
|
|
27563
|
+
}
|
|
27488
27564
|
const server = createMmtMcpServer();
|
|
27489
27565
|
const transport = new import_stdio.StdioServerTransport();
|
|
27490
27566
|
await server.connect(transport);
|
package/dist/server.js
CHANGED
|
@@ -8299,8 +8299,41 @@ var init_grpcCore = __esm({
|
|
|
8299
8299
|
});
|
|
8300
8300
|
|
|
8301
8301
|
// src/index.ts
|
|
8302
|
+
var import_module = require("module");
|
|
8302
8303
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8303
8304
|
|
|
8305
|
+
// ../core/src/testlightHelp.ts
|
|
8306
|
+
var TESTLIGHT_NAME = "testlight";
|
|
8307
|
+
var TESTLIGHT_DESCRIPTION = "Multimeter CLI \u2014 run .mmt API tests, suites, and docs";
|
|
8308
|
+
var TESTLIGHT_HELP_AFTER = [
|
|
8309
|
+
"",
|
|
8310
|
+
"Run options:",
|
|
8311
|
+
" -q, --quiet Minimal output",
|
|
8312
|
+
" -o, --out <file> Write result JSON to file",
|
|
8313
|
+
" -i, --input <k=v...> Input variables (repeatable)",
|
|
8314
|
+
" -e, --env <k=v...> Environment variables (repeatable)",
|
|
8315
|
+
" -F, --env-file <path> Environment file (.mmt/.yaml)",
|
|
8316
|
+
" -P, --preset <name> Preset from env file (repeatable)",
|
|
8317
|
+
" -x, --example <name|#n> Named example or index (#1 is first)",
|
|
8318
|
+
" -p, --print-js Print generated JS before executing",
|
|
8319
|
+
" -r, --report <format> junit | mmt | html | md | md-detailed",
|
|
8320
|
+
" -R, --report-file <path> Report output path",
|
|
8321
|
+
"",
|
|
8322
|
+
"Examples:",
|
|
8323
|
+
" testlight run path/to/test.mmt",
|
|
8324
|
+
" testlight run path/to/test.mmt -F env.mmt -P runner.dev -P custom.prod",
|
|
8325
|
+
" testlight run path/to/suite.mmt --report html",
|
|
8326
|
+
" testlight scaffold test --from path/to/api.mmt",
|
|
8327
|
+
" testlight scaffold test --from path/to/api.mmt -o tests/api-smoke.mmt",
|
|
8328
|
+
" testlight docs test",
|
|
8329
|
+
" testlight validate path/to/test.mmt",
|
|
8330
|
+
" testlight suggest asserts --from path/to/api.mmt",
|
|
8331
|
+
" testlight update",
|
|
8332
|
+
" testlight update --check",
|
|
8333
|
+
"",
|
|
8334
|
+
"Run `testlight <command> --help` for command-specific options."
|
|
8335
|
+
].join("\n");
|
|
8336
|
+
|
|
8304
8337
|
// src/server.ts
|
|
8305
8338
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
8306
8339
|
var import_zod = require("zod");
|
|
@@ -20707,9 +20740,6 @@ function matchesSource(filePath, src) {
|
|
|
20707
20740
|
if (!fp || !s) {
|
|
20708
20741
|
return false;
|
|
20709
20742
|
}
|
|
20710
|
-
if (s === ".") {
|
|
20711
|
-
return true;
|
|
20712
|
-
}
|
|
20713
20743
|
if (/\.mmt$/i.test(s)) {
|
|
20714
20744
|
return fp.endsWith(s) || fp === s;
|
|
20715
20745
|
}
|
|
@@ -21102,9 +21132,6 @@ function matchesSource2(filePath, src) {
|
|
|
21102
21132
|
if (!fp || !s) {
|
|
21103
21133
|
return false;
|
|
21104
21134
|
}
|
|
21105
|
-
if (s === ".") {
|
|
21106
|
-
return true;
|
|
21107
|
-
}
|
|
21108
21135
|
if (/\.mmt$/i.test(s)) {
|
|
21109
21136
|
return fp.endsWith(s) || fp === s;
|
|
21110
21137
|
}
|
|
@@ -24327,6 +24354,88 @@ function parseDurationMs(duration) {
|
|
|
24327
24354
|
return void 0;
|
|
24328
24355
|
}
|
|
24329
24356
|
|
|
24357
|
+
// ../core/src/agentDocs.ts
|
|
24358
|
+
var FULL_TOPIC_FILES = {
|
|
24359
|
+
overview: ["agent-workflow.md", "general.md", "generate.md"],
|
|
24360
|
+
workflow: ["agent-workflow.md"],
|
|
24361
|
+
test: ["generate-test.md"],
|
|
24362
|
+
api: ["generate-api.md"],
|
|
24363
|
+
loadtest: ["generate-loadtest.md"],
|
|
24364
|
+
suite: ["generate-suite.md"],
|
|
24365
|
+
env: ["generate-env.md"],
|
|
24366
|
+
doc: ["generate-doc.md"],
|
|
24367
|
+
constraints: ["generate-test-skill.md"]
|
|
24368
|
+
};
|
|
24369
|
+
var MIN_TOPIC_FILES = {
|
|
24370
|
+
overview: ["min/overview.md"],
|
|
24371
|
+
workflow: ["min/workflow.md"],
|
|
24372
|
+
test: ["min/test.md"],
|
|
24373
|
+
api: ["min/api.md"],
|
|
24374
|
+
loadtest: ["min/loadtest.md"],
|
|
24375
|
+
suite: ["min/suite.md"],
|
|
24376
|
+
env: ["min/env.md"],
|
|
24377
|
+
doc: ["min/doc.md"],
|
|
24378
|
+
constraints: ["min/constraints.md"]
|
|
24379
|
+
};
|
|
24380
|
+
var AGENT_DOC_FILE_TOPICS = Object.keys(MIN_TOPIC_FILES);
|
|
24381
|
+
function filesForAgentDocTopic(topic, pack = "min") {
|
|
24382
|
+
if (topic === "offline") {
|
|
24383
|
+
return ["offline-agent.md"];
|
|
24384
|
+
}
|
|
24385
|
+
const table = pack === "full" ? FULL_TOPIC_FILES : MIN_TOPIC_FILES;
|
|
24386
|
+
if (topic === "all") {
|
|
24387
|
+
return Array.from(new Set(Object.values(table).flat()));
|
|
24388
|
+
}
|
|
24389
|
+
return table[topic];
|
|
24390
|
+
}
|
|
24391
|
+
function loadAgentDocSections(opts) {
|
|
24392
|
+
const topic = opts.topic || "overview";
|
|
24393
|
+
const pack = opts.pack || "min";
|
|
24394
|
+
const files = filesForAgentDocTopic(topic, pack);
|
|
24395
|
+
return {
|
|
24396
|
+
topic,
|
|
24397
|
+
pack,
|
|
24398
|
+
sections: files.map((fileName) => ({
|
|
24399
|
+
fileName,
|
|
24400
|
+
content: opts.readText(fileName)
|
|
24401
|
+
}))
|
|
24402
|
+
};
|
|
24403
|
+
}
|
|
24404
|
+
|
|
24405
|
+
// ../core/src/validateMmt.ts
|
|
24406
|
+
function validateMmtContent(content, filePath, expectedType) {
|
|
24407
|
+
const detectedType = fileType(filePath || "", content);
|
|
24408
|
+
if (expectedType && detectedType && detectedType !== expectedType) {
|
|
24409
|
+
return {
|
|
24410
|
+
valid: false,
|
|
24411
|
+
detectedType,
|
|
24412
|
+
errors: [`Expected type "${expectedType}" but detected "${detectedType}"`]
|
|
24413
|
+
};
|
|
24414
|
+
}
|
|
24415
|
+
const type = expectedType || detectedType;
|
|
24416
|
+
try {
|
|
24417
|
+
if (type === "api") {
|
|
24418
|
+
yamlToAPIStrict(content);
|
|
24419
|
+
} else if (type === "test" || !type) {
|
|
24420
|
+
yamlToTestStrict(content);
|
|
24421
|
+
} else {
|
|
24422
|
+
return {
|
|
24423
|
+
valid: false,
|
|
24424
|
+
detectedType,
|
|
24425
|
+
errors: [`Validation for type "${type}" is not implemented yet`]
|
|
24426
|
+
};
|
|
24427
|
+
}
|
|
24428
|
+
return { valid: true, detectedType: type || detectedType, errors: [] };
|
|
24429
|
+
} catch (error) {
|
|
24430
|
+
const message = error?.message || String(error);
|
|
24431
|
+
return {
|
|
24432
|
+
valid: false,
|
|
24433
|
+
detectedType,
|
|
24434
|
+
errors: message.split("\n").filter(Boolean)
|
|
24435
|
+
};
|
|
24436
|
+
}
|
|
24437
|
+
}
|
|
24438
|
+
|
|
24330
24439
|
// ../core/src/mmtFormatAst.ts
|
|
24331
24440
|
var import_yaml3 = __toESM(require("yaml"));
|
|
24332
24441
|
var ROOT_KEY_ORDER = {
|
|
@@ -26634,42 +26743,23 @@ function toWorkspaceRelative(workspaceRoot, fullPath) {
|
|
|
26634
26743
|
// src/resources/documentation.ts
|
|
26635
26744
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
26636
26745
|
var import_path3 = __toESM(require("path"), 1);
|
|
26637
|
-
var FULL_TOPIC_FILES = {
|
|
26638
|
-
overview: ["agent-workflow.md", "general.md", "generate.md"],
|
|
26639
|
-
workflow: ["agent-workflow.md"],
|
|
26640
|
-
test: ["generate-test.md"],
|
|
26641
|
-
api: ["generate-api.md"],
|
|
26642
|
-
loadtest: ["generate-loadtest.md"],
|
|
26643
|
-
suite: ["generate-suite.md"],
|
|
26644
|
-
env: ["generate-env.md"],
|
|
26645
|
-
doc: ["generate-doc.md"],
|
|
26646
|
-
constraints: ["generate-test-skill.md"]
|
|
26647
|
-
};
|
|
26648
|
-
var MIN_TOPIC_FILES = {
|
|
26649
|
-
overview: ["min/overview.md"],
|
|
26650
|
-
workflow: ["min/workflow.md"],
|
|
26651
|
-
test: ["min/test.md"],
|
|
26652
|
-
api: ["min/api.md"],
|
|
26653
|
-
loadtest: ["min/loadtest.md"],
|
|
26654
|
-
suite: ["min/suite.md"],
|
|
26655
|
-
env: ["min/env.md"],
|
|
26656
|
-
doc: ["min/doc.md"],
|
|
26657
|
-
constraints: ["min/constraints.md"]
|
|
26658
|
-
};
|
|
26659
26746
|
function readDocumentation(topic = "overview", pack = "min") {
|
|
26660
|
-
const
|
|
26661
|
-
|
|
26662
|
-
|
|
26663
|
-
|
|
26747
|
+
const loaded = loadAgentDocSections({
|
|
26748
|
+
topic,
|
|
26749
|
+
pack,
|
|
26750
|
+
readText: readGuideContent
|
|
26751
|
+
});
|
|
26752
|
+
const sections = loaded.sections.map((section) => {
|
|
26753
|
+
const resource = GUIDE_RESOURCES.find((item) => item.fileName === section.fileName);
|
|
26664
26754
|
return {
|
|
26665
|
-
name: resource?.name || fileName.replace(/\.md$/, "").replace(/^min\//, ""),
|
|
26666
|
-
fileName,
|
|
26667
|
-
content:
|
|
26755
|
+
name: resource?.name || section.fileName.replace(/\.md$/, "").replace(/^min\//, ""),
|
|
26756
|
+
fileName: section.fileName,
|
|
26757
|
+
content: section.content
|
|
26668
26758
|
};
|
|
26669
26759
|
});
|
|
26670
26760
|
return {
|
|
26671
|
-
topic,
|
|
26672
|
-
pack,
|
|
26761
|
+
topic: loaded.topic,
|
|
26762
|
+
pack: loaded.pack,
|
|
26673
26763
|
sections,
|
|
26674
26764
|
usage: pack === "min" ? 'Default min pack. Request pack: "full" only when you need rare syntax.' : 'Full documentation pack. Prefer pack: "min" for routine generate/modify.'
|
|
26675
26765
|
};
|
|
@@ -26769,33 +26859,6 @@ function listExamples(options) {
|
|
|
26769
26859
|
}
|
|
26770
26860
|
|
|
26771
26861
|
// src/tools/handlers.ts
|
|
26772
|
-
function detectType(content, filePath) {
|
|
26773
|
-
if (filePath) {
|
|
26774
|
-
return JSer_exports.fileType(filePath, content);
|
|
26775
|
-
}
|
|
26776
|
-
if (content.includes("type: api")) {
|
|
26777
|
-
return "api";
|
|
26778
|
-
}
|
|
26779
|
-
if (content.includes("type: test")) {
|
|
26780
|
-
return "test";
|
|
26781
|
-
}
|
|
26782
|
-
if (content.includes("type: env")) {
|
|
26783
|
-
return "env";
|
|
26784
|
-
}
|
|
26785
|
-
if (content.includes("type: suite")) {
|
|
26786
|
-
return "suite";
|
|
26787
|
-
}
|
|
26788
|
-
if (content.includes("type: doc")) {
|
|
26789
|
-
return "doc";
|
|
26790
|
-
}
|
|
26791
|
-
if (content.includes("type: server")) {
|
|
26792
|
-
return "server";
|
|
26793
|
-
}
|
|
26794
|
-
if (content.includes("type: loadtest")) {
|
|
26795
|
-
return "loadtest";
|
|
26796
|
-
}
|
|
26797
|
-
return null;
|
|
26798
|
-
}
|
|
26799
26862
|
function buildValidationSuggestions(errors) {
|
|
26800
26863
|
const suggestions = /* @__PURE__ */ new Set();
|
|
26801
26864
|
for (const error of errors) {
|
|
@@ -26824,37 +26887,11 @@ function buildValidationSuggestions(errors) {
|
|
|
26824
26887
|
return Array.from(suggestions);
|
|
26825
26888
|
}
|
|
26826
26889
|
function validateContent(content, filePath, expectedType) {
|
|
26827
|
-
const
|
|
26828
|
-
|
|
26829
|
-
|
|
26830
|
-
|
|
26831
|
-
|
|
26832
|
-
detectedType,
|
|
26833
|
-
errors,
|
|
26834
|
-
suggestions: buildValidationSuggestions(errors)
|
|
26835
|
-
};
|
|
26836
|
-
}
|
|
26837
|
-
try {
|
|
26838
|
-
const type = expectedType || detectedType;
|
|
26839
|
-
if (type === "api") {
|
|
26840
|
-
apiParsePack_exports.yamlToAPIStrict(content);
|
|
26841
|
-
} else if (type === "test" || !type) {
|
|
26842
|
-
testParsePack_exports.yamlToTestStrict(content);
|
|
26843
|
-
} else {
|
|
26844
|
-
const errors = [`Validation for type "${type}" is not implemented yet`];
|
|
26845
|
-
return { valid: false, detectedType, errors, suggestions: buildValidationSuggestions(errors) };
|
|
26846
|
-
}
|
|
26847
|
-
return { valid: true, detectedType: type || detectedType, errors: [], suggestions: [] };
|
|
26848
|
-
} catch (error) {
|
|
26849
|
-
const message = error?.message || String(error);
|
|
26850
|
-
const errors = message.split("\n").filter(Boolean);
|
|
26851
|
-
return {
|
|
26852
|
-
valid: false,
|
|
26853
|
-
detectedType,
|
|
26854
|
-
errors,
|
|
26855
|
-
suggestions: buildValidationSuggestions(errors)
|
|
26856
|
-
};
|
|
26857
|
-
}
|
|
26890
|
+
const result = validateMmtContent(content, filePath, expectedType);
|
|
26891
|
+
return {
|
|
26892
|
+
...result,
|
|
26893
|
+
suggestions: result.valid ? [] : buildValidationSuggestions(result.errors)
|
|
26894
|
+
};
|
|
26858
26895
|
}
|
|
26859
26896
|
async function handleReadDocumentation(args) {
|
|
26860
26897
|
try {
|
|
@@ -27484,7 +27521,46 @@ function createMmtMcpServer() {
|
|
|
27484
27521
|
}
|
|
27485
27522
|
|
|
27486
27523
|
// src/index.ts
|
|
27524
|
+
var requireFromHere = (0, import_module.createRequire)(__filename);
|
|
27525
|
+
function resolveMcpVersion() {
|
|
27526
|
+
try {
|
|
27527
|
+
const version = requireFromHere("../package.json").version;
|
|
27528
|
+
if (typeof version === "string" && version) {
|
|
27529
|
+
return version;
|
|
27530
|
+
}
|
|
27531
|
+
} catch {
|
|
27532
|
+
}
|
|
27533
|
+
return "0.0.0";
|
|
27534
|
+
}
|
|
27535
|
+
function printHelp() {
|
|
27536
|
+
const version = resolveMcpVersion();
|
|
27537
|
+
process.stdout.write([
|
|
27538
|
+
`mmt-mcp ${version}`,
|
|
27539
|
+
"",
|
|
27540
|
+
"Multimeter MCP server over stdio.",
|
|
27541
|
+
"Tools: read_documentation, list_examples, discover_api, api_card,",
|
|
27542
|
+
" scaffold_test, suggest_assertions, validate, format, run",
|
|
27543
|
+
"",
|
|
27544
|
+
"Usage: npx -y mmt-mcp",
|
|
27545
|
+
"Docs: https://mmt.dev/docs/features/mcp",
|
|
27546
|
+
"",
|
|
27547
|
+
`${TESTLIGHT_NAME} \u2014 ${TESTLIGHT_DESCRIPTION}`,
|
|
27548
|
+
"npm (mmt-testlight) and GitHub/Homebrew binaries share this CLI:",
|
|
27549
|
+
TESTLIGHT_HELP_AFTER,
|
|
27550
|
+
""
|
|
27551
|
+
].join("\n"));
|
|
27552
|
+
}
|
|
27487
27553
|
async function main() {
|
|
27554
|
+
const args = process.argv.slice(2);
|
|
27555
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
27556
|
+
printHelp();
|
|
27557
|
+
return;
|
|
27558
|
+
}
|
|
27559
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
27560
|
+
process.stdout.write(`${resolveMcpVersion()}
|
|
27561
|
+
`);
|
|
27562
|
+
return;
|
|
27563
|
+
}
|
|
27488
27564
|
const server = createMmtMcpServer();
|
|
27489
27565
|
const transport = new import_stdio.StdioServerTransport();
|
|
27490
27566
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mmt-mcp",
|
|
3
|
-
"version": "1.42.
|
|
3
|
+
"version": "1.42.4",
|
|
4
4
|
"description": "Multimeter MCP server for Cursor, Copilot, and Claude. Scaffold, validate, format, and run YAML .mmt API tests. Do not invent .mmt syntax.",
|
|
5
5
|
"mcpName": "io.github.mshobeyri/multimeter",
|
|
6
6
|
"type": "module",
|