meguro-mcp 0.2.7 → 0.2.9
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/CHANGELOG.md +19 -0
- package/README.md +6 -5
- package/package.json +1 -1
- package/src/docs.mjs +139 -4
- package/src/server.mjs +1 -1
- package/src/tools.mjs +164 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `meguro-mcp` are recorded here. Versions follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.2.9 — 2026-08-10
|
|
6
|
+
|
|
7
|
+
- Keeps the full real-store history-run family in the public STDIO registry while the hosted OAuth
|
|
8
|
+
surface now teaches and exposes only the practice-world run lane.
|
|
9
|
+
- Adds immutable getting-started v7, product-guide v4, and documentation-index v2 resources with
|
|
10
|
+
hosted-first control-plane guidance, Gate-policy v2 citations, and one honest STDIO history-lane
|
|
11
|
+
bridge.
|
|
12
|
+
- Reconciles `usage_read` with the exempt auto-provisioned sample store shown by `stores_list`, while
|
|
13
|
+
preserving every existing tool name, input schema, and prior documentation byte stream.
|
|
14
|
+
|
|
15
|
+
## 0.2.8 — 2026-08-09
|
|
16
|
+
|
|
17
|
+
- Adds `practice_runs_list` so a cold MCP-only evaluator can discover existing practice attempts
|
|
18
|
+
without guessing a store or run identifier.
|
|
19
|
+
- Exposes `admin_schema` through the hosted-safe registry, corrects hosted OAuth connection
|
|
20
|
+
guidance, and adds immutable documentation currency/index metadata.
|
|
21
|
+
- Changes no earlier immutable documentation byte stream and carries no unrelated tool or protocol
|
|
22
|
+
behavior beyond the landed MEG-768 cold-walk corrections.
|
|
23
|
+
|
|
5
24
|
## 0.2.7 — 2026-08-08
|
|
6
25
|
|
|
7
26
|
- Adds the optional `storeId` selector to `gate_evaluate` and `gate_verdict`, preserving every
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Console provides fast trusted proof and evidence inspection; the agency agent no
|
|
|
43
43
|
|
|
44
44
|
<!-- BEGIN GENERATED MCP TOOL TABLE -->
|
|
45
45
|
<!-- Run `npm run docs:tools --workspace meguro-mcp` to refresh this section from `tools/list`. -->
|
|
46
|
-
This table is generated from the server's live `tools/list` response (
|
|
46
|
+
This table is generated from the server's live `tools/list` response (47 tools).
|
|
47
47
|
|
|
48
48
|
| Tool | Title | Behavior annotations |
|
|
49
49
|
|---|---|---|
|
|
@@ -84,6 +84,7 @@ This table is generated from the server's live `tools/list` response (46 tools).
|
|
|
84
84
|
| `exam_status` | Read Shopify Exam status | read-only · non-destructive · idempotent · closed-world |
|
|
85
85
|
| `exam_report` | Read a Shopify Exam receipt | read-only · non-destructive · idempotent · closed-world |
|
|
86
86
|
| `practice_run_start` | Start a practice run | read-write · non-destructive · non-idempotent · closed-world |
|
|
87
|
+
| `practice_runs_list` | List practice runs | read-only · non-destructive · idempotent · closed-world |
|
|
87
88
|
| `practice_run_status` | Read practice-run status | read-only · non-destructive · idempotent · closed-world |
|
|
88
89
|
| `practice_run_checkpoint` | Capture a practice-run checkpoint | read-write · non-destructive · non-idempotent · closed-world |
|
|
89
90
|
| `practice_run_advance` | Advance store time | read-write · non-destructive · non-idempotent · closed-world |
|
|
@@ -181,11 +182,11 @@ See [the agency quickstart](../../docs/agency-practice-run-quickstart.md) and [H
|
|
|
181
182
|
## Advanced: CI or local STDIO
|
|
182
183
|
|
|
183
184
|
Use the public STDIO package for CI, local automation, or clients without hosted Streamable HTTP and
|
|
184
|
-
OAuth support. It requires a workspace-bound `meg_sk_…` API key and exposes the full
|
|
185
|
+
OAuth support. It requires a workspace-bound `meg_sk_…` API key and exposes the full 47-tool local
|
|
185
186
|
surface. Pin the exact public version in client configuration so a quickstart stays reproducible:
|
|
186
187
|
|
|
187
188
|
```bash
|
|
188
|
-
npx -y meguro-mcp@0.2.
|
|
189
|
+
npx -y meguro-mcp@0.2.9
|
|
189
190
|
```
|
|
190
191
|
|
|
191
192
|
### Environment
|
|
@@ -203,7 +204,7 @@ claude mcp add meguro \
|
|
|
203
204
|
-e MEGURO_API_BASE_URL=https://api-dev.meguro.io \
|
|
204
205
|
-e MEGURO_API_TOKEN=meg_sk_... \
|
|
205
206
|
-e MEGURO_DASHBOARD_URL=https://... \
|
|
206
|
-
-- npx -y meguro-mcp@0.2.
|
|
207
|
+
-- npx -y meguro-mcp@0.2.9
|
|
207
208
|
```
|
|
208
209
|
|
|
209
210
|
### Register — Cursor (`.cursor/mcp.json`)
|
|
@@ -213,7 +214,7 @@ claude mcp add meguro \
|
|
|
213
214
|
"mcpServers": {
|
|
214
215
|
"meguro": {
|
|
215
216
|
"command": "npx",
|
|
216
|
-
"args": ["-y", "meguro-mcp@0.2.
|
|
217
|
+
"args": ["-y", "meguro-mcp@0.2.9"],
|
|
217
218
|
"env": {
|
|
218
219
|
"MEGURO_API_BASE_URL": "https://api-dev.meguro.io",
|
|
219
220
|
"MEGURO_API_TOKEN": "meg_sk_...",
|
package/package.json
CHANGED
package/src/docs.mjs
CHANGED
|
@@ -20,9 +20,11 @@ const GETTING_STARTED_LATEST_VERSION = 3;
|
|
|
20
20
|
const GETTING_STARTED_V4_VERSION = 4;
|
|
21
21
|
const GETTING_STARTED_V5_VERSION = 5;
|
|
22
22
|
const GETTING_STARTED_V6_VERSION = 6;
|
|
23
|
+
const GETTING_STARTED_V7_VERSION = 7;
|
|
23
24
|
const PRODUCT_GUIDE_VERSION = 1;
|
|
24
25
|
const PRODUCT_GUIDE_V2_VERSION = 2;
|
|
25
26
|
const PRODUCT_GUIDE_V3_VERSION = 3;
|
|
27
|
+
const PRODUCT_GUIDE_V4_VERSION = 4;
|
|
26
28
|
const RECEIPT_GUIDE_URI = `meguro://docs/receipt-guide/v${RECEIPT_GUIDE_VERSION}`;
|
|
27
29
|
const RECEIPT_GUIDE_V2_URI = `meguro://docs/receipt-guide/v${RECEIPT_GUIDE_V2_VERSION}`;
|
|
28
30
|
const RECEIPT_GUIDE_V3_URI = `meguro://docs/receipt-guide/v${RECEIPT_GUIDE_V3_VERSION}`;
|
|
@@ -38,11 +40,61 @@ const GETTING_STARTED_LATEST_URI = `meguro://docs/getting-started/v${GETTING_STA
|
|
|
38
40
|
const GETTING_STARTED_V4_URI = `meguro://docs/getting-started/v${GETTING_STARTED_V4_VERSION}`;
|
|
39
41
|
const GETTING_STARTED_V5_URI = `meguro://docs/getting-started/v${GETTING_STARTED_V5_VERSION}`;
|
|
40
42
|
const GETTING_STARTED_V6_URI = `meguro://docs/getting-started/v${GETTING_STARTED_V6_VERSION}`;
|
|
43
|
+
const GETTING_STARTED_V7_URI = `meguro://docs/getting-started/v${GETTING_STARTED_V7_VERSION}`;
|
|
41
44
|
const PRODUCT_GUIDE_URI = `meguro://docs/product-guide/v${PRODUCT_GUIDE_VERSION}`;
|
|
42
45
|
const PRODUCT_GUIDE_V2_URI = `meguro://docs/product-guide/v${PRODUCT_GUIDE_V2_VERSION}`;
|
|
43
46
|
const PRODUCT_GUIDE_V3_URI = `meguro://docs/product-guide/v${PRODUCT_GUIDE_V3_VERSION}`;
|
|
47
|
+
const PRODUCT_GUIDE_V4_URI = `meguro://docs/product-guide/v${PRODUCT_GUIDE_V4_VERSION}`;
|
|
48
|
+
export const DOCUMENTATION_INDEX_URI = 'meguro://docs/index/v1';
|
|
49
|
+
export const DOCUMENTATION_INDEX_V2_URI = 'meguro://docs/index/v2';
|
|
50
|
+
|
|
51
|
+
const DOCUMENTATION_CURRENCY_V1 = deepFreeze({
|
|
52
|
+
indexVersion: 1,
|
|
53
|
+
currentUriByTopic: {
|
|
54
|
+
'gate-policy': GATE_POLICY_V2_URI,
|
|
55
|
+
'getting-started': GETTING_STARTED_V6_URI,
|
|
56
|
+
index: DOCUMENTATION_INDEX_URI,
|
|
57
|
+
'product-guide': PRODUCT_GUIDE_V3_URI,
|
|
58
|
+
'receipt-guide': RECEIPT_GUIDE_V7_URI,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
const DOCUMENTATION_CURRENCY_V2 = deepFreeze({
|
|
62
|
+
indexVersion: 2,
|
|
63
|
+
currentUriByTopic: {
|
|
64
|
+
'gate-policy': GATE_POLICY_V2_URI,
|
|
65
|
+
'getting-started': GETTING_STARTED_V7_URI,
|
|
66
|
+
index: DOCUMENTATION_INDEX_V2_URI,
|
|
67
|
+
'product-guide': PRODUCT_GUIDE_V4_URI,
|
|
68
|
+
'receipt-guide': RECEIPT_GUIDE_V7_URI,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const CURRENT_DOCUMENTATION_CURRENCY = DOCUMENTATION_CURRENCY_V2;
|
|
72
|
+
|
|
73
|
+
function documentationVersionFromUri(uri) {
|
|
74
|
+
const match = /\/v([1-9][0-9]*)$/u.exec(uri);
|
|
75
|
+
if (!match) throw new Error(`Documentation URI has no immutable version: ${uri}`);
|
|
76
|
+
return Number(match[1]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function documentationIndexText(currency, publishedUri = DOCUMENTATION_INDEX_URI) {
|
|
80
|
+
const rows = Object.entries(currency.currentUriByTopic).sort(([left], [right]) => codepointCompare(left, right));
|
|
81
|
+
return [
|
|
82
|
+
`# Meguro documentation index v${currency.indexVersion}`,
|
|
83
|
+
'',
|
|
84
|
+
`Published URI: \`${publishedUri}\``,
|
|
85
|
+
'',
|
|
86
|
+
'This immutable index records the current published version of every documentation family at issuance.',
|
|
87
|
+
'Use the `meguro/status` annotations from `resources/list` for live currency; cited versioned resources never change.',
|
|
88
|
+
'',
|
|
89
|
+
'| Family | Current version | Current resource |',
|
|
90
|
+
'| --- | ---: | --- |',
|
|
91
|
+
...rows.map(([topic, uri]) => `| ${topic} | v${documentationVersionFromUri(uri)} | ${uri} |`),
|
|
92
|
+
].join('\n');
|
|
93
|
+
}
|
|
44
94
|
|
|
45
|
-
|
|
95
|
+
const CURRENT_GETTING_STARTED_URI = CURRENT_DOCUMENTATION_CURRENCY.currentUriByTopic['getting-started'];
|
|
96
|
+
const CURRENT_PRODUCT_GUIDE_URI = CURRENT_DOCUMENTATION_CURRENCY.currentUriByTopic['product-guide'];
|
|
97
|
+
export const MCP_INITIALIZE_INSTRUCTIONS = `Start with \`${CURRENT_GETTING_STARTED_URI}\` or call \`docs_read({ topic: "getting-started", version: ${documentationVersionFromUri(CURRENT_GETTING_STARTED_URI)} })\`; for general Meguro questions, read \`${CURRENT_PRODUCT_GUIDE_URI}\` or call \`docs_read({ topic: "product-guide", version: ${documentationVersionFromUri(CURRENT_PRODUCT_GUIDE_URI)} })\`.`;
|
|
46
98
|
export const PRODUCT_GUIDE_SHA256 = 'e5450c1b4181cec4d6ed0a498dbff1cb25d2e223ff2228928aecbbce9674f074';
|
|
47
99
|
|
|
48
100
|
function deepFreeze(value) {
|
|
@@ -1211,6 +1263,38 @@ a plan, consent for the human, or reveal a credential that the human has not gra
|
|
|
1211
1263
|
## Question-to-source routing`,
|
|
1212
1264
|
)
|
|
1213
1265
|
.replace('Read \`meguro://docs/getting-started/v1\`.', `Read \`${GETTING_STARTED_V6_URI}\`.`);
|
|
1266
|
+
const REAL_STORE_HISTORY_LANE_BRIDGE = 'Meguro\'s separate real-store history lane still exists in the public STDIO distribution for internal and CI use; hosted OAuth MCP does not expose or teach that lane.';
|
|
1267
|
+
const GETTING_STARTED_V7_TEXT = GETTING_STARTED_V6_TEXT
|
|
1268
|
+
.replace('# Getting started with Meguro v6', '# Getting started with Meguro v7')
|
|
1269
|
+
.replace(`Published URI: \`${GETTING_STARTED_V6_URI}\``, `Published URI: \`${GETTING_STARTED_V7_URI}\``)
|
|
1270
|
+
.replaceAll('meguro://docs/gate-policy/v1', 'meguro://docs/gate-policy/v2')
|
|
1271
|
+
.replace(
|
|
1272
|
+
`The local \`meguro-mcp\` server is the Meguro control plane: it discovers stores and drives run
|
|
1273
|
+
lifecycle. The practice store's returned Shopify-shaped Admin endpoint is the data plane used by the
|
|
1274
|
+
commerce agent under evaluation. A practice store's storefront MCP endpoint is neither of those and
|
|
1275
|
+
cannot replace the local control plane or the Shopify-shaped Admin endpoint.`,
|
|
1276
|
+
`Hosted OAuth MCP is the recommended control plane for interactive agents. The public STDIO
|
|
1277
|
+
distribution is the CI and internal fallback. The practice store's returned Shopify-shaped Admin
|
|
1278
|
+
endpoint is the data plane used by the commerce agent under evaluation; its storefront MCP endpoint
|
|
1279
|
+
is neither control plane nor a substitute for the Shopify-shaped Admin endpoint.
|
|
1280
|
+
|
|
1281
|
+
${REAL_STORE_HISTORY_LANE_BRIDGE}`,
|
|
1282
|
+
);
|
|
1283
|
+
const PRODUCT_GUIDE_V4_TEXT = PRODUCT_GUIDE_V3_TEXT
|
|
1284
|
+
.replace('# Meguro product guide v3', '# Meguro product guide v4')
|
|
1285
|
+
.replace(`Published URI: \`${PRODUCT_GUIDE_V3_URI}\``, `Published URI: \`${PRODUCT_GUIDE_V4_URI}\``)
|
|
1286
|
+
.replaceAll('meguro://docs/gate-policy/v1', 'meguro://docs/gate-policy/v2')
|
|
1287
|
+
.replace(`Read \`${GETTING_STARTED_V6_URI}\`.`, `Read \`${GETTING_STARTED_V7_URI}\`.`)
|
|
1288
|
+
.replace(
|
|
1289
|
+
'- **Public STDIO MCP** is the local and CI fallback.',
|
|
1290
|
+
`- **Public STDIO MCP** is the CI and internal fallback.
|
|
1291
|
+
|
|
1292
|
+
${REAL_STORE_HISTORY_LANE_BRIDGE}`,
|
|
1293
|
+
)
|
|
1294
|
+
.replace(
|
|
1295
|
+
'| What runs exist or what happened? | Call \`runs_list\` and the relevant status, report, or impact tool. |',
|
|
1296
|
+
'| What practice runs exist or what happened? | Call \`practice_runs_list\` and the relevant \`practice_run_status\`, \`practice_run_report\`, or \`practice_run_impact\` tool. |',
|
|
1297
|
+
);
|
|
1214
1298
|
const RECEIPT_GUIDE_V6_TEXT = simulationVocabularyText(
|
|
1215
1299
|
RECEIPT_GUIDE_V5_TEXT
|
|
1216
1300
|
.replace('# Meguro receipt guide v5', '# Meguro receipt guide v6')
|
|
@@ -1262,13 +1346,13 @@ function entry(input) {
|
|
|
1262
1346
|
name: input.name,
|
|
1263
1347
|
title: input.title,
|
|
1264
1348
|
description: input.description,
|
|
1265
|
-
mimeType: 'text/markdown',
|
|
1349
|
+
mimeType: input.mimeType ?? 'text/markdown',
|
|
1266
1350
|
text,
|
|
1267
1351
|
sha256: digest,
|
|
1268
1352
|
});
|
|
1269
1353
|
}
|
|
1270
1354
|
|
|
1271
|
-
export function buildDocumentationCatalog(inputs) {
|
|
1355
|
+
export function buildDocumentationCatalog(inputs, currency) {
|
|
1272
1356
|
const rows = inputs.map(entry).sort((left, right) => codepointCompare(left.uri, right.uri));
|
|
1273
1357
|
const byUri = new Map();
|
|
1274
1358
|
const byTopicVersion = new Map();
|
|
@@ -1279,6 +1363,19 @@ export function buildDocumentationCatalog(inputs) {
|
|
|
1279
1363
|
byUri.set(row.uri, row);
|
|
1280
1364
|
byTopicVersion.set(key, row);
|
|
1281
1365
|
}
|
|
1366
|
+
const currentUriByTopic = currency?.currentUriByTopic ?? Object.fromEntries(
|
|
1367
|
+
[...new Set(rows.map((row) => row.topic))].map((topic) => {
|
|
1368
|
+
const current = rows.filter((row) => row.topic === topic).sort((left, right) => left.version - right.version).at(-1);
|
|
1369
|
+
return [topic, current.uri];
|
|
1370
|
+
}),
|
|
1371
|
+
);
|
|
1372
|
+
for (const topic of new Set(rows.map((row) => row.topic))) {
|
|
1373
|
+
const currentUri = currentUriByTopic[topic];
|
|
1374
|
+
const current = byUri.get(currentUri);
|
|
1375
|
+
if (!current || current.topic !== topic) {
|
|
1376
|
+
throw new Error(`Documentation currency has no valid current resource for ${topic}`);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1282
1379
|
return deepFreeze({
|
|
1283
1380
|
list() {
|
|
1284
1381
|
return rows.map((row) => deepFreeze({
|
|
@@ -1292,6 +1389,8 @@ export function buildDocumentationCatalog(inputs) {
|
|
|
1292
1389
|
'meguro/topic': row.topic,
|
|
1293
1390
|
'meguro/version': row.version,
|
|
1294
1391
|
'meguro/sha256': row.sha256,
|
|
1392
|
+
'meguro/status': row.uri === currentUriByTopic[row.topic] ? 'current' : 'superseded',
|
|
1393
|
+
'meguro/current-uri': currentUriByTopic[row.topic],
|
|
1295
1394
|
},
|
|
1296
1395
|
}));
|
|
1297
1396
|
},
|
|
@@ -1363,6 +1462,15 @@ const CATALOG = buildDocumentationCatalog([
|
|
|
1363
1462
|
description: `World-first discovery sequence for Shopify Admin GraphQL ${ADMIN_API_SUPPORTED_VERSIONS.join(' and ')} with default ${ADMIN_API_DEFAULT_VERSION}.`,
|
|
1364
1463
|
text: GETTING_STARTED_V6_TEXT,
|
|
1365
1464
|
},
|
|
1465
|
+
{
|
|
1466
|
+
topic: 'getting-started',
|
|
1467
|
+
version: GETTING_STARTED_V7_VERSION,
|
|
1468
|
+
uri: GETTING_STARTED_V7_URI,
|
|
1469
|
+
name: 'Getting started with Meguro v7',
|
|
1470
|
+
title: 'Getting started with Meguro v7',
|
|
1471
|
+
description: `Hosted-first practice-store sequence for Shopify Admin GraphQL ${ADMIN_API_SUPPORTED_VERSIONS.join(' and ')} with default ${ADMIN_API_DEFAULT_VERSION}.`,
|
|
1472
|
+
text: GETTING_STARTED_V7_TEXT,
|
|
1473
|
+
},
|
|
1366
1474
|
{
|
|
1367
1475
|
topic: 'product-guide',
|
|
1368
1476
|
version: PRODUCT_GUIDE_VERSION,
|
|
@@ -1391,6 +1499,33 @@ const CATALOG = buildDocumentationCatalog([
|
|
|
1391
1499
|
description: 'World-first product concepts, evidence boundaries, surface responsibilities, and question-to-source routing.',
|
|
1392
1500
|
text: PRODUCT_GUIDE_V3_TEXT,
|
|
1393
1501
|
},
|
|
1502
|
+
{
|
|
1503
|
+
topic: 'product-guide',
|
|
1504
|
+
version: PRODUCT_GUIDE_V4_VERSION,
|
|
1505
|
+
uri: PRODUCT_GUIDE_V4_URI,
|
|
1506
|
+
name: 'Meguro product guide v4',
|
|
1507
|
+
title: 'Meguro product guide v4',
|
|
1508
|
+
description: 'Hosted-first product concepts, practice-run vocabulary, evidence boundaries, and question-to-source routing.',
|
|
1509
|
+
text: PRODUCT_GUIDE_V4_TEXT,
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
topic: 'index',
|
|
1513
|
+
version: DOCUMENTATION_CURRENCY_V1.indexVersion,
|
|
1514
|
+
uri: DOCUMENTATION_INDEX_URI,
|
|
1515
|
+
name: 'Meguro documentation index v1',
|
|
1516
|
+
title: 'Meguro documentation index v1',
|
|
1517
|
+
description: 'Immutable current-version pointers for every published Meguro documentation family.',
|
|
1518
|
+
text: documentationIndexText(DOCUMENTATION_CURRENCY_V1),
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
topic: 'index',
|
|
1522
|
+
version: DOCUMENTATION_CURRENCY_V2.indexVersion,
|
|
1523
|
+
uri: DOCUMENTATION_INDEX_V2_URI,
|
|
1524
|
+
name: 'Meguro documentation index v2',
|
|
1525
|
+
title: 'Meguro documentation index v2',
|
|
1526
|
+
description: 'Immutable current-version pointers for every published Meguro documentation family after the hosted run-lane separation.',
|
|
1527
|
+
text: documentationIndexText(DOCUMENTATION_CURRENCY_V2, DOCUMENTATION_INDEX_V2_URI),
|
|
1528
|
+
},
|
|
1394
1529
|
{
|
|
1395
1530
|
topic: 'receipt-guide',
|
|
1396
1531
|
version: RECEIPT_GUIDE_VERSION,
|
|
@@ -1472,7 +1607,7 @@ const CATALOG = buildDocumentationCatalog([
|
|
|
1472
1607
|
description: 'Immutable named checks and flip conditions republished with the simulation-run vocabulary.',
|
|
1473
1608
|
text: GATE_POLICY_V2_TEXT,
|
|
1474
1609
|
},
|
|
1475
|
-
]);
|
|
1610
|
+
], CURRENT_DOCUMENTATION_CURRENCY);
|
|
1476
1611
|
|
|
1477
1612
|
export function documentationResources() {
|
|
1478
1613
|
return CATALOG.list();
|
package/src/server.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from './protocol.mjs';
|
|
15
15
|
import { createTools, redactSecrets } from './tools.mjs';
|
|
16
16
|
|
|
17
|
-
const SERVER_INFO = { name: 'meguro', version: '0.2.
|
|
17
|
+
const SERVER_INFO = { name: 'meguro', version: '0.2.9' };
|
|
18
18
|
const PROTOCOL_VERSION = '2025-03-26';
|
|
19
19
|
|
|
20
20
|
const tools = createTools({
|
package/src/tools.mjs
CHANGED
|
@@ -26,6 +26,7 @@ const DOCUMENTATION_TOOL_CONTRACT = documentationToolContract();
|
|
|
26
26
|
const DOCUMENTATION_TOPICS = new Set(DOCUMENTATION_TOOL_CONTRACT.topics);
|
|
27
27
|
const FLEET_TOOL_NAMES = new Set([
|
|
28
28
|
'templates_list', 'stores_list', 'store_create', 'store_delete', 'store_passport',
|
|
29
|
+
'practice_runs_list',
|
|
29
30
|
'workspaces_list', 'workspace_create', 'workspace_archive', 'workspace_unarchive',
|
|
30
31
|
'share_create', 'shares_list', 'share_status', 'share_publish', 'share_revoke',
|
|
31
32
|
'catalog_slice_read', 'catalog_slice_snapshot', 'catalog_slices_saved',
|
|
@@ -69,6 +70,7 @@ const TOOL_PRESENTATION = Object.freeze({
|
|
|
69
70
|
exam_status: { title: 'Read Shopify Exam status', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
70
71
|
exam_report: { title: 'Read a Shopify Exam receipt', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
71
72
|
practice_run_start: { title: 'Start a practice run', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
73
|
+
practice_runs_list: { title: 'List practice runs', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
72
74
|
practice_run_status: { title: 'Read practice-run status', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
73
75
|
practice_run_checkpoint: { title: 'Capture a practice-run checkpoint', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
74
76
|
practice_run_advance: { title: 'Advance store time', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
@@ -832,13 +834,94 @@ function runsListProjection(value, lifecycle) {
|
|
|
832
834
|
...(visible.length === 0 ? {
|
|
833
835
|
emptyState: {
|
|
834
836
|
message: `No ${lifecycle ?? 'matching'} Shopify dev-store history runs were found. This says nothing about practice simulation attempts.`,
|
|
835
|
-
practiceAttemptRecovery: '
|
|
837
|
+
practiceAttemptRecovery: 'Call practice_runs_list to discover practice simulation attempts, then pass one exact attemptId to practice_run_report or practice_run_impact.',
|
|
836
838
|
},
|
|
837
839
|
} : {}),
|
|
838
840
|
clockDiscipline: 'runClock names lifecycle timestamps; worldClock names scenario coordinates and does not invent an unreported Store-time.',
|
|
839
841
|
});
|
|
840
842
|
}
|
|
841
843
|
|
|
844
|
+
function practiceRunsSelectionError(storeIds) {
|
|
845
|
+
const multiple = storeIds.length > 1;
|
|
846
|
+
const meaning = multiple
|
|
847
|
+
? `This workspace has more than one practice store (${storeIds.length}), so Meguro cannot infer which store's practice runs to list`
|
|
848
|
+
: 'This workspace has no practice store, so there are no store-owned practice runs to list';
|
|
849
|
+
const nextStep = multiple
|
|
850
|
+
? 'Call stores_list({}), choose one exact storeId, then call practice_runs_list({ storeId: "<exact storeId>" }). You may instead provide a known receiptId so Meguro can derive its owning store.'
|
|
851
|
+
: 'Create a practice store first, then call practice_runs_list with its storeId or with a receiptId from one of its runs.';
|
|
852
|
+
return {
|
|
853
|
+
content: [{
|
|
854
|
+
type: 'text',
|
|
855
|
+
text: JSON.stringify({
|
|
856
|
+
code: 'store-selection-required',
|
|
857
|
+
storeIds,
|
|
858
|
+
errors: [{ code: 'store-selection-required', message: `Store selection required. ${meaning}. ${nextStep}`, meaning, nextStep }],
|
|
859
|
+
}, null, 2),
|
|
860
|
+
}],
|
|
861
|
+
isError: true,
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function practiceRunReceiptSelectionError(receiptId) {
|
|
866
|
+
return {
|
|
867
|
+
content: [{
|
|
868
|
+
type: 'text',
|
|
869
|
+
text: JSON.stringify({
|
|
870
|
+
code: 'receipt-unavailable',
|
|
871
|
+
errors: [{
|
|
872
|
+
code: 'receipt-unavailable',
|
|
873
|
+
message: `Practice receipt ${receiptId} is not available in this workspace.`,
|
|
874
|
+
meaning: 'The receipt does not identify a retained practice run owned by this workspace.',
|
|
875
|
+
nextStep: 'Call practice_runs_list with an exact current storeId, or use a receiptId returned by a prior practice_runs_list or practice_run_report response.',
|
|
876
|
+
}],
|
|
877
|
+
}, null, 2),
|
|
878
|
+
}],
|
|
879
|
+
isError: true,
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
function practiceRunReceiptStoreMismatch(receiptId, receiptStoreId, requestedStoreId) {
|
|
884
|
+
return {
|
|
885
|
+
content: [{
|
|
886
|
+
type: 'text',
|
|
887
|
+
text: JSON.stringify({
|
|
888
|
+
code: 'receipt-store-mismatch',
|
|
889
|
+
errors: [{
|
|
890
|
+
code: 'receipt-store-mismatch',
|
|
891
|
+
message: `Receipt and storeId identify different practice stores. Receipt ${receiptId} belongs to ${receiptStoreId}, not ${requestedStoreId}.`,
|
|
892
|
+
meaning: `Receipt ${receiptId} belongs to store ${receiptStoreId}, not ${requestedStoreId}.`,
|
|
893
|
+
nextStep: `Retry with storeId ${receiptStoreId}, or omit storeId and let Meguro derive it from receiptId ${receiptId}.`,
|
|
894
|
+
}],
|
|
895
|
+
}, null, 2),
|
|
896
|
+
}],
|
|
897
|
+
isError: true,
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
function practiceRunsProjection(value, storeId, storeSelection) {
|
|
902
|
+
const attempts = Array.isArray(value?.playbacks) ? value.playbacks : [];
|
|
903
|
+
return secretSafe({
|
|
904
|
+
schemaVersion: 'meguro.practice-run-list.v1',
|
|
905
|
+
storeId,
|
|
906
|
+
storeSelection,
|
|
907
|
+
attempts: attempts
|
|
908
|
+
.filter((attempt) => attempt?.storeId === storeId || attempt?.worldId === storeId)
|
|
909
|
+
.map((attempt) => ({
|
|
910
|
+
attemptId: attempt.attemptId,
|
|
911
|
+
state: attempt.status,
|
|
912
|
+
clock: {
|
|
913
|
+
mode: attempt.clock?.mode ?? null,
|
|
914
|
+
baselineDay: attempt.baselineDay ?? null,
|
|
915
|
+
watermarkDay: attempt.watermarkDay ?? null,
|
|
916
|
+
simulationDays: attempt.simulationDays ?? attempt.clock?.simulationDays ?? null,
|
|
917
|
+
elapsedSimulationDays: attempt.elapsedSimulationDays ?? null,
|
|
918
|
+
remainingSimulationDays: attempt.remainingSimulationDays ?? null,
|
|
919
|
+
},
|
|
920
|
+
receiptRef: { attemptId: attempt.attemptId },
|
|
921
|
+
})),
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
|
|
842
925
|
function practiceAttemptComparisonGuidanceFor(toolName, a, b) {
|
|
843
926
|
const attemptIds = [a, b].filter((id) => PRACTICE_ATTEMPT_ID.test(id));
|
|
844
927
|
const calls = attemptIds.flatMap((attemptId) => [
|
|
@@ -900,6 +983,21 @@ function practiceStoreConnectionNotFoundGuidance(storeId) {
|
|
|
900
983
|
};
|
|
901
984
|
}
|
|
902
985
|
|
|
986
|
+
function practiceRunsStoreNotFoundGuidance(storeId) {
|
|
987
|
+
return {
|
|
988
|
+
content: [{
|
|
989
|
+
type: 'text',
|
|
990
|
+
text: JSON.stringify({
|
|
991
|
+
code: 'practice-store-not-found',
|
|
992
|
+
message: `practice_runs_list could not find practice store ${storeId} in this account or the store is no longer active.`,
|
|
993
|
+
nextAction: 'Call stores_list({}) and use an exact current storeId from the returned stores array.',
|
|
994
|
+
stopCondition: `If stores_list({}) returns no current stores, stop: there is no practice store whose attempts can be listed. Do not retry ${JSON.stringify(storeId)}.`,
|
|
995
|
+
}, null, 2),
|
|
996
|
+
}],
|
|
997
|
+
isError: true,
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
|
|
903
1001
|
function legacyGateArtifactNotFoundGuidance(runId) {
|
|
904
1002
|
return {
|
|
905
1003
|
content: [{
|
|
@@ -957,6 +1055,11 @@ function usageProjection(value) {
|
|
|
957
1055
|
},
|
|
958
1056
|
limits: {
|
|
959
1057
|
activeStores,
|
|
1058
|
+
activeStoreAccounting: {
|
|
1059
|
+
basis: 'metered-active-stores',
|
|
1060
|
+
exemptionMarker: 'auto-provisioned-sample-store',
|
|
1061
|
+
note: 'activeStores counts metered stores. A stores_list row marked auto-provisioned-sample-store is an exempt sample store and is not counted here.',
|
|
1062
|
+
},
|
|
960
1063
|
activeStoreLimit,
|
|
961
1064
|
activeWorkspaces,
|
|
962
1065
|
activeWorkspaceLimit,
|
|
@@ -1881,7 +1984,7 @@ export function createTools(config) {
|
|
|
1881
1984
|
},
|
|
1882
1985
|
{
|
|
1883
1986
|
name: 'runs_list',
|
|
1884
|
-
description: 'List Shopify dev-store history runs created by run_start so an agent can re-find that family of prior work. It does not list practice simulation attempts returned by practice_run_start; those
|
|
1987
|
+
description: 'List Shopify dev-store history runs created by run_start so an agent can re-find that family of prior work. It does not list practice simulation attempts returned by practice_run_start; call practice_runs_list for those pa-* ids, then use practice_run_report or practice_run_impact. Optional history-run lifecycle filtering supports running, paused, completed, failed, or cleaning. An empty result explicitly says it is only about history runs. The payload names run-clock lifecycle timestamps separately from world-clock scenario coordinates and returns no filter counts.',
|
|
1885
1988
|
inputSchema: {
|
|
1886
1989
|
type: 'object',
|
|
1887
1990
|
additionalProperties: false,
|
|
@@ -1992,6 +2095,20 @@ export function createTools(config) {
|
|
|
1992
2095
|
anyOf: [{ required: ['storeId'] }, { required: ['worldId'] }],
|
|
1993
2096
|
},
|
|
1994
2097
|
},
|
|
2098
|
+
{
|
|
2099
|
+
name: 'practice_runs_list',
|
|
2100
|
+
description: 'List bounded practice simulation attempt facts for one exact practice store: attemptId, lifecycle state, Store-clock summary, and a receiptRef that can be passed unchanged to practice_run_report. Store selection follows one fail-closed ladder: receiptId derives its owning store; otherwise an explicit storeId wins; omission is allowed only when the workspace has exactly one current store; zero or multiple stores return a structured store-selection-required error and never choose silently. An OAuth grant may select an owned workspace; an account API key remains bound to its own workspace.',
|
|
2101
|
+
inputSchema: {
|
|
2102
|
+
type: 'object',
|
|
2103
|
+
additionalProperties: false,
|
|
2104
|
+
properties: {
|
|
2105
|
+
workspaceId: { type: 'string', minLength: 1, description: 'Optional OAuth selector for an account-owned non-default workspace. An account API key can name only its bound workspace.' },
|
|
2106
|
+
storeId: { ...PRACTICE_STORE_ID_INPUT_SCHEMA, description: 'Optional exact practice-store id from stores_list. Omit only with receiptId or when the workspace has exactly one current store.' },
|
|
2107
|
+
receiptId: { type: 'string', minLength: 4, maxLength: 128, pattern: '^pa-[a-z0-9][a-z0-9-]{0,124}$', description: 'Optional known pa-* practice receipt identity. Meguro derives its owning store and refuses a conflicting storeId.' },
|
|
2108
|
+
},
|
|
2109
|
+
required: [],
|
|
2110
|
+
},
|
|
2111
|
+
},
|
|
1995
2112
|
{
|
|
1996
2113
|
name: 'practice_run_status',
|
|
1997
2114
|
description: 'Read the server-authoritative state of an external-agent practice simulation run, including its announced simulation-run deadlines and immutable simulation run receipt after any exit. Use Console for quick proof; the tested agent remains in the caller\'s environment.',
|
|
@@ -2059,7 +2176,7 @@ export function createTools(config) {
|
|
|
2059
2176
|
},
|
|
2060
2177
|
{
|
|
2061
2178
|
name: 'get_connection_details',
|
|
2062
|
-
description: `Fetch connection material for supported Shopify Admin GraphQL versions ${ADMIN_API_SUPPORTED_VERSION_LABEL}; the default is ${ADMIN_API_DEFAULT_VERSION}. Returns adminApiVersion (default), adminApiVersions (supported set), adminVersions (exact versioned URLs), the default URL, access token, and shop domain for an existing Meguro practice store so an assistant can configure a user agent without opening the dashboard. Inspect the selected version with admin_schema before the first Admin call; an agent targeting a newer Shopify release outside the supported set must treat that behavior as not established. Takes the canonical practice-store id (storeId) and returns it back, so the result passes directly into practice_run_start({ storeId }) — no identifier translation. The practice-store id is not an attemptId (run identity).
|
|
2179
|
+
description: `Fetch connection material for supported Shopify Admin GraphQL versions ${ADMIN_API_SUPPORTED_VERSION_LABEL}; the default is ${ADMIN_API_DEFAULT_VERSION}. Returns adminApiVersion (default), adminApiVersions (supported set), adminVersions (exact versioned URLs), the default URL, access token, and shop domain for an existing Meguro practice store so an assistant can configure a user agent without opening the dashboard. Inspect the selected version with admin_schema before the first Admin call; an agent targeting a newer Shopify release outside the supported set must treat that behavior as not established. Takes the canonical practice-store id (storeId) and returns it back, so the result passes directly into practice_run_start({ storeId }) — no identifier translation. The practice-store id is not an attemptId (run identity). The hosted MCP path uses the caller's OAuth grant; the public STDIO path uses its workspace-bound account API key.`,
|
|
2063
2180
|
inputSchema: {
|
|
2064
2181
|
type: 'object',
|
|
2065
2182
|
additionalProperties: false,
|
|
@@ -2630,6 +2747,50 @@ export function createTools(config) {
|
|
|
2630
2747
|
...consoleUrlFields(started.consoleRef, started.consoleRefExpiresAt),
|
|
2631
2748
|
}));
|
|
2632
2749
|
}
|
|
2750
|
+
case 'practice_runs_list': {
|
|
2751
|
+
const workspaceId = optionalWorkspaceId(args);
|
|
2752
|
+
const requestedStoreId = args.storeId === undefined
|
|
2753
|
+
? undefined
|
|
2754
|
+
: validatedStoreId(requiredString(args, 'storeId'), 'storeId');
|
|
2755
|
+
const receiptId = args.receiptId === undefined
|
|
2756
|
+
? undefined
|
|
2757
|
+
: requiredPracticeAttemptId(args, 'receiptId');
|
|
2758
|
+
if (receiptId) {
|
|
2759
|
+
const listed = await fleetRequest(name, 'GET', '/practice/playbacks', undefined, { workspaceId });
|
|
2760
|
+
if ('error' in listed) return listed.error;
|
|
2761
|
+
const playbacks = Array.isArray(listed.value?.playbacks) ? listed.value.playbacks : [];
|
|
2762
|
+
const referenced = playbacks.find((attempt) => attempt?.attemptId === receiptId);
|
|
2763
|
+
if (!referenced) return practiceRunReceiptSelectionError(receiptId);
|
|
2764
|
+
const receiptStoreId = String(referenced.storeId ?? referenced.worldId ?? '');
|
|
2765
|
+
if (requestedStoreId && requestedStoreId !== receiptStoreId) {
|
|
2766
|
+
return practiceRunReceiptStoreMismatch(receiptId, receiptStoreId, requestedStoreId);
|
|
2767
|
+
}
|
|
2768
|
+
return textResult(practiceRunsProjection(listed.value, receiptStoreId, 'receipt-derived'));
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
const fleet = await fleetRequest(name, 'GET', '/practice/stores', undefined, { workspaceId });
|
|
2772
|
+
if ('error' in fleet) return fleet.error;
|
|
2773
|
+
const storeIds = [...new Set((Array.isArray(fleet.value?.stores) ? fleet.value.stores : [])
|
|
2774
|
+
.map((store) => String(store?.storeId ?? store?.worldId ?? '').trim())
|
|
2775
|
+
.filter((storeId) => /^[a-z0-9-]+$/u.test(storeId)))].sort();
|
|
2776
|
+
|
|
2777
|
+
if (requestedStoreId && !storeIds.includes(requestedStoreId)) {
|
|
2778
|
+
return practiceRunsStoreNotFoundGuidance(requestedStoreId);
|
|
2779
|
+
}
|
|
2780
|
+
if (!requestedStoreId && storeIds.length !== 1) {
|
|
2781
|
+
return practiceRunsSelectionError(storeIds);
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
const listPath = queryPath('/practice/playbacks', { worldId: requestedStoreId ?? storeIds[0] });
|
|
2785
|
+
const listed = await fleetRequest(name, 'GET', listPath, undefined, { workspaceId });
|
|
2786
|
+
if ('error' in listed) return listed.error;
|
|
2787
|
+
const selectedStoreId = requestedStoreId ?? storeIds[0];
|
|
2788
|
+
return textResult(practiceRunsProjection(
|
|
2789
|
+
listed.value,
|
|
2790
|
+
selectedStoreId,
|
|
2791
|
+
requestedStoreId ? 'explicit-store-id' : 'single-store',
|
|
2792
|
+
));
|
|
2793
|
+
}
|
|
2633
2794
|
case 'practice_run_status': {
|
|
2634
2795
|
const attemptId = requiredPracticeAttemptId(args);
|
|
2635
2796
|
const response = await practiceApi('GET', `/practice/playbacks/${encodeURIComponent(attemptId)}/state`);
|