shopify-store-mcp 1.0.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 (88) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +172 -0
  3. package/dist/config.d.ts +10 -0
  4. package/dist/config.js +65 -0
  5. package/dist/db.d.ts +19 -0
  6. package/dist/db.js +161 -0
  7. package/dist/errors.d.ts +36 -0
  8. package/dist/errors.js +93 -0
  9. package/dist/graphql/admin/common/collections.d.ts +8 -0
  10. package/dist/graphql/admin/common/collections.js +44 -0
  11. package/dist/graphql/admin/common/customers.d.ts +13 -0
  12. package/dist/graphql/admin/common/customers.js +112 -0
  13. package/dist/graphql/admin/common/orders.d.ts +13 -0
  14. package/dist/graphql/admin/common/orders.js +142 -0
  15. package/dist/graphql/admin/common/products.d.ts +23 -0
  16. package/dist/graphql/admin/common/products.js +159 -0
  17. package/dist/graphql/admin/common/shop.d.ts +7 -0
  18. package/dist/graphql/admin/common/shop.js +38 -0
  19. package/dist/graphql/admin/index.d.ts +15 -0
  20. package/dist/graphql/admin/index.js +18 -0
  21. package/dist/graphql/admin/specialized/bulk.d.ts +33 -0
  22. package/dist/graphql/admin/specialized/bulk.js +132 -0
  23. package/dist/graphql/admin/specialized/files.d.ts +22 -0
  24. package/dist/graphql/admin/specialized/files.js +170 -0
  25. package/dist/graphql/admin/specialized/inventory.d.ts +13 -0
  26. package/dist/graphql/admin/specialized/inventory.js +78 -0
  27. package/dist/graphql/admin/specialized/metafields.d.ts +22 -0
  28. package/dist/graphql/admin/specialized/metafields.js +100 -0
  29. package/dist/graphql/admin/specialized/metaobjects.d.ts +36 -0
  30. package/dist/graphql/admin/specialized/metaobjects.js +239 -0
  31. package/dist/graphql/admin/specialized/search.d.ts +21 -0
  32. package/dist/graphql/admin/specialized/search.js +100 -0
  33. package/dist/graphql/collections.d.ts +1 -0
  34. package/dist/graphql/collections.js +37 -0
  35. package/dist/graphql/customers.d.ts +2 -0
  36. package/dist/graphql/customers.js +98 -0
  37. package/dist/graphql/inventory.d.ts +2 -0
  38. package/dist/graphql/inventory.js +67 -0
  39. package/dist/graphql/metafields.d.ts +2 -0
  40. package/dist/graphql/metafields.js +43 -0
  41. package/dist/graphql/orders.d.ts +2 -0
  42. package/dist/graphql/orders.js +116 -0
  43. package/dist/graphql/products.d.ts +4 -0
  44. package/dist/graphql/products.js +140 -0
  45. package/dist/graphql/shop.d.ts +1 -0
  46. package/dist/graphql/shop.js +32 -0
  47. package/dist/graphql/storefront/common/cart.d.ts +23 -0
  48. package/dist/graphql/storefront/common/cart.js +210 -0
  49. package/dist/graphql/storefront/common/collections.d.ts +11 -0
  50. package/dist/graphql/storefront/common/collections.js +114 -0
  51. package/dist/graphql/storefront/common/products.d.ts +14 -0
  52. package/dist/graphql/storefront/common/products.js +155 -0
  53. package/dist/graphql/storefront/index.d.ts +7 -0
  54. package/dist/graphql/storefront/index.js +8 -0
  55. package/dist/index.d.ts +2 -0
  56. package/dist/index.js +97 -0
  57. package/dist/logger.d.ts +58 -0
  58. package/dist/logger.js +165 -0
  59. package/dist/prompts/index.d.ts +2 -0
  60. package/dist/prompts/index.js +169 -0
  61. package/dist/queue.d.ts +73 -0
  62. package/dist/queue.js +120 -0
  63. package/dist/resources/index.d.ts +3 -0
  64. package/dist/resources/index.js +180 -0
  65. package/dist/shopify-client.d.ts +16 -0
  66. package/dist/shopify-client.js +39 -0
  67. package/dist/tools/graphql.d.ts +3 -0
  68. package/dist/tools/graphql.js +41 -0
  69. package/dist/tools/index.d.ts +3 -0
  70. package/dist/tools/index.js +23 -0
  71. package/dist/tools/infrastructure.d.ts +6 -0
  72. package/dist/tools/infrastructure.js +215 -0
  73. package/dist/tools/shop.d.ts +3 -0
  74. package/dist/tools/shop.js +28 -0
  75. package/dist/tools/smart-bulk.d.ts +7 -0
  76. package/dist/tools/smart-bulk.js +286 -0
  77. package/dist/tools/smart-files.d.ts +7 -0
  78. package/dist/tools/smart-files.js +169 -0
  79. package/dist/tools/smart-metaobjects.d.ts +7 -0
  80. package/dist/tools/smart-metaobjects.js +186 -0
  81. package/dist/tools/smart-schema.d.ts +7 -0
  82. package/dist/tools/smart-schema.js +138 -0
  83. package/dist/types.d.ts +19 -0
  84. package/dist/types.js +2 -0
  85. package/dist/utils/polling.d.ts +53 -0
  86. package/dist/utils/polling.js +77 -0
  87. package/package.json +83 -0
  88. package/prisma/schema.prisma +82 -0
