simple-dynamsoft-mcp 7.2.8 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
2
  import { dirname, join, relative } from "node:path";
3
3
  import { z } from "zod";
4
+ import { buildUnknownPublicProductResponse, isKnownPublicOffering } from "../public-offerings.js";
5
+ import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
4
6
 
5
7
  export function registerProjectTools({
6
8
  server,
@@ -22,10 +24,46 @@ export function registerProjectTools({
22
24
  getDcvMobileSamplePath,
23
25
  getDcvServerSamplePath,
24
26
  getDcvWebSamplePath,
27
+ getMrzWebSamplePath,
28
+ getMdsWebSamplePath,
25
29
  getDwtSamplePath,
26
30
  getDdvSamplePath,
27
31
  getSampleSuggestions
28
32
  }) {
33
+ async function resolveDedicatedPublicWebSamplePath({
34
+ product,
35
+ platform,
36
+ sampleName,
37
+ getSamplePath,
38
+ getSuggestions
39
+ }) {
40
+ const directPath = getSamplePath(undefined, sampleName);
41
+ if (directPath && existsSync(directPath)) {
42
+ return directPath;
43
+ }
44
+
45
+ const suggestions = await getSuggestions({
46
+ query: sampleName,
47
+ product,
48
+ edition: "web",
49
+ platform,
50
+ limit: 10
51
+ });
52
+
53
+ const matchingEntry = suggestions.find((entry) => {
54
+ if (entry.type !== "sample") return false;
55
+ const parsed = parseSampleUri(entry.uri);
56
+ return parsed?.product === product && parsed?.edition === "web" && parsed?.sampleName === sampleName;
57
+ });
58
+
59
+ if (!matchingEntry) {
60
+ return directPath;
61
+ }
62
+
63
+ const parsed = parseSampleUri(matchingEntry.uri);
64
+ return getSamplePath(parsed?.category, sampleName);
65
+ }
66
+
29
67
  server.registerTool(
30
68
  "get_sample_files",
31
69
  {
@@ -43,12 +81,12 @@ export function registerProjectTools({
43
81
  "- If the user just wants a quick code snippet, use get_quickstart instead.",
44
82
  "",
45
83
  "PARAMETERS:",
46
- "- product (required): dcv, dbr, dwt, or ddv.",
84
+ "- product (required): dbr, dwt, ddv, mrz, or mds.",
47
85
  "- edition: mobile, web, or server.",
48
86
  "- platform: android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.",
49
87
  "- version: Version constraint. Latest major is used by default.",
50
88
  "- sample_id: Sample identifier as returned by list_samples (e.g. 'hello-world', 'ScanSingleBarcode'). Requires product/edition.",
51
- "- resource_uri: A sample:// URI as returned by search (e.g. 'sample://dbr/mobile/android/10/high-level/ScanSingleBarcode'). Preferred over sample_id when available.",
89
+ "- resource_uri: A sample:// URI as returned by search (e.g. 'sample://dbr/mobile/android/10/high-level/ScanSingleBarcode' or 'sample://mrz/server/python/3/mrz_scanner'). Preferred over sample_id when available.",
52
90
  "- api_level: 'high-level' or 'low-level' (DBR mobile only).",
53
91
  "",
54
92
  "RETURNS: A text block containing all project files inline, each under a heading with its relative path and wrapped in a fenced code block. Files larger than 50KB are excluded. No zip file is created.",
@@ -58,7 +96,7 @@ export function registerProjectTools({
58
96
  "RELATED TOOLS: list_samples (discover sample IDs), search (find samples by keyword), get_quickstart (quick single-file snippet)."
59
97
  ].join("\n"),
60
98
  inputSchema: {
61
- product: z.string().trim().min(1, "Product is required.").describe("Product: dcv, dbr, dwt, or ddv"),
99
+ product: z.string().trim().min(1, "Product is required.").describe("Product: dbr, dwt, ddv, mrz, mds"),
62
100
  edition: z.string().optional().describe("Edition: mobile, web, server/desktop"),
63
101
  platform: z.string().optional().describe("Platform: android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview"),
64
102
  version: z.string().optional().describe("Version constraint"),
@@ -74,29 +112,6 @@ export function registerProjectTools({
74
112
  }
75
113
  },
76
114
  async ({ product, edition, platform, version, sample_id, resource_uri, api_level }) => {
77
- const normalizedProduct = normalizeProduct(product);
78
- const normalizedPlatform = normalizePlatform(platform);
79
- const normalizedEdition = normalizeEdition(edition, normalizedPlatform, normalizedProduct);
80
-
81
- await ensureScopeHydrated({
82
- product: normalizedProduct,
83
- edition: normalizedEdition,
84
- platform: normalizedPlatform,
85
- type: "sample"
86
- });
87
-
88
- const policy = ensureLatestMajor({
89
- product: normalizedProduct,
90
- version,
91
- query: sample_id,
92
- edition: normalizedEdition,
93
- platform: normalizedPlatform
94
- });
95
-
96
- if (!policy.ok) {
97
- return { isError: true, content: [{ type: "text", text: policy.message }] };
98
- }
99
-
100
115
  let sampleInfo = null;
101
116
  if (resource_uri) {
102
117
  const parsed = parseResourceUri(resource_uri);
@@ -130,6 +145,35 @@ export function registerProjectTools({
130
145
  }
131
146
  }
132
147
 
148
+ const normalizedProduct = normalizeProduct(sampleInfo?.product || product);
149
+ if ((sampleInfo?.product || product) && !isKnownPublicOffering(normalizedProduct)) {
150
+ return buildUnknownPublicProductResponse(sampleInfo?.product || product);
151
+ }
152
+
153
+ const normalizedPlatform = normalizePlatform(sampleInfo?.platform || platform);
154
+ const normalizedEdition = normalizeEdition(sampleInfo?.edition || edition, normalizedPlatform, normalizedProduct);
155
+ const unsupportedScopeResponse = buildUnsupportedPublicScopeResponse(normalizedProduct, normalizedEdition, normalizedPlatform);
156
+ if (unsupportedScopeResponse) return unsupportedScopeResponse;
157
+
158
+ await ensureScopeHydrated({
159
+ product: normalizedProduct,
160
+ edition: normalizedEdition,
161
+ platform: normalizedPlatform,
162
+ type: "sample"
163
+ });
164
+
165
+ const policy = ensureLatestMajor({
166
+ product: normalizedProduct,
167
+ version,
168
+ query: sample_id,
169
+ edition: normalizedEdition,
170
+ platform: normalizedPlatform
171
+ });
172
+
173
+ if (!policy.ok) {
174
+ return { isError: true, content: [{ type: "text", text: policy.message }] };
175
+ }
176
+
133
177
  let samplePath = null;
134
178
  let sampleLabel = "";
135
179
  let sampleQuery = "";
@@ -143,6 +187,14 @@ export function registerProjectTools({
143
187
  samplePath = getWebSamplePath(sampleInfo.category, sampleInfo.sampleName);
144
188
  } else if (sampleInfo.product === "dbr" && (sampleInfo.edition === "python" || sampleInfo.edition === "server")) {
145
189
  samplePath = getDbrServerSamplePath(sampleInfo.platform, sampleInfo.sampleName);
190
+ } else if ((sampleInfo.product === "mrz" || sampleInfo.product === "mds") && sampleInfo.edition === "mobile") {
191
+ samplePath = getDcvMobileSamplePath(sampleInfo.platform, sampleInfo.sampleName);
192
+ } else if ((sampleInfo.product === "mrz" || sampleInfo.product === "mds") && sampleInfo.edition === "server") {
193
+ samplePath = getDcvServerSamplePath(sampleInfo.platform, sampleInfo.sampleName);
194
+ } else if ((sampleInfo.product === "mrz" || sampleInfo.product === "mds") && sampleInfo.edition === "web") {
195
+ samplePath = sampleInfo.product === "mrz"
196
+ ? getMrzWebSamplePath(sampleInfo.category, sampleInfo.sampleName)
197
+ : getMdsWebSamplePath(sampleInfo.category, sampleInfo.sampleName);
146
198
  } else if (sampleInfo.product === "dcv" && sampleInfo.edition === "mobile") {
147
199
  samplePath = getDcvMobileSamplePath(sampleInfo.platform, sampleInfo.sampleName);
148
200
  } else if (sampleInfo.product === "dcv" && sampleInfo.edition === "server") {
@@ -176,6 +228,27 @@ export function registerProjectTools({
176
228
  const altLevel = level === "high-level" ? "low-level" : "high-level";
177
229
  const alternatePath = getMobileSamplePath(targetPlatform, altLevel, sampleName);
178
230
  samplePath = existsSync(primaryPath) ? primaryPath : (existsSync(alternatePath) ? alternatePath : null);
231
+ } else if ((normalizedProduct === "mrz" || normalizedProduct === "mds") && normalizedEdition === "mobile") {
232
+ const platformCandidates = normalizedPlatform
233
+ ? [normalizedPlatform]
234
+ : ["android", "ios", "react-native", "flutter", "maui", "spm"];
235
+ for (const platformCandidate of platformCandidates) {
236
+ const candidate = getDcvMobileSamplePath(platformCandidate, sampleName);
237
+ if (candidate && existsSync(candidate)) {
238
+ samplePath = candidate;
239
+ break;
240
+ }
241
+ }
242
+ } else if ((normalizedProduct === "mrz" || normalizedProduct === "mds") && normalizedEdition === "web") {
243
+ samplePath = await resolveDedicatedPublicWebSamplePath({
244
+ product: normalizedProduct,
245
+ platform: normalizedPlatform,
246
+ sampleName,
247
+ getSamplePath: normalizedProduct === "mrz" ? getMrzWebSamplePath : getMdsWebSamplePath,
248
+ getSuggestions: getSampleSuggestions
249
+ });
250
+ } else if ((normalizedProduct === "mrz" || normalizedProduct === "mds") && normalizedEdition === "server") {
251
+ samplePath = getDcvServerSamplePath(normalizedPlatform || "python", sampleName);
179
252
  } else if (normalizedProduct === "dcv" && normalizedEdition === "mobile") {
180
253
  const platformCandidates = normalizedPlatform
181
254
  ? [normalizedPlatform]
@@ -265,7 +338,7 @@ export function registerProjectTools({
265
338
  const textExtensions = [
266
339
  ".java", ".kt", ".swift", ".m", ".h", ".xml", ".gradle", ".properties",
267
340
  ".pro", ".json", ".plist", ".storyboard", ".xib", ".gitignore", ".md",
268
- ".js", ".jsx", ".ts", ".tsx", ".vue", ".cjs", ".html", ".css"
341
+ ".js", ".jsx", ".ts", ".tsx", ".vue", ".cjs", ".html", ".css", ".py"
269
342
  ];
270
343
 
271
344
  const files = [];
@@ -1,6 +1,8 @@
1
1
  import { existsSync, statSync } from "node:fs";
2
2
  import { extname, join } from "node:path";
3
3
  import { z } from "zod";
4
+ import { buildUnknownPublicProductResponse, isKnownPublicOffering } from "../public-offerings.js";
5
+ import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
4
6
 
5
7
  export function registerQuickstartTools({
6
8
  server,
@@ -25,6 +27,54 @@ export function registerQuickstartTools({
25
27
  getMainCodeFile,
26
28
  getWebSamplePath
27
29
  }) {
30
+ function getPublicWebQuickstartLinks(product) {
31
+ if (product === "mrz") {
32
+ return {
33
+ docsUrl: "https://www.dynamsoft.com/mrz-scanner/docs/web/",
34
+ samplesUrl: "https://github.com/Dynamsoft/mrz-scanner-javascript"
35
+ };
36
+ }
37
+
38
+ if (product === "mds") {
39
+ return {
40
+ docsUrl: "https://www.dynamsoft.com/mobile-document-scanner/docs/web/",
41
+ samplesUrl: "https://github.com/Dynamsoft/document-scanner-javascript"
42
+ };
43
+ }
44
+
45
+ return { docsUrl: "", samplesUrl: "" };
46
+ }
47
+
48
+ function getPublicProductLabel(product) {
49
+ if (product === "mrz") return "MRZ";
50
+ if (product === "mds") return "MDS";
51
+ if (product === "dbr") return "DBR";
52
+ if (product === "dwt") return "DWT";
53
+ if (product === "ddv") return "DDV";
54
+ return String(product || "").toUpperCase();
55
+ }
56
+
57
+ function buildPublicReferenceQuickstart({ product, edition, platform, docsUrl, samplesUrl }) {
58
+ const label = getPublicProductLabel(product);
59
+ const scopeParts = [];
60
+ for (const part of [edition, platform]) {
61
+ if (!part || scopeParts.includes(part)) continue;
62
+ scopeParts.push(part);
63
+ }
64
+ const scope = scopeParts.join(" / ") || "general";
65
+ const lines = [
66
+ `# Quick Start Redirect: ${label}`,
67
+ "",
68
+ `${label} is available as a public offering, but this ${scope} quickstart is currently served as reference links instead of an inline starter.`,
69
+ "",
70
+ "Reference links:",
71
+ docsUrl ? `- Docs: ${docsUrl}` : "",
72
+ samplesUrl ? `- Samples: ${samplesUrl}` : ""
73
+ ].filter(Boolean);
74
+
75
+ return { content: [{ type: "text", text: lines.join("\n") }] };
76
+ }
77
+
28
78
  server.registerTool(
29
79
  "get_quickstart",
30
80
  {
@@ -35,7 +85,7 @@ export function registerQuickstartTools({
35
85
  "WHEN TO USE:",
36
86
  "- When the user wants to get started quickly with a Dynamsoft SDK.",
37
87
  "- To generate a ready-to-run code snippet with install commands, license key, and SDK version.",
38
- "- For scenario-specific starters: pass scenario='MRZ' for passport reading, 'VIN' for vehicle identification, 'document scan' for document normalization, etc.",
88
+ "- For scenario-specific starters: pass scenario='MRZ' for passport reading, 'document scan' for document normalization, or barcode/image hints for DBR.",
39
89
  "",
40
90
  "WHEN NOT TO USE:",
41
91
  "- If the user wants full project files (multiple source files, build configs), use get_sample_files instead.",
@@ -43,20 +93,20 @@ export function registerQuickstartTools({
43
93
  "- If the user only needs version info, use resolve_version.",
44
94
  "",
45
95
  "PARAMETERS:",
46
- "- product (required): dcv, dbr, dwt, or ddv.",
96
+ "- product (required): dbr, dwt, ddv, mrz, or mds.",
47
97
  "- edition: core, mobile, web, or server. Inferred from platform if omitted.",
48
98
  "- platform: android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.",
49
99
  "- language: kotlin, java, swift, js, ts, python, cpp, csharp, react, vue, angular. Helps select the best sample variant.",
50
100
  "- version: Version constraint. Latest major is used by default.",
51
101
  "- api_level: 'high-level' or 'low-level' (mobile only). Controls API abstraction level in generated code.",
52
- "- scenario: MRZ, VIN, document scan, driver license, camera, image, single, multiple, etc. DCV supports MRZ/VIN/document-normalization/driver-license workflows.",
102
+ "- scenario: MRZ, document scan, camera, image, single, multiple, react, vue, angular, etc. DBR web defaults to foundational guidance; MRZ and MDS return public workflow guidance where available.",
53
103
  "",
54
104
  "RETURNS: A formatted text block with SDK version, trial license key, install commands, and sample code. Ready to copy-paste.",
55
105
  "",
56
106
  "RELATED TOOLS: search (find specific docs or samples), get_sample_files (get full multi-file project), resolve_version (version numbers only)."
57
107
  ].join("\n"),
58
108
  inputSchema: {
59
- product: z.string().trim().min(1, "Product is required.").describe("Product: dcv, dbr, dwt, or ddv"),
109
+ product: z.string().trim().min(1, "Product is required.").describe("Product: dbr, dwt, ddv, mrz, mds"),
60
110
  edition: z.string().optional().describe("Edition: core, mobile, web, server/desktop"),
61
111
  platform: z.string().optional().describe("Platform: android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core"),
62
112
  language: z.string().optional().describe("Language hint: kotlin, java, swift, js, ts, python, cpp, csharp, react, vue, angular"),
@@ -73,8 +123,18 @@ export function registerQuickstartTools({
73
123
  },
74
124
  async ({ product, edition, platform, language, version, api_level, scenario }) => {
75
125
  const normalizedProduct = normalizeProduct(product);
126
+ if (product && !isKnownPublicOffering(normalizedProduct)) {
127
+ return buildUnknownPublicProductResponse(product);
128
+ }
129
+
76
130
  const normalizedPlatform = normalizePlatform(platform);
77
131
  const normalizedEdition = normalizeEdition(edition, normalizedPlatform, normalizedProduct);
132
+ const unsupportedScopeResponse = buildUnsupportedPublicScopeResponse(normalizedProduct, normalizedEdition, normalizedPlatform);
133
+ if (unsupportedScopeResponse) return unsupportedScopeResponse;
134
+
135
+ const isPublicDcvProduct = normalizedProduct === "mrz" || normalizedProduct === "mds";
136
+ const effectiveProduct = isPublicDcvProduct ? "dcv" : normalizedProduct;
137
+ const publicProductLabel = getPublicProductLabel(normalizedProduct);
78
138
 
79
139
  await ensureScopeHydrated({
80
140
  product: normalizedProduct,
@@ -95,9 +155,12 @@ export function registerQuickstartTools({
95
155
  return { isError: true, content: [{ type: "text", text: policy.message }] };
96
156
  }
97
157
 
98
- if (normalizedProduct === "dcv") {
99
- const scenarioLower = `${scenario || ""} ${language || ""}`.toLowerCase();
100
- const effectiveEdition = normalizedEdition || (normalizedPlatform ? normalizeEdition("", normalizedPlatform, "dcv") : "server");
158
+ if (effectiveProduct === "dcv") {
159
+ const seededScenario = isPublicDcvProduct
160
+ ? `${normalizedProduct === "mrz" ? "mrz" : "document scan"} ${scenario || ""} ${language || ""}`
161
+ : `${scenario || ""} ${language || ""}`;
162
+ const scenarioLower = seededScenario.toLowerCase();
163
+ const effectiveEdition = normalizedEdition || (isPublicDcvProduct ? "web" : (normalizedPlatform ? normalizeEdition("", normalizedPlatform, "dcv") : "server"));
101
164
 
102
165
  function selectDcvServerSample(platformHint, hint) {
103
166
  const platformName = normalizePlatform(platformHint) || "python";
@@ -173,6 +236,17 @@ export function registerQuickstartTools({
173
236
  if (effectiveEdition === "server") {
174
237
  const sdkEntry = registry.sdks["dcv-server"];
175
238
  const targetPlatform = normalizePlatform(normalizedPlatform || sdkEntry.default_platform || "python");
239
+
240
+ if (isPublicDcvProduct) {
241
+ return buildPublicReferenceQuickstart({
242
+ product: normalizedProduct,
243
+ edition: effectiveEdition,
244
+ platform: targetPlatform,
245
+ docsUrl: "https://www.dynamsoft.com/capture-vision/docs/server/",
246
+ samplesUrl: sdkEntry.platforms?.[targetPlatform]?.samples?.repo || sdkEntry.platforms?.python?.samples?.repo || ""
247
+ });
248
+ }
249
+
176
250
  const sampleName = selectDcvServerSample(targetPlatform, scenarioLower);
177
251
  const samplePath = getDcvServerSamplePath(targetPlatform, sampleName);
178
252
 
@@ -187,7 +261,7 @@ export function registerQuickstartTools({
187
261
  content: [{
188
262
  type: "text",
189
263
  text: [
190
- `# Quick Start: DCV Server (${targetPlatform})`,
264
+ `# Quick Start: ${isPublicDcvProduct ? publicProductLabel : "DCV Server"} (${targetPlatform})`,
191
265
  "",
192
266
  `**SDK Version:** ${sdkEntry.version}`,
193
267
  `**Trial License:** \`${registry.trial_license}\``,
@@ -210,8 +284,20 @@ export function registerQuickstartTools({
210
284
 
211
285
  if (effectiveEdition === "web") {
212
286
  const sdkEntry = registry.sdks["dcv-web"];
287
+ if (isPublicDcvProduct) {
288
+ const publicLinks = getPublicWebQuickstartLinks(normalizedProduct);
289
+ return buildPublicReferenceQuickstart({
290
+ product: normalizedProduct,
291
+ edition: effectiveEdition,
292
+ platform: "web",
293
+ docsUrl: publicLinks.docsUrl,
294
+ samplesUrl: publicLinks.samplesUrl
295
+ });
296
+ }
213
297
  const available = discoverDcvWebSamples();
214
- const sampleName = scenarioLower.includes("vin") ? "VINScanner" : (available[0] || "VINScanner");
298
+ const sampleName = isPublicDcvProduct
299
+ ? (normalizedProduct === "mrz" ? "MRZScanner" : "DocumentScanner")
300
+ : (scenarioLower.includes("vin") ? "VINScanner" : (available[0] || "VINScanner"));
215
301
  const samplePath = getDcvWebSamplePath(sampleName);
216
302
  if (!samplePath || !existsSync(samplePath)) {
217
303
  return { isError: true, content: [{ type: "text", text: `Sample not found: ${sampleName}.` }] };
@@ -223,7 +309,7 @@ export function registerQuickstartTools({
223
309
  content: [{
224
310
  type: "text",
225
311
  text: [
226
- "# Quick Start: DCV Web",
312
+ `# Quick Start: ${isPublicDcvProduct ? publicProductLabel : "DCV Web"}`,
227
313
  "",
228
314
  `**SDK Version:** ${sdkEntry.version}`,
229
315
  `**Trial License:** \`${registry.trial_license}\``,
@@ -262,7 +348,7 @@ export function registerQuickstartTools({
262
348
  content: [{
263
349
  type: "text",
264
350
  text: [
265
- `# Quick Start: DCV Mobile (${targetPlatform})`,
351
+ `# Quick Start: ${isPublicDcvProduct ? publicProductLabel : "DCV Mobile"} (${targetPlatform})`,
266
352
  "",
267
353
  `**SDK Version:** ${sdkEntry.version}`,
268
354
  `**Trial License:** \`${registry.trial_license}\``,
@@ -289,7 +375,7 @@ export function registerQuickstartTools({
289
375
  content: [{
290
376
  type: "text",
291
377
  text: [
292
- "# Quick Start: DCV Core",
378
+ `# Quick Start: ${isPublicDcvProduct ? publicProductLabel : "DCV Core"}`,
293
379
  "",
294
380
  `**SDK Version:** ${sdkEntry.version}`,
295
381
  "",
@@ -341,7 +427,7 @@ export function registerQuickstartTools({
341
427
  if (normalizedProduct === "dbr" && normalizedEdition === "web") {
342
428
  const sdkEntry = registry.sdks["dbr-web"];
343
429
  const scenarioLower = (scenario || "").toLowerCase();
344
- const sampleName = scenarioLower.includes("image") ? "read-an-image" : "hello-world";
430
+ const sampleName = scenarioLower.includes("hello") ? "hello-world" : "read-an-image";
345
431
  const samplePath = getWebSamplePath("root", sampleName);
346
432
 
347
433
  if (!samplePath || !existsSync(samplePath)) {
@@ -358,6 +444,9 @@ export function registerQuickstartTools({
358
444
  "",
359
445
  `**SDK Version:** ${sdkEntry.version}`,
360
446
  `**Trial License:** \`${registry.trial_license}\``,
447
+ "**Starter profile:** Foundational-first",
448
+ "",
449
+ "Use the foundational web flow first so capture and decoding remain explicit and easier to adapt.",
361
450
  "",
362
451
  "## Option 1: CDN",
363
452
  "```html",
@@ -369,7 +458,7 @@ export function registerQuickstartTools({
369
458
  sdkEntry.platforms.web.installation.npm,
370
459
  "```",
371
460
  "",
372
- `## ${sampleName}.html`,
461
+ `## Foundational sample: ${sampleName}.html`,
373
462
  "```html",
374
463
  content,
375
464
  "```",
@@ -1,7 +1,10 @@
1
1
  import { z } from "zod";
2
+ import { buildUnknownPublicProductResponse, isKnownPublicOffering } from "../public-offerings.js";
3
+ import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
2
4
 
3
5
  export function registerSampleTools({
4
6
  server,
7
+ registry,
5
8
  ensureScopeHydrated,
6
9
  ensureLatestMajor,
7
10
  normalizeProduct,
@@ -23,14 +26,14 @@ export function registerSampleTools({
23
26
  "- To browse the full catalog of samples available for a product/edition/platform.",
24
27
  "- To discover sample IDs before calling get_sample_files.",
25
28
  "- When the user wants to see what samples exist without a specific keyword.",
26
- "- Use DCV scope for MRZ, VIN, document normalization, and driver license scenarios.",
29
+ "- Use MRZ for passport and machine-readable-zone workflows, and MDS for document scan and normalization workflows.",
27
30
  "",
28
31
  "WHEN NOT TO USE:",
29
32
  "- If you have a specific keyword or topic, use search instead (it ranks results by relevance).",
30
33
  "- If you already have a sample ID or URI, go directly to get_sample_files.",
31
34
  "",
32
35
  "PARAMETERS:",
33
- "- product: dcv, dbr, dwt, or ddv. Omit to list across all products.",
36
+ "- product: dbr, dwt, ddv, mrz, or mds. Omit to list across all public offerings.",
34
37
  "- edition: core, mobile, web, or server. Omit to list across all editions.",
35
38
  "- platform: android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.",
36
39
  "- limit: 1-200 (default 50). Max number of results.",
@@ -42,7 +45,7 @@ export function registerSampleTools({
42
45
  "RELATED TOOLS: search (keyword-based discovery), get_sample_files (retrieve full project files for a sample), get_index (discover valid product/edition/platform combinations)."
43
46
  ].join("\n"),
44
47
  inputSchema: {
45
- product: z.string().optional().describe("Product: dcv, dbr, dwt, ddv"),
48
+ product: z.string().optional().describe("Product: dbr, dwt, ddv, mrz, mds"),
46
49
  edition: z.string().optional().describe("Edition: core, mobile, web, server/desktop"),
47
50
  platform: z.string().optional().describe("Platform: android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core"),
48
51
  limit: z.number().int().min(1).max(200).optional().describe("Max results (default 50)")
@@ -56,8 +59,14 @@ export function registerSampleTools({
56
59
  },
57
60
  async ({ product, edition, platform, limit }) => {
58
61
  const normalizedProduct = normalizeProduct(product);
62
+ if (product && !isKnownPublicOffering(normalizedProduct)) {
63
+ return buildUnknownPublicProductResponse(product);
64
+ }
65
+
59
66
  const normalizedPlatform = normalizePlatform(platform);
60
67
  const normalizedEdition = normalizeEdition(edition, normalizedPlatform, normalizedProduct);
68
+ const unsupportedScopeResponse = buildUnsupportedPublicScopeResponse(normalizedProduct, normalizedEdition, normalizedPlatform);
69
+ if (unsupportedScopeResponse) return unsupportedScopeResponse;
61
70
 
62
71
  await ensureScopeHydrated({
63
72
  product: normalizedProduct,
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { buildUnknownPublicProductResponse, isKnownPublicOffering } from "../public-offerings.js";
2
3
 
3
4
  export function registerVersionTools({
4
5
  server,
@@ -9,6 +10,47 @@ export function registerVersionTools({
9
10
  LATEST_MAJOR,
10
11
  LATEST_VERSIONS
11
12
  }) {
13
+ function buildPublicDcvVersionResponse(product, edition, platform) {
14
+ const label = product === "mrz" ? "MRZ" : "MDS";
15
+ const supportedEditions = product === "mrz"
16
+ ? [
17
+ { key: "web", name: "Web", version: LATEST_VERSIONS.dcv.web },
18
+ { key: "mobile", name: "Mobile", version: LATEST_VERSIONS.dcv.mobile }
19
+ ]
20
+ : [{ key: "web", name: "Web", version: LATEST_VERSIONS.dcv.web }];
21
+ const supportedEditionKeys = supportedEditions.map((entry) => entry.key).join(", ");
22
+
23
+ if (!edition) {
24
+ const lines = [
25
+ `# ${label} Version Resolution`,
26
+ `- Latest major: v${LATEST_MAJOR.dcv}`,
27
+ ...supportedEditions.map((entry) => `- ${entry.name}: ${entry.version}`),
28
+ "",
29
+ "Specify edition/platform to resolve a single version."
30
+ ];
31
+ return { content: [{ type: "text", text: lines.join("\n") }] };
32
+ }
33
+
34
+ const supportedEdition = supportedEditions.find((entry) => entry.key === edition);
35
+ if (!supportedEdition) {
36
+ return {
37
+ isError: true,
38
+ content: [{ type: "text", text: `Edition "${edition}" is not hosted by this MCP server. Supported editions: ${supportedEditionKeys}.` }]
39
+ };
40
+ }
41
+
42
+ const displayPlatform = platform === "web" ? "js" : platform;
43
+ const lines = [
44
+ `# ${label} Version Resolution`,
45
+ `- Edition: ${edition}`,
46
+ displayPlatform ? `- Platform: ${displayPlatform}` : "",
47
+ `- Latest major: v${LATEST_MAJOR.dcv}`,
48
+ `- Resolved version: ${supportedEdition.version}`
49
+ ].filter(Boolean);
50
+
51
+ return { content: [{ type: "text", text: lines.join("\n") }] };
52
+ }
53
+
12
54
  server.registerTool(
13
55
  "resolve_version",
14
56
  {
@@ -26,20 +68,20 @@ export function registerVersionTools({
26
68
  "- For browsing docs or samples, use search or list_samples (they already scope to latest major).",
27
69
  "",
28
70
  "PARAMETERS:",
29
- "- product (required): dcv, dbr, dwt, or ddv.",
71
+ "- product (required): dbr, dwt, ddv, mrz, or mds.",
30
72
  "- edition: core, mobile, web, or server. Omit to see all editions for the product.",
31
73
  "- platform: android, ios, js, python, cpp, java, dotnet, nodejs, etc. Helps narrow edition when ambiguous.",
32
74
  "- constraint: Version constraint like 'latest', '11.x', '10'. Only latest major version is served; legacy versions (e.g. DBR v9) return an error with migration guidance.",
33
75
  "- feature: Optional feature hint for version policy checks.",
34
76
  "",
35
- "RETURNS: A text block showing the resolved version. For DCV/DBR without an edition, returns all edition versions. For DWT/DDV, returns the single web version.",
77
+ "RETURNS: A text block showing the resolved version. For MRZ/MDS without an edition, returns the backed public version matrix. For DBR without an edition, returns all edition versions. For DWT/DDV, returns the single web version.",
36
78
  "",
37
79
  "EXAMPLE: resolve_version with product='dbr', edition='web' returns the latest DBR web SDK version string.",
38
80
  "",
39
81
  "RELATED TOOLS: get_quickstart (includes version in starter code), get_index (shows version overview)."
40
82
  ].join("\n"),
41
83
  inputSchema: {
42
- product: z.string().trim().min(1, "Product is required.").describe("Product: dcv, dbr, dwt, or ddv"),
84
+ product: z.string().trim().min(1, "Product is required.").describe("Product: dbr, dwt, ddv, mrz, mds"),
43
85
  edition: z.string().optional().describe("Edition: core, mobile, web, server/desktop"),
44
86
  platform: z.string().optional().describe("Platform: android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core"),
45
87
  constraint: z.string().optional().describe("Version constraint, e.g., latest, 11.x, 10"),
@@ -54,16 +96,13 @@ export function registerVersionTools({
54
96
  },
55
97
  async ({ product, edition, platform, constraint, feature }) => {
56
98
  const normalizedProduct = normalizeProduct(product);
99
+ if (product && !isKnownPublicOffering(normalizedProduct)) {
100
+ return buildUnknownPublicProductResponse(product);
101
+ }
102
+
57
103
  const normalizedPlatform = normalizePlatform(platform);
58
104
  const normalizedEdition = normalizeEdition(edition, normalizedPlatform, normalizedProduct);
59
105
 
60
- if (!["dcv", "dbr", "dwt", "ddv"].includes(normalizedProduct)) {
61
- return {
62
- isError: true,
63
- content: [{ type: "text", text: `Unknown product "${product}". Use dcv, dbr, dwt, or ddv.` }]
64
- };
65
- }
66
-
67
106
  const policy = ensureLatestMajor({
68
107
  product: normalizedProduct,
69
108
  version: constraint,
@@ -76,39 +115,8 @@ export function registerVersionTools({
76
115
  return { isError: true, content: [{ type: "text", text: policy.message }] };
77
116
  }
78
117
 
79
- if (normalizedProduct === "dcv") {
80
- if (!normalizedEdition) {
81
- const lines = [
82
- "# DCV Version Resolution",
83
- `- Latest major: v${LATEST_MAJOR.dcv}`,
84
- `- Core: ${LATEST_VERSIONS.dcv.core}`,
85
- `- Web: ${LATEST_VERSIONS.dcv.web}`,
86
- `- Mobile: ${LATEST_VERSIONS.dcv.mobile}`,
87
- `- Server/Desktop: ${LATEST_VERSIONS.dcv.server}`,
88
- "",
89
- "Specify edition/platform to resolve a single version."
90
- ];
91
- return { content: [{ type: "text", text: lines.join("\n") }] };
92
- }
93
-
94
- const resolved = LATEST_VERSIONS.dcv[normalizedEdition];
95
- if (!resolved) {
96
- return {
97
- isError: true,
98
- content: [{ type: "text", text: `Edition "${normalizedEdition}" is not hosted by this MCP server.` }]
99
- };
100
- }
101
-
102
- const displayPlatform = normalizedPlatform === "web" ? "js" : normalizedPlatform;
103
- const lines = [
104
- "# DCV Version Resolution",
105
- `- Edition: ${normalizedEdition}`,
106
- displayPlatform ? `- Platform: ${displayPlatform}` : "",
107
- `- Latest major: v${LATEST_MAJOR.dcv}`,
108
- `- Resolved version: ${resolved}`
109
- ].filter(Boolean);
110
-
111
- return { content: [{ type: "text", text: lines.join("\n") }] };
118
+ if (normalizedProduct === "mrz" || normalizedProduct === "mds") {
119
+ return buildPublicDcvVersionResponse(normalizedProduct, normalizedEdition, normalizedPlatform);
112
120
  }
113
121
 
114
122
  if (normalizedProduct === "dbr") {