simple-dynamsoft-mcp 7.2.9 → 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.
@@ -18,12 +18,16 @@ let cachedWebFrameworkPlatforms = null;
18
18
  let cachedDbrWebFrameworkPlatforms = null;
19
19
  let cachedDdvWebFrameworkPlatforms = null;
20
20
  let cachedDcvWebFrameworkPlatforms = null;
21
+ let cachedMrzWebFrameworkPlatforms = null;
22
+ let cachedMdsWebFrameworkPlatforms = null;
21
23
 
22
24
  function resetSampleDiscoveryCaches() {
23
25
  cachedWebFrameworkPlatforms = null;
24
26
  cachedDbrWebFrameworkPlatforms = null;
25
27
  cachedDdvWebFrameworkPlatforms = null;
26
28
  cachedDcvWebFrameworkPlatforms = null;
29
+ cachedMrzWebFrameworkPlatforms = null;
30
+ cachedMdsWebFrameworkPlatforms = null;
27
31
  }
28
32
 
29
33
  function getCodeFileExtensions() {
@@ -46,6 +50,10 @@ function getDbrWebSamplesRoot() {
46
50
  return getExistingPath(join(SAMPLE_ROOTS.dbrWeb, "web"), SAMPLE_ROOTS.dbrWeb);
47
51
  }
48
52
 
53
+ function getDedicatedWebSamplesRoot(root) {
54
+ return getExistingPath(join(root, "samples"), root);
55
+ }
56
+
49
57
  function getDbrCrossMobileRoot(platform) {
50
58
  if (platform === "maui") return SAMPLE_ROOTS.dbrMaui;
51
59
  if (platform === "react-native") return SAMPLE_ROOTS.dbrReactNative;
@@ -291,6 +299,63 @@ function discoverWebSamples() {
291
299
  return categories;
292
300
  }
293
301
 
302
+ function discoverDedicatedWebSamples(root) {
303
+ const categories = { root: [] };
304
+ const webPath = getDedicatedWebSamplesRoot(root);
305
+ if (!webPath || !existsSync(webPath)) return categories;
306
+
307
+ for (const entry of readdirSync(webPath, { withFileTypes: true })) {
308
+ if (entry.name.startsWith(".")) continue;
309
+
310
+ if (entry.isFile() && entry.name.endsWith(".html")) {
311
+ if (entry.name !== "index.html") {
312
+ categories.root.push(entry.name.replace(".html", ""));
313
+ }
314
+ continue;
315
+ }
316
+
317
+ if (!entry.isDirectory()) continue;
318
+
319
+ const categoryPath = join(webPath, entry.name);
320
+
321
+ if (entry.name === "frameworks" || entry.name === "scenarios") {
322
+ const categorySamples = [];
323
+ for (const child of readdirSync(categoryPath, { withFileTypes: true })) {
324
+ if (child.name.startsWith(".")) continue;
325
+ if (child.isDirectory()) categorySamples.push(child.name);
326
+ else if (child.isFile() && child.name.endsWith(".html") && child.name !== "index.html") {
327
+ categorySamples.push(child.name.replace(".html", ""));
328
+ }
329
+ }
330
+
331
+ categories[entry.name] = sortUnique(categorySamples);
332
+ continue;
333
+ }
334
+
335
+ if (existsSync(join(categoryPath, "index.html")) || existsSync(join(categoryPath, "README.md"))) {
336
+ categories.root.push(entry.name);
337
+ continue;
338
+ }
339
+
340
+ const categorySamples = [];
341
+ for (const child of readdirSync(categoryPath, { withFileTypes: true })) {
342
+ if (child.name.startsWith(".")) continue;
343
+ if (child.isDirectory()) categorySamples.push(child.name);
344
+ else if (child.isFile() && child.name.endsWith(".html") && child.name !== "index.html") {
345
+ categorySamples.push(child.name.replace(".html", ""));
346
+ }
347
+ }
348
+
349
+ categories[entry.name] = sortUnique(categorySamples);
350
+ }
351
+
352
+ for (const [key, value] of Object.entries(categories)) {
353
+ if (value.length === 0) delete categories[key];
354
+ }
355
+
356
+ return categories;
357
+ }
358
+
294
359
  function getWebSamplePath(category, sampleName) {
295
360
  const webPath = getDbrWebSamplesRoot();
296
361
  if (!webPath || !existsSync(webPath)) return null;
@@ -316,6 +381,44 @@ function getWebSamplePath(category, sampleName) {
316
381
  return null;
317
382
  }
318
383
 
384
+ function getDedicatedWebSamplePath(root, category, sampleName) {
385
+ const webPath = getDedicatedWebSamplesRoot(root);
386
+ if (!webPath || !existsSync(webPath)) return null;
387
+
388
+ if (category === "root" || !category) {
389
+ const htmlPath = join(webPath, `${sampleName}.html`);
390
+ if (existsSync(htmlPath)) return htmlPath;
391
+
392
+ const dirPath = join(webPath, sampleName);
393
+ if (existsSync(dirPath) && statSync(dirPath).isDirectory()) {
394
+ const indexPath = join(dirPath, "index.html");
395
+ if (existsSync(indexPath)) return indexPath;
396
+ const readmePath = join(dirPath, "README.md");
397
+ if (existsSync(readmePath)) return readmePath;
398
+ return dirPath;
399
+ }
400
+
401
+ return null;
402
+ }
403
+
404
+ const dirPath = join(webPath, category, sampleName);
405
+ if (existsSync(dirPath) && statSync(dirPath).isDirectory()) {
406
+ return dirPath;
407
+ }
408
+
409
+ const htmlPath = join(webPath, category, `${sampleName}.html`);
410
+ if (existsSync(htmlPath)) return htmlPath;
411
+ return null;
412
+ }
413
+
414
+ function discoverMrzWebSamples() {
415
+ return discoverDedicatedWebSamples(SAMPLE_ROOTS.mrzWeb);
416
+ }
417
+
418
+ function discoverMdsWebSamples() {
419
+ return discoverDedicatedWebSamples(SAMPLE_ROOTS.mdsWeb);
420
+ }
421
+
319
422
  function discoverDwtSamples() {
320
423
  const categories = {};
321
424
  if (!existsSync(SAMPLE_ROOTS.dwt)) return categories;
@@ -388,12 +491,42 @@ function getDdvWebFrameworkPlatforms() {
388
491
  return cachedDdvWebFrameworkPlatforms;
389
492
  }
390
493
 
494
+ function getMrzWebFrameworkPlatforms() {
495
+ if (cachedMrzWebFrameworkPlatforms) return cachedMrzWebFrameworkPlatforms;
496
+ const frameworks = new Set();
497
+ const webSamples = discoverMrzWebSamples();
498
+ if (webSamples.frameworks) {
499
+ for (const name of webSamples.frameworks) {
500
+ const normalized = normalizePlatform(name);
501
+ if (normalized && normalized !== "web") frameworks.add(normalized);
502
+ }
503
+ }
504
+ cachedMrzWebFrameworkPlatforms = Array.from(frameworks).sort();
505
+ return cachedMrzWebFrameworkPlatforms;
506
+ }
507
+
508
+ function getMdsWebFrameworkPlatforms() {
509
+ if (cachedMdsWebFrameworkPlatforms) return cachedMdsWebFrameworkPlatforms;
510
+ const frameworks = new Set();
511
+ const webSamples = discoverMdsWebSamples();
512
+ if (webSamples.frameworks) {
513
+ for (const name of webSamples.frameworks) {
514
+ const normalized = normalizePlatform(name);
515
+ if (normalized && normalized !== "web") frameworks.add(normalized);
516
+ }
517
+ }
518
+ cachedMdsWebFrameworkPlatforms = Array.from(frameworks).sort();
519
+ return cachedMdsWebFrameworkPlatforms;
520
+ }
521
+
391
522
  function getWebFrameworkPlatforms() {
392
523
  if (cachedWebFrameworkPlatforms) return cachedWebFrameworkPlatforms;
393
524
  const frameworks = new Set([
394
525
  ...getDbrWebFrameworkPlatforms(),
395
526
  ...getDdvWebFrameworkPlatforms(),
396
- ...getDcvWebFrameworkPlatforms()
527
+ ...getDcvWebFrameworkPlatforms(),
528
+ ...getMrzWebFrameworkPlatforms(),
529
+ ...getMdsWebFrameworkPlatforms()
397
530
  ]);
398
531
  cachedWebFrameworkPlatforms = frameworks;
399
532
  return cachedWebFrameworkPlatforms;
@@ -575,6 +708,14 @@ function getDcvWebSamplePath(sampleName) {
575
708
  return null;
576
709
  }
577
710
 
711
+ function getMrzWebSamplePath(category, sampleName) {
712
+ return getDedicatedWebSamplePath(SAMPLE_ROOTS.mrzWeb, category, sampleName);
713
+ }
714
+
715
+ function getMdsWebSamplePath(category, sampleName) {
716
+ return getDedicatedWebSamplePath(SAMPLE_ROOTS.mdsWeb, category, sampleName);
717
+ }
718
+
578
719
  function readCodeFile(filePath) {
579
720
  if (!existsSync(filePath)) return null;
580
721
  return readFileSync(filePath, "utf8");
@@ -701,6 +842,8 @@ export {
701
842
  discoverDcvServerSamples,
702
843
  discoverDcvWebSamples,
703
844
  discoverWebSamples,
845
+ discoverMrzWebSamples,
846
+ discoverMdsWebSamples,
704
847
  getWebSamplePath,
705
848
  discoverDwtSamples,
706
849
  discoverDdvSamples,
@@ -708,6 +851,8 @@ export {
708
851
  getDbrWebFrameworkPlatforms,
709
852
  getDcvWebFrameworkPlatforms,
710
853
  getDdvWebFrameworkPlatforms,
854
+ getMrzWebFrameworkPlatforms,
855
+ getMdsWebFrameworkPlatforms,
711
856
  getWebFrameworkPlatforms,
712
857
  findCodeFilesInSample,
713
858
  getDbrMobilePlatforms,
@@ -720,6 +865,8 @@ export {
720
865
  getDcvMobileSamplePath,
721
866
  getDcvServerSamplePath,
722
867
  getDcvWebSamplePath,
868
+ getMrzWebSamplePath,
869
+ getMdsWebSamplePath,
723
870
  getDwtSamplePath,
724
871
  getDdvSamplePath,
725
872
  readCodeFile,
@@ -70,6 +70,18 @@ function parseSampleUri(uri) {
70
70
  };
71
71
  }
72
72
 
73
+ if ((parsed.product === "mrz" || parsed.product === "mds") && (parsed.edition === "mobile" || parsed.edition === "server" || parsed.edition === "web")) {
74
+ const isStructuredWebSample = parsed.edition === "web" && parsed.parts.length >= 6;
75
+ return {
76
+ product: parsed.product,
77
+ edition: parsed.edition,
78
+ platform: parsed.platform,
79
+ version: parsed.version,
80
+ category: isStructuredWebSample ? parsed.parts[4] : undefined,
81
+ sampleName: isStructuredWebSample ? parsed.parts[5] : parsed.parts[4]
82
+ };
83
+ }
84
+
73
85
  if (parsed.product === "dcv" && (parsed.edition === "mobile" || parsed.edition === "server" || parsed.edition === "web")) {
74
86
  return {
75
87
  product: "dcv",
@@ -1,6 +1,11 @@
1
1
  import { LEGACY_DBR_LINKS, LEGACY_DWT_LINKS } from "./config.js";
2
2
  import { inferProductFromQuery, normalizeEdition, normalizePlatform } from "../normalizers.js";
3
3
 
4
+ const VERSION_FAMILY_BY_PRODUCT = {
5
+ mrz: "dcv",
6
+ mds: "dcv"
7
+ };
8
+
4
9
  function parseMajorVersion(version) {
5
10
  if (!version) return null;
6
11
  const match = String(version).match(/(\d+)/);
@@ -69,7 +74,8 @@ function ensureLatestMajor({ product, version, query, edition, platform, latestM
69
74
  const inferredProduct = product || inferProductFromQuery(query);
70
75
  if (!inferredProduct) return { ok: true };
71
76
 
72
- const currentMajor = latestMajor[inferredProduct];
77
+ const versionFamily = VERSION_FAMILY_BY_PRODUCT[inferredProduct] || inferredProduct;
78
+ const currentMajor = latestMajor[versionFamily];
73
79
  const requestedMajor = parseMajorVersion(version) ?? detectMajorFromQuery(query);
74
80
 
75
81
  if (!requestedMajor || requestedMajor === currentMajor) {
@@ -83,10 +89,11 @@ function ensureLatestMajor({ product, version, query, edition, platform, latestM
83
89
  };
84
90
  }
85
91
 
86
- if (inferredProduct === "dcv") {
92
+ if (versionFamily === "dcv") {
93
+ const offeringName = inferredProduct === "dcv" ? "DCV" : inferredProduct.toUpperCase();
87
94
  return {
88
95
  ok: false,
89
- message: `This MCP server only serves the latest major version of DCV (v${currentMajor}).`
96
+ message: `This MCP server only serves the latest major version of ${offeringName} (DCV-backed, v${currentMajor}).`
90
97
  };
91
98
  }
92
99
 
@@ -140,13 +147,14 @@ function buildVersionPolicyText(latestMajor) {
140
147
  "This MCP server only serves the latest major versions of each product.",
141
148
  "",
142
149
  `- DBR latest major: v${latestMajor.dbr}`,
143
- `- DCV latest major: v${latestMajor.dcv}`,
150
+ `- MRZ latest major: v${latestMajor.dcv} (DCV-backed)`,
151
+ `- MDS latest major: v${latestMajor.dcv} (DCV-backed)`,
144
152
  `- DWT latest major: v${latestMajor.dwt}`,
145
153
  `- DDV latest major: v${latestMajor.ddv}`,
146
154
  "",
147
155
  "Legacy support:",
148
156
  "- DBR v9 and v10 docs are linked when requested.",
149
- "- DCV has no legacy archive links in this server.",
157
+ "- MRZ and MDS do not publish separate legacy archive links; they follow the latest DCV-backed major only.",
150
158
  `- DWT archived docs available: ${dwtLegacyVersions || "none"}.`,
151
159
  "- DDV has no legacy archive links in this server.",
152
160
  "",
@@ -32,14 +32,20 @@ import {
32
32
  discoverDcvMobileSamples,
33
33
  discoverDcvServerSamples,
34
34
  discoverDcvWebSamples,
35
+ discoverMrzWebSamples,
36
+ discoverMdsWebSamples,
35
37
  discoverWebSamples,
36
38
  getWebSamplePath,
39
+ getMrzWebSamplePath,
40
+ getMdsWebSamplePath,
37
41
  discoverDwtSamples,
38
42
  discoverDdvSamples,
39
43
  mapDdvSampleToFramework,
40
44
  getDbrWebFrameworkPlatforms,
41
45
  getDcvWebFrameworkPlatforms,
42
46
  getDdvWebFrameworkPlatforms,
47
+ getMrzWebFrameworkPlatforms,
48
+ getMdsWebFrameworkPlatforms,
43
49
  getWebFrameworkPlatforms,
44
50
  findCodeFilesInSample,
45
51
  getDbrMobilePlatforms,
@@ -137,6 +143,8 @@ let dbrMobileDocs = [];
137
143
  let dbrServerDocs = [];
138
144
  let dcvCoreDocs = [];
139
145
  let dcvWebDocs = [];
146
+ let mrzWebDocs = [];
147
+ let mdsWebDocs = [];
140
148
  let dcvMobileDocs = [];
141
149
  let dcvServerDocs = [];
142
150
  let dwtDocs = { articles: [] };
@@ -198,6 +206,28 @@ function loadDocumentationSets() {
198
206
  () => "web"
199
207
  );
200
208
 
209
+ mrzWebDocs = withEditionScope(
210
+ loadMarkdownDocs({
211
+ rootDir: DOC_ROOTS.mrzWeb,
212
+ urlBase: DOCS_CONFIG.mrzWeb.urlBase,
213
+ excludeDirs: DOCS_CONFIG.mrzWeb.excludeDirs,
214
+ excludeFiles: DOCS_CONFIG.mrzWeb.excludeFiles
215
+ }).articles,
216
+ "web",
217
+ () => "web"
218
+ );
219
+
220
+ mdsWebDocs = withEditionScope(
221
+ loadMarkdownDocs({
222
+ rootDir: DOC_ROOTS.mdsWeb,
223
+ urlBase: DOCS_CONFIG.mdsWeb.urlBase,
224
+ excludeDirs: DOCS_CONFIG.mdsWeb.excludeDirs,
225
+ excludeFiles: DOCS_CONFIG.mdsWeb.excludeFiles
226
+ }).articles,
227
+ "web",
228
+ () => "web"
229
+ );
230
+
201
231
  dcvMobileDocs = withEditionScope(
202
232
  loadMarkdownDocs({
203
233
  rootDir: DOC_ROOTS.dcvMobile,
@@ -292,6 +322,8 @@ function buildIndexData() {
292
322
  LATEST_MAJOR,
293
323
  dcvCoreDocs,
294
324
  dcvWebDocs,
325
+ mrzWebDocs,
326
+ mdsWebDocs,
295
327
  dcvMobileDocs,
296
328
  dcvServerDocs,
297
329
  dbrWebDocs,
@@ -301,6 +333,10 @@ function buildIndexData() {
301
333
  ddvDocs,
302
334
  discoverDcvWebSamples,
303
335
  getDcvWebFrameworkPlatforms,
336
+ discoverMrzWebSamples,
337
+ getMrzWebFrameworkPlatforms,
338
+ discoverMdsWebSamples,
339
+ getMdsWebFrameworkPlatforms,
304
340
  getDcvMobilePlatforms,
305
341
  getDcvServerPlatforms,
306
342
  discoverDcvMobileSamples,
@@ -313,7 +349,8 @@ function buildIndexData() {
313
349
  discoverDbrServerSamples,
314
350
  discoverDwtSamples,
315
351
  discoverDdvSamples,
316
- getDdvWebFrameworkPlatforms
352
+ getDdvWebFrameworkPlatforms,
353
+ resourceIndex
317
354
  });
318
355
  }
319
356
 
@@ -326,6 +363,8 @@ function buildResourceIndex() {
326
363
  LATEST_MAJOR,
327
364
  dcvCoreDocs,
328
365
  dcvWebDocs,
366
+ mrzWebDocs,
367
+ mdsWebDocs,
329
368
  dcvMobileDocs,
330
369
  dcvServerDocs,
331
370
  dbrWebDocs,
@@ -341,6 +380,10 @@ function buildResourceIndex() {
341
380
  getDcvServerSampleContent,
342
381
  discoverDcvWebSamples,
343
382
  getDcvWebSamplePath,
383
+ discoverMrzWebSamples,
384
+ getMrzWebSamplePath,
385
+ discoverMdsWebSamples,
386
+ getMdsWebSamplePath,
344
387
  discoverMobileSamples,
345
388
  getDbrMobilePlatforms,
346
389
  getMobileSamplePath,
@@ -393,9 +436,12 @@ function platformMatches(normalizedPlatform, entry) {
393
436
  if (normalizedPlatform === entry.platform) return true;
394
437
  if (normalizedPlatform === "web") return entry.platform === "web";
395
438
  if (isWebFrameworkPlatform(normalizedPlatform)) {
439
+ const aliases = WEB_FRAMEWORK_TAG_ALIASES[normalizedPlatform] || [normalizedPlatform];
440
+ if (aliases.includes(entry.platform)) {
441
+ return true;
442
+ }
396
443
  if (entry.platform === "web" && Array.isArray(entry.tags)) {
397
444
  const tags = entry.tags.map((tag) => String(tag).toLowerCase());
398
- const aliases = WEB_FRAMEWORK_TAG_ALIASES[normalizedPlatform] || [normalizedPlatform];
399
445
  return aliases.some((alias) => tags.includes(alias));
400
446
  }
401
447
  return entry.platform === normalizedPlatform;
@@ -499,6 +545,8 @@ function getRagSignatureData() {
499
545
  resourceCount: resourceIndex.length,
500
546
  dcvCoreDocCount: dcvCoreDocs.length,
501
547
  dcvWebDocCount: dcvWebDocs.length,
548
+ mrzWebDocCount: mrzWebDocs.length,
549
+ mdsWebDocCount: mdsWebDocs.length,
502
550
  dcvMobileDocCount: dcvMobileDocs.length,
503
551
  dcvServerDocCount: dcvServerDocs.length,
504
552
  dbrWebDocCount: dbrWebDocs.length,
@@ -519,6 +567,8 @@ function getRagSignatureData() {
519
567
  dbrFlutterSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dbrFlutter),
520
568
  dbrNodejsSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dbrNodejs),
521
569
  dcvWebSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dcvWeb),
570
+ mrzWebSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.mrzWeb),
571
+ mdsWebSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.mdsWeb),
522
572
  dcvMobileSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dcvMobile),
523
573
  dcvPythonSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dcvPython),
524
574
  dcvDotnetSamplesHead: readManifestRepoCommit(SAMPLE_ROOTS.dcvDotnet),
@@ -536,6 +586,8 @@ function getRagSignatureData() {
536
586
  dbrServerDocsHead: readManifestRepoCommit(DOC_ROOTS.dbrServer),
537
587
  dcvCoreDocsHead: readManifestRepoCommit(DOC_ROOTS.dcvCore),
538
588
  dcvWebDocsHead: readManifestRepoCommit(DOC_ROOTS.dcvWeb),
589
+ mrzWebDocsHead: readManifestRepoCommit(DOC_ROOTS.mrzWeb),
590
+ mdsWebDocsHead: readManifestRepoCommit(DOC_ROOTS.mdsWeb),
539
591
  dcvMobileDocsHead: readManifestRepoCommit(DOC_ROOTS.dcvMobile),
540
592
  dcvServerDocsHead: readManifestRepoCommit(DOC_ROOTS.dcvServer),
541
593
  dwtDocsHead: readManifestRepoCommit(DOC_ROOTS.dwt),
@@ -560,6 +612,8 @@ export {
560
612
  discoverDcvMobileSamples,
561
613
  discoverDcvServerSamples,
562
614
  discoverDcvWebSamples,
615
+ discoverMrzWebSamples,
616
+ discoverMdsWebSamples,
563
617
  discoverWebSamples,
564
618
  getWebSamplePath,
565
619
  discoverDwtSamples,
@@ -568,6 +622,8 @@ export {
568
622
  getDbrWebFrameworkPlatforms,
569
623
  getDcvWebFrameworkPlatforms,
570
624
  getDdvWebFrameworkPlatforms,
625
+ getMrzWebFrameworkPlatforms,
626
+ getMdsWebFrameworkPlatforms,
571
627
  getWebFrameworkPlatforms,
572
628
  findCodeFilesInSample,
573
629
  getDbrServerSamplePath,
@@ -580,6 +636,8 @@ export {
580
636
  getDcvMobileSamplePath,
581
637
  getDcvServerSamplePath,
582
638
  getDcvWebSamplePath,
639
+ getMrzWebSamplePath,
640
+ getMdsWebSamplePath,
583
641
  getDwtSamplePath,
584
642
  getDdvSamplePath,
585
643
  readCodeFile,
@@ -28,7 +28,7 @@ export function registerResourceHandlers({
28
28
  async function templateReadHandler(uri) {
29
29
  const uriStr = uri.toString();
30
30
  const parsed = parseResourceUri(uriStr);
31
- if (parsed && ["dcv", "dbr", "dwt", "ddv"].includes(parsed.product)) {
31
+ if (parsed && ["dbr", "dwt", "ddv", "mrz", "mds"].includes(parsed.product)) {
32
32
  const policy = ensureLatestMajor({
33
33
  product: parsed.product,
34
34
  version: parsed.version,
@@ -0,0 +1,75 @@
1
+ const SERVER_SAMPLE_REPOS = {
2
+ python: "https://github.com/Dynamsoft/capture-vision-python-samples",
3
+ cpp: "https://github.com/Dynamsoft/capture-vision-cpp-samples",
4
+ java: "https://github.com/Dynamsoft/capture-vision-java-samples",
5
+ dotnet: "https://github.com/Dynamsoft/capture-vision-dotnet-samples",
6
+ nodejs: "https://github.com/Dynamsoft/capture-vision-nodejs-samples"
7
+ };
8
+
9
+ const MOBILE_SAMPLE_REPOS = {
10
+ android: "https://github.com/Dynamsoft/capture-vision-mobile-samples/tree/main/Android",
11
+ ios: "https://github.com/Dynamsoft/capture-vision-mobile-samples/tree/main/iOS",
12
+ spm: "https://github.com/Dynamsoft/capture-vision-mobile-samples/tree/main/iOS",
13
+ "react-native": "https://github.com/Dynamsoft/capture-vision-react-native-samples",
14
+ flutter: "https://github.com/Dynamsoft/capture-vision-flutter-samples",
15
+ maui: "https://github.com/Dynamsoft/capture-vision-maui-samples"
16
+ };
17
+
18
+ function getPublicServerSamplesUrl(platform) {
19
+ return SERVER_SAMPLE_REPOS[platform] || SERVER_SAMPLE_REPOS.python;
20
+ }
21
+
22
+ function getPublicMobileSamplesUrl(platform) {
23
+ return MOBILE_SAMPLE_REPOS[platform] || MOBILE_SAMPLE_REPOS.android;
24
+ }
25
+
26
+ function getUnsupportedPublicScopeRedirect(product, edition, platform) {
27
+ if (product === "mrz" && edition === "server") {
28
+ return {
29
+ label: "MRZ",
30
+ docsUrl: "https://www.dynamsoft.com/capture-vision/docs/server/",
31
+ samplesUrl: getPublicServerSamplesUrl(platform)
32
+ };
33
+ }
34
+
35
+ if (product === "mds" && edition === "mobile") {
36
+ return {
37
+ label: "MDS",
38
+ docsUrl: "https://www.dynamsoft.com/capture-vision/docs/mobile/",
39
+ samplesUrl: getPublicMobileSamplesUrl(platform)
40
+ };
41
+ }
42
+
43
+ if (product === "mds" && edition === "server") {
44
+ return {
45
+ label: "MDS",
46
+ docsUrl: "https://www.dynamsoft.com/capture-vision/docs/server/",
47
+ samplesUrl: getPublicServerSamplesUrl(platform)
48
+ };
49
+ }
50
+
51
+ return null;
52
+ }
53
+
54
+ function buildUnsupportedPublicScopeResponse(product, edition, platform) {
55
+ const redirect = getUnsupportedPublicScopeRedirect(product, edition, platform);
56
+ if (!redirect) return null;
57
+
58
+ const scope = [edition, platform].filter(Boolean).join(" / ") || "general";
59
+ return {
60
+ content: [{
61
+ type: "text",
62
+ text: [
63
+ `${redirect.label} ${scope} is not indexed in this MCP yet. Use these official links instead.`,
64
+ "Reference links:",
65
+ `- Docs: ${redirect.docsUrl}`,
66
+ `- Samples: ${redirect.samplesUrl}`
67
+ ].join("\n")
68
+ }]
69
+ };
70
+ }
71
+
72
+ export {
73
+ getUnsupportedPublicScopeRedirect,
74
+ buildUnsupportedPublicScopeResponse
75
+ };
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { formatScoreLabel, formatScoreNote } from "../helpers/server-helpers.js";
3
+ import { buildUnknownPublicProductResponse, isKnownPublicOffering } from "../public-offerings.js";
4
+ import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
3
5
 
4
6
  export function registerIndexTools({
5
7
  server,
@@ -16,23 +18,29 @@ export function registerIndexTools({
16
18
  getSampleEntries,
17
19
  getSampleSuggestions
18
20
  }) {
21
+ function looksLikeSampleIdQuery(value) {
22
+ const normalized = String(value || "").trim();
23
+ if (!normalized) return false;
24
+ return /[-_/]/.test(normalized);
25
+ }
26
+
19
27
  server.registerTool(
20
28
  "get_index",
21
29
  {
22
30
  title: "Get Index",
23
31
  description: [
24
- "Get a compact index of all Dynamsoft products, editions, platforms, versions, and available docs/samples.",
32
+ "Get a compact index of the public Dynamsoft offerings, editions, platforms, versions, and available docs/samples.",
25
33
  "",
26
34
  "WHEN TO USE:",
27
35
  "- As the first call in any conversation to discover what is available.",
28
36
  "- To determine valid product/edition/platform combinations before calling other tools.",
29
- "- To get DBR-vs-DCV selection guidance (DBR for barcode-only; DCV for MRZ, VIN, document normalization, driver license).",
37
+ "- To get public product-selection guidance (DBR for barcode-only; MRZ for machine-readable-zone workflows; MDS for document scan and normalization workflows).",
30
38
  "",
31
39
  "WHEN NOT TO USE:",
32
40
  "- Do not call get_index repeatedly; the index is static within a session.",
33
41
  "- If you already know the product/edition/platform, skip directly to search or get_quickstart.",
34
42
  "",
35
- "RETURNS: A JSON object with top-level keys: productSelection and products. productSelection contains guidance for choosing between products (for example, DBR vs DCV), and products contains per-product entries (dcv, dbr, dwt, ddv) with editions, platforms, latest versions, and counts of available docs and samples.",
43
+ "RETURNS: A JSON object with top-level keys: productSelection and products. productSelection contains guidance for choosing between public offerings, and products contains per-product entries (dbr, dwt, ddv, mrz, mds) with editions, platforms, latest versions, and counts of available docs and samples.",
36
44
  "",
37
45
  "PARAMETERS: None.",
38
46
  "",
@@ -64,7 +72,7 @@ export function registerIndexTools({
64
72
  "",
65
73
  "WHEN TO USE:",
66
74
  "- To find docs or samples by keyword, topic, or exact sample ID.",
67
- "- To look up specific scenarios: MRZ scanning, VIN reading, barcode decoding, document normalization, etc.",
75
+ "- To look up specific scenarios: MRZ scanning, barcode decoding, document normalization, document scanning, and viewer workflows.",
68
76
  "- When you have a natural-language question about a Dynamsoft SDK.",
69
77
  "- For sample lookup by exact ID (e.g. query='hello-world', type='sample').",
70
78
  "",
@@ -75,7 +83,7 @@ export function registerIndexTools({
75
83
  "",
76
84
  "PARAMETERS:",
77
85
  "- query (required): Keywords or exact sample ID. Examples: 'barcode scanning from camera', 'MRZ passport reader', 'hello-world'.",
78
- "- product: dcv, dbr, dwt, or ddv. Prefer DCV for MRZ/VIN/document-normalization/driver-license; DBR for barcode-only.",
86
+ "- product: dbr, dwt, ddv, mrz, or mds. Use DBR for barcode-only, MRZ for passport/machine-readable-zone workflows, and MDS for document scan or normalization workflows.",
79
87
  "- edition: core, mobile, web, or server.",
80
88
  "- platform: android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.",
81
89
  "- version: Version constraint (e.g. '10', '11.x'). Only latest major is served by default.",
@@ -88,7 +96,7 @@ export function registerIndexTools({
88
96
  ].join("\n"),
89
97
  inputSchema: {
90
98
  query: z.string().trim().min(1, "Query is required.").describe("Keywords to search across docs and samples."),
91
- product: z.string().optional().describe("Product: dcv, dbr, dwt, ddv"),
99
+ product: z.string().optional().describe("Product: dbr, dwt, ddv, mrz, mds"),
92
100
  edition: z.string().optional().describe("Edition: core, mobile, web, server/desktop"),
93
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, spm, core"),
94
102
  version: z.string().optional().describe("Version constraint (major or full version)"),
@@ -104,8 +112,14 @@ export function registerIndexTools({
104
112
  },
105
113
  async ({ query, product, edition, platform, version, type, limit }) => {
106
114
  const normalizedProduct = normalizeProduct(product);
115
+ if (product && !isKnownPublicOffering(normalizedProduct)) {
116
+ return buildUnknownPublicProductResponse(product);
117
+ }
118
+
107
119
  const normalizedPlatform = normalizePlatform(platform);
108
120
  const normalizedEdition = normalizeEdition(edition, normalizedPlatform, normalizedProduct);
121
+ const unsupportedScopeResponse = buildUnsupportedPublicScopeResponse(normalizedProduct, normalizedEdition, normalizedPlatform);
122
+ if (unsupportedScopeResponse) return unsupportedScopeResponse;
109
123
 
110
124
  await ensureScopeHydrated({
111
125
  product: normalizedProduct,
@@ -185,14 +199,19 @@ export function registerIndexTools({
185
199
  }
186
200
  }
187
201
 
188
- const topResults = await searchResources({
189
- query,
190
- product: normalizedProduct,
191
- edition: normalizedEdition,
192
- platform: normalizedPlatform,
193
- type: effectiveType,
194
- limit: maxResults
195
- });
202
+ const preferSampleSuggestionFallback =
203
+ effectiveType === "sample" && looksLikeSampleIdQuery(query);
204
+
205
+ const topResults = preferSampleSuggestionFallback
206
+ ? []
207
+ : await searchResources({
208
+ query,
209
+ product: normalizedProduct,
210
+ edition: normalizedEdition,
211
+ platform: normalizedPlatform,
212
+ type: effectiveType,
213
+ limit: maxResults
214
+ });
196
215
 
197
216
  if (topResults.length === 0) {
198
217
  // Only try sample suggestions when searching samples or any type