simple-dynamsoft-mcp 7.2.9 → 7.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,10 +3,11 @@
3
3
  MCP server that helps AI assistants generate accurate code and guidance for Dynamsoft SDKs.
4
4
 
5
5
  Supported products:
6
- - Dynamsoft Capture Vision (DCV)
7
- - Dynamsoft Barcode Reader (DBR): mobile, web, server/desktop
8
6
  - Dynamic Web TWAIN (DWT)
9
7
  - Dynamsoft Document Viewer (DDV)
8
+ - Dynamsoft Barcode Reader (DBR): mobile, web, server/desktop
9
+ - Dynamsoft MRZ Scanner (MRZ)
10
+ - Dynamsoft Mobile Scanner (MDS)
10
11
 
11
12
  Default transport is `stdio`. Native Streamable HTTP is also supported at `/mcp`.
12
13
 
@@ -18,8 +18,8 @@
18
18
  "branch": "main",
19
19
  "owner": "dynamsoft-docs",
20
20
  "repo": "barcode-reader-docs-mobile",
21
- "commit": "e0308b08e0b235093b29af187839835e0e4b7c20",
22
- "archiveUrl": "https://codeload.github.com/dynamsoft-docs/barcode-reader-docs-mobile/zip/e0308b08e0b235093b29af187839835e0e4b7c20"
21
+ "commit": "73e2ec43e875e093367b385f167e021f47f2ee1b",
22
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/barcode-reader-docs-mobile/zip/73e2ec43e875e093367b385f167e021f47f2ee1b"
23
23
  },
24
24
  {
25
25
  "name": "data/documentation/barcode-reader-docs-server",
@@ -28,8 +28,8 @@
28
28
  "branch": "main",
29
29
  "owner": "dynamsoft-docs",
30
30
  "repo": "barcode-reader-docs-server",
31
- "commit": "bd73f570f60885da04c883241d282fa3f50b45de",
32
- "archiveUrl": "https://codeload.github.com/dynamsoft-docs/barcode-reader-docs-server/zip/bd73f570f60885da04c883241d282fa3f50b45de"
31
+ "commit": "2a786507c616bc82e79e626f6d03f6b67bf93059",
32
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/barcode-reader-docs-server/zip/2a786507c616bc82e79e626f6d03f6b67bf93059"
33
33
  },
34
34
  {
35
35
  "name": "data/documentation/capture-vision-docs",
@@ -48,8 +48,8 @@
48
48
  "branch": "main",
49
49
  "owner": "dynamsoft-docs",
50
50
  "repo": "capture-vision-docs-js",
51
- "commit": "0e1fbd5338505a8bbfc3310eb3c3fffe6a114cf5",
52
- "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-js/zip/0e1fbd5338505a8bbfc3310eb3c3fffe6a114cf5"
51
+ "commit": "e0a78b0bbe850feacac32c93ccc9f362ea7f2e2d",
52
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-js/zip/e0a78b0bbe850feacac32c93ccc9f362ea7f2e2d"
53
53
  },
54
54
  {
55
55
  "name": "data/documentation/capture-vision-docs-mobile",
@@ -58,8 +58,8 @@
58
58
  "branch": "main",
59
59
  "owner": "dynamsoft-docs",
60
60
  "repo": "capture-vision-docs-mobile",
61
- "commit": "618991bac7908e65aeb4669bcd2dd0f57c84bca3",
62
- "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-mobile/zip/618991bac7908e65aeb4669bcd2dd0f57c84bca3"
61
+ "commit": "06b8b0009ae72427dc63d4a2b58491c5fc74ed70",
62
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-mobile/zip/06b8b0009ae72427dc63d4a2b58491c5fc74ed70"
63
63
  },
64
64
  {
65
65
  "name": "data/documentation/capture-vision-docs-server",
@@ -68,8 +68,8 @@
68
68
  "branch": "main",
69
69
  "owner": "dynamsoft-docs",
70
70
  "repo": "capture-vision-docs-server",
71
- "commit": "d097a606f81cc2a3af5c813200715ed943009f5e",
72
- "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-server/zip/d097a606f81cc2a3af5c813200715ed943009f5e"
71
+ "commit": "f4653d3b7a5fa7e6706a3e848f676ed06f696685",
72
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/capture-vision-docs-server/zip/f4653d3b7a5fa7e6706a3e848f676ed06f696685"
73
73
  },
