@klaudworks/shopify-mcp 1.1.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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +531 -0
  3. package/dist/index.js +107 -0
  4. package/dist/lib/formatters.js +72 -0
  5. package/dist/lib/shopifyAuth.js +96 -0
  6. package/dist/lib/toolUtils.js +36 -0
  7. package/dist/tools/completeDraftOrder.js +76 -0
  8. package/dist/tools/createCustomer.js +142 -0
  9. package/dist/tools/createDraftOrder.js +160 -0
  10. package/dist/tools/createFulfillment.js +100 -0
  11. package/dist/tools/createProduct.js +123 -0
  12. package/dist/tools/createRefund.js +115 -0
  13. package/dist/tools/deleteCustomer.js +47 -0
  14. package/dist/tools/deleteMetafields.js +54 -0
  15. package/dist/tools/deleteProduct.js +43 -0
  16. package/dist/tools/deleteProductVariants.js +82 -0
  17. package/dist/tools/getCollectionById.js +123 -0
  18. package/dist/tools/getCollections.js +88 -0
  19. package/dist/tools/getCustomerById.js +122 -0
  20. package/dist/tools/getCustomerOrders.js +131 -0
  21. package/dist/tools/getCustomers.js +125 -0
  22. package/dist/tools/getFulfillmentOrders.js +106 -0
  23. package/dist/tools/getInventoryItems.js +86 -0
  24. package/dist/tools/getInventoryLevels.js +82 -0
  25. package/dist/tools/getLocations.js +85 -0
  26. package/dist/tools/getMarkets.js +91 -0
  27. package/dist/tools/getMetafieldDefinitions.js +112 -0
  28. package/dist/tools/getMetafields.js +68 -0
  29. package/dist/tools/getOrderById.js +212 -0
  30. package/dist/tools/getOrderRefundDetails.js +131 -0
  31. package/dist/tools/getOrderTransactions.js +85 -0
  32. package/dist/tools/getOrders.js +148 -0
  33. package/dist/tools/getPriceLists.js +92 -0
  34. package/dist/tools/getProductById.js +171 -0
  35. package/dist/tools/getProductVariantsDetailed.js +139 -0
  36. package/dist/tools/getProducts.js +155 -0
  37. package/dist/tools/getShopInfo.js +74 -0
  38. package/dist/tools/manageCustomerAddress.js +149 -0
  39. package/dist/tools/manageProductOptions.js +293 -0
  40. package/dist/tools/manageProductVariants.js +203 -0
  41. package/dist/tools/manageTags.js +79 -0
  42. package/dist/tools/mergeCustomers.js +74 -0
  43. package/dist/tools/orderCancel.js +77 -0
  44. package/dist/tools/orderCloseOpen.js +74 -0
  45. package/dist/tools/orderMarkAsPaid.js +51 -0
  46. package/dist/tools/registry.js +106 -0
  47. package/dist/tools/setInventoryQuantities.js +74 -0
  48. package/dist/tools/setMetafields.js +61 -0
  49. package/dist/tools/updateCustomer.js +119 -0
  50. package/dist/tools/updateOrder.js +131 -0
  51. package/dist/tools/updateProduct.js +132 -0
  52. package/package.json +66 -0
