@anton.andrusenko/shopify-mcp-admin 0.6.0 → 0.8.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.
Files changed (3) hide show
  1. package/README.md +84 -4
  2. package/dist/index.js +1143 -59
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -917,9 +917,351 @@ var PRODUCTS_QUERY = `
917
917
  }
918
918
  }
919
919
  `;
920
+ var STORE_LIMITS_QUERY = `
921
+ query ShopResourceLimits {
922
+ shop {
923
+ resourceLimits {
924
+ maxProductVariants
925
+ maxProductOptions
926
+ locationLimit
927
+ redirectLimitReached
928
+ }
929
+ }
930
+ }
931
+ `;
932
+ var STORE_FEATURES_QUERY = `
933
+ query ShopFeatures {
934
+ shop {
935
+ features {
936
+ giftCards
937
+ reports
938
+ storefront
939
+ bundles {
940
+ eligibleForBundles
941
+ }
942
+ sellsSubscriptions
943
+ }
944
+ }
945
+ }
946
+ `;
947
+ var STORE_CURRENCIES_QUERY = `
948
+ query ShopCurrencies {
949
+ shop {
950
+ currencyCode
951
+ enabledPresentmentCurrencies
952
+ currencyFormats {
953
+ moneyFormat
954
+ moneyWithCurrencyFormat
955
+ }
956
+ }
957
+ }
958
+ `;
959
+ var STORE_SHIPPING_QUERY = `
960
+ query ShopShipping {
961
+ shop {
962
+ shipsToCountries
963
+ countriesInShippingZones {
964
+ countryCodes
965
+ }
966
+ }
967
+ }
968
+ `;
969
+ var STORE_DOMAIN_QUERY = `
970
+ query ShopDomain {
971
+ shop {
972
+ primaryDomain {
973
+ host
974
+ url
975
+ sslEnabled
976
+ }
977
+ }
978
+ }
979
+ `;
980
+ var STORE_TAXES_QUERY = `
981
+ query ShopTaxes {
982
+ shop {
983
+ taxesIncluded
984
+ taxShipping
985
+ }
986
+ }
987
+ `;
988
+ var STORE_POLICIES_QUERY = `
989
+ query ShopPolicies {
990
+ shop {
991
+ shopPolicies {
992
+ title
993
+ type
994
+ url
995
+ }
996
+ }
997
+ }
998
+ `;
999
+ var STORE_ALERTS_QUERY = `
1000
+ query ShopAlerts {
1001
+ shop {
1002
+ alerts {
1003
+ action {
1004
+ title
1005
+ url
1006
+ }
1007
+ description
1008
+ }
1009
+ setupRequired
1010
+ }
1011
+ }
1012
+ `;
920
1013
 
921
- // src/shopify/store-info.ts
1014
+ // src/shopify/store-info-extended.ts
922
1015
  var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