74
74
  {
75
75
  "name": "data/documentation/document-viewer-docs",
@@ -81,6 +81,26 @@
81
81
  "commit": "b187c4d36884df285d02dfb977e450e53f097d51",
82
82
  "archiveUrl": "https://codeload.github.com/dynamsoft-docs/document-viewer-docs/zip/b187c4d36884df285d02dfb977e450e53f097d51"
83
83
  },
84
+ {
85
+ "name": "data/documentation/mobile-document-scanner-docs-js",
86
+ "path": "documentation/mobile-document-scanner-docs-js",
87
+ "url": "https://github.com/dynamsoft-docs/mobile-document-scanner-docs-js.git",
88
+ "branch": "main",
89
+ "owner": "dynamsoft-docs",
90
+ "repo": "mobile-document-scanner-docs-js",
91
+ "commit": "ebef2d269a114ac7763a6c0635d098a09cdcbf59",
92
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/mobile-document-scanner-docs-js/zip/ebef2d269a114ac7763a6c0635d098a09cdcbf59"
93
+ },
94
+ {
95
+ "name": "data/documentation/mrz-scanner-docs-js",
96
+ "path": "documentation/mrz-scanner-docs-js",
97
+ "url": "https://github.com/dynamsoft-docs/mrz-scanner-docs-js.git",
98
+ "branch": "main",
99
+ "owner": "dynamsoft-docs",
100
+ "repo": "mrz-scanner-docs-js",
101
+ "commit": "9a4a8914a3c20f10267e5947c27e33264767f342",
102
+ "archiveUrl": "https://codeload.github.com/dynamsoft-docs/mrz-scanner-docs-js/zip/9a4a8914a3c20f10267e5947c27e33264767f342"
103
+ },
84
104
  {
85
105
  "name": "data/documentation/web-twain-docs",
86
106
  "path": "documentation/web-twain-docs",
@@ -91,6 +111,16 @@
91
111
  "commit": "7b8e127b298a2ef9abb7cd870bb742b44a132503",
92
112
  "archiveUrl": "https://codeload.github.com/dynamsoft-docs/web-twain-docs/zip/7b8e127b298a2ef9abb7cd870bb742b44a132503"
93
113
  },
114
+ {
115
+ "name": "data/samples/document-scanner-javascript",
116
+ "path": "samples/document-scanner-javascript",
117
+ "url": "https://github.com/Dynamsoft/document-scanner-javascript.git",
118
+ "branch": "main",
119
+ "owner": "Dynamsoft",
120
+ "repo": "document-scanner-javascript",
121
+ "commit": "af8d65b104ffef6f846b64fc2598baaa2a6ff6ea",
122
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/document-scanner-javascript/zip/af8d65b104ffef6f846b64fc2598baaa2a6ff6ea"
123
+ },
94
124
  {
95
125
  "name": "data/samples/dynamic-web-twain",
96
126
  "path": "samples/dynamic-web-twain",
@@ -118,8 +148,8 @@
118
148
  "branch": "main",
119
149
  "owner": "Dynamsoft",
120
150
  "repo": "barcode-reader-c-cpp-samples",
121
- "commit": "31193773be1b64616d84a0ac439dde1a1e1d3067",
122
- "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-c-cpp-samples/zip/31193773be1b64616d84a0ac439dde1a1e1d3067"
151
+ "commit": "3af2b7b60342e97b8f91ef803ea26e777bb4b4dd",
152
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-c-cpp-samples/zip/3af2b7b60342e97b8f91ef803ea26e777bb4b4dd"
123
153
  },