@@ -0,0 +1,180 @@
1
+ export function registerAllResources(server, config) {
2
+ // Store Configuration Resource
3
+ server.registerResource("store-config", "shopify://config", {
4
+ title: "Store Configuration",
5
+ description: "Current store connection configuration including domain and API version. " +
6
+ "Use this to verify which store you're connected to.",
7
+ mimeType: "application/json",
8
+ }, async () => ({
9
+ contents: [
10
+ {
11
+ uri: "shopify://config",
12
+ mimeType: "application/json",
13
+ text: JSON.stringify({
14
+ storeDomain: config.storeDomain,
15
+ apiVersion: config.apiVersion,
16
+ hasStorefrontAccess: !!config.storefrontAccessToken,
17
+ hasCustomerAccess: !!config.customerAccessToken,
18
+ }, null, 2),
19
+ },
20
+ ],
21
+ }));
22
+ // Shopify Query Syntax Reference
23
+ server.registerResource("query-syntax", "shopify://docs/query-syntax", {
24
+ title: "Shopify Query Syntax Reference",
25
+ description: "Reference guide for Shopify's search query syntax used in filtering products, orders, customers, etc.",
26
+ mimeType: "text/markdown",
27
+ }, async () => ({
28
+ contents: [
29
+ {
30
+ uri: "shopify://docs/query-syntax",
31
+ mimeType: "text/markdown",
32
+ text: `# Shopify Query Syntax Reference
33
+
34
+ ## Basic Syntax
35
+
36
+ Queries use field:value pairs separated by spaces (AND logic).
37
+
38
+ ## Common Fields by Resource
39
+
40
+ ### Products
41
+ - \`title:boots\` - Title contains "boots"
42
+ - \`status:active\` - Product status (active, draft, archived)
43
+ - \`vendor:Nike\` - Filter by vendor
44
+ - \`product_type:shoes\` - Filter by product type
45
+ - \`tag:sale\` - Has specific tag
46
+ - \`created_at:>2024-01-01\` - Created after date
47
+ - \`inventory_total:>0\` - Has inventory
48
+
49
+ ### Orders
50
+ - \`name:#1001\` - Order number
51
+ - \`email:customer@example.com\` - Customer email
52
+ - \`financial_status:paid\` - Payment status (paid, pending, refunded, voided)
53
+ - \`fulfillment_status:unfulfilled\` - Fulfillment status (unfulfilled, partial, fulfilled)
54
+ - \`created_at:>=7_days_ago\` - Relative date
55
+ - \`tag:wholesale\` - Has specific tag
56
+
57
+ ### Customers
58
+ - \`email:john@example.com\` - Email address
59
+ - \`country:US\` - Country code
60
+ - \`orders_count:>5\` - Number of orders
61
+ - \`total_spent:>100\` - Total amount spent
62
+ - \`tag:vip\` - Has specific tag
63
+ - \`state:enabled\` - Account state
64
+
65
+ ### Collections
66
+ - \`title:Summer\` - Collection title
67
+ - \`collection_type:smart\` - Type (smart or custom)
68
+
69
+ ## Operators
70
+ - \`:value\` - Equals or contains
71
+ - \`:>value\` - Greater than
72
+ - \`:>=value\` - Greater than or equal
73
+ - \`:<value\` - Less than
74
+ - \`:<=value\` - Less than or equal
75
+
76
+ ## Date Shortcuts
77
+ - \`today\`
78
+ - \`yesterday\`
79
+ - \`7_days_ago\`
80
+ - \`30_days_ago\`
81
+ - \`90_days_ago\`
82
+
83
+ ## Examples
84
+ \`\`\`
85
+ # Active products from Nike with low inventory
86
+ status:active vendor:Nike inventory_total:<10
87
+
88
+ # Paid but unfulfilled orders from this week
89
+ financial_status:paid fulfillment_status:unfulfilled created_at:>=7_days_ago
90
+
91
+ # VIP customers with multiple orders
92
+ tag:vip orders_count:>3
93
+ \`\`\`
94
+ `,
95
+ },
96
+ ],
97
+ }));
98
+ // GID Format Reference
99
+ server.registerResource("gid-format", "shopify://docs/gid-format", {
100
+ title: "Shopify GID Format Reference",
101
+ description: "Reference for Shopify's Global ID (GID) format used to identify resources.",
102
+ mimeType: "text/markdown",
103
+ }, async () => ({
104
+ contents: [
105
+ {
106
+ uri: "shopify://docs/gid-format",
107
+ mimeType: "text/markdown",
108
+ text: `# Shopify GID (Global ID) Format
109
+
110
+ ## Format
111
+ \`gid://shopify/{ResourceType}/{NumericID}\`
112
+
113
+ ## Common Resource Types
114
+ | Type | GID Example |
115
+ |------|-------------|
116
+ | Product | \`gid://shopify/Product/123456789\` |
117
+ | ProductVariant | \`gid://shopify/ProductVariant/123456789\` |
118
+ | Order | \`gid://shopify/Order/123456789\` |
119
+ | Customer | \`gid://shopify/Customer/123456789\` |
120
+ | Collection | \`gid://shopify/Collection/123456789\` |
121
+ | InventoryItem | \`gid://shopify/InventoryItem/123456789\` |
122
+ | InventoryLevel | \`gid://shopify/InventoryLevel/123456789?inventory_item_id=X&location_id=Y\` |
123
+ | Location | \`gid://shopify/Location/123456789\` |
124
+ | Metafield | \`gid://shopify/Metafield/123456789\` |
125
+ | FulfillmentOrder | \`gid://shopify/FulfillmentOrder/123456789\` |
126
+
127
+ ## Notes
128
+ - Most tools in this MCP accept both numeric IDs and full GIDs
129
+ - When in doubt, use the full GID format
130
+ - GIDs from query responses can be used directly in subsequent calls
131
+ `,
132
+ },
133
+ ],
134
+ }));
135
+ // Available Scopes Reference
136
+ server.registerResource("api-scopes", "shopify://docs/scopes", {
137
+ title: "API Scopes Reference",
138
+ description: "Reference for Shopify Admin API access scopes required for different operations.",
139
+ mimeType: "text/markdown",
140
+ }, async () => ({
141
+ contents: [
142
+ {
143
+ uri: "shopify://docs/scopes",
144
+ mimeType: "text/markdown",
145
+ text: `# Shopify Admin API Scopes
146
+
147
+ ## Required Scopes by Operation
148
+
149
+ ### Products
150
+ - \`read_products\` - List and view products
151
+ - \`write_products\` - Create and update products
152
+
153
+ ### Orders
154
+ - \`read_orders\` - List and view orders
155
+ - \`write_orders\` - Update orders, create fulfillments
156
+
157
+ ### Customers
158
+ - \`read_customers\` - List and view customers
159
+ - \`write_customers\` - Create and update customers
160
+
161
+ ### Inventory
162
+ - \`read_inventory\` - View inventory levels
163
+ - \`write_inventory\` - Adjust inventory quantities
164
+
165
+ ### Other Common Scopes
166
+ - \`read_locations\` - View store locations
167
+ - \`read_shipping\` - View shipping settings
168
+ - \`read_fulfillments\` - View fulfillments
169
+ - \`write_fulfillments\` - Create fulfillments
170
+
171
+ ## Checking Your Scopes
172
+ If a tool returns a 403 error, it likely means your custom app is missing the required scope. Update your app's API access scopes in:
173
+
174
+ **Shopify Admin → Settings → Apps and sales channels → Develop apps → [Your App] → Configuration**
175
+ `,
176
+ },
177
+ ],
178
+ }));
179
+ }
180
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,16 @@
1
+ import { type AdminApiClient } from "@shopify/admin-api-client";
2
+ import { type StorefrontApiClient } from "@shopify/storefront-api-client";
3
+ import type { ShopifyConfig } from "./config.js";
4
+ /**
5
+ * Get the Admin API client (singleton).
6
+ * Used for store management operations: products, orders, customers, inventory, etc.
7
+ */
8
+ export declare function getAdminClient(config: ShopifyConfig): AdminApiClient;
9
+ /**
10
+ * Get the Storefront API client (singleton).
11
+ * Used for customer-facing operations: product browsing, cart, checkout, etc.
12
+ * Requires SHOPIFY_STOREFRONT_ACCESS_TOKEN to be set.
13
+ */
14
+ export declare function getStorefrontClient(config: ShopifyConfig): StorefrontApiClient | null;
15
+ export declare const getShopifyClient: typeof getAdminClient;
16
+ export type { AdminApiClient, StorefrontApiClient };
@@ -0,0 +1,39 @@
1
+ import { createAdminApiClient } from "@shopify/admin-api-client";
2
+ import { createStorefrontApiClient } from "@shopify/storefront-api-client";
3
+ let adminClientInstance = null;
4
+ let storefrontClientInstance = null;
5
+ /**
6
+ * Get the Admin API client (singleton).
7
+ * Used for store management operations: products, orders, customers, inventory, etc.
8
+ */
9
+ export function getAdminClient(config) {
10
+ if (!adminClientInstance) {
11
+ adminClientInstance = createAdminApiClient({
12
+ storeDomain: config.storeDomain,
13
+ apiVersion: config.apiVersion,
14
+ accessToken: config.adminAccessToken,
15
+ });
16
+ }
17
+ return adminClientInstance;
18
+ }
19
+ /**
20
+ * Get the Storefront API client (singleton).
21
+ * Used for customer-facing operations: product browsing, cart, checkout, etc.
22
+ * Requires SHOPIFY_STOREFRONT_ACCESS_TOKEN to be set.
23
+ */
24
+ export function getStorefrontClient(config) {
25
+ if (!config.storefrontAccessToken) {
26
+ return null;
27
+ }
28
+ if (!storefrontClientInstance) {
29
+ storefrontClientInstance = createStorefrontApiClient({
30
+ storeDomain: config.storeDomain,
31
+ apiVersion: config.apiVersion,
32
+ publicAccessToken: config.storefrontAccessToken,
33
+ });
34
+ }
35
+ return storefrontClientInstance;
36
+ }
37
+ // Legacy alias for backwards compatibility
38
+ export const getShopifyClient = getAdminClient;
39
+ //# sourceMappingURL=shopify-client.js.map
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AdminApiClient } from "../shopify-client.js";
3
+ export declare function registerGraphQLTools(server: McpServer, client: AdminApiClient): void;
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ import { formatSuccessResponse, formatGraphQLErrors, formatErrorResponse, } from "../errors.js";
3
+ export function registerGraphQLTools(server, client) {
4
+ server.registerTool("run_graphql_query", {
5
+ title: "Run GraphQL Query",
6
+ description: "Execute any GraphQL query or mutation against the Shopify Admin API. " +
7
+ "This is the most powerful and flexible tool - use it when other specialized tools " +
8
+ "don't cover your use case, or when you need precise control over the query shape. " +
9
+ "Returns the raw API response including data and any errors. " +
10
+ "Refer to Shopify's Admin API GraphQL reference for available queries and mutations.",
11
+ inputSchema: {
12
+ query: z
13
+ .string()
14
+ .describe("The GraphQL query or mutation string. Must be valid GraphQL syntax. " +
15
+ "Example: 'query { shop { name } }'"),
16
+ variables: z
17
+ .record(z.unknown())
18
+ .optional()
19
+ .describe("Variables to pass to the GraphQL operation as a JSON object. " +
20
+ "Keys should match the variable names in your query (without the $ prefix)."),
21
+ },
22
+ annotations: {
23
+ // Cannot determine if read-only since it could be a mutation
24
+ openWorldHint: true,
25
+ },
26
+ }, async ({ query, variables }) => {
27
+ try {
28
+ const response = await client.request(query, {
29
+ variables: variables,
30
+ });
31
+ if (response.errors) {
32
+ return formatGraphQLErrors(response);
33
+ }
34
+ return formatSuccessResponse(response.data);
35
+ }
36
+ catch (error) {
37
+ return formatErrorResponse(error);
38
+ }
39
+ });
40
+ }
41
+ //# sourceMappingURL=graphql.js.map
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AdminApiClient } from "../shopify-client.js";
3
+ export declare function registerAllTools(server: McpServer, client: AdminApiClient, storeDomain: string): void;
@@ -0,0 +1,23 @@
1
+ // Core tools
2
+ import { registerShopTools } from "./shop.js";
3
+ import { registerGraphQLTools } from "./graphql.js";
4
+ // Smart tools (multi-step workflows)
5
+ import { registerSmartFileTools } from "./smart-files.js";
6
+ import { registerSmartBulkTools } from "./smart-bulk.js";
7
+ import { registerSmartMetaobjectTools } from "./smart-metaobjects.js";
8
+ import { registerSmartSchemaTools } from "./smart-schema.js";
9
+ // Infrastructure tools
10
+ import { registerInfrastructureTools } from "./infrastructure.js";
11
+ export function registerAllTools(server, client, storeDomain) {
12
+ // Core tools (2)
13
+ registerShopTools(server, client); // get_shop_info
14
+ registerGraphQLTools(server, client); // run_graphql_query - the universal escape hatch
15
+ // Smart tools (5) - multi-step workflows that agents would struggle with
16
+ registerSmartFileTools(server, client, storeDomain); // upload_file
17
+ registerSmartBulkTools(server, client, storeDomain); // bulk_export, bulk_import
18
+ registerSmartMetaobjectTools(server, client, storeDomain); // upsert_metaobject
19
+ registerSmartSchemaTools(server, client, storeDomain); // schema_discover
20
+ // Infrastructure tools (3) - config, debugging, stats
21
+ registerInfrastructureTools(server, client, storeDomain); // configure, get_history, get_stats
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Infrastructure tools for configuration, history, and stats
3
+ */
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import type { AdminApiClient } from "../shopify-client.js";
6
+ export declare function registerInfrastructureTools(server: McpServer, client: AdminApiClient, storeDomain: string): void;
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Infrastructure tools for configuration, history, and stats
3
+ */
4
+ import { z } from "zod";
5
+ import { formatSuccessResponse, formatGraphQLErrors, formatErrorResponse, } from "../errors.js";
6
+ import prisma from "../db.js";
7
+ import { updateQueue, detectTierFromPlan, getCurrentTierInfo, SHOPIFY_TIER_CONFIGS, } from "../queue.js";
8
+ import { getOperationHistory, getOperationStats, getSessionId, } from "../logger.js";
9
+ import { GET_SHOP } from "../graphql/admin/index.js";
10
+ import { enqueue } from "../queue.js";
11
+ export function registerInfrastructureTools(server, client, storeDomain) {
12
+ // CONFIGURE
13
+ server.registerTool("configure", {
14
+ title: "Configure MCP",
15
+ description: "Configure the MCP server settings. " +
16
+ "Set the rate limit tier manually or auto-detect from shop plan. " +
17
+ "Returns current configuration including tier, queue settings, and session info.",
18
+ inputSchema: {
19
+ tier: z
20
+ .enum(["STANDARD", "ADVANCED", "PLUS", "ENTERPRISE"])
21
+ .optional()
22
+ .describe("Manually set the rate limit tier. " +
23
+ "STANDARD: 1 req/sec (Basic, Development plans). " +
24
+ "ADVANCED: 2 req/sec (Advanced plans). " +
25
+ "PLUS: 5 req/sec (Shopify Plus). " +
26
+ "ENTERPRISE: 10 req/sec (Commerce Components)."),
27
+ autoDetect: z
28
+ .boolean()
29
+ .optional()
30
+ .describe("Auto-detect tier from shop plan. " +
31
+ "Queries the shop and sets tier based on plan name."),
32
+ },
33
+ annotations: {
34
+ readOnlyHint: false,
35
+ destructiveHint: false,
36
+ idempotentHint: true,
37
+ openWorldHint: false,
38
+ },
39
+ }, async ({ tier, autoDetect }) => {
40
+ try {
41
+ let detectedTier;
42
+ let shopPlan;
43
+ let shopName;
44
+ // Auto-detect from shop plan
45
+ if (autoDetect) {
46
+ const response = await enqueue(() => client.request(GET_SHOP, {}));
47
+ if (response.errors) {
48
+ return formatGraphQLErrors(response);
49
+ }
50
+ const shopData = response.data;
51
+ shopName = shopData.shop.name;
52
+ shopPlan = shopData.shop.plan.displayName;
53
+ detectedTier = detectTierFromPlan({
54
+ shopifyPlus: shopData.shop.plan.shopifyPlus,
55
+ displayName: shopData.shop.plan.displayName,
56
+ });
57
+ }
58
+ // Use provided tier, or detected tier, or keep current
59
+ const newTier = tier || detectedTier;
60
+ if (newTier) {
61
+ updateQueue(newTier);
62
+ // Save to database
63
+ await prisma.storeConfig.upsert({
64
+ where: { storeDomain },
65
+ update: {
66
+ tier: newTier,
67
+ autoDetected: !!autoDetect,
68
+ shopName,
69
+ shopPlan,
70
+ },
71
+ create: {
72
+ storeDomain,
73
+ tier: newTier,
74
+ autoDetected: !!autoDetect,
75
+ shopName,
76
+ shopPlan,
77
+ },
78
+ });
79
+ }
80
+ // Get current config
81
+ const currentTier = getCurrentTierInfo();
82
+ const config = await prisma.storeConfig.findUnique({
83
+ where: { storeDomain },
84
+ });
85
+ return formatSuccessResponse({
86
+ success: true,
87
+ config: {
88
+ storeDomain,
89
+ tier: currentTier.tier,
90
+ tierConfig: currentTier.config,
91
+ autoDetected: config?.autoDetected || false,
92
+ shopName: config?.shopName || shopName,
93
+ shopPlan: config?.shopPlan || shopPlan,
94
+ sessionId: getSessionId(),
95
+ },
96
+ availableTiers: Object.keys(SHOPIFY_TIER_CONFIGS),
97
+ });
98
+ }
99
+ catch (error) {
100
+ return formatErrorResponse(error);
101
+ }
102
+ });
103
+ // GET HISTORY
104
+ server.registerTool("get_history", {
105
+ title: "Get Operation History",
106
+ description: "Query past operations for debugging. " +
107
+ "Filter by tool name, operation type, success/failure, or date range. " +
108
+ "Returns recent operations with query, response, duration, and errors.",
109
+ inputSchema: {
110
+ toolName: z
111
+ .string()
112
+ .optional()
113
+ .describe("Filter by tool name (e.g., 'get_products', 'upload_file')"),
114
+ operationType: z
115
+ .enum(["query", "mutation"])
116
+ .optional()
117
+ .describe("Filter by operation type"),
118
+ success: z
119
+ .boolean()
120
+ .optional()
121
+ .describe("Filter by success (true) or failure (false)"),
122
+ since: z
123
+ .string()
124
+ .optional()
125
+ .describe("ISO date string. Only return operations after this date."),
126
+ limit: z
127
+ .number()
128
+ .int()
129
+ .min(1)
130
+ .max(500)
131
+ .default(50)
132
+ .describe("Maximum number of operations to return (1-500). Default: 50"),
133
+ },
134
+ annotations: {
135
+ readOnlyHint: true,
136
+ destructiveHint: false,
137
+ idempotentHint: true,
138
+ openWorldHint: false,
139
+ },
140
+ }, async ({ toolName, operationType, success, since, limit }) => {
141
+ try {
142
+ const operations = await getOperationHistory({
143
+ storeDomain,
144
+ toolName,
145
+ operationType,
146
+ success,
147
+ since: since ? new Date(since) : undefined,
148
+ limit,
149
+ });
150
+ return formatSuccessResponse({
151
+ success: true,
152
+ count: operations.length,
153
+ operations,
154
+ });
155
+ }
156
+ catch (error) {
157
+ return formatErrorResponse(error);
158
+ }
159
+ });
160
+ // GET STATS
161
+ server.registerTool("get_stats", {
162
+ title: "Get Usage Statistics",
163
+ description: "Get aggregated statistics for operations. " +
164
+ "Includes total calls, success rate, average duration, and breakdown by tool.",
165
+ inputSchema: {
166
+ period: z
167
+ .enum(["day", "week", "month"])
168
+ .default("day")
169
+ .describe("Time period for statistics. Default: day"),
170
+ },
171
+ annotations: {
172
+ readOnlyHint: true,
173
+ destructiveHint: false,
174
+ idempotentHint: true,
175
+ openWorldHint: false,
176
+ },
177
+ }, async ({ period }) => {
178
+ try {
179
+ // Calculate since date based on period
180
+ const since = new Date();
181
+ switch (period) {
182
+ case "day":
183
+ since.setDate(since.getDate() - 1);
184
+ break;
185
+ case "week":
186
+ since.setDate(since.getDate() - 7);
187
+ break;
188
+ case "month":
189
+ since.setMonth(since.getMonth() - 1);
190
+ break;
191
+ }
192
+ const stats = await getOperationStats({
193
+ storeDomain,
194
+ since,
195
+ });
196
+ return formatSuccessResponse({
197
+ success: true,
198
+ period,
199
+ since: since.toISOString(),
200
+ stats: {
201
+ totalCalls: stats.totalCalls,
202
+ successCount: stats.successCount,
203
+ errorCount: stats.errorCount,
204
+ successRate: stats.totalCalls > 0 ? stats.successCount / stats.totalCalls : 0,
205
+ avgDurationMs: Math.round(stats.avgDurationMs),
206
+ byTool: stats.byTool,
207
+ },
208
+ });
209
+ }
210
+ catch (error) {
211
+ return formatErrorResponse(error);
212
+ }
213
+ });
214
+ }
215
+ //# sourceMappingURL=infrastructure.js.map
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AdminApiClient } from "../shopify-client.js";
3
+ export declare function registerShopTools(server: McpServer, client: AdminApiClient): void;
@@ -0,0 +1,28 @@
1
+ import { formatSuccessResponse, formatGraphQLErrors, formatErrorResponse, } from "../errors.js";
2
+ import { GET_SHOP } from "../graphql/admin/index.js";
3
+ export function registerShopTools(server, client) {
4
+ server.registerTool("get_shop_info", {
5
+ title: "Get Shop Info",
6
+ description: "Retrieve the store's configuration and settings. Returns store name, email, domain, " +
7
+ "Shopify plan details, primary domain, currency, weight unit, timezone, and billing address. " +
8
+ "Use this to verify store connection or get store-wide settings.",
9
+ inputSchema: {},
10
+ annotations: {
11
+ readOnlyHint: true,
12
+ idempotentHint: true,
13
+ openWorldHint: false,
14
+ },
15
+ }, async () => {
16
+ try {
17
+ const response = await client.request(GET_SHOP);
18
+ if (response.errors) {
19
+ return formatGraphQLErrors(response);
20
+ }
21
+ return formatSuccessResponse(response.data);
22
+ }
23
+ catch (error) {
24
+ return formatErrorResponse(error);
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=shop.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Smart bulk operation tools
3
+ * Handles bulk export and import with polling
4
+ */
5
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import type { AdminApiClient } from "../shopify-client.js";
7
+ export declare function registerSmartBulkTools(server: McpServer, client: AdminApiClient, storeDomain: string): void;