1016
+ var ALERTS_CACHE_TTL_MS = 60 * 1e3;
1017
+ var _cachedStoreLimits = null;
1018
+ var _limitsTimestamp = 0;
1019
+ var _cachedStoreFeatures = null;
1020
+ var _featuresTimestamp = 0;
1021
+ var _cachedStoreCurrencies = null;
1022
+ var _currenciesTimestamp = 0;
1023
+ var _cachedStoreShipping = null;
1024
+ var _shippingTimestamp = 0;
1025
+ var _cachedStoreDomain = null;
1026
+ var _domainTimestamp = 0;
1027
+ var _cachedStoreTaxes = null;
1028
+ var _taxesTimestamp = 0;
1029
+ var _cachedStorePolicies = null;
1030
+ var _policiesTimestamp = 0;
1031
+ var _cachedStoreAlerts = null;
1032
+ var _alertsTimestamp = 0;
1033
+ async function getStoreLimits() {
1034
+ const now = Date.now();
1035
+ const config = getConfig();
1036
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1037
+ if (_cachedStoreLimits && now - _limitsTimestamp < ttl) {
1038
+ log.debug("Returning cached store limits");
1039
+ return _cachedStoreLimits;
1040
+ }
1041
+ log.debug("Fetching fresh store limits from Shopify");
1042
+ const client = await getShopifyClient();
1043
+ const response = await withRateLimit(
1044
+ () => client.graphql.request(STORE_LIMITS_QUERY),
1045
+ "getStoreLimits"
1046
+ );
1047
+ if (response.errors && response.errors.length > 0) {
1048
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1049
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1050
+ }
1051
+ if (!response.data?.shop?.resourceLimits) {
1052
+ throw new Error("Invalid response: missing shop.resourceLimits data");
1053
+ }
1054
+ _cachedStoreLimits = response.data.shop.resourceLimits;
1055
+ _limitsTimestamp = now;
1056
+ return _cachedStoreLimits;
1057
+ }
1058
+ async function getStoreFeatures() {
1059
+ const now = Date.now();
1060
+ const config = getConfig();
1061
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1062
+ if (_cachedStoreFeatures && now - _featuresTimestamp < ttl) {
1063
+ log.debug("Returning cached store features");
1064
+ return _cachedStoreFeatures;
1065
+ }
1066
+ log.debug("Fetching fresh store features from Shopify");
1067
+ const client = await getShopifyClient();
1068
+ const response = await withRateLimit(
1069
+ () => client.graphql.request(STORE_FEATURES_QUERY),
1070
+ "getStoreFeatures"
1071
+ );
1072
+ if (response.errors && response.errors.length > 0) {
1073
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1074
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1075
+ }
1076
+ if (!response.data?.shop?.features) {
1077
+ throw new Error("Invalid response: missing shop.features data");
1078
+ }
1079
+ _cachedStoreFeatures = response.data.shop.features;
1080
+ _featuresTimestamp = now;
1081
+ return _cachedStoreFeatures;
1082
+ }
1083
+ async function getStoreCurrencies() {
1084
+ const now = Date.now();
1085
+ const config = getConfig();
1086
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1087
+ if (_cachedStoreCurrencies && now - _currenciesTimestamp < ttl) {
1088
+ log.debug("Returning cached store currencies");
1089
+ return _cachedStoreCurrencies;
1090
+ }
1091
+ log.debug("Fetching fresh store currencies from Shopify");
1092
+ const client = await getShopifyClient();
1093
+ const response = await withRateLimit(
1094
+ () => client.graphql.request(STORE_CURRENCIES_QUERY),
1095
+ "getStoreCurrencies"
1096
+ );
1097
+ if (response.errors && response.errors.length > 0) {
1098
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1099
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1100
+ }
1101
+ if (!response.data?.shop) {
1102
+ throw new Error("Invalid response: missing shop data");
1103
+ }
1104
+ const { currencyCode, enabledPresentmentCurrencies, currencyFormats } = response.data.shop;
1105
+ _cachedStoreCurrencies = {
1106
+ currencyCode,
1107
+ enabledPresentmentCurrencies,
1108
+ currencyFormats
1109
+ };
1110
+ _currenciesTimestamp = now;
1111
+ return _cachedStoreCurrencies;
1112
+ }
1113
+ async function getStoreShipping() {
1114
+ const now = Date.now();
1115
+ const config = getConfig();
1116
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1117
+ if (_cachedStoreShipping && now - _shippingTimestamp < ttl) {
1118
+ log.debug("Returning cached store shipping");
1119
+ return _cachedStoreShipping;
1120
+ }
1121
+ log.debug("Fetching fresh store shipping from Shopify");
1122
+ const client = await getShopifyClient();
1123
+ const response = await withRateLimit(
1124
+ () => client.graphql.request(STORE_SHIPPING_QUERY),
1125
+ "getStoreShipping"
1126
+ );
1127
+ if (response.errors && response.errors.length > 0) {
1128
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1129
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1130
+ }
1131
+ if (!response.data?.shop) {
1132
+ throw new Error("Invalid response: missing shop data");
1133
+ }
1134
+ _cachedStoreShipping = {
1135
+ shipsToCountries: response.data.shop.shipsToCountries,
1136
+ countriesInShippingZones: response.data.shop.countriesInShippingZones
1137
+ };
1138
+ _shippingTimestamp = now;
1139
+ return _cachedStoreShipping;
1140
+ }
1141
+ async function getStoreDomain() {
1142
+ const now = Date.now();
1143
+ const config = getConfig();
1144
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1145
+ if (_cachedStoreDomain && now - _domainTimestamp < ttl) {
1146
+ log.debug("Returning cached store domain");
1147
+ return _cachedStoreDomain;
1148
+ }
1149
+ log.debug("Fetching fresh store domain from Shopify");
1150
+ const client = await getShopifyClient();
1151
+ const response = await withRateLimit(
1152
+ () => client.graphql.request(STORE_DOMAIN_QUERY),
1153
+ "getStoreDomain"
1154
+ );
1155
+ if (response.errors && response.errors.length > 0) {
1156
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1157
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1158
+ }
1159
+ if (!response.data?.shop?.primaryDomain) {
1160
+ throw new Error("Invalid response: missing shop.primaryDomain data");
1161
+ }
1162
+ _cachedStoreDomain = {
1163
+ primaryDomain: response.data.shop.primaryDomain
1164
+ };
1165
+ _domainTimestamp = now;
1166
+ return _cachedStoreDomain;
1167
+ }
1168
+ async function getStoreTaxes() {
1169
+ const now = Date.now();
1170
+ const config = getConfig();
1171
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1172
+ if (_cachedStoreTaxes && now - _taxesTimestamp < ttl) {
1173
+ log.debug("Returning cached store taxes");
1174
+ return _cachedStoreTaxes;
1175
+ }
1176
+ log.debug("Fetching fresh store taxes from Shopify");
1177
+ const client = await getShopifyClient();
1178
+ const response = await withRateLimit(
1179
+ () => client.graphql.request(STORE_TAXES_QUERY),
1180
+ "getStoreTaxes"
1181
+ );
1182
+ if (response.errors && response.errors.length > 0) {
1183
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1184
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1185
+ }
1186
+ if (response.data?.shop === void 0 || response.data?.shop === null) {
1187
+ throw new Error("Invalid response: missing shop data");
1188
+ }
1189
+ _cachedStoreTaxes = {
1190
+ taxesIncluded: response.data.shop.taxesIncluded,
1191
+ taxShipping: response.data.shop.taxShipping
1192
+ };
1193
+ _taxesTimestamp = now;
1194
+ return _cachedStoreTaxes;
1195
+ }
1196
+ async function getStorePolicies() {
1197
+ const now = Date.now();
1198
+ const config = getConfig();
1199
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1200
+ if (_cachedStorePolicies && now - _policiesTimestamp < ttl) {
1201
+ log.debug("Returning cached store policies");
1202
+ return _cachedStorePolicies;
1203
+ }
1204
+ try {
1205
+ log.debug("Fetching fresh store policies from Shopify");
1206
+ const client = await getShopifyClient();
1207
+ const response = await withRateLimit(
1208
+ () => client.graphql.request(STORE_POLICIES_QUERY),
1209
+ "getStorePolicies"
1210
+ );
1211
+ if (response.errors && response.errors.length > 0) {
1212
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1213
+ if (errorMessages.toLowerCase().includes("access denied") || errorMessages.toLowerCase().includes("unauthorized")) {
1214
+ log.debug("read_legal_policies scope not available, returning empty policies");
1215
+ _cachedStorePolicies = { shopPolicies: [] };
1216
+ _policiesTimestamp = now;
1217
+ return _cachedStorePolicies;
1218
+ }
1219
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1220
+ }
1221
+ const policies = response.data?.shop?.shopPolicies ?? [];
1222
+ _cachedStorePolicies = { shopPolicies: policies };
1223
+ _policiesTimestamp = now;
1224
+ return _cachedStorePolicies;
1225
+ } catch (error) {
1226
+ if (error instanceof Error && (error.message.toLowerCase().includes("access denied") || error.message.toLowerCase().includes("unauthorized"))) {
1227
+ log.debug("read_legal_policies scope not available, returning empty policies");
1228
+ _cachedStorePolicies = { shopPolicies: [] };
1229
+ _policiesTimestamp = now;
1230
+ return _cachedStorePolicies;
1231
+ }
1232
+ throw error;
1233
+ }
1234
+ }
1235
+ async function getStoreAlerts() {
1236
+ const now = Date.now();
1237
+ const ttl = ALERTS_CACHE_TTL_MS;
1238
+ if (_cachedStoreAlerts && now - _alertsTimestamp < ttl) {
1239
+ log.debug("Returning cached store alerts");
1240
+ return _cachedStoreAlerts;
1241
+ }
1242
+ log.debug("Fetching fresh store alerts from Shopify");
1243
+ const client = await getShopifyClient();
1244
+ const response = await withRateLimit(
1245
+ () => client.graphql.request(STORE_ALERTS_QUERY),
1246
+ "getStoreAlerts"
1247
+ );
1248
+ if (response.errors && response.errors.length > 0) {
1249
+ const errorMessages = response.errors.map((e) => e.message).join(", ");
1250
+ throw new Error(`GraphQL errors: ${errorMessages}`);
1251
+ }
1252
+ if (response.data?.shop === void 0 || response.data?.shop === null) {
1253
+ throw new Error("Invalid response: missing shop data");
1254
+ }
1255
+ _cachedStoreAlerts = {
1256
+ alerts: response.data.shop.alerts ?? [],
1257
+ setupRequired: response.data.shop.setupRequired
1258
+ };
1259
+ _alertsTimestamp = now;
1260
+ return _cachedStoreAlerts;
1261
+ }
1262
+
1263
+ // src/shopify/store-info.ts
1264
+ var DEFAULT_CACHE_TTL_MS2 = 5 * 60 * 1e3;
923
1265
  var _cachedStoreInfo = null;
924
1266
  var _cacheTimestamp = 0;