124
154
  {
125
155
  "name": "data/samples/dynamsoft-barcode-reader-dotnet",
@@ -128,8 +158,8 @@
128
158
  "branch": "main",
129
159
  "owner": "Dynamsoft",
130
160
  "repo": "barcode-reader-dotnet-samples",
131
- "commit": "5d7abad2ba3a23bff70ccbd8359f47ebb8605953",
132
- "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-dotnet-samples/zip/5d7abad2ba3a23bff70ccbd8359f47ebb8605953"
161
+ "commit": "e1779bb6996510225bb7e3adac365b3bed688be2",
162
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-dotnet-samples/zip/e1779bb6996510225bb7e3adac365b3bed688be2"
133
163
  },
134
164
  {
135
165
  "name": "data/samples/dynamsoft-barcode-reader-flutter",
@@ -148,8 +178,8 @@
148
178
  "branch": "main",
149
179
  "owner": "Dynamsoft",
150
180
  "repo": "barcode-reader-java-samples",
151
- "commit": "16cc16f9e0c8625842a43d6bdd1474720976ecd7",
152
- "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-java-samples/zip/16cc16f9e0c8625842a43d6bdd1474720976ecd7"
181
+ "commit": "c3f164a5eefd795ae2a7bb0cd8dacb70db7450b2",
182
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-java-samples/zip/c3f164a5eefd795ae2a7bb0cd8dacb70db7450b2"
153
183
  },
154
184
  {
155
185
  "name": "data/samples/dynamsoft-barcode-reader-maui",
@@ -188,8 +218,8 @@
188
218
  "branch": "main",
189
219
  "owner": "Dynamsoft",
190
220
  "repo": "barcode-reader-react-native-samples",
191
- "commit": "acb3ac877853f1543ff086fb15df30335b0d4cbe",
192
- "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-react-native-samples/zip/acb3ac877853f1543ff086fb15df30335b0d4cbe"
221
+ "commit": "05c43007ec6b64221d6ffad986ed6623195cb88b",
222
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/barcode-reader-react-native-samples/zip/05c43007ec6b64221d6ffad986ed6623195cb88b"
193
223
  },
194
224
  {
195
225
  "name": "data/samples/dynamsoft-capture-vision-c-cpp",
@@ -198,8 +228,8 @@
198
228
  "branch": "main",
199
229
  "owner": "Dynamsoft",
200
230
  "repo": "capture-vision-cpp-samples",
201
- "commit": "6d37fa7f16bc84cbd2b78651549cb900cf222571",
202
- "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-cpp-samples/zip/6d37fa7f16bc84cbd2b78651549cb900cf222571"
231
+ "commit": "dc2f6f21579591b95b6d5251066cb0094fa4ce74",
232
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-cpp-samples/zip/dc2f6f21579591b95b6d5251066cb0094fa4ce74"
203
233
  },
204
234
  {
205
235
  "name": "data/samples/dynamsoft-capture-vision-dotnet",
@@ -208,8 +238,8 @@
208
238
  "branch": "main",
209
239
  "owner": "Dynamsoft",
210
240
  "repo": "capture-vision-dotnet-samples",
211
- "commit": "1ac2d63ea45d63ee7421725e351936ca5c321ce2",
212
- "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-dotnet-samples/zip/1ac2d63ea45d63ee7421725e351936ca5c321ce2"
241
+ "commit": "1c6d1f3dbdcc11192b83498f5dca01fd192ee26a",
242
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-dotnet-samples/zip/1c6d1f3dbdcc11192b83498f5dca01fd192ee26a"
213
243
  },
214
244
  {
215
245
  "name": "data/samples/dynamsoft-capture-vision-flutter",
@@ -228,8 +258,8 @@
228
258
  "branch": "main",
229
259
  "owner": "Dynamsoft",
230
260
  "repo": "capture-vision-java-samples",
231
- "commit": "974c436210232a8579fc68b98f610c9d46e86979",
232
- "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-java-samples/zip/974c436210232a8579fc68b98f610c9d46e86979"
261
+ "commit": "ad9d5516cdae5d1240966271896f6f13e6ae5476",
262
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-java-samples/zip/ad9d5516cdae5d1240966271896f6f13e6ae5476"
233
263
  },