@@ -0,0 +1,85 @@
1
+ import { gql } from "graphql-request";
2
+ import { z } from "zod";
3
+ import { handleToolError } from "../lib/toolUtils.js";
4
+ const GetOrderTransactionsInputSchema = z.object({
5
+ orderId: z
6
+ .string()
7
+ .min(1)
8
+ .describe("The order ID (e.g. gid://shopify/Order/123 or just 123)"),
9
+ });
10
+ let shopifyClient;
11
+ const getOrderTransactions = {
12
+ name: "get-order-transactions",
13
+ description: "Get all payment transactions for an order including authorizations, captures, refunds, and voids with gateway, status, and amounts",
14
+ schema: GetOrderTransactionsInputSchema,
15
+ initialize(client) {
16
+ shopifyClient = client;
17
+ },
18
+ execute: async (input) => {
19
+ try {
20
+ const orderId = input.orderId.startsWith("gid://")
21
+ ? input.orderId
22
+ : `gid://shopify/Order/${input.orderId}`;
23
+ const query = gql `
24
+ #graphql
25
+
26
+ query GetOrderTransactions($id: ID!) {
27
+ order(id: $id) {
28
+ id
29
+ name
30
+ transactions {
31
+ id
32
+ kind
33
+ status
34
+ gateway
35
+ formattedGateway
36
+ amountSet {
37
+ shopMoney {
38
+ amount
39
+ currencyCode
40
+ }
41
+ presentmentMoney {
42
+ amount
43
+ currencyCode
44
+ }
45
+ }
46
+ processedAt
47
+ createdAt
48
+ authorizationCode
49
+ authorizationExpiresAt
50
+ errorCode
51
+ test
52
+ parentTransaction {
53
+ id
54
+ kind
55
+ }
56
+ paymentDetails {
57
+ ... on CardPaymentDetails {
58
+ company
59
+ number
60
+ name
61
+ }
62
+ }
63
+ receiptJson
64
+ }
65
+ }
66
+ }
67
+ `;
68
+ const data = await shopifyClient.request(query, { id: orderId });
69
+ if (!data.order) {
70
+ throw new Error(`Order not found: ${orderId}`);
71
+ }
72
+ const transactions = data.order.transactions;
73
+ return {
74
+ orderId: data.order.id,
75
+ orderName: data.order.name,
76
+ transactionsCount: transactions.length,
77
+ transactions,
78
+ };
79
+ }
80
+ catch (error) {
81
+ handleToolError("fetch order transactions", error);
82
+ }
83
+ },
84
+ };
85
+ export { getOrderTransactions };
@@ -0,0 +1,148 @@
1
+ import { gql } from "graphql-request";
2
+ import { z } from "zod";
3
+ import { handleToolError, edgesToNodes } from "../lib/toolUtils.js";
4
+ import { formatOrderSummary } from "../lib/formatters.js";
5
+ // Input schema for getOrders
6
+ const GetOrdersInputSchema = z.object({
7
+ status: z.enum(["any", "open", "closed", "cancelled"]).default("any"),
8
+ limit: z.number().default(10),
9
+ after: z.string().optional().describe("Cursor for forward pagination"),
10
+ before: z.string().optional().describe("Cursor for backward pagination"),
11
+ sortKey: z.enum([
12
+ "CREATED_AT", "ORDER_NUMBER", "TOTAL_PRICE", "FINANCIAL_STATUS",
13
+ "FULFILLMENT_STATUS", "UPDATED_AT", "CUSTOMER_NAME", "PROCESSED_AT",
14
+ "ID", "RELEVANCE"
15
+ ]).optional().describe("Sort key for orders"),
16
+ reverse: z.boolean().optional().describe("Reverse the sort order"),
17
+ query: z.string().optional().describe("Raw query string for advanced filtering (e.g. 'financial_status:paid fulfillment_status:shipped')")
18
+ });
19
+ // Will be initialized in index.ts
20
+ let shopifyClient;
21
+ const getOrders = {
22
+ name: "get-orders",
23
+ description: "Get orders with optional filtering by status",
24
+ schema: GetOrdersInputSchema,
25
+ // Add initialize method to set up the GraphQL client
26
+ initialize(client) {
27
+ shopifyClient = client;
28
+ },
29
+ execute: async (input) => {
30
+ try {
31
+ const { status, limit, after, before, sortKey, reverse, query: rawQuery } = input;
32
+ // Build query filters
33
+ const queryParts = [];
34
+ if (status !== "any") {
35
+ queryParts.push(`status:${status}`);
36
+ }
37
+ if (rawQuery) {
38
+ queryParts.push(rawQuery);
39
+ }
40
+ const queryFilter = queryParts.join(" ") || undefined;
41
+ const query = gql `
42
+ #graphql
43
+
44
+ query GetOrders($first: Int!, $query: String, $after: String, $before: String, $sortKey: OrderSortKeys, $reverse: Boolean) {
45
+ orders(first: $first, query: $query, after: $after, before: $before, sortKey: $sortKey, reverse: $reverse) {
46
+ edges {
47
+ node {
48
+ id
49
+ name
50
+ createdAt
51
+ displayFinancialStatus
52
+ displayFulfillmentStatus
53
+ totalPriceSet {
54
+ shopMoney {
55
+ amount
56
+ currencyCode
57
+ }
58
+ }
59
+ subtotalPriceSet {
60
+ shopMoney {
61
+ amount
62
+ currencyCode
63
+ }
64
+ }
65
+ totalShippingPriceSet {
66
+ shopMoney {
67
+ amount
68
+ currencyCode
69
+ }
70
+ }
71
+ totalTaxSet {
72
+ shopMoney {
73
+ amount
74
+ currencyCode
75
+ }
76
+ }
77
+ customer {
78
+ id
79
+ firstName
80
+ lastName
81
+ defaultEmailAddress {
82
+ emailAddress
83
+ }
84
+ }
85
+ shippingAddress {
86
+ address1
87
+ address2
88
+ city
89
+ provinceCode
90
+ zip
91
+ country
92
+ phone
93
+ }
94
+ lineItems(first: 10) {
95
+ edges {
96
+ node {
97
+ id
98
+ title
99
+ quantity
100
+ originalTotalSet {
101
+ shopMoney {
102
+ amount
103
+ currencyCode
104
+ }
105
+ }
106
+ variant {
107
+ id
108
+ title
109
+ sku
110
+ }
111
+ }
112
+ }
113
+ }
114
+ tags
115
+ note
116
+ }
117
+ }
118
+ pageInfo {
119
+ hasNextPage
120
+ hasPreviousPage
121
+ startCursor
122
+ endCursor
123
+ }
124
+ }
125
+ }
126
+ `;
127
+ const variables = {
128
+ first: limit,
129
+ query: queryFilter,
130
+ ...(after && { after }),
131
+ ...(before && { before }),
132
+ ...(sortKey && { sortKey }),
133
+ ...(reverse !== undefined && { reverse })
134
+ };
135
+ const data = (await shopifyClient.request(query, variables));
136
+ // Extract and format order data
137
+ const orders = edgesToNodes(data.orders).map(formatOrderSummary);
138
+ return {
139
+ orders,
140
+ pageInfo: data.orders.pageInfo
141
+ };
142
+ }
143
+ catch (error) {
144
+ handleToolError("fetch orders", error);
145
+ }
146
+ }
147
+ };
148
+ export { getOrders };
@@ -0,0 +1,92 @@
1
+ import { gql } from "graphql-request";
2
+ import { z } from "zod";
3
+ import { edgesToNodes, handleToolError } from "../lib/toolUtils.js";
4
+ const GetPriceListsInputSchema = z.object({
5
+ first: z
6
+ .number()
7
+ .min(1)
8
+ .max(50)
9
+ .default(25)
10
+ .optional()
11
+ .describe("Number of price lists to return (default 25, max 50)"),
12
+ });
13
+ let shopifyClient;
14
+ const getPriceLists = {
15
+ name: "get-price-lists",
16
+ description: "Get all price lists with their currency, fixed/relative adjustments, and associated catalog context",
17
+ schema: GetPriceListsInputSchema,
18
+ initialize(client) {
19
+ shopifyClient = client;
20
+ },
21
+ execute: async (input) => {
22
+ try {
23
+ const query = gql `
24
+ #graphql
25
+
26
+ query GetPriceLists($first: Int!) {
27
+ priceLists(first: $first) {
28
+ edges {
29
+ node {
30
+ id
31
+ name
32
+ currency
33
+ fixedPricesCount
34
+ parent {
35
+ adjustment {
36
+ type
37
+ value
38
+ }
39
+ }
40
+ catalog {
41
+ ... on MarketCatalog {
42
+ id
43
+ title
44
+ }
45
+ }
46
+ prices(first: 10) {
47
+ edges {
48
+ node {
49
+ variant {
50
+ id
51
+ title
52
+ product {
53
+ id
54
+ title
55
+ }
56
+ }
57
+ price {
58
+ amount
59
+ currencyCode
60
+ }
61
+ compareAtPrice {
62
+ amount
63
+ currencyCode
64
+ }
65
+ originType
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ `;
74
+ const variables = {
75
+ first: input.first ?? 25,
76
+ };
77
+ const data = await shopifyClient.request(query, variables);
78
+ const priceLists = edgesToNodes(data.priceLists).map((priceList) => ({
79
+ ...priceList,
80
+ prices: edgesToNodes(priceList.prices),
81
+ }));
82
+ return {
83
+ priceListsCount: priceLists.length,
84
+ priceLists,
85
+ };
86
+ }
87
+ catch (error) {
88
+ handleToolError("fetch price lists", error);
89
+ }
90
+ },
91
+ };
92
+ export { getPriceLists };
@@ -0,0 +1,171 @@
1
+ import { gql } from "graphql-request";
2
+ import { z } from "zod";
3
+ import { handleToolError } from "../lib/toolUtils.js";
4
+ // Input schema for getProductById
5
+ const GetProductByIdInputSchema = z.object({
6
+ productId: z.string().min(1)
7
+ });
8
+ // Will be initialized in index.ts
9
+ let shopifyClient;
10
+ const getProductById = {
11
+ name: "get-product-by-id",
12
+ description: "Get a specific product by ID",
13
+ schema: GetProductByIdInputSchema,
14
+ // Add initialize method to set up the GraphQL client
15
+ initialize(client) {
16
+ shopifyClient = client;
17
+ },
18
+ execute: async (input) => {
19
+ try {
20
+ const { productId } = input;
21
+ const query = gql `
22
+ #graphql
23
+
24
+ query GetProductById($id: ID!) {
25
+ product(id: $id) {
26
+ id
27
+ title
28
+ description
29
+ handle
30
+ status
31
+ createdAt
32
+ updatedAt
33
+ totalInventory
34
+ priceRangeV2 {
35
+ minVariantPrice {
36
+ amount
37
+ currencyCode
38
+ }
39
+ maxVariantPrice {
40
+ amount
41
+ currencyCode
42
+ }
43
+ }
44
+ media(first: 5) {
45
+ edges {
46
+ node {
47
+ ... on MediaImage {
48
+ id
49
+ image {
50
+ url
51
+ altText
52
+ width
53
+ height
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ variants(first: 20) {
60
+ edges {
61
+ node {
62
+ id
63
+ title
64
+ price
65
+ inventoryQuantity
66
+ sku
67
+ selectedOptions {
68
+ name
69
+ value
70
+ }
71
+ }
72
+ }
73
+ }
74
+ collections(first: 5) {
75
+ edges {
76
+ node {
77
+ id
78
+ title
79
+ }
80
+ }
81
+ }
82
+ tags
83
+ vendor
84
+ productType
85
+ descriptionHtml
86
+ seo {
87
+ title
88
+ description
89
+ }
90
+ options {
91
+ id
92
+ name
93
+ position
94
+ optionValues {
95
+ id
96
+ name
97
+ }
98
+ }
99
+ }
100
+ }
101
+ `;
102
+ const variables = {
103
+ id: productId
104
+ };
105
+ const data = (await shopifyClient.request(query, variables));
106
+ if (!data.product) {
107
+ throw new Error(`Product with ID ${productId} not found`);
108
+ }
109
+ // Format product data
110
+ const product = data.product;
111
+ // Format variants
112
+ const variants = product.variants.edges.map((variantEdge) => ({
113
+ id: variantEdge.node.id,
114
+ title: variantEdge.node.title,
115
+ price: variantEdge.node.price,
116
+ inventoryQuantity: variantEdge.node.inventoryQuantity,
117
+ sku: variantEdge.node.sku,
118
+ options: variantEdge.node.selectedOptions
119
+ }));
120
+ // Format images from media
121
+ const images = product.media.edges
122
+ .filter((mediaEdge) => mediaEdge.node.image)
123
+ .map((mediaEdge) => ({
124
+ id: mediaEdge.node.id,
125
+ url: mediaEdge.node.image.url,
126
+ altText: mediaEdge.node.image.altText,
127
+ width: mediaEdge.node.image.width,
128
+ height: mediaEdge.node.image.height
129
+ }));
130
+ // Format collections
131
+ const collections = product.collections.edges.map((collectionEdge) => ({
132
+ id: collectionEdge.node.id,
133
+ title: collectionEdge.node.title
134
+ }));
135
+ const formattedProduct = {
136
+ id: product.id,
137
+ title: product.title,
138
+ description: product.description,
139
+ handle: product.handle,
140
+ status: product.status,
141
+ createdAt: product.createdAt,
142
+ updatedAt: product.updatedAt,
143
+ totalInventory: product.totalInventory,
144
+ priceRange: {
145
+ minPrice: {
146
+ amount: product.priceRangeV2.minVariantPrice.amount,
147
+ currencyCode: product.priceRangeV2.minVariantPrice.currencyCode
148
+ },
149
+ maxPrice: {
150
+ amount: product.priceRangeV2.maxVariantPrice.amount,
151
+ currencyCode: product.priceRangeV2.maxVariantPrice.currencyCode
152
+ }
153
+ },
154
+ images,
155
+ variants,
156
+ collections,
157
+ tags: product.tags,
158
+ vendor: product.vendor,
159
+ productType: product.productType,
160
+ descriptionHtml: product.descriptionHtml,
161
+ seo: product.seo,
162
+ options: product.options
163
+ };
164
+ return { product: formattedProduct };
165
+ }
166
+ catch (error) {
167
+ handleToolError("fetch product", error);
168
+ }
169
+ }
170
+ };
171
+ export { getProductById };
@@ -0,0 +1,139 @@
1
+ import { gql } from "graphql-request";
2
+ import { z } from "zod";
3
+ import { edgesToNodes, handleToolError } from "../lib/toolUtils.js";
4
+ const GetProductVariantsDetailedInputSchema = z.object({
5
+ productId: z
6
+ .string()
7
+ .min(1)
8
+ .describe("The product ID (e.g. gid://shopify/Product/123 or just 123)"),
9
+ first: z
10
+ .number()
11
+ .min(1)
12
+ .max(100)
13
+ .default(50)
14
+ .optional()
15
+ .describe("Number of variants to return (default 50, max 100)"),
16
+ });
17
+ let shopifyClient;
18
+ const getProductVariantsDetailed = {
19
+ name: "get-product-variants-detailed",
20
+ description: "Get all variant fields for a product: pricing, inventory, barcode, weight, tax code, selected options, metafields, and image",
21
+ schema: GetProductVariantsDetailedInputSchema,
22
+ initialize(client) {
23
+ shopifyClient = client;
24
+ },
25
+ execute: async (input) => {
26
+ try {
27
+ const productId = input.productId.startsWith("gid://")
28
+ ? input.productId
29
+ : `gid://shopify/Product/${input.productId}`;
30
+ const query = gql `
31
+ #graphql
32
+
33
+ query GetProductVariantsDetailed($id: ID!, $first: Int!) {
34
+ product(id: $id) {
35
+ id
36
+ title
37
+ variants(first: $first) {
38
+ edges {
39
+ node {
40
+ id
41
+ title
42
+ displayName
43
+ sku
44
+ barcode
45
+ price
46
+ compareAtPrice
47
+ taxable
48
+ availableForSale
49
+ inventoryQuantity
50
+ position
51
+ createdAt
52
+ updatedAt
53
+ selectedOptions {
54
+ name
55
+ value
56
+ }
57
+ media(first: 1) {
58
+ edges {
59
+ node {
60
+ ... on MediaImage {
61
+ image {
62
+ url
63
+ altText
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ inventoryItem {
70
+ id
71
+ tracked
72
+ requiresShipping
73
+ unitCost {
74
+ amount
75
+ currencyCode
76
+ }
77
+ measurement {
78
+ weight {
79
+ unit
80
+ value
81
+ }
82
+ }
83
+ }
84
+ metafields(first: 25) {
85
+ edges {
86
+ node {
87
+ namespace
88
+ key
89
+ value
90
+ type
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ pageInfo {
97
+ hasNextPage
98
+ endCursor
99
+ }
100
+ }
101
+ }
102
+ }
103
+ `;
104
+ const data = await shopifyClient.request(query, {
105
+ id: productId,
106
+ first: input.first ?? 50,
107
+ });
108
+ if (!data.product) {
109
+ throw new Error(`Product not found: ${productId}`);
110
+ }
111
+ const variants = edgesToNodes(data.product.variants).map((variant) => {
112
+ const mediaNodes = variant.media
113
+ ? edgesToNodes(variant.media)
114
+ : [];
115
+ const firstImage = mediaNodes.find((m) => m.image);
116
+ const image = firstImage?.image ?? null;
117
+ delete variant.media;
118
+ return {
119
+ ...variant,
120
+ image,
121
+ metafields: variant.metafields
122
+ ? edgesToNodes(variant.metafields)
123
+ : [],
124
+ };
125
+ });
126
+ return {
127
+ productId: data.product.id,
128
+ productTitle: data.product.title,
129
+ variantsCount: variants.length,
130
+ variants,
131
+ pageInfo: data.product.variants.pageInfo,
132
+ };
133
+ }
134
+ catch (error) {
135
+ handleToolError("fetch product variants", error);
136
+ }
137
+ },
138
+ };
139
+ export { getProductVariantsDetailed };