925
1267
  function transformShopResponse(shop) {
@@ -939,7 +1281,7 @@ function transformShopResponse(shop) {
939
1281
  async function getStoreInfo() {
940
1282
  const now = Date.now();
941
1283
  const config = getConfig();
942
- const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS;
1284
+ const ttl = config.STORE_INFO_CACHE_TTL_MS ?? DEFAULT_CACHE_TTL_MS2;
943
1285
  if (_cachedStoreInfo && now - _cacheTimestamp < ttl) {
944
1286
  log.debug("Returning cached store info");
945
1287
  return _cachedStoreInfo;
@@ -1009,54 +1351,358 @@ function createServer() {
1009
1351
  const server = new McpServer(
1010
1352
  // Server info (sent to clients in initialize response)
1011
1353
  {
1012
- name: SERVER_NAME,
1013
- version: getServerVersion()
1354
+ name: SERVER_NAME,
1355
+ version: getServerVersion()
1356
+ },
1357
+ // Server options (capabilities for handler enforcement)
1358
+ {
1359
+ capabilities: {
1360
+ tools: {},
1361
+ // Enable tools capability (AC-2.1.4)
1362
+ resources: {},
1363
+ // Enable resources capability (AC-2.1.4)
1364
+ logging: {}
1365
+ // Enable logging capability (AC-9.5.1.2)
1366
+ },
1367
+ instructions: SERVER_INSTRUCTIONS
1368
+ // Provide Shopify context to AI agents (AC-9.5.1.1)
1369
+ }
1370
+ );
1371
+ return server;
1372
+ }
1373
+ function registerResources(server) {
1374
+ server.resource(
1375
+ "store-info",
1376
+ "shopify://store/info",
1377
+ {
1378
+ description: "Basic information about the connected Shopify store including name, domain, plan, currency, and timezone. Use this to understand the store context before performing operations.",
1379
+ mimeType: "application/json"
1380
+ },
1381
+ async () => {
1382
+ try {
1383
+ const storeInfo = await getStoreInfo();
1384
+ return {
1385
+ contents: [
1386
+ {
1387
+ uri: "shopify://store/info",
1388
+ mimeType: "application/json",
1389
+ text: JSON.stringify(storeInfo, null, 2)
1390
+ }
1391
+ ]
1392
+ };
1393
+ } catch (error) {
1394
+ log.error("Failed to fetch store info", error instanceof Error ? error : void 0);
1395
+ return {
1396
+ contents: [
1397
+ {
1398
+ uri: "shopify://store/info",
1399
+ mimeType: "application/json",
1400
+ text: JSON.stringify({
1401
+ error: "Failed to fetch store information",
1402
+ message: sanitizeLogMessage(
1403
+ error instanceof Error ? error.message : "Unknown error"
1404
+ )
1405
+ })
1406
+ }
1407
+ ]
1408
+ };
1409
+ }
1410
+ }
1411
+ );
1412
+ server.resource(
1413
+ "store-limits",
1414
+ "shopify://store/limits",
1415
+ {
1416
+ description: "Resource limits for the Shopify store including max product variants, max product options, location limit, and redirect limit status. Use this to validate operations against store constraints.",
1417
+ mimeType: "application/json"
1418
+ },
1419
+ async () => {
1420
+ try {
1421
+ const limits = await getStoreLimits();
1422
+ return {
1423
+ contents: [
1424
+ {
1425
+ uri: "shopify://store/limits",
1426
+ mimeType: "application/json",
1427
+ text: JSON.stringify(limits, null, 2)
1428
+ }
1429
+ ]
1430
+ };
1431
+ } catch (error) {
1432
+ log.error("Failed to fetch store limits", error instanceof Error ? error : void 0);
1433
+ return {
1434
+ contents: [
1435
+ {
1436
+ uri: "shopify://store/limits",
1437
+ mimeType: "application/json",
1438
+ text: JSON.stringify({
1439
+ error: "Failed to fetch store limits",
1440
+ message: sanitizeLogMessage(
1441
+ error instanceof Error ? error.message : "Unknown error"
1442
+ )
1443
+ })
1444
+ }
1445
+ ]
1446
+ };
1447
+ }
1448
+ }
1449
+ );
1450
+ server.resource(
1451
+ "store-features",
1452
+ "shopify://store/features",
1453
+ {
1454
+ description: "Feature flags for the Shopify store including gift cards, reports, storefront, bundles eligibility, and subscriptions. Use this to determine available store capabilities.",
1455
+ mimeType: "application/json"
1456
+ },
1457
+ async () => {
1458
+ try {
1459
+ const features = await getStoreFeatures();
1460
+ return {
1461
+ contents: [
1462
+ {
1463
+ uri: "shopify://store/features",
1464
+ mimeType: "application/json",
1465
+ text: JSON.stringify(features, null, 2)
1466
+ }
1467
+ ]
1468
+ };
1469
+ } catch (error) {
1470
+ log.error("Failed to fetch store features", error instanceof Error ? error : void 0);
1471
+ return {
1472
+ contents: [
1473
+ {
1474
+ uri: "shopify://store/features",
1475
+ mimeType: "application/json",
1476
+ text: JSON.stringify({
1477
+ error: "Failed to fetch store features",
1478
+ message: sanitizeLogMessage(
1479
+ error instanceof Error ? error.message : "Unknown error"
1480
+ )
1481
+ })
1482
+ }
1483
+ ]
1484
+ };
1485
+ }
1486
+ }
1487
+ );
1488
+ server.resource(
1489
+ "store-currencies",
1490
+ "shopify://store/currencies",
1491
+ {
1492
+ description: "Currency configuration for the Shopify store including base currency, enabled presentment currencies, and money format patterns. Use this to understand multi-currency setup.",
1493
+ mimeType: "application/json"
1494
+ },
1495
+ async () => {
1496
+ try {
1497
+ const currencies = await getStoreCurrencies();
1498
+ return {
1499
+ contents: [
1500
+ {
1501
+ uri: "shopify://store/currencies",
1502
+ mimeType: "application/json",
1503
+ text: JSON.stringify(currencies, null, 2)
1504
+ }
1505
+ ]
1506
+ };
1507
+ } catch (error) {
1508
+ log.error("Failed to fetch store currencies", error instanceof Error ? error : void 0);
1509
+ return {
1510
+ contents: [
1511
+ {
1512
+ uri: "shopify://store/currencies",
1513
+ mimeType: "application/json",
1514
+ text: JSON.stringify({
1515
+ error: "Failed to fetch store currencies",
1516
+ message: sanitizeLogMessage(
1517
+ error instanceof Error ? error.message : "Unknown error"
1518
+ )
1519
+ })
1520
+ }
1521
+ ]
1522
+ };
1523
+ }
1524
+ }
1525
+ );
1526
+ server.resource(
1527
+ "store-shipping",
1528
+ "shopify://store/shipping",
1529
+ {
1530
+ description: "Shipping configuration for the Shopify store including ships-to countries and countries with configured shipping zones. Use this to understand international shipping capabilities.",
1531
+ mimeType: "application/json"
1532
+ },
1533
+ async () => {
1534
+ try {
1535
+ const shipping = await getStoreShipping();
1536
+ return {
1537
+ contents: [
1538
+ {
1539
+ uri: "shopify://store/shipping",
1540
+ mimeType: "application/json",
1541
+ text: JSON.stringify(shipping, null, 2)
1542
+ }
1543
+ ]
1544
+ };
1545
+ } catch (error) {
1546
+ log.error("Failed to fetch store shipping", error instanceof Error ? error : void 0);
1547
+ return {
1548
+ contents: [
1549
+ {
1550
+ uri: "shopify://store/shipping",
1551
+ mimeType: "application/json",
1552
+ text: JSON.stringify({
1553
+ error: "Failed to fetch store shipping",
1554
+ message: sanitizeLogMessage(
1555
+ error instanceof Error ? error.message : "Unknown error"
1556
+ )
1557
+ })
1558
+ }
1559
+ ]
1560
+ };
1561
+ }
1562
+ }
1563
+ );
1564
+ server.resource(
1565
+ "store-domain",
1566
+ "shopify://store/domain",
1567
+ {
1568
+ description: "Primary domain configuration for the Shopify store including hostname, URL, and SSL status. Use this to construct proper URLs and understand store identity.",
1569
+ mimeType: "application/json"
1570
+ },
1571
+ async () => {
1572
+ try {
1573
+ const domain = await getStoreDomain();
1574
+ return {
1575
+ contents: [
1576
+ {
1577
+ uri: "shopify://store/domain",
1578
+ mimeType: "application/json",
1579
+ text: JSON.stringify(domain, null, 2)
1580
+ }
1581
+ ]
1582
+ };
1583
+ } catch (error) {
1584
+ log.error("Failed to fetch store domain", error instanceof Error ? error : void 0);
1585
+ return {
1586
+ contents: [
1587
+ {
1588
+ uri: "shopify://store/domain",
1589
+ mimeType: "application/json",
1590
+ text: JSON.stringify({
1591
+ error: "Failed to fetch store domain",
1592
+ message: sanitizeLogMessage(
1593
+ error instanceof Error ? error.message : "Unknown error"
1594
+ )
1595
+ })
1596
+ }
1597
+ ]
1598
+ };
1599
+ }
1600
+ }
1601
+ );
1602
+ server.resource(
1603
+ "store-taxes",
1604
+ "shopify://store/taxes",
1605
+ {
1606
+ description: "Tax configuration for the Shopify store including whether taxes are included in prices and tax shipping settings. Use this to understand pricing structure for tax calculations.",
1607
+ mimeType: "application/json"
1608
+ },
1609
+ async () => {
1610
+ try {
1611
+ const taxes = await getStoreTaxes();
1612
+ return {
1613
+ contents: [
1614
+ {
1615
+ uri: "shopify://store/taxes",
1616
+ mimeType: "application/json",
1617
+ text: JSON.stringify(taxes, null, 2)
1618
+ }
1619
+ ]
1620
+ };
1621
+ } catch (error) {
1622
+ log.error("Failed to fetch store taxes", error instanceof Error ? error : void 0);
1623
+ return {
1624
+ contents: [
1625
+ {
1626
+ uri: "shopify://store/taxes",
1627
+ mimeType: "application/json",
1628
+ text: JSON.stringify({
1629
+ error: "Failed to fetch store taxes",
1630
+ message: sanitizeLogMessage(
1631
+ error instanceof Error ? error.message : "Unknown error"
1632
+ )
1633
+ })
1634
+ }
1635
+ ]
1636
+ };
1637
+ }
1638
+ }
1639
+ );
1640
+ server.resource(
1641
+ "store-policies",
1642
+ "shopify://store/policies",
1643
+ {
1644
+ description: "Legal policies for the Shopify store (privacy policy, terms of service, refund policy). Returns empty array if read_legal_policies scope is not available. Use this to reference store policies in customer communications.",
1645
+ mimeType: "application/json"
1014
1646
  },
1015
- // Server options (capabilities for handler enforcement)
1016
- {
1017
- capabilities: {
1018
- tools: {},
1019
- // Enable tools capability (AC-2.1.4)
1020
- resources: {},
1021
- // Enable resources capability (AC-2.1.4)
1022
- logging: {}
1023
- // Enable logging capability (AC-9.5.1.2)
1024
- },
1025
- instructions: SERVER_INSTRUCTIONS
1026
- // Provide Shopify context to AI agents (AC-9.5.1.1)
1647
+ async () => {
1648
+ try {
1649
+ const policies = await getStorePolicies();
1650
+ return {
1651
+ contents: [
1652
+ {
1653
+ uri: "shopify://store/policies",
1654
+ mimeType: "application/json",
1655
+ text: JSON.stringify(policies, null, 2)
1656
+ }
1657
+ ]
1658
+ };
1659
+ } catch (error) {
1660
+ log.error("Failed to fetch store policies", error instanceof Error ? error : void 0);
1661
+ return {
1662
+ contents: [
1663
+ {
1664
+ uri: "shopify://store/policies",
1665
+ mimeType: "application/json",
1666
+ text: JSON.stringify({
1667
+ error: "Failed to fetch store policies",
1668
+ message: sanitizeLogMessage(
1669
+ error instanceof Error ? error.message : "Unknown error"
1670
+ )
1671
+ })
1672
+ }
1673
+ ]
1674
+ };
1675
+ }
1027
1676
  }
1028
1677
  );
1029
- return server;
1030
- }
1031
- function registerResources(server) {
1032
1678
  server.resource(
1033
- "store-info",
1034
- "shopify://store/info",
1679
+ "store-alerts",
1680
+ "shopify://store/alerts",
1035
1681
  {
1036
- description: "Basic information about the connected Shopify store including name, domain, plan, currency, and timezone. Use this to understand the store context before performing operations.",
1682
+ description: "Active admin alerts and setup requirements for the Shopify store. Use this to proactively identify issues needing merchant attention.",
1037
1683
  mimeType: "application/json"
1038
1684
  },
1039
1685
  async () => {
1040
1686
  try {
1041
- const storeInfo = await getStoreInfo();
1687
+ const alerts = await getStoreAlerts();
1042
1688
  return {
1043
1689
  contents: [
1044
1690
  {
1045
- uri: "shopify://store/info",
1691
+ uri: "shopify://store/alerts",
1046
1692
  mimeType: "application/json",
1047
- text: JSON.stringify(storeInfo, null, 2)
1693
+ text: JSON.stringify(alerts, null, 2)
1048
1694
  }
1049
1695
  ]
1050
1696
  };
1051
1697
  } catch (error) {
1052
- log.error("Failed to fetch store info", error instanceof Error ? error : void 0);
1698
+ log.error("Failed to fetch store alerts", error instanceof Error ? error : void 0);
1053
1699
  return {
1054
1700
  contents: [
1055
1701
  {
1056
- uri: "shopify://store/info",
1702
+ uri: "shopify://store/alerts",
1057
1703
  mimeType: "application/json",
1058
1704
  text: JSON.stringify({
1059
- error: "Failed to fetch store information",
1705
+ error: "Failed to fetch store alerts",
1060
1706
  message: sanitizeLogMessage(
1061
1707
  error instanceof Error ? error.message : "Unknown error"
1062
1708
  )
@@ -2451,7 +3097,7 @@ function wrapToolHandler(toolName, schema, handler) {
2451
3097
  };
2452
3098
  }
2453
3099
  function registerTool(definition, handler, options = {}) {
2454
- const { name, title, description, inputSchema: inputSchema71, annotations } = definition;
3100
+ const { name, title, description, inputSchema: inputSchema80, annotations } = definition;
2455
3101
  try {
2456
3102
  if (!options.skipNameValidation) {
2457
3103
  validateToolName(name);
@@ -2459,8 +3105,8 @@ function registerTool(definition, handler, options = {}) {
2459
3105
  if (registeredTools.has(name)) {
2460
3106
  throw new Error(`Tool "${name}" is already registered. Tool names must be unique.`);
2461
3107
  }
2462
- const jsonSchema = convertZodToJsonSchema(inputSchema71);
2463
- const wrappedHandler = wrapToolHandler(name, inputSchema71, handler);
3108
+ const jsonSchema = convertZodToJsonSchema(inputSchema80);
3109
+ const wrappedHandler = wrapToolHandler(name, inputSchema80, handler);
2464
3110
  const finalAnnotations = {
2465
3111
  ...deriveDefaultAnnotations(name),
2466
3112
  ...annotations,
@@ -2472,7 +3118,7 @@ function registerTool(definition, handler, options = {}) {
2472
3118
  title,
2473
3119
  description,
2474
3120
  inputSchema: jsonSchema,
2475
- zodSchema: inputSchema71,
3121
+ zodSchema: inputSchema80,
2476
3122
  handler: wrappedHandler,
2477
3123
  annotations: finalAnnotations
2478
3124
  };
@@ -2648,6 +3294,28 @@ var PRODUCT_VARIANTS_BULK_UPDATE_MUTATION = `
2648
3294
  }
2649
3295
  }
2650
3296
  `;
3297
+ var PRODUCT_VARIANTS_BULK_CREATE_MUTATION = `
3298
+ mutation ProductVariantsBulkCreate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
3299
+ productVariantsBulkCreate(productId: $productId, variants: $variants) {
3300
+ product {
3301
+ id
3302
+ }
3303
+ productVariants {
3304
+ id
3305
+ title
3306
+ price
3307
+ compareAtPrice
3308
+ sku
3309
+ barcode
3310
+ inventoryQuantity
3311
+ }
3312
+ userErrors {
3313
+ field
3314
+ message
3315
+ }
3316
+ }
3317
+ }
3318
+ `;
2651
3319
  var PRODUCT_SET_MEDIA_MUTATION = `
2652
3320
  mutation ProductSetMedia($input: ProductSetInput!) {
2653
3321
  productSet(input: $input) {
@@ -2781,26 +3449,6 @@ function buildProductCreateVariables(input) {
2781
3449
  if (input.handle !== void 0) {
2782
3450
  productData.handle = input.handle;
2783
3451
  }
2784
- if (input.variants && input.variants.length > 0) {
2785
- productData.variants = input.variants.map((variant) => {
2786
- const variantInput = {
2787
- price: variant.price
2788
- };
2789
- if (variant.compareAtPrice !== void 0) {
2790
- variantInput.compareAtPrice = variant.compareAtPrice;
2791
- }
2792
- if (variant.sku !== void 0) {
2793
- variantInput.sku = variant.sku;
2794
- }
2795
- if (variant.barcode !== void 0) {
2796
- variantInput.barcode = variant.barcode;
2797
- }
2798
- if (variant.options !== void 0 && variant.options.length > 0) {
2799
- variantInput.options = variant.options;
2800
- }
2801
- return variantInput;
2802
- });
2803
- }
2804
3452
  let media;
2805
3453
  if (input.images && input.images.length > 0) {
2806
3454
  media = input.images.map((image) => ({
@@ -2811,6 +3459,65 @@ function buildProductCreateVariables(input) {
2811
3459
  }
2812
3460
  return { product: productData, media };
2813
3461
  }
3462
+ async function createProductVariants(productId, variants) {
3463
+ const client = await getShopifyClient();
3464
+ const variantInputs = variants.map((variant) => {
3465
+ const variantInput = {
3466
+ price: variant.price
3467
+ };
3468
+ if (variant.compareAtPrice !== void 0) {
3469
+ variantInput.compareAtPrice = variant.compareAtPrice;
3470
+ }
3471
+ if (variant.sku !== void 0) {
3472
+ variantInput.sku = variant.sku;
3473
+ }
3474
+ if (variant.barcode !== void 0) {
3475
+ variantInput.barcode = variant.barcode;
3476
+ }
3477
+ if (variant.options !== void 0 && variant.options.length > 0) {
3478
+ variantInput.optionValues = variant.options.map((optionValue) => ({
3479
+ name: optionValue,
3480
+ optionName: optionValue
3481
+ // Use the option value as the option name for simple cases
3482
+ }));
3483
+ }
3484
+ return variantInput;
3485
+ });
3486
+ log.debug(`Creating ${variants.length} variants for product: ${productId}`);
3487
+ const response = await withRateLimit(
3488
+ () => client.graphql.request(
3489
+ PRODUCT_VARIANTS_BULK_CREATE_MUTATION,
3490
+ {
3491
+ variables: { productId, variants: variantInputs }
3492
+ }
3493
+ ),
3494
+ "create-product-variants"
3495
+ );
3496
+ if (response.errors && response.errors.length > 0) {
3497
+ const errorMessage = response.errors.map((e) => e.message).join(", ");
3498
+ throw new Error(`GraphQL error: ${errorMessage}`);
3499
+ }
3500
+ const result = response.data?.productVariantsBulkCreate;
3501
+ if (!result) {
3502
+ throw new Error("No response data from productVariantsBulkCreate mutation");
3503
+ }
3504
+ if (result.userErrors && result.userErrors.length > 0) {
3505
+ throw new ShopifyUserErrorException(result.userErrors);
3506
+ }
3507
+ if (!result.productVariants || result.productVariants.length === 0) {
3508
+ throw new Error("No variants were created");
3509
+ }
3510
+ log.debug(`Created ${result.productVariants.length} variants`);
3511
+ return result.productVariants.map((variant) => ({
3512
+ id: variant.id,
3513
+ title: variant.title,
3514
+ price: variant.price,
3515
+ compareAtPrice: variant.compareAtPrice,
3516
+ sku: variant.sku,
3517
+ barcode: variant.barcode,
3518
+ inventoryQuantity: variant.inventoryQuantity
3519
+ }));
3520
+ }
2814
3521
  async function createProduct(input) {
2815
3522
  const client = await getShopifyClient();
2816
3523
  const variables = buildProductCreateVariables(input);
@@ -2836,7 +3543,23 @@ async function createProduct(input) {
2836
3543
  throw new Error("Product was not created (no product in response)");
2837
3544
  }
2838
3545
  log.debug(`Created product: ${result.product.id}`);
2839
- return transformProductToOutput(result.product);
3546
+ let productOutput = transformProductToOutput(result.product);
3547
+ if (input.variants && input.variants.length > 0) {
3548
+ try {
3549
+ const createdVariants = await createProductVariants(result.product.id, input.variants);
3550
+ productOutput = {
3551
+ ...productOutput,
3552
+ variants: createdVariants
3553
+ };
3554
+ log.debug(`Created ${createdVariants.length} variants for product: ${result.product.id}`);
3555
+ } catch (variantError) {
3556
+ log.warn(
3557
+ `Product created but variant creation failed: ${variantError instanceof Error ? variantError.message : "Unknown error"}`
3558
+ );
3559
+ log.warn("Variants can be added using update-product-variant tool");
3560
+ }
3561
+ }
3562
+ return productOutput;
2840
3563
  }
2841
3564
  async function getProduct(id) {
2842
3565
  const client = await getShopifyClient();
@@ -5540,10 +6263,10 @@ var inputSchema8 = z10.object({
5540
6263
  // Variants
5541
6264
  variants: z10.array(
5542
6265
  z10.object({
5543
- price: z10.string().describe('Variant price as decimal string. Example: "29.99"'),
5544
- compareAtPrice: z10.string().optional().describe('Original price for sale display. Example: "39.99"'),
6266
+ price: z10.union([z10.string(), z10.number()]).transform((val) => typeof val === "number" ? String(val) : val).describe('Variant price as decimal string. Example: "29.99"'),
6267
+ compareAtPrice: z10.union([z10.string(), z10.number()]).optional().transform((val) => typeof val === "number" ? String(val) : val).describe('Original price for sale display. Example: "39.99"'),
5545
6268
  sku: z10.string().optional().describe('Stock keeping unit. Example: "SHIRT-001-RED-M"'),
5546
- barcode: z10.string().optional().describe("Barcode (UPC, EAN, etc.)"),
6269
+ barcode: z10.union([z10.string(), z10.number()]).optional().transform((val) => typeof val === "number" ? String(val) : val).describe("Barcode (UPC, EAN, etc.)"),
5547
6270
  inventoryQuantity: z10.number().int().min(0).optional().describe("Initial inventory quantity (note: may require separate inventory API)"),
5548
6271
  options: z10.array(z10.string()).optional().describe('Variant options. Example: ["Red", "Medium"]')
5549
6272
  })
@@ -10300,11 +11023,11 @@ var inputSchema44 = z46.object({
10300
11023
  id: variantIdSchema.describe(
10301
11024
  'Shopify variant GID (e.g., "gid://shopify/ProductVariant/456"). Required. Use get-product to find variant IDs for a product.'
10302
11025
  ),
10303
- price: z46.string().optional().describe('New variant price as decimal string (e.g., "29.99")'),
10304
- compareAtPrice: z46.string().nullable().optional().describe(
11026
+ price: z46.union([z46.string(), z46.number()]).optional().transform((val) => typeof val === "number" ? String(val) : val).describe('New variant price as decimal string (e.g., "29.99")'),
11027
+ compareAtPrice: z46.union([z46.string(), z46.number()]).nullable().optional().transform((val) => typeof val === "number" ? String(val) : val).describe(
10305
11028
  'Original price for sale display (e.g., "39.99"). When set higher than price, Shopify shows strikethrough pricing. Set to null to remove the compare at price.'
10306
11029
  ),
10307
- barcode: z46.string().nullable().optional().describe("Barcode (UPC, EAN, ISBN, etc.). Set to null to remove.")
11030
+ barcode: z46.union([z46.string(), z46.number()]).nullable().optional().transform((val) => typeof val === "number" ? String(val) : val).describe("Barcode (UPC, EAN, ISBN, etc.). Set to null to remove.")
10308
11031
  }).refine(
10309
11032
  (data) => {
10310
11033
  const { productId: _productId, id: _id, ...updateFields } = data;
@@ -12483,6 +13206,358 @@ function registerSubmitRedirectImportTool() {
12483
13206
  );
12484
13207
  }
12485
13208
 
13209
+ // src/tools/get-store-alerts.ts
13210
+ import { z as z73 } from "zod";
13211
+ var inputSchema71 = z73.object({});
13212
+ var outputSchema71 = z73.object({
13213
+ alerts: z73.array(
13214
+ z73.object({
13215
+ action: z73.object({
13216
+ title: z73.string().describe('The text for the button in the alert (e.g., "Add credit card")'),
13217
+ url: z73.string().describe("The target URL that the button links to")
13218
+ }).describe("Action to resolve the alert"),
13219
+ description: z73.string().describe("Human-readable alert description")
13220
+ })
13221
+ ).describe("Array of active admin alerts"),
13222
+ setupRequired: z73.boolean().describe("Whether store setup is incomplete")
13223
+ });
13224
+ async function handleGetStoreAlerts(context, _params) {
13225
+ log.debug(`Getting store alerts for shop: ${context.shopDomain}`);
13226
+ return await getStoreAlerts();
13227
+ }
13228
+ function registerGetStoreAlertsTool() {
13229
+ registerContextAwareTool(
13230
+ {
13231
+ name: "get-store-alerts",
13232
+ title: "Get Store Alerts",
13233
+ description: "Get active admin alerts and setup requirements for the connected Shopify store. **Prerequisites:** None. **Use this** to proactively identify issues needing merchant attention.",
13234
+ inputSchema: inputSchema71,
13235
+ outputSchema: outputSchema71,
13236
+ category: "store",
13237
+ relationships: {
13238
+ relatedTools: ["get-store-info", "list-low-inventory"],
13239
+ followUps: []
13240
+ },
13241
+ annotations: {
13242
+ readOnlyHint: true,
13243
+ destructiveHint: false,
13244
+ idempotentHint: true,
13245
+ openWorldHint: true
13246
+ }
13247
+ },
13248
+ handleGetStoreAlerts
13249
+ );
13250
+ }
13251
+
13252
+ // src/tools/get-store-currencies.ts
13253
+ import { z as z74 } from "zod";
13254
+ var inputSchema72 = z74.object({});
13255
+ var outputSchema72 = z74.object({
13256
+ currencyCode: z74.string().describe("Base currency code (e.g., USD)"),
13257
+ enabledPresentmentCurrencies: z74.array(z74.string()).describe("Enabled multi-currency codes"),
13258
+ currencyFormats: z74.object({
13259
+ moneyFormat: z74.string().describe("Money format pattern (e.g., ${{amount}})"),
13260
+ moneyWithCurrencyFormat: z74.string().describe("Money with currency format (e.g., ${{amount}} USD)")
13261
+ }).describe("Currency format patterns")
13262
+ });
13263
+ async function handleGetStoreCurrencies(context, _params) {
13264
+ log.debug(`Getting store currencies for shop: ${context.shopDomain}`);
13265
+ return await getStoreCurrencies();
13266
+ }
13267
+ function registerGetStoreCurrenciesTool() {
13268
+ registerContextAwareTool(
13269
+ {
13270
+ name: "get-store-currencies",
13271
+ title: "Get Store Currencies",
13272
+ description: "Get currency configuration for the connected Shopify store including base currency, enabled presentment currencies, and money format patterns. **Prerequisites:** None. **Use this** to understand multi-currency setup.",
13273
+ inputSchema: inputSchema72,
13274
+ outputSchema: outputSchema72,
13275
+ category: "store",
13276
+ relationships: {
13277
+ relatedTools: ["get-store-info", "get-store-limits"],
13278
+ followUps: ["list-markets", "list-products"]
13279
+ },
13280
+ annotations: {
13281
+ readOnlyHint: true,
13282
+ destructiveHint: false,
13283
+ idempotentHint: true,
13284
+ openWorldHint: true
13285
+ }
13286
+ },
13287
+ handleGetStoreCurrencies
13288
+ );
13289
+ }
13290
+
13291
+ // src/tools/get-store-domain.ts
13292
+ import { z as z75 } from "zod";
13293
+ var inputSchema73 = z75.object({});
13294
+ var outputSchema73 = z75.object({
13295
+ primaryDomain: z75.object({
13296
+ host: z75.string().describe('Domain hostname (e.g., "mystore.com")'),
13297
+ url: z75.string().describe('Full domain URL (e.g., "https://mystore.com")'),
13298
+ sslEnabled: z75.boolean().describe("Whether SSL is enabled")
13299
+ })
13300
+ });
13301
+ async function handleGetStoreDomain(context, _params) {
13302
+ log.debug(`Getting store domain for shop: ${context.shopDomain}`);
13303
+ return await getStoreDomain();
13304
+ }
13305
+ function registerGetStoreDomainTool() {
13306
+ registerContextAwareTool(
13307
+ {
13308
+ name: "get-store-domain",
13309
+ title: "Get Store Domain",
13310
+ description: "Get primary domain configuration for the connected Shopify store including hostname, URL, and SSL status. **Prerequisites:** None. **Use this** to construct proper URLs and understand store identity.",
13311
+ inputSchema: inputSchema73,
13312
+ outputSchema: outputSchema73,
13313
+ category: "store",
13314
+ relationships: {
13315
+ relatedTools: ["get-store-info", "get-store-shipping"],
13316
+ followUps: ["create-redirect"]
13317
+ },
13318
+ annotations: {
13319
+ readOnlyHint: true,
13320
+ destructiveHint: false,
13321
+ idempotentHint: true,
13322
+ openWorldHint: true
13323
+ }
13324
+ },
13325
+ handleGetStoreDomain
13326
+ );
13327
+ }
13328
+
13329
+ // src/tools/get-store-features.ts
13330
+ import { z as z76 } from "zod";
13331
+ var inputSchema74 = z76.object({});
13332
+ var outputSchema74 = z76.object({
13333
+ giftCards: z76.boolean().describe("Gift cards enabled"),
13334
+ reports: z76.boolean().describe("Reports enabled"),
13335
+ storefront: z76.boolean().describe("Storefront enabled"),
13336
+ bundles: z76.object({
13337
+ eligibleForBundles: z76.boolean().describe("Whether store is eligible for bundles")
13338
+ }).describe("Bundles feature configuration"),
13339
+ sellsSubscriptions: z76.boolean().describe("Subscriptions enabled")
13340
+ });
13341
+ async function handleGetStoreFeatures(context, _params) {
13342
+ log.debug(`Getting store features for shop: ${context.shopDomain}`);
13343
+ return await getStoreFeatures();
13344
+ }
13345
+ function registerGetStoreFeaturesTool() {
13346
+ registerContextAwareTool(
13347
+ {
13348
+ name: "get-store-features",
13349
+ title: "Get Store Features",
13350
+ description: "Get feature flags for the connected Shopify store including gift cards, reports, storefront, bundles eligibility, and subscriptions. **Prerequisites:** None. **Use this** to determine available store capabilities.",
13351
+ inputSchema: inputSchema74,
13352
+ outputSchema: outputSchema74,
13353
+ category: "store",
13354
+ relationships: {
13355
+ relatedTools: ["get-store-info", "get-store-limits"],
13356
+ followUps: ["list-products", "list-collections"]
13357
+ },
13358
+ annotations: {
13359
+ readOnlyHint: true,
13360
+ destructiveHint: false,
13361
+ idempotentHint: true,
13362
+ openWorldHint: true
13363
+ }
13364
+ },
13365
+ handleGetStoreFeatures
13366
+ );
13367
+ }
13368
+
13369
+ // src/tools/get-store-info.ts
13370
+ import { z as z77 } from "zod";
13371
+ var inputSchema75 = z77.object({});
13372
+ var outputSchema75 = z77.object({
13373
+ name: z77.string().describe("Store name"),
13374
+ domain: z77.string().describe("Store domain (without .myshopify.com)"),
13375
+ myshopifyDomain: z77.string().describe("Full myshopify.com domain"),
13376
+ plan: z77.object({
13377
+ displayName: z77.string().describe("Current plan name"),
13378
+ partnerDevelopment: z77.boolean().describe("Whether partner development store")
13379
+ }).describe("Store plan details"),
13380
+ currencyCode: z77.string().describe("Store currency code (e.g., USD, EUR)"),
13381
+ timezone: z77.string().describe("Store IANA timezone"),
13382
+ contactEmail: z77.string().describe("Store contact email")
13383
+ });
13384
+ async function handleGetStoreInfo(context, _params) {
13385
+ log.debug(`Getting store info for shop: ${context.shopDomain}`);
13386
+ return await getStoreInfo();
13387
+ }
13388
+ function registerGetStoreInfoTool() {
13389
+ registerContextAwareTool(
13390
+ {
13391
+ name: "get-store-info",
13392
+ title: "Get Store Info",
13393
+ description: "Get basic information about the connected Shopify store including name, domain, plan, currency, timezone, and contact email. **Prerequisites:** None. **Use this** to understand store context before performing operations.",
13394
+ inputSchema: inputSchema75,
13395
+ outputSchema: outputSchema75,
13396
+ category: "store",
13397
+ relationships: {
13398
+ relatedTools: [],
13399
+ followUps: ["list-products", "list-collections"]
13400
+ },
13401
+ annotations: {
13402
+ readOnlyHint: true,
13403
+ destructiveHint: false,
13404
+ idempotentHint: true,
13405
+ openWorldHint: true
13406
+ }
13407
+ },
13408
+ handleGetStoreInfo
13409
+ );
13410
+ }
13411
+
13412
+ // src/tools/get-store-limits.ts
13413
+ import { z as z78 } from "zod";
13414
+ var inputSchema76 = z78.object({});
13415
+ var outputSchema76 = z78.object({
13416
+ maxProductVariants: z78.number().describe("Maximum variants per product"),
13417
+ maxProductOptions: z78.number().describe("Maximum product options"),
13418
+ locationLimit: z78.number().describe("Maximum locations"),
13419
+ redirectLimitReached: z78.boolean().describe("Whether redirect limit is reached")
13420
+ });
13421
+ async function handleGetStoreLimits(context, _params) {
13422
+ log.debug(`Getting store limits for shop: ${context.shopDomain}`);
13423
+ return await getStoreLimits();
13424
+ }
13425
+ function registerGetStoreLimitsTool() {
13426
+ registerContextAwareTool(
13427
+ {
13428
+ name: "get-store-limits",
13429
+ title: "Get Store Limits",
13430
+ description: "Get resource limits for the connected Shopify store including max product variants, max product options, location limit, and redirect limit status. **Prerequisites:** None. **Use this** to validate operations against store constraints.",
13431
+ inputSchema: inputSchema76,
13432
+ outputSchema: outputSchema76,
13433
+ category: "store",
13434
+ relationships: {
13435
+ relatedTools: ["get-store-info", "get-store-features"],
13436
+ followUps: ["list-products", "create-product"]
13437
+ },
13438
+ annotations: {
13439
+ readOnlyHint: true,
13440
+ destructiveHint: false,
13441
+ idempotentHint: true,
13442
+ openWorldHint: true
13443
+ }
13444
+ },
13445
+ handleGetStoreLimits
13446
+ );
13447
+ }
13448
+
13449
+ // src/tools/get-store-policies.ts
13450
+ import { z as z79 } from "zod";
13451
+ var inputSchema77 = z79.object({});
13452
+ var outputSchema77 = z79.object({
13453
+ shopPolicies: z79.array(
13454
+ z79.object({
13455
+ title: z79.string().describe('Policy title (e.g., "Privacy Policy")'),
13456
+ type: z79.string().describe('Policy type (e.g., "PRIVACY_POLICY")'),
13457
+ url: z79.string().describe("Full URL to the policy page")
13458
+ })
13459
+ ).describe("Array of store policy items (empty if scope unavailable)")
13460
+ });
13461
+ async function handleGetStorePolicies(context, _params) {
13462
+ log.debug(`Getting store policies for shop: ${context.shopDomain}`);
13463
+ return await getStorePolicies();
13464
+ }
13465
+ function registerGetStorePoliciesTool() {
13466
+ registerContextAwareTool(
13467
+ {
13468
+ name: "get-store-policies",
13469
+ title: "Get Store Policies",
13470
+ description: "Get legal policies for the connected Shopify store (privacy policy, terms of service, refund policy). Returns empty array if read_legal_policies scope is not available. **Prerequisites:** None. **Use this** to reference store policies in customer communications.",
13471
+ inputSchema: inputSchema77,
13472
+ outputSchema: outputSchema77,
13473
+ category: "store",
13474
+ relationships: {
13475
+ relatedTools: ["get-store-info", "get-store-domain"],
13476
+ followUps: []
13477
+ },
13478
+ annotations: {
13479
+ readOnlyHint: true,
13480
+ destructiveHint: false,
13481
+ idempotentHint: true,
13482
+ openWorldHint: true
13483
+ }
13484
+ },
13485
+ handleGetStorePolicies
13486
+ );
13487
+ }
13488
+
13489
+ // src/tools/get-store-shipping.ts
13490
+ import { z as z80 } from "zod";
13491
+ var inputSchema78 = z80.object({});
13492
+ var outputSchema78 = z80.object({
13493
+ shipsToCountries: z80.array(z80.string()).describe("Countries the store ships to"),
13494
+ countriesInShippingZones: z80.object({
13495
+ countryCodes: z80.array(z80.string()).describe("Countries with configured shipping zones")
13496
+ })
13497
+ });
13498
+ async function handleGetStoreShipping(context, _params) {
13499
+ log.debug(`Getting store shipping for shop: ${context.shopDomain}`);
13500
+ return await getStoreShipping();
13501
+ }
13502
+ function registerGetStoreShippingTool() {
13503
+ registerContextAwareTool(
13504
+ {
13505
+ name: "get-store-shipping",
13506
+ title: "Get Store Shipping",
13507
+ description: "Get shipping configuration for the connected Shopify store including ships-to countries and countries with configured shipping zones. **Prerequisites:** None. **Use this** to understand international shipping capabilities.",
13508
+ inputSchema: inputSchema78,
13509
+ outputSchema: outputSchema78,
13510
+ category: "store",
13511
+ relationships: {
13512
+ relatedTools: ["get-store-info", "get-store-domain", "list-markets"],
13513
+ followUps: ["get-store-domain"]
13514
+ },
13515
+ annotations: {
13516
+ readOnlyHint: true,
13517
+ destructiveHint: false,
13518
+ idempotentHint: true,
13519
+ openWorldHint: true
13520
+ }
13521
+ },
13522
+ handleGetStoreShipping
13523
+ );
13524
+ }
13525
+
13526
+ // src/tools/get-store-taxes.ts
13527
+ import { z as z81 } from "zod";
13528
+ var inputSchema79 = z81.object({});
13529
+ var outputSchema79 = z81.object({
13530
+ taxesIncluded: z81.boolean().describe("Whether taxes are included in product prices"),
13531
+ taxShipping: z81.boolean().describe("Whether shipping is taxed")
13532
+ });
13533
+ async function handleGetStoreTaxes(context, _params) {
13534
+ log.debug(`Getting store taxes for shop: ${context.shopDomain}`);
13535
+ return await getStoreTaxes();
13536
+ }
13537
+ function registerGetStoreTaxesTool() {
13538
+ registerContextAwareTool(
13539
+ {
13540
+ name: "get-store-taxes",
13541
+ title: "Get Store Taxes",
13542
+ description: "Get tax configuration for the connected Shopify store including whether taxes are included in prices and tax shipping settings. **Prerequisites:** None. **Use this** to understand pricing structure for tax calculations.",
13543
+ inputSchema: inputSchema79,
13544
+ outputSchema: outputSchema79,
13545
+ category: "store",
13546
+ relationships: {
13547
+ relatedTools: ["get-store-info", "get-store-currencies"],
13548
+ followUps: []
13549
+ },
13550
+ annotations: {
13551
+ readOnlyHint: true,
13552
+ destructiveHint: false,
13553
+ idempotentHint: true,
13554
+ openWorldHint: true
13555
+ }
13556
+ },
13557
+ handleGetStoreTaxes
13558
+ );
13559
+ }
13560
+
12486
13561
  // src/tools/index.ts
12487
13562
  function setupToolHandlers(server) {
12488
13563
  server.server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -12609,6 +13684,15 @@ function registerAllTools(server) {
12609
13684
  registerBulkDeleteRedirectsBySearchTool();
12610
13685
  registerImportRedirectsTool();
12611
13686
  registerSubmitRedirectImportTool();
13687
+ registerGetStoreInfoTool();
13688
+ registerGetStoreLimitsTool();
13689
+ registerGetStoreFeaturesTool();
13690
+ registerGetStoreCurrenciesTool();
13691
+ registerGetStoreShippingTool();
13692
+ registerGetStoreDomainTool();
13693
+ registerGetStoreTaxesTool();
13694
+ registerGetStorePoliciesTool();
13695
+ registerGetStoreAlertsTool();
12612
13696
  const toolCount = getRegisteredTools().length;
12613
13697
  log.debug(`Tool registration complete: ${toolCount} tools registered`);
12614
13698
  }