234
264
  {
235
265
  "name": "data/samples/dynamsoft-capture-vision-javascript",
@@ -288,8 +318,8 @@
288
318
  "branch": "main",
289
319
  "owner": "Dynamsoft",
290
320
  "repo": "capture-vision-react-native-samples",
291
- "commit": "c00158c5f3be2716a391d2f6f1412f9c8a2ac52f",
292
- "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-react-native-samples/zip/c00158c5f3be2716a391d2f6f1412f9c8a2ac52f"
321
+ "commit": "e27f4e6708f4eb8570893bf36399cc02b6f7759f",
322
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/capture-vision-react-native-samples/zip/e27f4e6708f4eb8570893bf36399cc02b6f7759f"
293
323
  },
294
324
  {
295
325
  "name": "data/samples/dynamsoft-capture-vision-spm",
@@ -310,6 +340,16 @@
310
340
  "repo": "document-viewer-samples",
311
341
  "commit": "84fbb0ce71aa4d327aeeb39dab57cab92c43cd9d",
312
342
  "archiveUrl": "https://codeload.github.com/Dynamsoft/document-viewer-samples/zip/84fbb0ce71aa4d327aeeb39dab57cab92c43cd9d"
343
+ },
344
+ {
345
+ "name": "data/samples/mrz-scanner-javascript",
346
+ "path": "samples/mrz-scanner-javascript",
347
+ "url": "https://github.com/Dynamsoft/mrz-scanner-javascript.git",
348
+ "branch": "main",
349
+ "owner": "Dynamsoft",
350
+ "repo": "mrz-scanner-javascript",
351
+ "commit": "1e33685573dafa918bc81a7baa9fc628e3830775",
352
+ "archiveUrl": "https://codeload.github.com/Dynamsoft/mrz-scanner-javascript/zip/1e33685573dafa918bc81a7baa9fc628e3830775"
313
353
  }
314
354
  ]
315
355
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simple-dynamsoft-mcp",
3
- "version": "7.2.9",
3
+ "version": "7.3.1",
4
4
  "description": "MCP server for Dynamsoft SDKs - Capture Vision, Barcode Reader (Mobile/Python/Web), Dynamic Web TWAIN, and Document Viewer. Provides documentation, code snippets, and API guidance.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,4 +1,5 @@
1
1
  import { normalizeHydrationScopes } from "./hydration-policy.js";
2
+ import { getHydrationProduct } from "../server/public-offerings.js";
2
3
 
3
4
  const REPO_MAP = {
4
5
  dbr: {
@@ -85,6 +86,39 @@ const REPO_MAP = {
85
86
  ]
86
87
  }
87
88
  },
89
+ mrz: {
90
+ docs: {
91
+ web: ["documentation/mrz-scanner-docs-js"],
92
+ any: [
93
+ "documentation/mrz-scanner-docs-js",
94
+ "documentation/capture-vision-docs-mobile"
95
+ ]
96
+ },
97
+ samples: {
98
+ web: ["samples/mrz-scanner-javascript"],
99
+ mobile: [
100
+ "samples/dynamsoft-capture-vision-react-native",
101
+ "samples/dynamsoft-capture-vision-flutter",
102
+ "samples/dynamsoft-capture-vision-mobile"
103
+ ],
104
+ any: [
105
+ "samples/mrz-scanner-javascript",
106
+ "samples/dynamsoft-capture-vision-react-native",
107
+ "samples/dynamsoft-capture-vision-flutter",
108
+ "samples/dynamsoft-capture-vision-mobile"
109
+ ]
110
+ }
111
+ },
112
+ mds: {
113
+ docs: {
114
+ web: ["documentation/mobile-document-scanner-docs-js"],
115
+ any: ["documentation/mobile-document-scanner-docs-js"]
116
+ },
117
+ samples: {
118
+ web: ["samples/document-scanner-javascript"],
119
+ any: ["samples/document-scanner-javascript"]
120
+ }
121
+ },
88
122
  dwt: {
89
123
  docs: {
90
124
  any: ["documentation/web-twain-docs"]
@@ -129,12 +163,18 @@ function resolveRepoPathsForScopes(scopes = [], manifest = null) {
129
163
  const includeSamples = scope.type === "any" || scope.type === "sample";
130
164
 
131
165
  if (includeDocs) {
132
- for (const path of getMappedPaths(scope.product, scope.edition, "docs")) {
166
+ const docsPaths = getMappedPaths(scope.product, scope.edition, "docs");
167
+ for (const path of (docsPaths.length > 0
168
+ ? docsPaths
169
+ : getMappedPaths(getHydrationProduct(scope.product), scope.edition, "docs"))) {
133
170
  resolved.add(path);
134
171
  }
135
172
  }
136
173
  if (includeSamples) {
137
- for (const path of getMappedPaths(scope.product, scope.edition, "samples")) {
174
+ const samplePaths = getMappedPaths(scope.product, scope.edition, "samples");
175
+ for (const path of (samplePaths.length > 0
176
+ ? samplePaths
177
+ : getMappedPaths(getHydrationProduct(scope.product), scope.edition, "samples"))) {
138
178
  resolved.add(path);
139
179
  }
140
180
  }
@@ -22,6 +22,8 @@ export function createMcpServerInstance({ pkgVersion, resourceIndexApi, ragApi }
22
22
  getDcvMobileSamplePath,
23
23
  getDcvServerSamplePath,
24
24
  getDcvWebSamplePath,
25
+ getMrzWebSamplePath,
26
+ getMdsWebSamplePath,
25
27
  getDwtSamplePath,
26
28
  getDdvSamplePath,
27
29
  readCodeFile,
@@ -62,7 +64,7 @@ export function createMcpServerInstance({ pkgVersion, resourceIndexApi, ragApi }
62
64
  const server = new McpServer({
63
65
  name: "simple-dynamsoft-mcp",
64
66
  version: pkgVersion,
65
- description: "MCP server for latest major versions of Dynamsoft SDKs: Capture Vision, Barcode Reader, Dynamic Web TWAIN, and Document Viewer. Includes guidance for choosing DBR vs DCV by scenario."
67
+ description: "MCP server for the public Dynamsoft offerings: Barcode Reader, Dynamic Web TWAIN, Document Viewer, MRZ, and MDS. Includes guidance for choosing the right public product by workflow."
66
68
  });
67
69
 
68
70
  registerIndexTools({
@@ -83,6 +85,7 @@ registerIndexTools({
83
85
 
84
86
  registerSampleTools({
85
87
  server,
88
+ registry,
86
89
  ensureScopeHydrated,
87
90
  ensureLatestMajor,
88
91
  normalizeProduct,
@@ -148,6 +151,8 @@ registerProjectTools({
148
151
  getDcvMobileSamplePath,
149
152
  getDcvServerSamplePath,
150
153
  getDcvWebSamplePath,
154
+ getMrzWebSamplePath,
155
+ getMdsWebSamplePath,
151
156
  getDwtSamplePath,
152
157
  getDdvSamplePath,
153
158
  getSampleSuggestions
@@ -1,3 +1,5 @@
1
+ import { normalizePublicOffering } from "./public-offerings.js";
2
+
1
3
  const sdkAliases = {
2
4
  // DCV
3
5
  "dcv": "dcv-mobile",
@@ -94,6 +96,7 @@ const platformAliases = {
94
96
  reactjs: "react",
95
97
  "react.js": "react",
96
98
  "react-vite": "react",
99
+ "react-hooks": "react",
97
100
  vue: "vue",
98
101
  vuejs: "vue",
99
102
  next: "next",
@@ -113,7 +116,7 @@ const platformAliases = {
113
116
 
114
117
  const SERVER_PLATFORMS = new Set(["python", "cpp", "java", "dotnet", "nodejs"]);
115
118
  const WEB_FRAMEWORK_TAG_ALIASES = {
116
- react: ["react", "react-vite"]
119
+ react: ["react", "react-vite", "react-hooks"]
117
120
  };
118
121
 
119
122
  const languageAliases = {
@@ -234,6 +237,9 @@ function normalizeSampleName(name) {
234
237
  function normalizeProduct(product) {
235
238
  if (!product) return "";
236
239
  const normalized = product.trim().toLowerCase();
240
+ const publicOffering = normalizePublicOffering(normalized);
241
+ if (publicOffering) return publicOffering;
242
+
237
243
  if (
238
244
  [
239
245
  "dcv",
@@ -242,24 +248,12 @@ function normalizeProduct(product) {
242
248
  "dynamsoft capture vision",
243
249
  "dynamsoft capture vision sdk",
244
250
  "capture vision bundle",
245
- "mrz scanner",
246
251
  "vin scanner",
247
- "driver license scanner",
248
- "document scanner",
249
- "document normalization"
252
+ "driver license scanner"
250
253
  ].includes(normalized)
251
254
  ) {
252
255
  return "dcv";
253
256
  }
254
- if (["ddv", "document viewer", "document-viewer", "dynamsoft document viewer", "doc viewer", "pdf viewer"].includes(normalized)) {
255
- return "ddv";
256
- }
257
- if (["dbr", "barcode reader", "barcode-reader", "dynamsoft barcode reader"].includes(normalized)) {
258
- return "dbr";
259
- }
260
- if (["dwt", "dynamic web twain", "web twain", "webtwain"].includes(normalized)) {
261
- return "dwt";
262
- }
263
257
  return normalized;
264
258
  }
265
259
 
@@ -0,0 +1,71 @@
1
+ const PUBLIC_OFFERING_ALIASES = {
2
+ dwt: "dwt",
3
+ "dynamic web twain": "dwt",
4
+ "web twain": "dwt",
5
+ webtwain: "dwt",
6
+ twain: "dwt",
7
+ ddv: "ddv",
8
+ "document viewer": "ddv",
9
+ "document-viewer": "ddv",
10
+ "dynamsoft document viewer": "ddv",
11
+ "doc viewer": "ddv",
12
+ "pdf viewer": "ddv",
13
+ "edit viewer": "ddv",
14
+ dbr: "dbr",
15
+ "barcode reader": "dbr",
16
+ "barcode-reader": "dbr",
17
+ "dynamsoft barcode reader": "dbr",
18
+ mrz: "mrz",
19
+ "mrz scanner": "mrz",
20
+ "machine readable zone": "mrz",
21
+ mds: "mds",
22
+ "document scanner": "mds",
23
+ "document scanning": "mds",
24
+ "document scan": "mds",
25
+ "document normalization": "mds",
26
+ "document normalizer": "mds"
27
+ };
28
+
29
+ const PUBLIC_OFFERING_PRODUCTS = ["dwt", "ddv", "dbr", "mrz", "mds"];
30
+
31
+ const HYDRATION_PRODUCT_MAP = {
32
+ mrz: "dcv",
33
+ mds: "dcv"
34
+ };
35
+
36
+ const PUBLIC_OFFERINGS_TEXT = "dbr, dwt, ddv, mrz, or mds";
37
+
38
+ function normalizePublicOffering(product) {
39
+ if (!product) return "";
40
+ const normalized = product.trim().toLowerCase();
41
+ return PUBLIC_OFFERING_ALIASES[normalized] || "";
42
+ }
43
+
44
+ function getHydrationProduct(product) {
45
+ const normalized = normalizePublicOffering(product) || String(product || "").trim().toLowerCase();
46
+ return HYDRATION_PRODUCT_MAP[normalized] || normalized;
47
+ }
48
+
49
+ function isKnownPublicOffering(product) {
50
+ return PUBLIC_OFFERING_PRODUCTS.includes(product);
51
+ }
52
+
53
+ function buildUnknownPublicProductResponse(requestedProduct) {
54
+ const value = String(requestedProduct || "").trim();
55
+ return {
56
+ isError: true,
57
+ content: [{
58
+ type: "text",
59
+ text: `Unknown public product "${value}". Use ${PUBLIC_OFFERINGS_TEXT}.`
60
+ }]
61
+ };
62
+ }
63
+
64
+ export {
65
+ PUBLIC_OFFERING_PRODUCTS,
66
+ PUBLIC_OFFERINGS_TEXT,
67
+ normalizePublicOffering,
68
+ getHydrationProduct,
69
+ isKnownPublicOffering,
70
+ buildUnknownPublicProductResponse
71
+ };