@anton.andrusenko/shopify-mcp-admin 0.3.0 → 0.4.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.
- package/dist/index.js +1250 -649
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2451,7 +2451,7 @@ function wrapToolHandler(toolName, schema, handler) {
|
|
|
2451
2451
|
};
|
|
2452
2452
|
}
|
|
2453
2453
|
function registerTool(definition, handler, options = {}) {
|
|
2454
|
-
const { name, title, description, inputSchema:
|
|
2454
|
+
const { name, title, description, inputSchema: inputSchema46, annotations } = definition;
|
|
2455
2455
|
try {
|
|
2456
2456
|
if (!options.skipNameValidation) {
|
|
2457
2457
|
validateToolName(name);
|
|
@@ -2459,8 +2459,8 @@ function registerTool(definition, handler, options = {}) {
|
|
|
2459
2459
|
if (registeredTools.has(name)) {
|
|
2460
2460
|
throw new Error(`Tool "${name}" is already registered. Tool names must be unique.`);
|
|
2461
2461
|
}
|
|
2462
|
-
const jsonSchema = convertZodToJsonSchema(
|
|
2463
|
-
const wrappedHandler = wrapToolHandler(name,
|
|
2462
|
+
const jsonSchema = convertZodToJsonSchema(inputSchema46);
|
|
2463
|
+
const wrappedHandler = wrapToolHandler(name, inputSchema46, handler);
|
|
2464
2464
|
const finalAnnotations = {
|
|
2465
2465
|
...deriveDefaultAnnotations(name),
|
|
2466
2466
|
...annotations,
|
|
@@ -2472,7 +2472,7 @@ function registerTool(definition, handler, options = {}) {
|
|
|
2472
2472
|
title,
|
|
2473
2473
|
description,
|
|
2474
2474
|
inputSchema: jsonSchema,
|
|
2475
|
-
zodSchema:
|
|
2475
|
+
zodSchema: inputSchema46,
|
|
2476
2476
|
handler: wrappedHandler,
|
|
2477
2477
|
annotations: finalAnnotations
|
|
2478
2478
|
};
|
|
@@ -3172,6 +3172,7 @@ var articleIdSchema = gidSchema("Article");
|
|
|
3172
3172
|
var redirectIdSchema = gidSchema("UrlRedirect");
|
|
3173
3173
|
var inventoryItemIdSchema = gidSchema("InventoryItem");
|
|
3174
3174
|
var locationIdSchema = gidSchema("Location");
|
|
3175
|
+
var marketIdSchema = gidSchema("Market");
|
|
3175
3176
|
|
|
3176
3177
|
// src/tools/add-product-image.ts
|
|
3177
3178
|
var inputSchema = z3.object({
|
|
@@ -4518,9 +4519,339 @@ function registerCreateCollectionTool() {
|
|
|
4518
4519
|
);
|
|
4519
4520
|
}
|
|
4520
4521
|
|
|
4521
|
-
// src/tools/create-
|
|
4522
|
+
// src/tools/create-market.ts
|
|
4522
4523
|
import { z as z8 } from "zod";
|
|
4523
4524
|
|
|
4525
|
+
// src/shopify/markets.ts
|
|
4526
|
+
var LIST_MARKETS_QUERY = `
|
|
4527
|
+
query Markets($first: Int!, $after: String) {
|
|
4528
|
+
markets(first: $first, after: $after) {
|
|
4529
|
+
nodes {
|
|
4530
|
+
id
|
|
4531
|
+
name
|
|
4532
|
+
handle
|
|
4533
|
+
enabled
|
|
4534
|
+
status
|
|
4535
|
+
type
|
|
4536
|
+
currencySettings {
|
|
4537
|
+
baseCurrency { currencyCode }
|
|
4538
|
+
localCurrencies
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
pageInfo {
|
|
4542
|
+
hasNextPage
|
|
4543
|
+
endCursor
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4547
|
+
`;
|
|
4548
|
+
var GET_MARKET_QUERY = `
|
|
4549
|
+
query Market($id: ID!) {
|
|
4550
|
+
market(id: $id) {
|
|
4551
|
+
id
|
|
4552
|
+
name
|
|
4553
|
+
handle
|
|
4554
|
+
enabled
|
|
4555
|
+
status
|
|
4556
|
+
type
|
|
4557
|
+
currencySettings {
|
|
4558
|
+
baseCurrency { currencyCode currencyName }
|
|
4559
|
+
localCurrencies
|
|
4560
|
+
}
|
|
4561
|
+
webPresences(first: 10) {
|
|
4562
|
+
nodes {
|
|
4563
|
+
id
|
|
4564
|
+
defaultLocale { locale name }
|
|
4565
|
+
alternateLocales { locale name }
|
|
4566
|
+
subfolderSuffix
|
|
4567
|
+
domain { host }
|
|
4568
|
+
rootUrls { locale url }
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
`;
|
|
4574
|
+
var MARKET_CREATE_MUTATION = `
|
|
4575
|
+
mutation MarketCreate($input: MarketCreateInput!) {
|
|
4576
|
+
marketCreate(input: $input) {
|
|
4577
|
+
market { id name handle enabled }
|
|
4578
|
+
userErrors { field message }
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
`;
|
|
4582
|
+
var MARKET_UPDATE_MUTATION = `
|
|
4583
|
+
mutation MarketUpdate($id: ID!, $input: MarketUpdateInput!) {
|
|
4584
|
+
marketUpdate(id: $id, input: $input) {
|
|
4585
|
+
market { id name handle enabled }
|
|
4586
|
+
userErrors { field message }
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
`;
|
|
4590
|
+
var MARKET_DELETE_MUTATION = `
|
|
4591
|
+
mutation MarketDelete($id: ID!) {
|
|
4592
|
+
marketDelete(id: $id) {
|
|
4593
|
+
deletedId
|
|
4594
|
+
userErrors { field message }
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
`;
|
|
4598
|
+
async function listMarkets(first = 50, after) {
|
|
4599
|
+
const client = await getShopifyClient();
|
|
4600
|
+
log.debug(`Listing markets: first=${first}, after=${after}`);
|
|
4601
|
+
const response = await withRateLimit(
|
|
4602
|
+
() => client.graphql.request(LIST_MARKETS_QUERY, {
|
|
4603
|
+
variables: { first, after }
|
|
4604
|
+
}),
|
|
4605
|
+
"list-markets"
|
|
4606
|
+
);
|
|
4607
|
+
if (response.errors && response.errors.length > 0) {
|
|
4608
|
+
const errorMessage = response.errors.map((e) => e.message).join(", ");
|
|
4609
|
+
throw new Error(`GraphQL error: ${errorMessage}`);
|
|
4610
|
+
}
|
|
4611
|
+
const marketsData = response.data?.markets;
|
|
4612
|
+
if (!marketsData) {
|
|
4613
|
+
throw new Error("No response data from markets query");
|
|
4614
|
+
}
|
|
4615
|
+
const markets = marketsData.nodes.map((node) => ({
|
|
4616
|
+
id: node.id,
|
|
4617
|
+
name: node.name,
|
|
4618
|
+
handle: node.handle,
|
|
4619
|
+
enabled: node.enabled,
|
|
4620
|
+
status: node.status,
|
|
4621
|
+
type: node.type,
|
|
4622
|
+
currencySettings: node.currencySettings ? {
|
|
4623
|
+
baseCurrency: {
|
|
4624
|
+
currencyCode: node.currencySettings.baseCurrency.currencyCode
|
|
4625
|
+
},
|
|
4626
|
+
localCurrencies: node.currencySettings.localCurrencies
|
|
4627
|
+
} : void 0
|
|
4628
|
+
}));
|
|
4629
|
+
log.debug(`Listed ${markets.length} markets`);
|
|
4630
|
+
return {
|
|
4631
|
+
markets,
|
|
4632
|
+
pageInfo: {
|
|
4633
|
+
hasNextPage: marketsData.pageInfo.hasNextPage,
|
|
4634
|
+
endCursor: marketsData.pageInfo.endCursor
|
|
4635
|
+
}
|
|
4636
|
+
};
|
|
4637
|
+
}
|
|
4638
|
+
async function getMarket(marketId) {
|
|
4639
|
+
const client = await getShopifyClient();
|
|
4640
|
+
log.debug(`Fetching market: ${marketId}`);
|
|
4641
|
+
const response = await withRateLimit(
|
|
4642
|
+
() => client.graphql.request(GET_MARKET_QUERY, {
|
|
4643
|
+
variables: { id: marketId }
|
|
4644
|
+
}),
|
|
4645
|
+
"get-market"
|
|
4646
|
+
);
|
|
4647
|
+
if (response.errors && response.errors.length > 0) {
|
|
4648
|
+
const errorMessage = response.errors.map((e) => e.message).join(", ");
|
|
4649
|
+
throw new Error(`GraphQL error: ${errorMessage}`);
|
|
4650
|
+
}
|
|
4651
|
+
const market = response.data?.market;
|
|
4652
|
+
if (!market) {
|
|
4653
|
+
log.debug(`Market not found: ${marketId}`);
|
|
4654
|
+
return null;
|
|
4655
|
+
}
|
|
4656
|
+
return {
|
|
4657
|
+
id: market.id,
|
|
4658
|
+
name: market.name,
|
|
4659
|
+
handle: market.handle,
|
|
4660
|
+
enabled: market.enabled,
|
|
4661
|
+
status: market.status,
|
|
4662
|
+
type: market.type,
|
|
4663
|
+
currencySettings: market.currencySettings ? {
|
|
4664
|
+
baseCurrency: {
|
|
4665
|
+
currencyCode: market.currencySettings.baseCurrency.currencyCode,
|
|
4666
|
+
currencyName: market.currencySettings.baseCurrency.currencyName
|
|
4667
|
+
},
|
|
4668
|
+
localCurrencies: market.currencySettings.localCurrencies
|
|
4669
|
+
} : void 0,
|
|
4670
|
+
webPresences: market.webPresences?.nodes.map((wp) => ({
|
|
4671
|
+
id: wp.id,
|
|
4672
|
+
defaultLocale: {
|
|
4673
|
+
locale: wp.defaultLocale.locale,
|
|
4674
|
+
name: wp.defaultLocale.name
|
|
4675
|
+
},
|
|
4676
|
+
alternateLocales: wp.alternateLocales?.map((al) => ({
|
|
4677
|
+
locale: al.locale,
|
|
4678
|
+
name: al.name
|
|
4679
|
+
})),
|
|
4680
|
+
subfolderSuffix: wp.subfolderSuffix ?? void 0,
|
|
4681
|
+
domain: wp.domain ? { host: wp.domain.host } : void 0,
|
|
4682
|
+
rootUrls: wp.rootUrls?.map((ru) => ({
|
|
4683
|
+
locale: ru.locale,
|
|
4684
|
+
url: ru.url
|
|
4685
|
+
}))
|
|
4686
|
+
}))
|
|
4687
|
+
};
|
|
4688
|
+
}
|
|
4689
|
+
async function createMarket(input) {
|
|
4690
|
+
const client = await getShopifyClient();
|
|
4691
|
+
log.debug(`Creating market: ${input.name}`);
|
|
4692
|
+
const graphqlInput = {
|
|
4693
|
+
name: input.name
|
|
4694
|
+
};
|
|
4695
|
+
if (input.handle !== void 0) {
|
|
4696
|
+
graphqlInput.handle = input.handle;
|
|
4697
|
+
}
|
|
4698
|
+
if (input.regions !== void 0) {
|
|
4699
|
+
graphqlInput.regions = input.regions;
|
|
4700
|
+
}
|
|
4701
|
+
if (input.enabled !== void 0) {
|
|
4702
|
+
graphqlInput.enabled = input.enabled;
|
|
4703
|
+
}
|
|
4704
|
+
const response = await withRateLimit(
|
|
4705
|
+
() => client.graphql.request(MARKET_CREATE_MUTATION, {
|
|
4706
|
+
variables: { input: graphqlInput }
|
|
4707
|
+
}),
|
|
4708
|
+
"create-market"
|
|
4709
|
+
);
|
|
4710
|
+
if (response.errors && response.errors.length > 0) {
|
|
4711
|
+
const errorMessage = response.errors.map((e) => e.message).join(", ");
|
|
4712
|
+
throw new Error(`GraphQL error: ${errorMessage}`);
|
|
4713
|
+
}
|
|
4714
|
+
const result = response.data?.marketCreate;
|
|
4715
|
+
if (!result) {
|
|
4716
|
+
throw new Error("No response data from marketCreate mutation");
|
|
4717
|
+
}
|
|
4718
|
+
if (result.userErrors && result.userErrors.length > 0) {
|
|
4719
|
+
throw new ShopifyUserErrorException(result.userErrors);
|
|
4720
|
+
}
|
|
4721
|
+
if (!result.market) {
|
|
4722
|
+
throw new Error("Market creation succeeded but no market was returned");
|
|
4723
|
+
}
|
|
4724
|
+
log.debug(`Created market: ${result.market.id}`);
|
|
4725
|
+
return result.market;
|
|
4726
|
+
}
|
|
4727
|
+
async function updateMarket(marketId, input) {
|
|
4728
|
+
const client = await getShopifyClient();
|
|
4729
|
+
log.debug(`Updating market: ${marketId}`);
|
|
4730
|
+
const graphqlInput = {};
|
|
4731
|
+
if (input.name !== void 0) {
|
|
4732
|
+
graphqlInput.name = input.name;
|
|
4733
|
+
}
|
|
4734
|
+
if (input.handle !== void 0) {
|
|
4735
|
+
graphqlInput.handle = input.handle;
|
|
4736
|
+
}
|
|
4737
|
+
if (input.enabled !== void 0) {
|
|
4738
|
+
graphqlInput.enabled = input.enabled;
|
|
4739
|
+
}
|
|
4740
|
+
const response = await withRateLimit(
|
|
4741
|
+
() => client.graphql.request(MARKET_UPDATE_MUTATION, {
|
|
4742
|
+
variables: { id: marketId, input: graphqlInput }
|
|
4743
|
+
}),
|
|
4744
|
+
"update-market"
|
|
4745
|
+
);
|
|
4746
|
+
if (response.errors && response.errors.length > 0) {
|
|
4747
|
+
const errorMessage = response.errors.map((e) => e.message).join(", ");
|
|
4748
|
+
throw new Error(`GraphQL error: ${errorMessage}`);
|
|
4749
|
+
}
|
|
4750
|
+
const result = response.data?.marketUpdate;
|
|
4751
|
+
if (!result) {
|
|
4752
|
+
throw new Error("No response data from marketUpdate mutation");
|
|
4753
|
+
}
|
|
4754
|
+
if (result.userErrors && result.userErrors.length > 0) {
|
|
4755
|
+
throw new ShopifyUserErrorException(result.userErrors);
|
|
4756
|
+
}
|
|
4757
|
+
if (!result.market) {
|
|
4758
|
+
throw new Error("Market update succeeded but no market was returned");
|
|
4759
|
+
}
|
|
4760
|
+
log.debug(`Updated market: ${result.market.id}`);
|
|
4761
|
+
return result.market;
|
|
4762
|
+
}
|
|
4763
|
+
async function deleteMarket(marketId) {
|
|
4764
|
+
const client = await getShopifyClient();
|
|
4765
|
+
log.debug(`Deleting market: ${marketId}`);
|
|
4766
|
+
const response = await withRateLimit(
|
|
4767
|
+
() => client.graphql.request(MARKET_DELETE_MUTATION, {
|
|
4768
|
+
variables: { id: marketId }
|
|
4769
|
+
}),
|
|
4770
|
+
"delete-market"
|
|
4771
|
+
);
|
|
4772
|
+
if (response.errors && response.errors.length > 0) {
|
|
4773
|
+
const errorMessage = response.errors.map((e) => e.message).join(", ");
|
|
4774
|
+
throw new Error(`GraphQL error: ${errorMessage}`);
|
|
4775
|
+
}
|
|
4776
|
+
const result = response.data?.marketDelete;
|
|
4777
|
+
if (!result) {
|
|
4778
|
+
throw new Error("No response data from marketDelete mutation");
|
|
4779
|
+
}
|
|
4780
|
+
if (result.userErrors && result.userErrors.length > 0) {
|
|
4781
|
+
throw new ShopifyUserErrorException(result.userErrors);
|
|
4782
|
+
}
|
|
4783
|
+
if (!result.deletedId) {
|
|
4784
|
+
throw new Error("Market deletion succeeded but no deletedId was returned");
|
|
4785
|
+
}
|
|
4786
|
+
log.debug(`Deleted market: ${result.deletedId}`);
|
|
4787
|
+
return result.deletedId;
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
// src/tools/create-market.ts
|
|
4791
|
+
var inputSchema6 = z8.object({
|
|
4792
|
+
name: z8.string().min(1).describe('Market name (required). Not shown to customers. Example: "Canada", "Europe"'),
|
|
4793
|
+
handle: z8.string().optional().describe(
|
|
4794
|
+
'URL handle/slug for the market. Auto-generated from name if not provided. Example: "ca" for Canada, "eu" for Europe'
|
|
4795
|
+
),
|
|
4796
|
+
countryCodes: z8.array(z8.string().length(2)).optional().describe(
|
|
4797
|
+
'Array of ISO 3166-1 alpha-2 country codes to include in this market. Example: ["CA"] for Canada, ["FR", "DE", "IT"] for multiple European countries'
|
|
4798
|
+
),
|
|
4799
|
+
enabled: z8.boolean().optional().default(true).describe("Whether the market should be enabled. Default: true")
|
|
4800
|
+
});
|
|
4801
|
+
var outputSchema6 = z8.object({
|
|
4802
|
+
id: z8.string().describe("Created market GID"),
|
|
4803
|
+
name: z8.string().describe("Market name"),
|
|
4804
|
+
handle: z8.string().describe("URL handle"),
|
|
4805
|
+
enabled: z8.boolean().describe("Whether the market is enabled")
|
|
4806
|
+
});
|
|
4807
|
+
var handleCreateMarket = async (context, params) => {
|
|
4808
|
+
log.debug(`Creating market "${params.name}" on shop: ${context.shopDomain}`);
|
|
4809
|
+
const input = {
|
|
4810
|
+
name: params.name
|
|
4811
|
+
};
|
|
4812
|
+
if (params.handle !== void 0) {
|
|
4813
|
+
input.handle = params.handle;
|
|
4814
|
+
}
|
|
4815
|
+
if (params.countryCodes !== void 0 && params.countryCodes.length > 0) {
|
|
4816
|
+
input.regions = { countryCodes: params.countryCodes };
|
|
4817
|
+
}
|
|
4818
|
+
if (params.enabled !== void 0) {
|
|
4819
|
+
input.enabled = params.enabled;
|
|
4820
|
+
}
|
|
4821
|
+
const market = await createMarket(input);
|
|
4822
|
+
log.debug(`Created market: ${market.id}`);
|
|
4823
|
+
return market;
|
|
4824
|
+
};
|
|
4825
|
+
function registerCreateMarketTool() {
|
|
4826
|
+
registerContextAwareTool(
|
|
4827
|
+
{
|
|
4828
|
+
name: "create-market",
|
|
4829
|
+
title: "Create Market",
|
|
4830
|
+
description: "Create a new market for regional targeting. Markets group one or more regions (countries) for localized shopping experiences. Provide a name (required) and optionally: handle, country codes, and enabled status. **Typical workflow:** create-market \u2192 create-web-presence (configure SEO URLs) \u2192 enable-shop-locale (add languages). **Prerequisites:** None. Store must have Markets feature enabled on their plan. **Follow-ups:** get-market, create-web-presence, update-market.",
|
|
4831
|
+
inputSchema: inputSchema6,
|
|
4832
|
+
outputSchema: outputSchema6,
|
|
4833
|
+
// AI Agent Optimization
|
|
4834
|
+
category: "market",
|
|
4835
|
+
relationships: {
|
|
4836
|
+
relatedTools: ["list-markets", "get-market"],
|
|
4837
|
+
followUps: ["get-market", "update-market"]
|
|
4838
|
+
},
|
|
4839
|
+
// MCP Tool Annotations (Epic 9.5 - MCP Best Practices)
|
|
4840
|
+
annotations: {
|
|
4841
|
+
readOnlyHint: false,
|
|
4842
|
+
destructiveHint: false,
|
|
4843
|
+
idempotentHint: false,
|
|
4844
|
+
// Creating markets is not idempotent
|
|
4845
|
+
openWorldHint: true
|
|
4846
|
+
}
|
|
4847
|
+
},
|
|
4848
|
+
handleCreateMarket
|
|
4849
|
+
);
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
// src/tools/create-page.ts
|
|
4853
|
+
import { z as z9 } from "zod";
|
|
4854
|
+
|
|
4524
4855
|
// src/shopify/pages.ts
|
|
4525
4856
|
var PAGE_QUERY = `
|
|
4526
4857
|
query GetPage($id: ID!) {
|
|
@@ -4801,28 +5132,28 @@ async function deletePage(pageId) {
|
|
|
4801
5132
|
}
|
|
4802
5133
|
|
|
4803
5134
|
// src/tools/create-page.ts
|
|
4804
|
-
var
|
|
4805
|
-
title:
|
|
5135
|
+
var inputSchema7 = z9.object({
|
|
5136
|
+
title: z9.string().min(1).describe(
|
|
4806
5137
|
"The title of the page (required). This will be displayed as the page heading. Example: 'About Us', 'Contact', 'Privacy Policy'."
|
|
4807
5138
|
),
|
|
4808
|
-
body:
|
|
5139
|
+
body: z9.string().optional().describe(
|
|
4809
5140
|
"The HTML body content of the page. Supports HTML markup for formatting. Example: '<h1>About Our Company</h1><p>We are a great company.</p>'"
|
|
4810
5141
|
),
|
|
4811
|
-
handle:
|
|
5142
|
+
handle: z9.string().optional().describe(
|
|
4812
5143
|
"The URL handle/slug for the page. If not provided, it will be auto-generated from the title. Example: 'about-us' would create URL /pages/about-us."
|
|
4813
5144
|
),
|
|
4814
|
-
isPublished:
|
|
5145
|
+
isPublished: z9.boolean().optional().describe(
|
|
4815
5146
|
"Whether the page should be visible on the storefront. Defaults to false (unpublished). Set to true to make the page immediately visible."
|
|
4816
5147
|
),
|
|
4817
|
-
templateSuffix:
|
|
5148
|
+
templateSuffix: z9.string().optional().describe(
|
|
4818
5149
|
"The suffix of the Liquid template used to render the page. For example, 'contact' would use the template 'page.contact.liquid'."
|
|
4819
5150
|
)
|
|
4820
5151
|
});
|
|
4821
|
-
var
|
|
4822
|
-
id:
|
|
4823
|
-
title:
|
|
4824
|
-
handle:
|
|
4825
|
-
isPublished:
|
|
5152
|
+
var outputSchema7 = z9.object({
|
|
5153
|
+
id: z9.string().describe('Created page GID (e.g., "gid://shopify/Page/123")'),
|
|
5154
|
+
title: z9.string().describe("Page title"),
|
|
5155
|
+
handle: z9.string().describe("URL handle/slug"),
|
|
5156
|
+
isPublished: z9.boolean().describe("Whether page is visible on storefront")
|
|
4826
5157
|
});
|
|
4827
5158
|
var handleCreatePage = async (context, params) => {
|
|
4828
5159
|
log.debug(`Creating page on shop: ${context.shopDomain}`);
|
|
@@ -4859,8 +5190,8 @@ function registerCreatePageTool() {
|
|
|
4859
5190
|
name: "create-page",
|
|
4860
5191
|
title: "Create Page",
|
|
4861
5192
|
description: "Create a new online store page. Pages are static content like 'About Us', 'Contact', 'FAQ', or policy pages. Provide a title (required) and optional body content (HTML supported), handle (URL slug), and publish status. New pages are unpublished by default. Useful for: creating informational pages, legal pages, landing pages. **Typical workflow:** create-page \u2192 update-page (to publish). **Prerequisites:** None. **Follow-ups:** get-page, update-page. Returns created page ID, title, handle, and publish status.",
|
|
4862
|
-
inputSchema:
|
|
4863
|
-
outputSchema:
|
|
5193
|
+
inputSchema: inputSchema7,
|
|
5194
|
+
outputSchema: outputSchema7,
|
|
4864
5195
|
category: "content",
|
|
4865
5196
|
relationships: {
|
|
4866
5197
|
relatedTools: ["list-pages", "get-page", "update-page"],
|
|
@@ -4880,78 +5211,78 @@ function registerCreatePageTool() {
|
|
|
4880
5211
|
}
|
|
4881
5212
|
|
|
4882
5213
|
// src/tools/create-product.ts
|
|
4883
|
-
import { z as
|
|
4884
|
-
var
|
|
5214
|
+
import { z as z10 } from "zod";
|
|
5215
|
+
var inputSchema8 = z10.object({
|
|
4885
5216
|
// Required field
|
|
4886
|
-
title:
|
|
5217
|
+
title: z10.string().min(1, "title is required").describe('Product title (required). Example: "Premium Cotton T-Shirt"'),
|
|
4887
5218
|
// Optional core fields
|
|
4888
|
-
description:
|
|
4889
|
-
vendor:
|
|
4890
|
-
productType:
|
|
4891
|
-
tags:
|
|
4892
|
-
status:
|
|
5219
|
+
description: z10.string().optional().describe('Product description (HTML supported). Example: "<p>Soft cotton t-shirt.</p>"'),
|
|
5220
|
+
vendor: z10.string().optional().describe('Product vendor/brand name. Example: "Acme Corp"'),
|
|
5221
|
+
productType: z10.string().optional().describe('Product type for categorization. Example: "T-Shirts"'),
|
|
5222
|
+
tags: z10.array(z10.string()).optional().describe('Tags for search and filtering. Example: ["summer", "cotton", "casual"]'),
|
|
5223
|
+
status: z10.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).optional().default("DRAFT").describe(
|
|
4893
5224
|
"Product status: ACTIVE (visible), DRAFT (hidden), ARCHIVED (hidden). Default: DRAFT"
|
|
4894
5225
|
),
|
|
4895
5226
|
// SEO metadata
|
|
4896
|
-
seo:
|
|
4897
|
-
title:
|
|
4898
|
-
description:
|
|
5227
|
+
seo: z10.object({
|
|
5228
|
+
title: z10.string().optional().describe("SEO title for search engine results"),
|
|
5229
|
+
description: z10.string().optional().describe("SEO meta description for search engines")
|
|
4899
5230
|
}).optional().describe(
|
|
4900
5231
|
"SEO metadata for search engine optimization. If not provided, Shopify uses product title/description."
|
|
4901
5232
|
),
|
|
4902
5233
|
// Variants
|
|
4903
|
-
variants:
|
|
4904
|
-
|
|
4905
|
-
price:
|
|
4906
|
-
compareAtPrice:
|
|
4907
|
-
sku:
|
|
4908
|
-
barcode:
|
|
4909
|
-
inventoryQuantity:
|
|
4910
|
-
options:
|
|
5234
|
+
variants: z10.array(
|
|
5235
|
+
z10.object({
|
|
5236
|
+
price: z10.string().describe('Variant price as decimal string. Example: "29.99"'),
|
|
5237
|
+
compareAtPrice: z10.string().optional().describe('Original price for sale display. Example: "39.99"'),
|
|
5238
|
+
sku: z10.string().optional().describe('Stock keeping unit. Example: "SHIRT-001-RED-M"'),
|
|
5239
|
+
barcode: z10.string().optional().describe("Barcode (UPC, EAN, etc.)"),
|
|
5240
|
+
inventoryQuantity: z10.number().int().min(0).optional().describe("Initial inventory quantity (note: may require separate inventory API)"),
|
|
5241
|
+
options: z10.array(z10.string()).optional().describe('Variant options. Example: ["Red", "Medium"]')
|
|
4911
5242
|
})
|
|
4912
5243
|
).optional().describe("Product variants. If not provided, a default variant is created."),
|
|
4913
5244
|
// Images
|
|
4914
|
-
images:
|
|
4915
|
-
|
|
4916
|
-
url:
|
|
4917
|
-
altText:
|
|
5245
|
+
images: z10.array(
|
|
5246
|
+
z10.object({
|
|
5247
|
+
url: z10.string().url("Invalid image URL format").describe("Publicly accessible image URL"),
|
|
5248
|
+
altText: z10.string().optional().describe("Alt text for accessibility")
|
|
4918
5249
|
})
|
|
4919
5250
|
).optional().describe("Product images. Shopify fetches images from URLs.")
|
|
4920
5251
|
});
|
|
4921
|
-
var
|
|
4922
|
-
id:
|
|
4923
|
-
title:
|
|
4924
|
-
handle:
|
|
4925
|
-
description:
|
|
4926
|
-
vendor:
|
|
4927
|
-
productType:
|
|
4928
|
-
status:
|
|
4929
|
-
tags:
|
|
4930
|
-
seo:
|
|
4931
|
-
title:
|
|
4932
|
-
description:
|
|
5252
|
+
var outputSchema8 = z10.object({
|
|
5253
|
+
id: z10.string().describe('Product GID (e.g., "gid://shopify/Product/123")'),
|
|
5254
|
+
title: z10.string().describe("Product title"),
|
|
5255
|
+
handle: z10.string().describe("URL handle/slug"),
|
|
5256
|
+
description: z10.string().nullable().describe("Product description (HTML)"),
|
|
5257
|
+
vendor: z10.string().describe("Vendor/brand name"),
|
|
5258
|
+
productType: z10.string().describe("Product type"),
|
|
5259
|
+
status: z10.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).describe("Product status"),
|
|
5260
|
+
tags: z10.array(z10.string()).describe("Product tags"),
|
|
5261
|
+
seo: z10.object({
|
|
5262
|
+
title: z10.string().nullable().describe("SEO title for search engines"),
|
|
5263
|
+
description: z10.string().nullable().describe("SEO description/meta description")
|
|
4933
5264
|
}).describe("SEO metadata for search engine optimization"),
|
|
4934
|
-
createdAt:
|
|
4935
|
-
updatedAt:
|
|
4936
|
-
variants:
|
|
4937
|
-
|
|
4938
|
-
id:
|
|
4939
|
-
title:
|
|
4940
|
-
price:
|
|
4941
|
-
compareAtPrice:
|
|
4942
|
-
sku:
|
|
4943
|
-
barcode:
|
|
4944
|
-
inventoryQuantity:
|
|
5265
|
+
createdAt: z10.string().describe("Creation timestamp (ISO 8601)"),
|
|
5266
|
+
updatedAt: z10.string().describe("Last update timestamp (ISO 8601)"),
|
|
5267
|
+
variants: z10.array(
|
|
5268
|
+
z10.object({
|
|
5269
|
+
id: z10.string().describe("Variant GID"),
|
|
5270
|
+
title: z10.string().describe("Variant title"),
|
|
5271
|
+
price: z10.string().describe("Price"),
|
|
5272
|
+
compareAtPrice: z10.string().nullable().describe("Compare at price"),
|
|
5273
|
+
sku: z10.string().nullable().describe("SKU"),
|
|
5274
|
+
barcode: z10.string().nullable().describe("Barcode"),
|
|
5275
|
+
inventoryQuantity: z10.number().nullable().describe("Inventory quantity")
|
|
4945
5276
|
})
|
|
4946
5277
|
).describe("Product variants"),
|
|
4947
|
-
images:
|
|
4948
|
-
|
|
4949
|
-
id:
|
|
4950
|
-
url:
|
|
4951
|
-
altText:
|
|
5278
|
+
images: z10.array(
|
|
5279
|
+
z10.object({
|
|
5280
|
+
id: z10.string().describe("Image GID"),
|
|
5281
|
+
url: z10.string().describe("Image URL"),
|
|
5282
|
+
altText: z10.string().nullable().describe("Alt text")
|
|
4952
5283
|
})
|
|
4953
5284
|
).describe("Product images"),
|
|
4954
|
-
totalInventory:
|
|
5285
|
+
totalInventory: z10.number().describe("Total inventory across variants")
|
|
4955
5286
|
});
|
|
4956
5287
|
var handleCreateProduct = async (context, params) => {
|
|
4957
5288
|
log.debug(`Creating product on shop: ${context.shopDomain}`);
|
|
@@ -4986,8 +5317,8 @@ function registerCreateProductTool() {
|
|
|
4986
5317
|
name: "create-product",
|
|
4987
5318
|
title: "Create Product",
|
|
4988
5319
|
description: "Create a new product in the Shopify store. Supports setting title, description, vendor, type, tags, status, and SEO metadata. Optionally include variants with pricing/SKU and images with URLs. SEO (seo.title, seo.description) is optional - defaults to product title/description if not set. Returns the created product with ID, handle, SEO, variants, and images. Status defaults to DRAFT if not specified. **Typical workflow:** create-product \u2192 add-product-image \u2192 set-product-metafields \u2192 add-products-to-collection. **Prerequisites:** None. **Follow-ups:** add-product-image, set-product-metafields, add-products-to-collection.",
|
|
4989
|
-
inputSchema:
|
|
4990
|
-
outputSchema:
|
|
5320
|
+
inputSchema: inputSchema8,
|
|
5321
|
+
outputSchema: outputSchema8,
|
|
4991
5322
|
// AI Agent Optimization (Story 5.5)
|
|
4992
5323
|
category: "product",
|
|
4993
5324
|
relationships: {
|
|
@@ -5009,7 +5340,7 @@ function registerCreateProductTool() {
|
|
|
5009
5340
|
}
|
|
5010
5341
|
|
|
5011
5342
|
// src/tools/create-redirect.ts
|
|
5012
|
-
import { z as
|
|
5343
|
+
import { z as z11 } from "zod";
|
|
5013
5344
|
|
|
5014
5345
|
// src/shopify/redirects.ts
|
|
5015
5346
|
var URL_REDIRECT_CREATE_MUTATION = `
|
|
@@ -5157,20 +5488,20 @@ async function deleteRedirect(redirectId) {
|
|
|
5157
5488
|
}
|
|
5158
5489
|
|
|
5159
5490
|
// src/tools/create-redirect.ts
|
|
5160
|
-
var
|
|
5161
|
-
path:
|
|
5491
|
+
var inputSchema9 = z11.object({
|
|
5492
|
+
path: z11.string().min(1).refine((val) => val.startsWith("/"), {
|
|
5162
5493
|
message: "Path must start with '/' (e.g., '/old-product-url')"
|
|
5163
5494
|
}).describe(
|
|
5164
5495
|
"The source path to redirect FROM. Must start with '/'. Example: '/old-product-url' or '/collections/old-collection'."
|
|
5165
5496
|
),
|
|
5166
|
-
target:
|
|
5497
|
+
target: z11.string().min(1).describe(
|
|
5167
5498
|
"The destination URL to redirect TO. Can be relative ('/new-product-url') or absolute ('https://example.com/page')."
|
|
5168
5499
|
)
|
|
5169
5500
|
});
|
|
5170
|
-
var
|
|
5171
|
-
id:
|
|
5172
|
-
path:
|
|
5173
|
-
target:
|
|
5501
|
+
var outputSchema9 = z11.object({
|
|
5502
|
+
id: z11.string().describe('Created redirect GID (e.g., "gid://shopify/UrlRedirect/123")'),
|
|
5503
|
+
path: z11.string().describe("Source path that will redirect"),
|
|
5504
|
+
target: z11.string().describe("Target URL visitors will be redirected to")
|
|
5174
5505
|
});
|
|
5175
5506
|
var handleCreateRedirect = async (context, params) => {
|
|
5176
5507
|
log.debug(`Creating redirect on shop: ${context.shopDomain}`);
|
|
@@ -5204,8 +5535,8 @@ function registerCreateRedirectTool() {
|
|
|
5204
5535
|
name: "create-redirect",
|
|
5205
5536
|
title: "Create URL Redirect",
|
|
5206
5537
|
description: "Create a URL redirect to preserve SEO value when URLs change. Redirects automatically forward visitors and search engines from an old path to a new target URL. Path must start with '/'. Useful for: product URL changes, collection restructuring, page migrations, fixing broken links. **Prerequisites:** None. **Follow-ups:** list-redirects to verify creation.",
|
|
5207
|
-
inputSchema:
|
|
5208
|
-
outputSchema:
|
|
5538
|
+
inputSchema: inputSchema9,
|
|
5539
|
+
outputSchema: outputSchema9,
|
|
5209
5540
|
// AI Agent Optimization (Story 5.5)
|
|
5210
5541
|
category: "seo",
|
|
5211
5542
|
relationships: {
|
|
@@ -5226,15 +5557,15 @@ function registerCreateRedirectTool() {
|
|
|
5226
5557
|
}
|
|
5227
5558
|
|
|
5228
5559
|
// src/tools/delete-article.ts
|
|
5229
|
-
import { z as
|
|
5230
|
-
var
|
|
5560
|
+
import { z as z12 } from "zod";
|
|
5561
|
+
var inputSchema10 = z12.object({
|
|
5231
5562
|
id: articleIdSchema.describe(
|
|
5232
5563
|
'The article ID to delete (required). Must be a valid Shopify GID format. Example: "gid://shopify/Article/12345". Use list-articles to find article IDs. This action cannot be undone - consider using update-article to unpublish instead.'
|
|
5233
5564
|
)
|
|
5234
5565
|
});
|
|
5235
|
-
var
|
|
5236
|
-
success:
|
|
5237
|
-
deletedArticleId:
|
|
5566
|
+
var outputSchema10 = z12.object({
|
|
5567
|
+
success: z12.boolean().describe("Whether the deletion was successful"),
|
|
5568
|
+
deletedArticleId: z12.string().describe("The ID of the deleted article")
|
|
5238
5569
|
});
|
|
5239
5570
|
var handleDeleteArticle = async (context, params) => {
|
|
5240
5571
|
log.debug(`Deleting article on shop: ${context.shopDomain}`);
|
|
@@ -5268,8 +5599,8 @@ function registerDeleteArticleTool() {
|
|
|
5268
5599
|
name: "delete-article",
|
|
5269
5600
|
title: "Delete Article",
|
|
5270
5601
|
description: "Permanently delete an article by ID. This action cannot be undone. The article will no longer be accessible on the storefront. Use list-articles to find the article ID first. Consider unpublishing instead of deleting if you may need the content later. **Typical workflow:** list-articles \u2192 delete-article. **Prerequisites:** Article ID. **Follow-ups:** None. Returns success confirmation and deleted article ID.",
|
|
5271
|
-
inputSchema:
|
|
5272
|
-
outputSchema:
|
|
5602
|
+
inputSchema: inputSchema10,
|
|
5603
|
+
outputSchema: outputSchema10,
|
|
5273
5604
|
category: "content",
|
|
5274
5605
|
relationships: {
|
|
5275
5606
|
relatedTools: ["list-articles", "update-article"],
|
|
@@ -5290,15 +5621,15 @@ function registerDeleteArticleTool() {
|
|
|
5290
5621
|
}
|
|
5291
5622
|
|
|
5292
5623
|
// src/tools/delete-blog.ts
|
|
5293
|
-
import { z as
|
|
5294
|
-
var
|
|
5624
|
+
import { z as z13 } from "zod";
|
|
5625
|
+
var inputSchema11 = z13.object({
|
|
5295
5626
|
id: blogIdSchema.describe(
|
|
5296
5627
|
'The blog ID to delete (required). Must be a valid Shopify GID format. Example: "gid://shopify/Blog/12345". Use list-blogs to find blog IDs. WARNING: Deleting a blog also deletes ALL articles within it.'
|
|
5297
5628
|
)
|
|
5298
5629
|
});
|
|
5299
|
-
var
|
|
5300
|
-
success:
|
|
5301
|
-
deletedBlogId:
|
|
5630
|
+
var outputSchema11 = z13.object({
|
|
5631
|
+
success: z13.boolean().describe("Whether the deletion was successful"),
|
|
5632
|
+
deletedBlogId: z13.string().describe("The ID of the deleted blog")
|
|
5302
5633
|
});
|
|
5303
5634
|
var handleDeleteBlog = async (context, params) => {
|
|
5304
5635
|
log.debug(`Deleting blog on shop: ${context.shopDomain}`);
|
|
@@ -5332,8 +5663,8 @@ function registerDeleteBlogTool() {
|
|
|
5332
5663
|
name: "delete-blog",
|
|
5333
5664
|
title: "Delete Blog",
|
|
5334
5665
|
description: "Permanently delete a blog by ID. This will also delete ALL articles within the blog. This action cannot be undone. Use list-blogs to find the blog ID first. Consider archiving articles before deletion if content may be needed later. **Typical workflow:** list-blogs \u2192 list-articles \u2192 delete-blog. **Prerequisites:** Blog ID. **Follow-ups:** None. Returns success confirmation and deleted blog ID.",
|
|
5335
|
-
inputSchema:
|
|
5336
|
-
outputSchema:
|
|
5666
|
+
inputSchema: inputSchema11,
|
|
5667
|
+
outputSchema: outputSchema11,
|
|
5337
5668
|
category: "content",
|
|
5338
5669
|
relationships: {
|
|
5339
5670
|
relatedTools: ["list-blogs", "list-articles"],
|
|
@@ -5353,14 +5684,14 @@ function registerDeleteBlogTool() {
|
|
|
5353
5684
|
}
|
|
5354
5685
|
|
|
5355
5686
|
// src/tools/delete-collection.ts
|
|
5356
|
-
import { z as
|
|
5357
|
-
var
|
|
5687
|
+
import { z as z14 } from "zod";
|
|
5688
|
+
var inputSchema12 = z14.object({
|
|
5358
5689
|
collectionId: collectionIdSchema.describe(
|
|
5359
5690
|
'Collection ID to delete (GID format, e.g., "gid://shopify/Collection/123"). Use list-collections or get-collection to find collection IDs.'
|
|
5360
5691
|
)
|
|
5361
5692
|
});
|
|
5362
|
-
var
|
|
5363
|
-
deletedCollectionId:
|
|
5693
|
+
var outputSchema12 = z14.object({
|
|
5694
|
+
deletedCollectionId: z14.string().describe("The GID of the deleted collection")
|
|
5364
5695
|
});
|
|
5365
5696
|
var handleDeleteCollection = async (context, params) => {
|
|
5366
5697
|
log.debug(`Deleting collection on shop: ${context.shopDomain}`);
|
|
@@ -5390,8 +5721,8 @@ function registerDeleteCollectionTool() {
|
|
|
5390
5721
|
name: "delete-collection",
|
|
5391
5722
|
title: "Delete Collection",
|
|
5392
5723
|
description: "Permanently delete a collection from the store. This removes the collection but does NOT delete the products within it - they remain in the catalog. **Warning:** This action cannot be undone. **Prerequisites:** get-collection to verify the correct collection before deleting.",
|
|
5393
|
-
inputSchema:
|
|
5394
|
-
outputSchema:
|
|
5724
|
+
inputSchema: inputSchema12,
|
|
5725
|
+
outputSchema: outputSchema12,
|
|
5395
5726
|
// AI Agent Optimization (Story 5.5)
|
|
5396
5727
|
category: "collection",
|
|
5397
5728
|
relationships: {
|
|
@@ -5412,16 +5743,66 @@ function registerDeleteCollectionTool() {
|
|
|
5412
5743
|
);
|
|
5413
5744
|
}
|
|
5414
5745
|
|
|
5746
|
+
// src/tools/delete-market.ts
|
|
5747
|
+
import { z as z15 } from "zod";
|
|
5748
|
+
var inputSchema13 = z15.object({
|
|
5749
|
+
id: marketIdSchema.describe(
|
|
5750
|
+
'Shopify Market GID to delete (e.g., "gid://shopify/Market/123"). Use list-markets or get-market to find market IDs. WARNING: This action cannot be undone.'
|
|
5751
|
+
)
|
|
5752
|
+
});
|
|
5753
|
+
var outputSchema13 = z15.object({
|
|
5754
|
+
deletedId: z15.string().describe("Deleted market GID"),
|
|
5755
|
+
success: z15.boolean().describe("Whether the deletion was successful"),
|
|
5756
|
+
message: z15.string().describe("Confirmation message")
|
|
5757
|
+
});
|
|
5758
|
+
var handleDeleteMarket = async (context, params) => {
|
|
5759
|
+
log.debug(`Deleting market ${params.id} on shop: ${context.shopDomain}`);
|
|
5760
|
+
const deletedId = await deleteMarket(params.id);
|
|
5761
|
+
log.debug(`Deleted market: ${deletedId}`);
|
|
5762
|
+
return {
|
|
5763
|
+
deletedId,
|
|
5764
|
+
success: true,
|
|
5765
|
+
message: `Market ${deletedId} has been permanently deleted. All associated web presences, currency settings, and region configurations have been removed.`
|
|
5766
|
+
};
|
|
5767
|
+
};
|
|
5768
|
+
function registerDeleteMarketTool() {
|
|
5769
|
+
registerContextAwareTool(
|
|
5770
|
+
{
|
|
5771
|
+
name: "delete-market",
|
|
5772
|
+
title: "Delete Market",
|
|
5773
|
+
description: "Permanently delete a market from the store. **WARNING:** This action cannot be undone. Deleting a market removes all its configurations including web presences, currency settings, and region assignments. Products assigned to this market will no longer be available in those regions. **Prerequisites:** get-market to verify the correct market before deleting. **Note:** The primary market cannot be deleted.",
|
|
5774
|
+
inputSchema: inputSchema13,
|
|
5775
|
+
outputSchema: outputSchema13,
|
|
5776
|
+
// AI Agent Optimization
|
|
5777
|
+
category: "market",
|
|
5778
|
+
relationships: {
|
|
5779
|
+
relatedTools: ["get-market", "list-markets"],
|
|
5780
|
+
followUps: ["list-markets"]
|
|
5781
|
+
},
|
|
5782
|
+
// MCP Tool Annotations (Epic 9.5 - MCP Best Practices)
|
|
5783
|
+
annotations: {
|
|
5784
|
+
readOnlyHint: false,
|
|
5785
|
+
destructiveHint: true,
|
|
5786
|
+
// This is a destructive operation
|
|
5787
|
+
idempotentHint: false,
|
|
5788
|
+
// Deleting twice will fail the second time
|
|
5789
|
+
openWorldHint: true
|
|
5790
|
+
}
|
|
5791
|
+
},
|
|
5792
|
+
handleDeleteMarket
|
|
5793
|
+
);
|
|
5794
|
+
}
|
|
5795
|
+
|
|
5415
5796
|
// src/tools/delete-page.ts
|
|
5416
|
-
import { z as
|
|
5417
|
-
var
|
|
5797
|
+
import { z as z16 } from "zod";
|
|
5798
|
+
var inputSchema14 = z16.object({
|
|
5418
5799
|
id: pageIdSchema.describe(
|
|
5419
5800
|
'The page ID to delete (required). Must be a valid Shopify GID format. Example: "gid://shopify/Page/123456789". Use list-pages to find page IDs. WARNING: This action is permanent and cannot be undone.'
|
|
5420
5801
|
)
|
|
5421
5802
|
});
|
|
5422
|
-
var
|
|
5423
|
-
success:
|
|
5424
|
-
deletedPageId:
|
|
5803
|
+
var outputSchema14 = z16.object({
|
|
5804
|
+
success: z16.boolean().describe("Whether the deletion was successful"),
|
|
5805
|
+
deletedPageId: z16.string().describe("The ID of the deleted page")
|
|
5425
5806
|
});
|
|
5426
5807
|
var handleDeletePage = async (context, params) => {
|
|
5427
5808
|
log.debug(`Deleting page on shop: ${context.shopDomain}`);
|
|
@@ -5455,8 +5836,8 @@ function registerDeletePageTool() {
|
|
|
5455
5836
|
name: "delete-page",
|
|
5456
5837
|
title: "Delete Page",
|
|
5457
5838
|
description: "Permanently delete a page by ID. This action cannot be undone. The page will no longer be accessible on the storefront. Use list-pages to find the page ID first. Consider unpublishing instead of deleting if you may need the content later. **Typical workflow:** get-page \u2192 delete-page. **Prerequisites:** Page ID. **Follow-ups:** None. Returns success confirmation and deleted page ID.",
|
|
5458
|
-
inputSchema:
|
|
5459
|
-
outputSchema:
|
|
5839
|
+
inputSchema: inputSchema14,
|
|
5840
|
+
outputSchema: outputSchema14,
|
|
5460
5841
|
category: "content",
|
|
5461
5842
|
relationships: {
|
|
5462
5843
|
relatedTools: ["get-page", "list-pages"],
|
|
@@ -5477,7 +5858,7 @@ function registerDeletePageTool() {
|
|
|
5477
5858
|
}
|
|
5478
5859
|
|
|
5479
5860
|
// src/tools/delete-product-image.ts
|
|
5480
|
-
import { z as
|
|
5861
|
+
import { z as z17 } from "zod";
|
|
5481
5862
|
var FILE_DELETE_MUTATION = `
|
|
5482
5863
|
mutation FileDelete($fileIds: [ID!]!) {
|
|
5483
5864
|
fileDelete(fileIds: $fileIds) {
|
|
@@ -5489,14 +5870,14 @@ var FILE_DELETE_MUTATION = `
|
|
|
5489
5870
|
}
|
|
5490
5871
|
}
|
|
5491
5872
|
`;
|
|
5492
|
-
var
|
|
5873
|
+
var inputSchema15 = z17.object({
|
|
5493
5874
|
imageId: imageIdSchema.describe(
|
|
5494
5875
|
'Shopify image GID to delete (e.g., "gid://shopify/MediaImage/123"). Required. Use get-product to find image IDs in the images array.'
|
|
5495
5876
|
)
|
|
5496
5877
|
});
|
|
5497
|
-
var
|
|
5498
|
-
success:
|
|
5499
|
-
deletedImageId:
|
|
5878
|
+
var outputSchema15 = z17.object({
|
|
5879
|
+
success: z17.boolean().describe("Whether the deletion was successful"),
|
|
5880
|
+
deletedImageId: z17.string().describe("ID of the deleted image")
|
|
5500
5881
|
});
|
|
5501
5882
|
var handleDeleteProductImage = async (context, params) => {
|
|
5502
5883
|
log.debug(`Deleting image on shop: ${context.shopDomain}`);
|
|
@@ -5547,8 +5928,8 @@ function registerDeleteProductImageTool() {
|
|
|
5547
5928
|
name: "delete-product-image",
|
|
5548
5929
|
title: "Delete Product Image",
|
|
5549
5930
|
description: "Remove an image from a product. This permanently deletes the image from Shopify's CDN. **Warning:** Cannot be undone - the image will need to be re-uploaded using add-product-image if needed again. **Prerequisites:** get-product to find image IDs in the images array.",
|
|
5550
|
-
inputSchema:
|
|
5551
|
-
outputSchema:
|
|
5931
|
+
inputSchema: inputSchema15,
|
|
5932
|
+
outputSchema: outputSchema15,
|
|
5552
5933
|
// AI Agent Optimization (Story 5.5)
|
|
5553
5934
|
category: "media",
|
|
5554
5935
|
relationships: {
|
|
@@ -5570,7 +5951,7 @@ function registerDeleteProductImageTool() {
|
|
|
5570
5951
|
}
|
|
5571
5952
|
|
|
5572
5953
|
// src/tools/delete-product-metafields.ts
|
|
5573
|
-
import { z as
|
|
5954
|
+
import { z as z18 } from "zod";
|
|
5574
5955
|
|
|
5575
5956
|
// src/shopify/metafields.ts
|
|
5576
5957
|
var GET_PRODUCT_METAFIELDS_QUERY = `
|
|
@@ -5749,28 +6130,28 @@ async function deleteProductMetafields(productId, identifiers) {
|
|
|
5749
6130
|
}
|
|
5750
6131
|
|
|
5751
6132
|
// src/tools/delete-product-metafields.ts
|
|
5752
|
-
var metafieldIdentifierSchema =
|
|
5753
|
-
namespace:
|
|
5754
|
-
key:
|
|
6133
|
+
var metafieldIdentifierSchema = z18.object({
|
|
6134
|
+
namespace: z18.string().min(1).describe('Metafield namespace (e.g., "custom", "seo"). Must match existing metafield.'),
|
|
6135
|
+
key: z18.string().min(1).describe('Metafield key (e.g., "color_hex"). Must match existing metafield.')
|
|
5755
6136
|
});
|
|
5756
|
-
var
|
|
6137
|
+
var inputSchema16 = z18.object({
|
|
5757
6138
|
productId: productIdSchema.describe(
|
|
5758
6139
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Use get-product or list-products to find product IDs.'
|
|
5759
6140
|
),
|
|
5760
|
-
identifiers:
|
|
6141
|
+
identifiers: z18.array(metafieldIdentifierSchema).min(1, "At least one metafield identifier is required").describe(
|
|
5761
6142
|
"Array of metafield identifiers to delete. Each identifier must have namespace and key. Use get-product-metafields first to verify which metafields exist."
|
|
5762
6143
|
)
|
|
5763
6144
|
});
|
|
5764
|
-
var
|
|
5765
|
-
success:
|
|
5766
|
-
deletedMetafields:
|
|
5767
|
-
|
|
5768
|
-
ownerId:
|
|
5769
|
-
namespace:
|
|
5770
|
-
key:
|
|
6145
|
+
var outputSchema16 = z18.object({
|
|
6146
|
+
success: z18.boolean().describe("Whether the operation succeeded"),
|
|
6147
|
+
deletedMetafields: z18.array(
|
|
6148
|
+
z18.object({
|
|
6149
|
+
ownerId: z18.string().describe("Product GID that owned the metafield"),
|
|
6150
|
+
namespace: z18.string().describe("Namespace of deleted metafield"),
|
|
6151
|
+
key: z18.string().describe("Key of deleted metafield")
|
|
5771
6152
|
})
|
|
5772
6153
|
).describe("Identifiers of successfully deleted metafields"),
|
|
5773
|
-
deletedCount:
|
|
6154
|
+
deletedCount: z18.number().describe("Number of metafields deleted")
|
|
5774
6155
|
});
|
|
5775
6156
|
var handleDeleteProductMetafields = async (context, params) => {
|
|
5776
6157
|
log.debug(
|
|
@@ -5800,8 +6181,8 @@ function registerDeleteProductMetafieldsTool() {
|
|
|
5800
6181
|
name: "delete-product-metafields",
|
|
5801
6182
|
title: "Delete Product Metafields",
|
|
5802
6183
|
description: "Remove metafields from a product. Identify metafields to delete by their namespace and key combination. Non-existent metafields are silently ignored (no error). **Warning:** This operation is irreversible - deleted metafield data cannot be recovered. **Prerequisites:** get-product-metafields to verify which metafields exist before deletion.",
|
|
5803
|
-
inputSchema:
|
|
5804
|
-
outputSchema:
|
|
6184
|
+
inputSchema: inputSchema16,
|
|
6185
|
+
outputSchema: outputSchema16,
|
|
5805
6186
|
// AI Agent Optimization (Story 5.5)
|
|
5806
6187
|
category: "seo",
|
|
5807
6188
|
relationships: {
|
|
@@ -5823,15 +6204,15 @@ function registerDeleteProductMetafieldsTool() {
|
|
|
5823
6204
|
}
|
|
5824
6205
|
|
|
5825
6206
|
// src/tools/delete-product.ts
|
|
5826
|
-
import { z as
|
|
5827
|
-
var
|
|
6207
|
+
import { z as z19 } from "zod";
|
|
6208
|
+
var inputSchema17 = z19.object({
|
|
5828
6209
|
id: productIdSchema.describe(
|
|
5829
6210
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Required.'
|
|
5830
6211
|
)
|
|
5831
6212
|
});
|
|
5832
|
-
var
|
|
5833
|
-
deletedProductId:
|
|
5834
|
-
title:
|
|
6213
|
+
var outputSchema17 = z19.object({
|
|
6214
|
+
deletedProductId: z19.string().describe("The ID of the deleted product"),
|
|
6215
|
+
title: z19.string().describe("The title of the deleted product (for confirmation)")
|
|
5835
6216
|
});
|
|
5836
6217
|
var handleDeleteProduct = async (context, params) => {
|
|
5837
6218
|
log.debug(`Deleting product on shop: ${context.shopDomain}`);
|
|
@@ -5873,8 +6254,8 @@ function registerDeleteProductTool() {
|
|
|
5873
6254
|
name: "delete-product",
|
|
5874
6255
|
title: "Delete Product",
|
|
5875
6256
|
description: "Delete a product from the Shopify store permanently. Requires the product ID (GID format). Returns confirmation with the deleted product ID and title. **Prerequisites:** get-product or list-products to find the correct product ID. **Warning:** This action cannot be undone.",
|
|
5876
|
-
inputSchema:
|
|
5877
|
-
outputSchema:
|
|
6257
|
+
inputSchema: inputSchema17,
|
|
6258
|
+
outputSchema: outputSchema17,
|
|
5878
6259
|
// AI Agent Optimization (Story 5.5)
|
|
5879
6260
|
category: "product",
|
|
5880
6261
|
relationships: {
|
|
@@ -5896,15 +6277,15 @@ function registerDeleteProductTool() {
|
|
|
5896
6277
|
}
|
|
5897
6278
|
|
|
5898
6279
|
// src/tools/delete-redirect.ts
|
|
5899
|
-
import { z as
|
|
5900
|
-
var
|
|
6280
|
+
import { z as z20 } from "zod";
|
|
6281
|
+
var inputSchema18 = z20.object({
|
|
5901
6282
|
id: redirectIdSchema.describe(
|
|
5902
6283
|
'Shopify redirect GID (e.g., "gid://shopify/UrlRedirect/123"). Use list-redirects to find redirect IDs.'
|
|
5903
6284
|
)
|
|
5904
6285
|
});
|
|
5905
|
-
var
|
|
5906
|
-
success:
|
|
5907
|
-
deletedRedirectId:
|
|
6286
|
+
var outputSchema18 = z20.object({
|
|
6287
|
+
success: z20.boolean().describe("Whether the deletion succeeded"),
|
|
6288
|
+
deletedRedirectId: z20.string().describe("ID of the deleted redirect")
|
|
5908
6289
|
});
|
|
5909
6290
|
var handleDeleteRedirect = async (context, params) => {
|
|
5910
6291
|
log.debug(`Deleting redirect on shop: ${context.shopDomain}`);
|
|
@@ -5946,8 +6327,8 @@ function registerDeleteRedirectTool() {
|
|
|
5946
6327
|
name: "delete-redirect",
|
|
5947
6328
|
title: "Delete URL Redirect",
|
|
5948
6329
|
description: "Remove a URL redirect by ID. **Warning:** Deleting means visitors to that path will see 404 error - can hurt SEO if old URL still receives traffic. **Prerequisites:** list-redirects to find redirect IDs.",
|
|
5949
|
-
inputSchema:
|
|
5950
|
-
outputSchema:
|
|
6330
|
+
inputSchema: inputSchema18,
|
|
6331
|
+
outputSchema: outputSchema18,
|
|
5951
6332
|
// AI Agent Optimization (Story 5.5)
|
|
5952
6333
|
category: "seo",
|
|
5953
6334
|
relationships: {
|
|
@@ -5969,7 +6350,7 @@ function registerDeleteRedirectTool() {
|
|
|
5969
6350
|
}
|
|
5970
6351
|
|
|
5971
6352
|
// src/tools/get-bulk-inventory.ts
|
|
5972
|
-
import { z as
|
|
6353
|
+
import { z as z21 } from "zod";
|
|
5973
6354
|
|
|
5974
6355
|
// src/shopify/inventory.ts
|
|
5975
6356
|
var GET_INVENTORY_ITEM_QUERY = `
|
|
@@ -6540,46 +6921,46 @@ async function getBulkInventory(options) {
|
|
|
6540
6921
|
}
|
|
6541
6922
|
|
|
6542
6923
|
// src/tools/get-bulk-inventory.ts
|
|
6543
|
-
var
|
|
6544
|
-
productIds:
|
|
6924
|
+
var inputSchema19 = z21.object({
|
|
6925
|
+
productIds: z21.array(productIdSchema).min(1, { message: "productIds array cannot be empty" }).max(50, { message: "Maximum 50 product IDs allowed per request" }).describe(
|
|
6545
6926
|
'Array of Shopify product IDs (e.g., ["gid://shopify/Product/123", "gid://shopify/Product/456"]). Maximum 50 products per request. Get product IDs from list-products or search.'
|
|
6546
6927
|
),
|
|
6547
|
-
includeVariants:
|
|
6928
|
+
includeVariants: z21.boolean().default(true).describe(
|
|
6548
6929
|
"Include per-variant inventory breakdown. Default: true. Set to false for faster response with only product totals."
|
|
6549
6930
|
),
|
|
6550
6931
|
locationId: locationIdSchema.optional().describe(
|
|
6551
6932
|
'Optional location ID to filter inventory (e.g., "gid://shopify/Location/789"). If not provided, returns total inventory across all locations.'
|
|
6552
6933
|
)
|
|
6553
6934
|
});
|
|
6554
|
-
var
|
|
6555
|
-
products:
|
|
6556
|
-
|
|
6557
|
-
productId:
|
|
6558
|
-
productTitle:
|
|
6559
|
-
totalInventory:
|
|
6560
|
-
variants:
|
|
6561
|
-
|
|
6562
|
-
variantId:
|
|
6563
|
-
variantTitle:
|
|
6564
|
-
sku:
|
|
6565
|
-
inventoryItemId:
|
|
6566
|
-
available:
|
|
6567
|
-
locations:
|
|
6568
|
-
|
|
6569
|
-
locationId:
|
|
6570
|
-
locationName:
|
|
6571
|
-
available:
|
|
6935
|
+
var outputSchema19 = z21.object({
|
|
6936
|
+
products: z21.array(
|
|
6937
|
+
z21.object({
|
|
6938
|
+
productId: z21.string().describe("Product GID"),
|
|
6939
|
+
productTitle: z21.string().describe("Product title"),
|
|
6940
|
+
totalInventory: z21.number().describe("Total inventory across all variants"),
|
|
6941
|
+
variants: z21.array(
|
|
6942
|
+
z21.object({
|
|
6943
|
+
variantId: z21.string().describe("Variant GID"),
|
|
6944
|
+
variantTitle: z21.string().describe('Variant title (e.g., "Red / Large")'),
|
|
6945
|
+
sku: z21.string().nullable().describe("SKU (Stock Keeping Unit)"),
|
|
6946
|
+
inventoryItemId: z21.string().describe("Inventory item GID"),
|
|
6947
|
+
available: z21.number().describe("Available quantity"),
|
|
6948
|
+
locations: z21.array(
|
|
6949
|
+
z21.object({
|
|
6950
|
+
locationId: z21.string().describe("Location GID"),
|
|
6951
|
+
locationName: z21.string().describe("Human-readable location name"),
|
|
6952
|
+
available: z21.number().describe("Available quantity at this location")
|
|
6572
6953
|
})
|
|
6573
6954
|
).optional().describe("Per-location inventory breakdown")
|
|
6574
6955
|
})
|
|
6575
6956
|
).optional().describe("Variant details (if includeVariants=true)")
|
|
6576
6957
|
})
|
|
6577
6958
|
).describe("Products with inventory data"),
|
|
6578
|
-
notFound:
|
|
6579
|
-
summary:
|
|
6580
|
-
productsQueried:
|
|
6581
|
-
productsFound:
|
|
6582
|
-
totalInventory:
|
|
6959
|
+
notFound: z21.array(z21.string()).describe("Product IDs that were not found in the store"),
|
|
6960
|
+
summary: z21.object({
|
|
6961
|
+
productsQueried: z21.number().describe("Total number of product IDs provided"),
|
|
6962
|
+
productsFound: z21.number().describe("Number of products found in the store"),
|
|
6963
|
+
totalInventory: z21.number().describe("Sum of inventory across all found products")
|
|
6583
6964
|
}).describe("Summary statistics")
|
|
6584
6965
|
});
|
|
6585
6966
|
var handleGetBulkInventory = async (context, params) => {
|
|
@@ -6611,8 +6992,8 @@ function registerGetBulkInventoryTool() {
|
|
|
6611
6992
|
name: "get-bulk-inventory",
|
|
6612
6993
|
title: "Get Bulk Inventory",
|
|
6613
6994
|
description: "Efficiently query inventory levels for multiple products in a single request. Accepts up to 50 product IDs and returns total inventory plus optional per-variant breakdown. Use this instead of multiple get-inventory calls when checking stock across several products. Returns a summary with counts of products queried vs found, plus total inventory across all products. Products not found in the store are listed in the notFound array rather than causing an error. Perfect for cart verification, collection audits, and batch inventory checks. **Typical workflow:** list-products \u2192 get-bulk-inventory. **Prerequisites:** Product IDs. **Follow-ups:** update-inventory, get-inventory. Returns products with inventory data and summary statistics.",
|
|
6614
|
-
inputSchema:
|
|
6615
|
-
outputSchema:
|
|
6995
|
+
inputSchema: inputSchema19,
|
|
6996
|
+
outputSchema: outputSchema19,
|
|
6616
6997
|
category: "inventory",
|
|
6617
6998
|
relationships: {
|
|
6618
6999
|
relatedTools: ["list-products", "get-inventory", "update-inventory"],
|
|
@@ -6633,30 +7014,30 @@ function registerGetBulkInventoryTool() {
|
|
|
6633
7014
|
}
|
|
6634
7015
|
|
|
6635
7016
|
// src/tools/get-collection.ts
|
|
6636
|
-
import { z as
|
|
6637
|
-
var
|
|
7017
|
+
import { z as z22 } from "zod";
|
|
7018
|
+
var inputSchema20 = z22.object({
|
|
6638
7019
|
collectionId: collectionIdSchema.describe(
|
|
6639
7020
|
'Collection ID (GID format, e.g., "gid://shopify/Collection/123"). Use list-collections to find collection IDs.'
|
|
6640
7021
|
)
|
|
6641
7022
|
});
|
|
6642
|
-
var
|
|
6643
|
-
id:
|
|
6644
|
-
title:
|
|
6645
|
-
handle:
|
|
6646
|
-
description:
|
|
6647
|
-
descriptionHtml:
|
|
6648
|
-
seo:
|
|
6649
|
-
title:
|
|
6650
|
-
description:
|
|
7023
|
+
var outputSchema20 = z22.object({
|
|
7024
|
+
id: z22.string().describe("Collection GID"),
|
|
7025
|
+
title: z22.string().describe("Collection title"),
|
|
7026
|
+
handle: z22.string().describe("URL handle/slug"),
|
|
7027
|
+
description: z22.string().describe("Plain text description"),
|
|
7028
|
+
descriptionHtml: z22.string().describe("HTML description"),
|
|
7029
|
+
seo: z22.object({
|
|
7030
|
+
title: z22.string().nullable().describe("SEO title"),
|
|
7031
|
+
description: z22.string().nullable().describe("SEO description")
|
|
6651
7032
|
}),
|
|
6652
|
-
image:
|
|
6653
|
-
id:
|
|
6654
|
-
url:
|
|
6655
|
-
altText:
|
|
7033
|
+
image: z22.object({
|
|
7034
|
+
id: z22.string().describe("Image GID"),
|
|
7035
|
+
url: z22.string().describe("Image URL"),
|
|
7036
|
+
altText: z22.string().nullable().describe("Alt text")
|
|
6656
7037
|
}).nullable(),
|
|
6657
|
-
sortOrder:
|
|
6658
|
-
productsCount:
|
|
6659
|
-
updatedAt:
|
|
7038
|
+
sortOrder: z22.string().describe("Product sort order within collection"),
|
|
7039
|
+
productsCount: z22.number().describe("Number of products in collection"),
|
|
7040
|
+
updatedAt: z22.string().describe("Last update timestamp (ISO 8601)")
|
|
6660
7041
|
});
|
|
6661
7042
|
var handleGetCollection = async (context, params) => {
|
|
6662
7043
|
log.debug(`Getting collection on shop: ${context.shopDomain}`);
|
|
@@ -6676,8 +7057,8 @@ function registerGetCollectionTool() {
|
|
|
6676
7057
|
name: "get-collection",
|
|
6677
7058
|
title: "Get Collection",
|
|
6678
7059
|
description: "Retrieve complete details of a collection by ID. Returns all collection attributes including SEO metadata, product count, sort order, and timestamps. **Prerequisites:** list-collections to find collection IDs. **Follow-ups:** update-collection, delete-collection, add-products-to-collection.",
|
|
6679
|
-
inputSchema:
|
|
6680
|
-
outputSchema:
|
|
7060
|
+
inputSchema: inputSchema20,
|
|
7061
|
+
outputSchema: outputSchema20,
|
|
6681
7062
|
// AI Agent Optimization (Story 5.5)
|
|
6682
7063
|
category: "collection",
|
|
6683
7064
|
relationships: {
|
|
@@ -6697,8 +7078,8 @@ function registerGetCollectionTool() {
|
|
|
6697
7078
|
}
|
|
6698
7079
|
|
|
6699
7080
|
// src/tools/get-inventory.ts
|
|
6700
|
-
import { z as
|
|
6701
|
-
var
|
|
7081
|
+
import { z as z23 } from "zod";
|
|
7082
|
+
var inputSchema21 = z23.object({
|
|
6702
7083
|
variantId: variantIdSchema.optional().describe(
|
|
6703
7084
|
'The Shopify product variant ID (e.g., "gid://shopify/ProductVariant/123"). Use this when you have a variant ID from a product query (get-product or list-products).'
|
|
6704
7085
|
),
|
|
@@ -6711,23 +7092,23 @@ var inputSchema19 = z21.object({
|
|
|
6711
7092
|
}).refine((data) => data.variantId || data.inventoryItemId, {
|
|
6712
7093
|
message: "Either variantId or inventoryItemId must be provided"
|
|
6713
7094
|
});
|
|
6714
|
-
var
|
|
6715
|
-
inventoryItemId:
|
|
6716
|
-
variantId:
|
|
6717
|
-
variantTitle:
|
|
6718
|
-
productId:
|
|
6719
|
-
productTitle:
|
|
6720
|
-
sku:
|
|
6721
|
-
tracked:
|
|
6722
|
-
totalAvailable:
|
|
6723
|
-
locations:
|
|
6724
|
-
|
|
6725
|
-
locationId:
|
|
6726
|
-
locationName:
|
|
6727
|
-
isActive:
|
|
6728
|
-
available:
|
|
6729
|
-
onHand:
|
|
6730
|
-
committed:
|
|
7095
|
+
var outputSchema21 = z23.object({
|
|
7096
|
+
inventoryItemId: z23.string().describe("Inventory item GID"),
|
|
7097
|
+
variantId: z23.string().describe("Product variant GID"),
|
|
7098
|
+
variantTitle: z23.string().describe('Variant title (e.g., "Red / Large")'),
|
|
7099
|
+
productId: z23.string().describe("Product GID"),
|
|
7100
|
+
productTitle: z23.string().describe("Product title"),
|
|
7101
|
+
sku: z23.string().nullable().describe("SKU (Stock Keeping Unit)"),
|
|
7102
|
+
tracked: z23.boolean().describe("Whether inventory tracking is enabled for this item"),
|
|
7103
|
+
totalAvailable: z23.number().describe("Total available quantity across all locations"),
|
|
7104
|
+
locations: z23.array(
|
|
7105
|
+
z23.object({
|
|
7106
|
+
locationId: z23.string().describe("Location GID"),
|
|
7107
|
+
locationName: z23.string().describe("Human-readable location name"),
|
|
7108
|
+
isActive: z23.boolean().describe("Whether the location is active"),
|
|
7109
|
+
available: z23.number().describe("Quantity available for sale"),
|
|
7110
|
+
onHand: z23.number().describe("Physical quantity on hand"),
|
|
7111
|
+
committed: z23.number().describe("Quantity committed to orders")
|
|
6731
7112
|
})
|
|
6732
7113
|
).describe("Inventory levels by location")
|
|
6733
7114
|
});
|
|
@@ -6789,8 +7170,8 @@ function registerGetInventoryTool() {
|
|
|
6789
7170
|
name: "get-inventory",
|
|
6790
7171
|
title: "Get Inventory",
|
|
6791
7172
|
description: "Retrieve inventory levels for a product variant across all store locations. Provide either a variantId (from get-product or list-products) or inventoryItemId (if you have it directly). Returns available, on-hand, and committed quantities per location, plus totals. Useful for: checking stock before making availability promises, identifying which locations have stock, understanding inventory distribution across warehouse locations. Optionally filter by locationId to get inventory at a specific location only. **Typical workflow:** get-product \u2192 get-inventory \u2192 update-inventory. **Prerequisites:** Variant ID or Inventory Item ID. **Follow-ups:** update-inventory. Returns inventory levels per location with totals.",
|
|
6792
|
-
inputSchema:
|
|
6793
|
-
outputSchema:
|
|
7173
|
+
inputSchema: inputSchema21,
|
|
7174
|
+
outputSchema: outputSchema21,
|
|
6794
7175
|
category: "inventory",
|
|
6795
7176
|
relationships: {
|
|
6796
7177
|
relatedTools: [
|
|
@@ -6814,24 +7195,106 @@ function registerGetInventoryTool() {
|
|
|
6814
7195
|
);
|
|
6815
7196
|
}
|
|
6816
7197
|
|
|
7198
|
+
// src/tools/get-market.ts
|
|
7199
|
+
import { z as z24 } from "zod";
|
|
7200
|
+
var inputSchema22 = z24.object({
|
|
7201
|
+
id: marketIdSchema.describe(
|
|
7202
|
+
'Shopify Market GID (e.g., "gid://shopify/Market/123"). Use list-markets to find market IDs.'
|
|
7203
|
+
)
|
|
7204
|
+
});
|
|
7205
|
+
var outputSchema22 = z24.object({
|
|
7206
|
+
id: z24.string().describe("Market GID"),
|
|
7207
|
+
name: z24.string().describe("Market name (not shown to customers)"),
|
|
7208
|
+
handle: z24.string().describe("URL handle"),
|
|
7209
|
+
enabled: z24.boolean().describe("Whether the market is enabled"),
|
|
7210
|
+
status: z24.enum(["ACTIVE", "INACTIVE"]).describe("Market status"),
|
|
7211
|
+
type: z24.string().describe("Market type (PRIMARY, SINGLE_COUNTRY, MULTI_COUNTRY, CONTINENT)"),
|
|
7212
|
+
currencySettings: z24.object({
|
|
7213
|
+
baseCurrency: z24.object({
|
|
7214
|
+
currencyCode: z24.string().describe("Base currency code (e.g., USD, EUR)"),
|
|
7215
|
+
currencyName: z24.string().optional().describe("Base currency name")
|
|
7216
|
+
}),
|
|
7217
|
+
localCurrencies: z24.boolean().describe("Whether local currencies are enabled")
|
|
7218
|
+
}).optional(),
|
|
7219
|
+
webPresences: z24.array(
|
|
7220
|
+
z24.object({
|
|
7221
|
+
id: z24.string().describe("Web presence GID"),
|
|
7222
|
+
defaultLocale: z24.object({
|
|
7223
|
+
locale: z24.string().describe("Locale code (e.g., en-CA)"),
|
|
7224
|
+
name: z24.string().describe("Locale display name")
|
|
7225
|
+
}),
|
|
7226
|
+
alternateLocales: z24.array(
|
|
7227
|
+
z24.object({
|
|
7228
|
+
locale: z24.string(),
|
|
7229
|
+
name: z24.string()
|
|
7230
|
+
})
|
|
7231
|
+
).optional(),
|
|
7232
|
+
subfolderSuffix: z24.string().optional().describe("Subfolder suffix (e.g., /en-ca)"),
|
|
7233
|
+
domain: z24.object({
|
|
7234
|
+
host: z24.string().describe("Domain host")
|
|
7235
|
+
}).optional(),
|
|
7236
|
+
rootUrls: z24.array(
|
|
7237
|
+
z24.object({
|
|
7238
|
+
locale: z24.string(),
|
|
7239
|
+
url: z24.string()
|
|
7240
|
+
})
|
|
7241
|
+
).optional()
|
|
7242
|
+
})
|
|
7243
|
+
).optional().describe("Web presences (SEO URL configurations)")
|
|
7244
|
+
});
|
|
7245
|
+
var handleGetMarket = async (context, params) => {
|
|
7246
|
+
log.debug(`Getting market ${params.id} on shop: ${context.shopDomain}`);
|
|
7247
|
+
const market = await getMarket(params.id);
|
|
7248
|
+
if (!market) {
|
|
7249
|
+
throw new Error(`Market not found: ${params.id}. Use list-markets to see available markets.`);
|
|
7250
|
+
}
|
|
7251
|
+
log.debug(`Retrieved market: ${market.name}`);
|
|
7252
|
+
return market;
|
|
7253
|
+
};
|
|
7254
|
+
function registerGetMarketTool() {
|
|
7255
|
+
registerContextAwareTool(
|
|
7256
|
+
{
|
|
7257
|
+
name: "get-market",
|
|
7258
|
+
title: "Get Market",
|
|
7259
|
+
description: "Retrieve full details of a specific market by ID. Returns market name, handle, status, type, currency settings, and web presences. Web presences define SEO URL structures (domains, subfolders, locales). **Prerequisites:** Use list-markets to find market IDs. **Follow-ups:** update-market, delete-market, create-web-presence.",
|
|
7260
|
+
inputSchema: inputSchema22,
|
|
7261
|
+
outputSchema: outputSchema22,
|
|
7262
|
+
// AI Agent Optimization
|
|
7263
|
+
category: "market",
|
|
7264
|
+
relationships: {
|
|
7265
|
+
relatedTools: ["list-markets"],
|
|
7266
|
+
followUps: ["update-market", "delete-market"]
|
|
7267
|
+
},
|
|
7268
|
+
// MCP Tool Annotations (Epic 9.5 - MCP Best Practices)
|
|
7269
|
+
annotations: {
|
|
7270
|
+
readOnlyHint: true,
|
|
7271
|
+
destructiveHint: false,
|
|
7272
|
+
idempotentHint: true,
|
|
7273
|
+
openWorldHint: true
|
|
7274
|
+
}
|
|
7275
|
+
},
|
|
7276
|
+
handleGetMarket
|
|
7277
|
+
);
|
|
7278
|
+
}
|
|
7279
|
+
|
|
6817
7280
|
// src/tools/get-page.ts
|
|
6818
|
-
import { z as
|
|
6819
|
-
var
|
|
7281
|
+
import { z as z25 } from "zod";
|
|
7282
|
+
var inputSchema23 = z25.object({
|
|
6820
7283
|
id: pageIdSchema.describe(
|
|
6821
7284
|
'The page ID to retrieve. Must be a valid Shopify GID format. Example: "gid://shopify/Page/123456789". Use list-pages to find page IDs.'
|
|
6822
7285
|
)
|
|
6823
7286
|
});
|
|
6824
|
-
var
|
|
6825
|
-
id:
|
|
6826
|
-
title:
|
|
6827
|
-
handle:
|
|
6828
|
-
body:
|
|
6829
|
-
bodySummary:
|
|
6830
|
-
isPublished:
|
|
6831
|
-
publishedAt:
|
|
6832
|
-
templateSuffix:
|
|
6833
|
-
createdAt:
|
|
6834
|
-
updatedAt:
|
|
7287
|
+
var outputSchema23 = z25.object({
|
|
7288
|
+
id: z25.string().describe("Page GID"),
|
|
7289
|
+
title: z25.string().describe("Page title"),
|
|
7290
|
+
handle: z25.string().describe("URL handle/slug"),
|
|
7291
|
+
body: z25.string().describe("HTML body content"),
|
|
7292
|
+
bodySummary: z25.string().describe("Plain text summary (first 150 chars)"),
|
|
7293
|
+
isPublished: z25.boolean().describe("Whether page is visible on storefront"),
|
|
7294
|
+
publishedAt: z25.string().nullable().describe("ISO timestamp when published"),
|
|
7295
|
+
templateSuffix: z25.string().nullable().describe("Custom template suffix"),
|
|
7296
|
+
createdAt: z25.string().describe("ISO timestamp of creation"),
|
|
7297
|
+
updatedAt: z25.string().describe("ISO timestamp of last update")
|
|
6835
7298
|
});
|
|
6836
7299
|
var handleGetPage = async (context, params) => {
|
|
6837
7300
|
log.debug(`Getting page on shop: ${context.shopDomain}`);
|
|
@@ -6851,8 +7314,8 @@ function registerGetPageTool() {
|
|
|
6851
7314
|
name: "get-page",
|
|
6852
7315
|
title: "Get Page",
|
|
6853
7316
|
description: "Retrieve details of a specific page by ID. Returns the full page including title, body content, handle, publish status, and timestamps. Use list-pages first to find page IDs. Useful for: inspecting page content before editing, verifying page details. **Typical workflow:** list-pages \u2192 get-page \u2192 update-page. **Prerequisites:** Page ID. **Follow-ups:** update-page, delete-page. Returns a single page object with full content.",
|
|
6854
|
-
inputSchema:
|
|
6855
|
-
outputSchema:
|
|
7317
|
+
inputSchema: inputSchema23,
|
|
7318
|
+
outputSchema: outputSchema23,
|
|
6856
7319
|
category: "content",
|
|
6857
7320
|
relationships: {
|
|
6858
7321
|
relatedTools: ["list-pages", "update-page", "delete-page"],
|
|
@@ -6872,27 +7335,27 @@ function registerGetPageTool() {
|
|
|
6872
7335
|
}
|
|
6873
7336
|
|
|
6874
7337
|
// src/tools/get-product-metafields.ts
|
|
6875
|
-
import { z as
|
|
6876
|
-
var
|
|
7338
|
+
import { z as z26 } from "zod";
|
|
7339
|
+
var inputSchema24 = z26.object({
|
|
6877
7340
|
productId: productIdSchema.describe(
|
|
6878
7341
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Use get-product or list-products to find product IDs.'
|
|
6879
7342
|
),
|
|
6880
|
-
namespace:
|
|
7343
|
+
namespace: z26.string().optional().describe(
|
|
6881
7344
|
'Filter metafields by namespace (e.g., "custom", "seo", "my_app"). If not provided, returns metafields from all namespaces.'
|
|
6882
7345
|
),
|
|
6883
|
-
keys:
|
|
7346
|
+
keys: z26.array(z26.string()).optional().describe(
|
|
6884
7347
|
'Filter by specific metafield keys within the namespace (e.g., ["color", "size"]). Requires namespace to be specified for meaningful filtering.'
|
|
6885
7348
|
)
|
|
6886
7349
|
});
|
|
6887
|
-
var
|
|
6888
|
-
|
|
6889
|
-
id:
|
|
6890
|
-
namespace:
|
|
6891
|
-
key:
|
|
6892
|
-
value:
|
|
6893
|
-
type:
|
|
6894
|
-
createdAt:
|
|
6895
|
-
updatedAt:
|
|
7350
|
+
var outputSchema24 = z26.array(
|
|
7351
|
+
z26.object({
|
|
7352
|
+
id: z26.string().describe('Metafield GID (e.g., "gid://shopify/Metafield/123")'),
|
|
7353
|
+
namespace: z26.string().describe("Metafield namespace (grouping identifier)"),
|
|
7354
|
+
key: z26.string().describe("Metafield key (field name)"),
|
|
7355
|
+
value: z26.string().describe("Metafield value (the stored data)"),
|
|
7356
|
+
type: z26.string().describe('Metafield type (e.g., "single_line_text_field", "json", "number_integer")'),
|
|
7357
|
+
createdAt: z26.string().describe("Creation timestamp (ISO 8601)"),
|
|
7358
|
+
updatedAt: z26.string().describe("Last update timestamp (ISO 8601)")
|
|
6896
7359
|
})
|
|
6897
7360
|
);
|
|
6898
7361
|
var handleGetProductMetafields = async (context, params) => {
|
|
@@ -6917,8 +7380,8 @@ function registerGetProductMetafieldsTool() {
|
|
|
6917
7380
|
name: "get-product-metafields",
|
|
6918
7381
|
title: "Get Product Metafields",
|
|
6919
7382
|
description: 'Retrieve metafields attached to a product. Metafields store custom data like SEO schema markup, product specifications, or custom attributes. Filter by namespace to get specific app/integration data, or by keys to retrieve specific fields. Common namespaces include "custom" (user-defined), "seo" (search optimization), and app-specific namespaces. Returns all matching metafields with their id, namespace, key, value, type, and timestamps. **Prerequisites:** get-product to obtain the product ID. **Follow-ups:** set-product-metafields to update values, delete-product-metafields to remove.',
|
|
6920
|
-
inputSchema:
|
|
6921
|
-
outputSchema:
|
|
7383
|
+
inputSchema: inputSchema24,
|
|
7384
|
+
outputSchema: outputSchema24,
|
|
6922
7385
|
// AI Agent Optimization (Story 5.5)
|
|
6923
7386
|
category: "seo",
|
|
6924
7387
|
relationships: {
|
|
@@ -6939,51 +7402,51 @@ function registerGetProductMetafieldsTool() {
|
|
|
6939
7402
|
}
|
|
6940
7403
|
|
|
6941
7404
|
// src/tools/get-product.ts
|
|
6942
|
-
import { z as
|
|
6943
|
-
var
|
|
7405
|
+
import { z as z27 } from "zod";
|
|
7406
|
+
var inputSchema25 = z27.object({
|
|
6944
7407
|
id: productIdSchema.optional().describe(
|
|
6945
7408
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Use either id or handle.'
|
|
6946
7409
|
),
|
|
6947
|
-
handle:
|
|
7410
|
+
handle: z27.string().optional().describe(
|
|
6948
7411
|
'Product URL handle/slug (e.g., "premium-cotton-t-shirt"). Use either id or handle.'
|
|
6949
7412
|
)
|
|
6950
7413
|
}).refine((data) => data.id || data.handle, {
|
|
6951
7414
|
message: "Either id or handle must be provided"
|
|
6952
7415
|
});
|
|
6953
|
-
var
|
|
6954
|
-
id:
|
|
6955
|
-
title:
|
|
6956
|
-
handle:
|
|
6957
|
-
description:
|
|
6958
|
-
vendor:
|
|
6959
|
-
productType:
|
|
6960
|
-
status:
|
|
6961
|
-
tags:
|
|
6962
|
-
seo:
|
|
6963
|
-
title:
|
|
6964
|
-
description:
|
|
7416
|
+
var outputSchema25 = z27.object({
|
|
7417
|
+
id: z27.string().describe('Product GID (e.g., "gid://shopify/Product/123")'),
|
|
7418
|
+
title: z27.string().describe("Product title"),
|
|
7419
|
+
handle: z27.string().describe("URL handle/slug"),
|
|
7420
|
+
description: z27.string().nullable().describe("Product description (HTML)"),
|
|
7421
|
+
vendor: z27.string().describe("Vendor/brand name"),
|
|
7422
|
+
productType: z27.string().describe("Product type"),
|
|
7423
|
+
status: z27.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).describe("Product status"),
|
|
7424
|
+
tags: z27.array(z27.string()).describe("Product tags"),
|
|
7425
|
+
seo: z27.object({
|
|
7426
|
+
title: z27.string().nullable().describe("SEO title for search engines"),
|
|
7427
|
+
description: z27.string().nullable().describe("SEO description/meta description")
|
|
6965
7428
|
}).describe("SEO metadata for search engine optimization"),
|
|
6966
|
-
createdAt:
|
|
6967
|
-
updatedAt:
|
|
6968
|
-
variants:
|
|
6969
|
-
|
|
6970
|
-
id:
|
|
6971
|
-
title:
|
|
6972
|
-
price:
|
|
6973
|
-
compareAtPrice:
|
|
6974
|
-
sku:
|
|
6975
|
-
barcode:
|
|
6976
|
-
inventoryQuantity:
|
|
7429
|
+
createdAt: z27.string().describe("Creation timestamp (ISO 8601)"),
|
|
7430
|
+
updatedAt: z27.string().describe("Last update timestamp (ISO 8601)"),
|
|
7431
|
+
variants: z27.array(
|
|
7432
|
+
z27.object({
|
|
7433
|
+
id: z27.string().describe("Variant GID"),
|
|
7434
|
+
title: z27.string().describe("Variant title"),
|
|
7435
|
+
price: z27.string().describe("Price"),
|
|
7436
|
+
compareAtPrice: z27.string().nullable().describe("Compare at price"),
|
|
7437
|
+
sku: z27.string().nullable().describe("SKU"),
|
|
7438
|
+
barcode: z27.string().nullable().describe("Barcode"),
|
|
7439
|
+
inventoryQuantity: z27.number().nullable().describe("Inventory quantity")
|
|
6977
7440
|
})
|
|
6978
7441
|
).describe("Product variants"),
|
|
6979
|
-
images:
|
|
6980
|
-
|
|
6981
|
-
id:
|
|
6982
|
-
url:
|
|
6983
|
-
altText:
|
|
7442
|
+
images: z27.array(
|
|
7443
|
+
z27.object({
|
|
7444
|
+
id: z27.string().describe("Image GID"),
|
|
7445
|
+
url: z27.string().describe("Image URL"),
|
|
7446
|
+
altText: z27.string().nullable().describe("Alt text")
|
|
6984
7447
|
})
|
|
6985
7448
|
).describe("Product images"),
|
|
6986
|
-
totalInventory:
|
|
7449
|
+
totalInventory: z27.number().describe("Total inventory across variants")
|
|
6987
7450
|
});
|
|
6988
7451
|
var handleGetProduct = async (context, params) => {
|
|
6989
7452
|
log.debug(`Getting product on shop: ${context.shopDomain}`);
|
|
@@ -7022,8 +7485,8 @@ function registerGetProductTool() {
|
|
|
7022
7485
|
name: "get-product",
|
|
7023
7486
|
title: "Get Product",
|
|
7024
7487
|
description: "Retrieve details of a specific product from the Shopify store. Provide either the product ID (GID format) or handle (URL slug). Returns full product details including title, description, vendor, type, status, tags, SEO metadata (title/description for search engines), variants (with pricing/SKU/inventory), and images. **Prerequisites:** Use list-products to find product IDs or handles. **Follow-ups:** update-product, delete-product, add-product-image, get-product-metafields.",
|
|
7025
|
-
inputSchema:
|
|
7026
|
-
outputSchema:
|
|
7488
|
+
inputSchema: inputSchema25,
|
|
7489
|
+
outputSchema: outputSchema25,
|
|
7027
7490
|
// AI Agent Optimization (Story 5.5)
|
|
7028
7491
|
category: "product",
|
|
7029
7492
|
relationships: {
|
|
@@ -7048,36 +7511,36 @@ function registerGetProductTool() {
|
|
|
7048
7511
|
}
|
|
7049
7512
|
|
|
7050
7513
|
// src/tools/list-articles.ts
|
|
7051
|
-
import { z as
|
|
7052
|
-
var
|
|
7053
|
-
first:
|
|
7054
|
-
cursor:
|
|
7514
|
+
import { z as z28 } from "zod";
|
|
7515
|
+
var inputSchema26 = z28.object({
|
|
7516
|
+
first: z28.number().int().min(1).max(50).optional().default(10).describe("Number of articles to return (1-50). Defaults to 10."),
|
|
7517
|
+
cursor: z28.string().optional().describe(
|
|
7055
7518
|
"Pagination cursor from a previous response. Use the endCursor from the previous response to get the next page of results."
|
|
7056
7519
|
),
|
|
7057
|
-
query:
|
|
7520
|
+
query: z28.string().optional().describe(
|
|
7058
7521
|
"Search query to filter articles. Supports Shopify search syntax. Examples: 'title:Guide', 'tag:tutorial', 'blog_id:123456789'."
|
|
7059
7522
|
),
|
|
7060
|
-
blogId:
|
|
7523
|
+
blogId: z28.string().optional().describe(
|
|
7061
7524
|
'Filter articles by blog ID. Provide the numeric ID (not the full GID) to filter. Example: To filter blog "gid://shopify/Blog/123456", pass blogId as "123456".'
|
|
7062
7525
|
),
|
|
7063
|
-
sortKey:
|
|
7526
|
+
sortKey: z28.enum(["ID", "TITLE", "UPDATED_AT", "PUBLISHED_AT", "AUTHOR", "BLOG_TITLE"]).optional().describe("Sort order for results. Defaults to ID.")
|
|
7064
7527
|
});
|
|
7065
|
-
var
|
|
7066
|
-
articles:
|
|
7067
|
-
|
|
7068
|
-
id:
|
|
7069
|
-
title:
|
|
7070
|
-
handle:
|
|
7071
|
-
blog:
|
|
7072
|
-
id:
|
|
7073
|
-
title:
|
|
7528
|
+
var outputSchema26 = z28.object({
|
|
7529
|
+
articles: z28.array(
|
|
7530
|
+
z28.object({
|
|
7531
|
+
id: z28.string().describe("Article GID"),
|
|
7532
|
+
title: z28.string().describe("Article title"),
|
|
7533
|
+
handle: z28.string().describe("URL handle/slug"),
|
|
7534
|
+
blog: z28.object({
|
|
7535
|
+
id: z28.string().describe("Parent blog GID"),
|
|
7536
|
+
title: z28.string().describe("Parent blog title")
|
|
7074
7537
|
}),
|
|
7075
|
-
isPublished:
|
|
7076
|
-
publishedAt:
|
|
7538
|
+
isPublished: z28.boolean().describe("Whether article is visible on storefront"),
|
|
7539
|
+
publishedAt: z28.string().nullable().describe("ISO timestamp when published")
|
|
7077
7540
|
})
|
|
7078
7541
|
),
|
|
7079
|
-
hasNextPage:
|
|
7080
|
-
endCursor:
|
|
7542
|
+
hasNextPage: z28.boolean().describe("Whether more articles are available"),
|
|
7543
|
+
endCursor: z28.string().nullable().describe("Cursor for next page pagination")
|
|
7081
7544
|
});
|
|
7082
7545
|
var handleListArticles = async (context, params) => {
|
|
7083
7546
|
log.debug(`Listing articles on shop: ${context.shopDomain}`);
|
|
@@ -7121,8 +7584,8 @@ function registerListArticlesTool() {
|
|
|
7121
7584
|
name: "list-articles",
|
|
7122
7585
|
title: "List Articles",
|
|
7123
7586
|
description: "List articles with optional filtering and pagination. Use blogId to filter articles from a specific blog. Use query to search by title or tags. Returns article ID, title, handle, blog reference, and publish status. Useful for: finding articles to edit, auditing blog content, bulk operations. **Typical workflow:** list-blogs \u2192 list-articles \u2192 update-article. **Prerequisites:** None (optional Blog ID for filtering). **Follow-ups:** update-article, delete-article, create-article. Returns a paginated list of article summaries with a response summary.",
|
|
7124
|
-
inputSchema:
|
|
7125
|
-
outputSchema:
|
|
7587
|
+
inputSchema: inputSchema26,
|
|
7588
|
+
outputSchema: outputSchema26,
|
|
7126
7589
|
category: "content",
|
|
7127
7590
|
relationships: {
|
|
7128
7591
|
relatedTools: ["list-blogs", "create-article", "update-article"],
|
|
@@ -7141,29 +7604,29 @@ function registerListArticlesTool() {
|
|
|
7141
7604
|
}
|
|
7142
7605
|
|
|
7143
7606
|
// src/tools/list-blogs.ts
|
|
7144
|
-
import { z as
|
|
7145
|
-
var
|
|
7146
|
-
first:
|
|
7147
|
-
cursor:
|
|
7607
|
+
import { z as z29 } from "zod";
|
|
7608
|
+
var inputSchema27 = z29.object({
|
|
7609
|
+
first: z29.number().int().min(1).max(50).optional().default(10).describe("Number of blogs to return (1-50). Defaults to 10."),
|
|
7610
|
+
cursor: z29.string().optional().describe(
|
|
7148
7611
|
"Pagination cursor from a previous response. Use the endCursor from the previous response to get the next page of results."
|
|
7149
7612
|
),
|
|
7150
|
-
query:
|
|
7613
|
+
query: z29.string().optional().describe(
|
|
7151
7614
|
"Search query to filter blogs. Supports Shopify search syntax. Examples: 'title:News', 'handle:company-blog'."
|
|
7152
7615
|
),
|
|
7153
|
-
sortKey:
|
|
7616
|
+
sortKey: z29.enum(["ID", "TITLE", "UPDATED_AT"]).optional().describe("Sort order for results. Defaults to ID.")
|
|
7154
7617
|
});
|
|
7155
|
-
var
|
|
7156
|
-
blogs:
|
|
7157
|
-
|
|
7158
|
-
id:
|
|
7159
|
-
title:
|
|
7160
|
-
handle:
|
|
7161
|
-
commentPolicy:
|
|
7162
|
-
articlesCount:
|
|
7618
|
+
var outputSchema27 = z29.object({
|
|
7619
|
+
blogs: z29.array(
|
|
7620
|
+
z29.object({
|
|
7621
|
+
id: z29.string().describe("Blog GID"),
|
|
7622
|
+
title: z29.string().describe("Blog title"),
|
|
7623
|
+
handle: z29.string().describe("URL handle/slug"),
|
|
7624
|
+
commentPolicy: z29.enum(["CLOSED", "MODERATE", "OPEN"]).describe("Comment moderation policy"),
|
|
7625
|
+
articlesCount: z29.number().describe("Number of articles in the blog")
|
|
7163
7626
|
})
|
|
7164
7627
|
),
|
|
7165
|
-
hasNextPage:
|
|
7166
|
-
endCursor:
|
|
7628
|
+
hasNextPage: z29.boolean().describe("Whether more blogs are available"),
|
|
7629
|
+
endCursor: z29.string().nullable().describe("Cursor for next page pagination")
|
|
7167
7630
|
});
|
|
7168
7631
|
var handleListBlogs = async (context, params) => {
|
|
7169
7632
|
log.debug(`Listing blogs on shop: ${context.shopDomain}`);
|
|
@@ -7201,8 +7664,8 @@ function registerListBlogsTool() {
|
|
|
7201
7664
|
name: "list-blogs",
|
|
7202
7665
|
title: "List Blogs",
|
|
7203
7666
|
description: "List all blogs with optional filtering and pagination. Use the query parameter to search blogs by title or handle. Returns blog ID, title, handle, and article count. Useful for: finding blogs to manage, auditing content, selecting a blog for new articles. **Typical workflow:** list-blogs \u2192 list-articles. **Prerequisites:** None. **Follow-ups:** create-article, update-blog, create-blog. Returns a paginated list of blog summaries with a response summary.",
|
|
7204
|
-
inputSchema:
|
|
7205
|
-
outputSchema:
|
|
7667
|
+
inputSchema: inputSchema27,
|
|
7668
|
+
outputSchema: outputSchema27,
|
|
7206
7669
|
category: "content",
|
|
7207
7670
|
relationships: {
|
|
7208
7671
|
relatedTools: ["create-blog", "update-blog", "list-articles"],
|
|
@@ -7221,40 +7684,40 @@ function registerListBlogsTool() {
|
|
|
7221
7684
|
}
|
|
7222
7685
|
|
|
7223
7686
|
// src/tools/list-collections.ts
|
|
7224
|
-
import { z as
|
|
7225
|
-
var
|
|
7226
|
-
first:
|
|
7227
|
-
after:
|
|
7687
|
+
import { z as z30 } from "zod";
|
|
7688
|
+
var inputSchema28 = z30.object({
|
|
7689
|
+
first: z30.number().int().min(1).max(50).optional().default(10).describe("Number of collections to return (1-50). Default: 10"),
|
|
7690
|
+
after: z30.string().optional().describe(
|
|
7228
7691
|
"Pagination cursor from previous response. Use the endCursor value from the previous page to get the next page of results."
|
|
7229
7692
|
),
|
|
7230
|
-
query:
|
|
7693
|
+
query: z30.string().optional().describe(
|
|
7231
7694
|
'Search query to filter collections. Searches across collection titles and handles. Example: "summer" finds collections with "summer" in the title or handle.'
|
|
7232
7695
|
),
|
|
7233
|
-
sortKey:
|
|
7696
|
+
sortKey: z30.enum(["TITLE", "UPDATED_AT", "ID", "RELEVANCE"]).optional().describe(
|
|
7234
7697
|
"Sort collections by: TITLE (alphabetical), UPDATED_AT (most recently updated first), ID (by collection ID), or RELEVANCE (best match when using query filter)"
|
|
7235
7698
|
)
|
|
7236
7699
|
});
|
|
7237
|
-
var
|
|
7238
|
-
collections:
|
|
7239
|
-
|
|
7240
|
-
id:
|
|
7241
|
-
title:
|
|
7242
|
-
handle:
|
|
7243
|
-
seo:
|
|
7244
|
-
title:
|
|
7245
|
-
description:
|
|
7700
|
+
var outputSchema28 = z30.object({
|
|
7701
|
+
collections: z30.array(
|
|
7702
|
+
z30.object({
|
|
7703
|
+
id: z30.string().describe("Collection GID"),
|
|
7704
|
+
title: z30.string().describe("Collection title"),
|
|
7705
|
+
handle: z30.string().describe("URL handle"),
|
|
7706
|
+
seo: z30.object({
|
|
7707
|
+
title: z30.string().nullable().describe("SEO title"),
|
|
7708
|
+
description: z30.string().nullable().describe("SEO description")
|
|
7246
7709
|
}),
|
|
7247
|
-
productsCount:
|
|
7710
|
+
productsCount: z30.number().describe("Number of products in collection")
|
|
7248
7711
|
})
|
|
7249
7712
|
),
|
|
7250
|
-
pageInfo:
|
|
7251
|
-
hasNextPage:
|
|
7252
|
-
endCursor:
|
|
7713
|
+
pageInfo: z30.object({
|
|
7714
|
+
hasNextPage: z30.boolean().describe("Whether more pages exist"),
|
|
7715
|
+
endCursor: z30.string().nullable().describe("Cursor for next page")
|
|
7253
7716
|
}),
|
|
7254
|
-
summary:
|
|
7255
|
-
totalReturned:
|
|
7256
|
-
hasMore:
|
|
7257
|
-
hint:
|
|
7717
|
+
summary: z30.object({
|
|
7718
|
+
totalReturned: z30.number().describe("Number of collections in this response"),
|
|
7719
|
+
hasMore: z30.boolean().describe("Whether more collections are available"),
|
|
7720
|
+
hint: z30.string().describe("Suggestion for next action")
|
|
7258
7721
|
}).describe("AI-friendly summary for context management")
|
|
7259
7722
|
});
|
|
7260
7723
|
var handleListCollections = async (context, params) => {
|
|
@@ -7281,8 +7744,8 @@ function registerListCollectionsTool() {
|
|
|
7281
7744
|
name: "list-collections",
|
|
7282
7745
|
title: "List Collections",
|
|
7283
7746
|
description: 'List and search collections with pagination and filtering. Use the query parameter for text search across collection titles and handles. Supports sorting by TITLE, UPDATED_AT, ID, or RELEVANCE. Returns up to 50 collections per page. Response includes summary with totalReturned, hasMore, and pagination hint. **Pagination:** Use "after" cursor from pageInfo.endCursor to get next page. **Follow-ups:** get-collection (for full details), update-collection, add-products-to-collection.',
|
|
7284
|
-
inputSchema:
|
|
7285
|
-
outputSchema:
|
|
7747
|
+
inputSchema: inputSchema28,
|
|
7748
|
+
outputSchema: outputSchema28,
|
|
7286
7749
|
// AI Agent Optimization (Story 5.5)
|
|
7287
7750
|
category: "collection",
|
|
7288
7751
|
relationships: {
|
|
@@ -7302,47 +7765,47 @@ function registerListCollectionsTool() {
|
|
|
7302
7765
|
}
|
|
7303
7766
|
|
|
7304
7767
|
// src/tools/list-low-inventory.ts
|
|
7305
|
-
import { z as
|
|
7306
|
-
var
|
|
7307
|
-
threshold:
|
|
7768
|
+
import { z as z31 } from "zod";
|
|
7769
|
+
var inputSchema29 = z31.object({
|
|
7770
|
+
threshold: z31.number().int().min(0).default(10).describe(
|
|
7308
7771
|
"Products with total inventory at or below this number will be included. Default: 10. Use 0 to find only out-of-stock products."
|
|
7309
7772
|
),
|
|
7310
|
-
includeZero:
|
|
7773
|
+
includeZero: z31.boolean().default(true).describe(
|
|
7311
7774
|
"Include products with zero inventory. Default: true. Set to false to see only low-stock (not out-of-stock) products."
|
|
7312
7775
|
),
|
|
7313
|
-
status:
|
|
7776
|
+
status: z31.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).optional().describe(
|
|
7314
7777
|
"Filter by product status. Default: ACTIVE. Use DRAFT to check pre-launch products, ARCHIVED for historical."
|
|
7315
7778
|
),
|
|
7316
|
-
first:
|
|
7317
|
-
after:
|
|
7779
|
+
first: z31.number().int().min(1).max(100).default(50).describe("Number of products to return per page. Default: 50, max: 100."),
|
|
7780
|
+
after: z31.string().optional().describe("Pagination cursor from previous response. Use pageInfo.endCursor to get next page.")
|
|
7318
7781
|
});
|
|
7319
|
-
var
|
|
7320
|
-
products:
|
|
7321
|
-
|
|
7322
|
-
productId:
|
|
7323
|
-
productTitle:
|
|
7324
|
-
status:
|
|
7325
|
-
totalInventory:
|
|
7326
|
-
isOutOfStock:
|
|
7327
|
-
variants:
|
|
7328
|
-
|
|
7329
|
-
variantId:
|
|
7330
|
-
variantTitle:
|
|
7331
|
-
sku:
|
|
7332
|
-
inventoryItemId:
|
|
7333
|
-
available:
|
|
7782
|
+
var outputSchema29 = z31.object({
|
|
7783
|
+
products: z31.array(
|
|
7784
|
+
z31.object({
|
|
7785
|
+
productId: z31.string().describe('Product GID (e.g., "gid://shopify/Product/123")'),
|
|
7786
|
+
productTitle: z31.string().describe("Product title"),
|
|
7787
|
+
status: z31.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).describe("Product status"),
|
|
7788
|
+
totalInventory: z31.number().describe("Total inventory across all variants"),
|
|
7789
|
+
isOutOfStock: z31.boolean().describe("True if total inventory is zero"),
|
|
7790
|
+
variants: z31.array(
|
|
7791
|
+
z31.object({
|
|
7792
|
+
variantId: z31.string().describe("Variant GID"),
|
|
7793
|
+
variantTitle: z31.string().describe('Variant title (e.g., "Red / Large")'),
|
|
7794
|
+
sku: z31.string().nullable().describe("SKU (Stock Keeping Unit)"),
|
|
7795
|
+
inventoryItemId: z31.string().describe("Inventory item GID"),
|
|
7796
|
+
available: z31.number().describe("Available quantity for sale")
|
|
7334
7797
|
})
|
|
7335
7798
|
).describe("Variant breakdown with inventory")
|
|
7336
7799
|
})
|
|
7337
7800
|
).describe("Products with low inventory, sorted by total inventory ascending"),
|
|
7338
|
-
pageInfo:
|
|
7339
|
-
hasNextPage:
|
|
7340
|
-
endCursor:
|
|
7801
|
+
pageInfo: z31.object({
|
|
7802
|
+
hasNextPage: z31.boolean().describe("Whether more products exist after this page"),
|
|
7803
|
+
endCursor: z31.string().nullable().describe('Cursor for the last item - use as "after" to get next page')
|
|
7341
7804
|
}).describe("Pagination information"),
|
|
7342
|
-
summary:
|
|
7343
|
-
totalProducts:
|
|
7344
|
-
outOfStockCount:
|
|
7345
|
-
lowStockCount:
|
|
7805
|
+
summary: z31.object({
|
|
7806
|
+
totalProducts: z31.number().describe("Number of products in this response"),
|
|
7807
|
+
outOfStockCount: z31.number().describe("Number of products with zero inventory"),
|
|
7808
|
+
lowStockCount: z31.number().describe("Number of products with inventory > 0 but below threshold")
|
|
7346
7809
|
}).describe("Summary statistics")
|
|
7347
7810
|
});
|
|
7348
7811
|
var handleListLowInventory = async (context, params) => {
|
|
@@ -7366,8 +7829,8 @@ function registerListLowInventoryTool() {
|
|
|
7366
7829
|
name: "list-low-inventory",
|
|
7367
7830
|
title: "List Low Inventory",
|
|
7368
7831
|
description: 'Find products with low or zero inventory that may need restocking. Returns products sorted by inventory level (lowest first). Use threshold parameter to customize what counts as "low stock" (default: 10 units). Includes variant breakdown and summary statistics showing how many products are out-of-stock vs. low-stock. Perfect for daily inventory checks, restocking alerts, and identifying products at risk of stockout. Use includeZero=false to exclude completely sold-out items. Use status=DRAFT to check pre-launch products before publishing. **Typical workflow:** list-low-inventory \u2192 get-inventory \u2192 update-inventory. **Prerequisites:** None. **Follow-ups:** get-inventory, update-inventory. Returns paginated products with inventory levels and summary statistics.',
|
|
7369
|
-
inputSchema:
|
|
7370
|
-
outputSchema:
|
|
7832
|
+
inputSchema: inputSchema29,
|
|
7833
|
+
outputSchema: outputSchema29,
|
|
7371
7834
|
category: "inventory",
|
|
7372
7835
|
relationships: {
|
|
7373
7836
|
relatedTools: ["get-inventory", "update-inventory", "get-bulk-inventory"],
|
|
@@ -7385,32 +7848,106 @@ function registerListLowInventoryTool() {
|
|
|
7385
7848
|
);
|
|
7386
7849
|
}
|
|
7387
7850
|
|
|
7851
|
+
// src/tools/list-markets.ts
|
|
7852
|
+
import { z as z32 } from "zod";
|
|
7853
|
+
var inputSchema30 = z32.object({
|
|
7854
|
+
first: z32.number().int().min(1).max(50).optional().default(10).describe("Number of markets to return (1-50). Default: 10"),
|
|
7855
|
+
after: z32.string().optional().describe(
|
|
7856
|
+
"Pagination cursor from previous response. Use the endCursor value from the previous page to get the next page of results."
|
|
7857
|
+
)
|
|
7858
|
+
});
|
|
7859
|
+
var outputSchema30 = z32.object({
|
|
7860
|
+
markets: z32.array(
|
|
7861
|
+
z32.object({
|
|
7862
|
+
id: z32.string().describe("Market GID"),
|
|
7863
|
+
name: z32.string().describe("Market name (not shown to customers)"),
|
|
7864
|
+
handle: z32.string().describe("URL handle"),
|
|
7865
|
+
enabled: z32.boolean().describe("Whether the market is enabled"),
|
|
7866
|
+
status: z32.enum(["ACTIVE", "INACTIVE"]).describe("Market status"),
|
|
7867
|
+
type: z32.string().describe("Market type (PRIMARY, SINGLE_COUNTRY, MULTI_COUNTRY, CONTINENT)"),
|
|
7868
|
+
currencySettings: z32.object({
|
|
7869
|
+
baseCurrency: z32.object({
|
|
7870
|
+
currencyCode: z32.string().describe("Base currency code (e.g., USD, EUR)")
|
|
7871
|
+
}),
|
|
7872
|
+
localCurrencies: z32.boolean().describe("Whether local currencies are enabled")
|
|
7873
|
+
}).optional()
|
|
7874
|
+
})
|
|
7875
|
+
),
|
|
7876
|
+
pageInfo: z32.object({
|
|
7877
|
+
hasNextPage: z32.boolean().describe("Whether more pages exist"),
|
|
7878
|
+
endCursor: z32.string().nullable().describe("Cursor for next page")
|
|
7879
|
+
}),
|
|
7880
|
+
summary: z32.object({
|
|
7881
|
+
totalReturned: z32.number().describe("Number of markets in this response"),
|
|
7882
|
+
hasMore: z32.boolean().describe("Whether more markets are available"),
|
|
7883
|
+
hint: z32.string().describe("Suggestion for next action")
|
|
7884
|
+
}).describe("AI-friendly summary for context management")
|
|
7885
|
+
});
|
|
7886
|
+
var handleListMarkets = async (context, params) => {
|
|
7887
|
+
log.debug(`Listing markets on shop: ${context.shopDomain}`);
|
|
7888
|
+
const result = await listMarkets(params.first, params.after);
|
|
7889
|
+
log.debug(`Listed ${result.markets.length} markets via tool`);
|
|
7890
|
+
return {
|
|
7891
|
+
...result,
|
|
7892
|
+
summary: {
|
|
7893
|
+
totalReturned: result.markets.length,
|
|
7894
|
+
hasMore: result.pageInfo.hasNextPage,
|
|
7895
|
+
hint: result.pageInfo.hasNextPage ? `Use "after" parameter with value "${result.pageInfo.endCursor}" to fetch next page` : "All markets returned"
|
|
7896
|
+
}
|
|
7897
|
+
};
|
|
7898
|
+
};
|
|
7899
|
+
function registerListMarketsTool() {
|
|
7900
|
+
registerContextAwareTool(
|
|
7901
|
+
{
|
|
7902
|
+
name: "list-markets",
|
|
7903
|
+
title: "List Markets",
|
|
7904
|
+
description: 'List all configured markets in the Shopify store with pagination. Markets enable regional targeting for international stores. Returns market id, name, handle, status, type, and currency settings. Response includes summary with totalReturned, hasMore, and pagination hint. **Pagination:** Use "after" cursor from pageInfo.endCursor to get next page. **Prerequisites:** Store must have Markets feature enabled. **Follow-ups:** get-market (for full details including web presences), create-market.',
|
|
7905
|
+
inputSchema: inputSchema30,
|
|
7906
|
+
outputSchema: outputSchema30,
|
|
7907
|
+
// AI Agent Optimization
|
|
7908
|
+
category: "market",
|
|
7909
|
+
relationships: {
|
|
7910
|
+
relatedTools: ["get-market"],
|
|
7911
|
+
followUps: ["get-market", "create-market", "update-market"]
|
|
7912
|
+
},
|
|
7913
|
+
// MCP Tool Annotations (Epic 9.5 - MCP Best Practices)
|
|
7914
|
+
annotations: {
|
|
7915
|
+
readOnlyHint: true,
|
|
7916
|
+
destructiveHint: false,
|
|
7917
|
+
idempotentHint: true,
|
|
7918
|
+
openWorldHint: true
|
|
7919
|
+
}
|
|
7920
|
+
},
|
|
7921
|
+
handleListMarkets
|
|
7922
|
+
);
|
|
7923
|
+
}
|
|
7924
|
+
|
|
7388
7925
|
// src/tools/list-pages.ts
|
|
7389
|
-
import { z as
|
|
7390
|
-
var
|
|
7391
|
-
first:
|
|
7926
|
+
import { z as z33 } from "zod";
|
|
7927
|
+
var inputSchema31 = z33.object({
|
|
7928
|
+
first: z33.number().int().min(1).max(50).optional().describe(
|
|
7392
7929
|
"Number of pages to return per request. Default: 10, Maximum: 50. Use pagination (cursor) to retrieve more results."
|
|
7393
7930
|
),
|
|
7394
|
-
cursor:
|
|
7931
|
+
cursor: z33.string().optional().describe(
|
|
7395
7932
|
"Pagination cursor from a previous list-pages response (endCursor). Use this to get the next page of results."
|
|
7396
7933
|
),
|
|
7397
|
-
query:
|
|
7934
|
+
query: z33.string().optional().describe(
|
|
7398
7935
|
"Search query to filter pages. Supports Shopify search syntax. Examples: 'title:About', 'handle:contact', 'created_at:>2024-01-01'."
|
|
7399
7936
|
),
|
|
7400
|
-
sortKey:
|
|
7937
|
+
sortKey: z33.enum(["ID", "TITLE", "UPDATED_AT", "PUBLISHED_AT"]).optional().describe("Field to sort pages by. Options: ID (default), TITLE, UPDATED_AT, PUBLISHED_AT.")
|
|
7401
7938
|
});
|
|
7402
|
-
var
|
|
7403
|
-
pages:
|
|
7404
|
-
|
|
7405
|
-
id:
|
|
7406
|
-
title:
|
|
7407
|
-
handle:
|
|
7408
|
-
isPublished:
|
|
7409
|
-
updatedAt:
|
|
7939
|
+
var outputSchema31 = z33.object({
|
|
7940
|
+
pages: z33.array(
|
|
7941
|
+
z33.object({
|
|
7942
|
+
id: z33.string().describe("Page GID"),
|
|
7943
|
+
title: z33.string().describe("Page title"),
|
|
7944
|
+
handle: z33.string().describe("URL handle/slug"),
|
|
7945
|
+
isPublished: z33.boolean().describe("Whether page is visible"),
|
|
7946
|
+
updatedAt: z33.string().describe("ISO timestamp of last update")
|
|
7410
7947
|
})
|
|
7411
7948
|
),
|
|
7412
|
-
hasNextPage:
|
|
7413
|
-
endCursor:
|
|
7949
|
+
hasNextPage: z33.boolean().describe("Whether more pages exist"),
|
|
7950
|
+
endCursor: z33.string().nullable().describe("Cursor for next page of results")
|
|
7414
7951
|
});
|
|
7415
7952
|
var handleListPages = async (context, params) => {
|
|
7416
7953
|
log.debug(`Listing pages on shop: ${context.shopDomain}`);
|
|
@@ -7436,8 +7973,8 @@ function registerListPagesTool() {
|
|
|
7436
7973
|
name: "list-pages",
|
|
7437
7974
|
title: "List Pages",
|
|
7438
7975
|
description: "List all pages with optional filtering and pagination. Use the query parameter to search pages by title or handle. Returns page ID, title, handle, and publish status. Use pagination (cursor) for stores with many pages. Useful for: finding pages to edit, auditing content, bulk operations. **Typical workflow:** list-pages \u2192 get-page. **Prerequisites:** None. **Follow-ups:** get-page, update-page, create-page. Returns a paginated list of page summaries with a response summary.",
|
|
7439
|
-
inputSchema:
|
|
7440
|
-
outputSchema:
|
|
7976
|
+
inputSchema: inputSchema31,
|
|
7977
|
+
outputSchema: outputSchema31,
|
|
7441
7978
|
category: "content",
|
|
7442
7979
|
relationships: {
|
|
7443
7980
|
relatedTools: ["get-page", "create-page"],
|
|
@@ -7456,46 +7993,46 @@ function registerListPagesTool() {
|
|
|
7456
7993
|
}
|
|
7457
7994
|
|
|
7458
7995
|
// src/tools/list-products.ts
|
|
7459
|
-
import { z as
|
|
7460
|
-
var
|
|
7461
|
-
first:
|
|
7462
|
-
after:
|
|
7463
|
-
query:
|
|
7996
|
+
import { z as z34 } from "zod";
|
|
7997
|
+
var inputSchema32 = z34.object({
|
|
7998
|
+
first: z34.number().int().min(1).max(50).optional().describe("Number of products to return (1-50). Default: 10"),
|
|
7999
|
+
after: z34.string().optional().describe("Pagination cursor from previous response's endCursor. Omit for first page."),
|
|
8000
|
+
query: z34.string().optional().describe(
|
|
7464
8001
|
'Search query for title, description, tags. Example: "summer dress", "organic cotton"'
|
|
7465
8002
|
),
|
|
7466
|
-
status:
|
|
8003
|
+
status: z34.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).optional().describe(
|
|
7467
8004
|
"Filter by product status. ACTIVE = published, DRAFT = not published, ARCHIVED = hidden"
|
|
7468
8005
|
),
|
|
7469
|
-
vendor:
|
|
7470
|
-
productType:
|
|
7471
|
-
sortBy:
|
|
7472
|
-
sortOrder:
|
|
8006
|
+
vendor: z34.string().optional().describe('Filter by exact vendor name. Example: "Acme Corp", "Nike"'),
|
|
8007
|
+
productType: z34.string().optional().describe('Filter by exact product type. Example: "T-Shirts", "Shoes"'),
|
|
8008
|
+
sortBy: z34.enum(["TITLE", "CREATED_AT", "UPDATED_AT", "INVENTORY_TOTAL"]).optional().describe("Sort field. TITLE, CREATED_AT (default), UPDATED_AT, or INVENTORY_TOTAL"),
|
|
8009
|
+
sortOrder: z34.enum(["ASC", "DESC"]).optional().describe("Sort direction. ASC (default) for ascending, DESC for descending")
|
|
7473
8010
|
});
|
|
7474
|
-
var
|
|
7475
|
-
products:
|
|
7476
|
-
|
|
7477
|
-
id:
|
|
7478
|
-
title:
|
|
7479
|
-
handle:
|
|
7480
|
-
status:
|
|
7481
|
-
vendor:
|
|
7482
|
-
productType:
|
|
7483
|
-
totalInventory:
|
|
7484
|
-
primaryVariantPrice:
|
|
7485
|
-
imageUrl:
|
|
8011
|
+
var outputSchema32 = z34.object({
|
|
8012
|
+
products: z34.array(
|
|
8013
|
+
z34.object({
|
|
8014
|
+
id: z34.string().describe('Product GID (e.g., "gid://shopify/Product/123")'),
|
|
8015
|
+
title: z34.string().describe("Product title"),
|
|
8016
|
+
handle: z34.string().describe("URL handle/slug"),
|
|
8017
|
+
status: z34.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).describe("Product status"),
|
|
8018
|
+
vendor: z34.string().describe("Vendor/brand name"),
|
|
8019
|
+
productType: z34.string().describe("Product type"),
|
|
8020
|
+
totalInventory: z34.number().describe("Total inventory across all variants"),
|
|
8021
|
+
primaryVariantPrice: z34.string().describe('Price of the first variant (e.g., "29.99")'),
|
|
8022
|
+
imageUrl: z34.string().nullable().describe("First image URL or null if no images")
|
|
7486
8023
|
})
|
|
7487
8024
|
).describe("Array of product summaries"),
|
|
7488
|
-
pageInfo:
|
|
7489
|
-
hasNextPage:
|
|
7490
|
-
hasPreviousPage:
|
|
7491
|
-
startCursor:
|
|
7492
|
-
endCursor:
|
|
8025
|
+
pageInfo: z34.object({
|
|
8026
|
+
hasNextPage: z34.boolean().describe("Whether more products exist after this page"),
|
|
8027
|
+
hasPreviousPage: z34.boolean().describe("Whether products exist before this page"),
|
|
8028
|
+
startCursor: z34.string().nullable().describe("Cursor for the first item in this page"),
|
|
8029
|
+
endCursor: z34.string().nullable().describe('Cursor for the last item - use as "after" to get next page')
|
|
7493
8030
|
}).describe("Pagination information"),
|
|
7494
|
-
totalCount:
|
|
7495
|
-
summary:
|
|
7496
|
-
totalReturned:
|
|
7497
|
-
hasMore:
|
|
7498
|
-
hint:
|
|
8031
|
+
totalCount: z34.number().describe("Number of products returned in this page"),
|
|
8032
|
+
summary: z34.object({
|
|
8033
|
+
totalReturned: z34.number().describe("Number of products in this response"),
|
|
8034
|
+
hasMore: z34.boolean().describe("Whether more products are available"),
|
|
8035
|
+
hint: z34.string().describe("Suggestion for next action")
|
|
7499
8036
|
}).describe("AI-friendly summary for context management")
|
|
7500
8037
|
});
|
|
7501
8038
|
var handleListProducts = async (context, params) => {
|
|
@@ -7529,8 +8066,8 @@ function registerListProductsTool() {
|
|
|
7529
8066
|
name: "list-products",
|
|
7530
8067
|
title: "List Products",
|
|
7531
8068
|
description: 'List products from the Shopify store with pagination and filtering. Returns product summaries including title, status, vendor, type, price, and inventory. Supports filtering by status (ACTIVE/DRAFT/ARCHIVED), vendor, productType, and search query. Sort by TITLE, CREATED_AT, UPDATED_AT, or INVENTORY_TOTAL. Response includes summary with totalReturned, hasMore, and pagination hint. **Pagination:** Use "after" cursor from pageInfo.endCursor to get next page. **Follow-ups:** get-product (for full details), update-product, delete-product.',
|
|
7532
|
-
inputSchema:
|
|
7533
|
-
outputSchema:
|
|
8069
|
+
inputSchema: inputSchema32,
|
|
8070
|
+
outputSchema: outputSchema32,
|
|
7534
8071
|
// AI Agent Optimization (Story 5.5)
|
|
7535
8072
|
category: "product",
|
|
7536
8073
|
relationships: {
|
|
@@ -7550,30 +8087,30 @@ function registerListProductsTool() {
|
|
|
7550
8087
|
}
|
|
7551
8088
|
|
|
7552
8089
|
// src/tools/list-redirects.ts
|
|
7553
|
-
import { z as
|
|
7554
|
-
var
|
|
7555
|
-
first:
|
|
7556
|
-
cursor:
|
|
8090
|
+
import { z as z35 } from "zod";
|
|
8091
|
+
var inputSchema33 = z35.object({
|
|
8092
|
+
first: z35.number().int().min(1).max(50).optional().default(10).describe("Number of redirects to return (1-50, default: 10)."),
|
|
8093
|
+
cursor: z35.string().optional().describe(
|
|
7557
8094
|
"Pagination cursor from previous response (endCursor). Use this to fetch the next page of results."
|
|
7558
8095
|
),
|
|
7559
|
-
query:
|
|
8096
|
+
query: z35.string().optional().describe(
|
|
7560
8097
|
"Search filter. Supports 'path:' and 'target:' prefixes. Examples: 'path:/old-' to find redirects starting with /old-, 'target:/products/' to find redirects pointing to /products/."
|
|
7561
8098
|
)
|
|
7562
8099
|
});
|
|
7563
|
-
var
|
|
7564
|
-
redirects:
|
|
7565
|
-
|
|
7566
|
-
id:
|
|
7567
|
-
path:
|
|
7568
|
-
target:
|
|
8100
|
+
var outputSchema33 = z35.object({
|
|
8101
|
+
redirects: z35.array(
|
|
8102
|
+
z35.object({
|
|
8103
|
+
id: z35.string().describe("Redirect GID"),
|
|
8104
|
+
path: z35.string().describe("Source path"),
|
|
8105
|
+
target: z35.string().describe("Target URL")
|
|
7569
8106
|
})
|
|
7570
8107
|
),
|
|
7571
|
-
hasNextPage:
|
|
7572
|
-
endCursor:
|
|
7573
|
-
summary:
|
|
7574
|
-
totalReturned:
|
|
7575
|
-
hasMore:
|
|
7576
|
-
hint:
|
|
8108
|
+
hasNextPage: z35.boolean().describe("Whether more results exist"),
|
|
8109
|
+
endCursor: z35.string().nullable().describe("Cursor for fetching next page"),
|
|
8110
|
+
summary: z35.object({
|
|
8111
|
+
totalReturned: z35.number().describe("Number of redirects in this response"),
|
|
8112
|
+
hasMore: z35.boolean().describe("Whether more redirects are available"),
|
|
8113
|
+
hint: z35.string().describe("Suggestion for next action")
|
|
7577
8114
|
}).describe("AI-friendly summary for context management")
|
|
7578
8115
|
});
|
|
7579
8116
|
var handleListRedirects = async (context, params) => {
|
|
@@ -7611,8 +8148,8 @@ function registerListRedirectsTool() {
|
|
|
7611
8148
|
name: "list-redirects",
|
|
7612
8149
|
title: "List URL Redirects",
|
|
7613
8150
|
description: `List all URL redirects with optional filtering and pagination. Use query parameter to search by path or target (supports 'path:' and 'target:' prefixes). Response includes summary with totalReturned, hasMore, and pagination hint. **Pagination:** Use "cursor" with endCursor value to get next page. **Follow-ups:** delete-redirect to remove unwanted redirects.`,
|
|
7614
|
-
inputSchema:
|
|
7615
|
-
outputSchema:
|
|
8151
|
+
inputSchema: inputSchema33,
|
|
8152
|
+
outputSchema: outputSchema33,
|
|
7616
8153
|
// AI Agent Optimization (Story 5.5)
|
|
7617
8154
|
category: "seo",
|
|
7618
8155
|
relationships: {
|
|
@@ -7632,18 +8169,18 @@ function registerListRedirectsTool() {
|
|
|
7632
8169
|
}
|
|
7633
8170
|
|
|
7634
8171
|
// src/tools/remove-products-from-collection.ts
|
|
7635
|
-
import { z as
|
|
7636
|
-
var
|
|
8172
|
+
import { z as z36 } from "zod";
|
|
8173
|
+
var inputSchema34 = z36.object({
|
|
7637
8174
|
collectionId: collectionIdSchema.describe(
|
|
7638
8175
|
'Collection GID (e.g., "gid://shopify/Collection/123"). Use list-collections to find valid collection IDs.'
|
|
7639
8176
|
),
|
|
7640
|
-
productIds:
|
|
8177
|
+
productIds: z36.array(productIdSchema).min(1).max(250).describe(
|
|
7641
8178
|
'Array of product GIDs to remove (e.g., ["gid://shopify/Product/123", "gid://shopify/Product/456"]). Maximum 250 products per call. Use list-products to find valid product IDs.'
|
|
7642
8179
|
)
|
|
7643
8180
|
});
|
|
7644
|
-
var
|
|
7645
|
-
success:
|
|
7646
|
-
removedCount:
|
|
8181
|
+
var outputSchema34 = z36.object({
|
|
8182
|
+
success: z36.boolean().describe("Whether the operation succeeded"),
|
|
8183
|
+
removedCount: z36.number().describe("Number of products removed from the collection")
|
|
7647
8184
|
});
|
|
7648
8185
|
var handleRemoveProductsFromCollection = async (context, params) => {
|
|
7649
8186
|
log.debug(
|
|
@@ -7673,8 +8210,8 @@ function registerRemoveProductsFromCollectionTool() {
|
|
|
7673
8210
|
name: "remove-products-from-collection",
|
|
7674
8211
|
title: "Remove Products from Collection",
|
|
7675
8212
|
description: "Remove products from a collection by their product IDs. This does NOT delete the products - they remain in the catalog but are no longer part of this collection. Maximum 250 products per call. **Prerequisites:** get-collection to verify collection contents before removing.",
|
|
7676
|
-
inputSchema:
|
|
7677
|
-
outputSchema:
|
|
8213
|
+
inputSchema: inputSchema34,
|
|
8214
|
+
outputSchema: outputSchema34,
|
|
7678
8215
|
// AI Agent Optimization (Story 5.5)
|
|
7679
8216
|
category: "collection",
|
|
7680
8217
|
relationships: {
|
|
@@ -7696,7 +8233,7 @@ function registerRemoveProductsFromCollectionTool() {
|
|
|
7696
8233
|
}
|
|
7697
8234
|
|
|
7698
8235
|
// src/tools/reorder-product-images.ts
|
|
7699
|
-
import { z as
|
|
8236
|
+
import { z as z37 } from "zod";
|
|
7700
8237
|
var PRODUCT_REORDER_MEDIA_MUTATION = `
|
|
7701
8238
|
mutation ProductReorderMedia($id: ID!, $moves: [MoveInput!]!) {
|
|
7702
8239
|
productReorderMedia(id: $id, moves: $moves) {
|
|
@@ -7711,23 +8248,23 @@ var PRODUCT_REORDER_MEDIA_MUTATION = `
|
|
|
7711
8248
|
}
|
|
7712
8249
|
}
|
|
7713
8250
|
`;
|
|
7714
|
-
var moveSchema =
|
|
8251
|
+
var moveSchema = z37.object({
|
|
7715
8252
|
id: imageIdSchema.describe('Image GID to move (e.g., "gid://shopify/MediaImage/123")'),
|
|
7716
|
-
newPosition:
|
|
8253
|
+
newPosition: z37.number().int().min(0).describe("Zero-based target position. Position 0 is the featured image.")
|
|
7717
8254
|
});
|
|
7718
|
-
var
|
|
8255
|
+
var inputSchema35 = z37.object({
|
|
7719
8256
|
productId: productIdSchema.describe(
|
|
7720
8257
|
'Shopify product GID (e.g., "gid://shopify/Product/123"). Required. Use list-products to find product IDs.'
|
|
7721
8258
|
),
|
|
7722
|
-
moves:
|
|
8259
|
+
moves: z37.array(moveSchema).min(1).describe(
|
|
7723
8260
|
"Array of move operations. Each move specifies an image ID and its new position. Only include images whose position is actually changing. Positions are 0-indexed (position 0 is the featured/hero image)."
|
|
7724
8261
|
)
|
|
7725
8262
|
});
|
|
7726
|
-
var
|
|
7727
|
-
success:
|
|
7728
|
-
jobId:
|
|
7729
|
-
jobDone:
|
|
7730
|
-
message:
|
|
8263
|
+
var outputSchema35 = z37.object({
|
|
8264
|
+
success: z37.boolean().describe("Whether the reorder operation was initiated successfully"),
|
|
8265
|
+
jobId: z37.string().nullable().describe("Background job ID for tracking (may be null if processed immediately)"),
|
|
8266
|
+
jobDone: z37.boolean().describe("Whether the job completed immediately"),
|
|
8267
|
+
message: z37.string().describe("Human-readable message describing the result")
|
|
7731
8268
|
});
|
|
7732
8269
|
var handleReorderProductImages = async (context, params) => {
|
|
7733
8270
|
log.debug(`Reordering images on shop: ${context.shopDomain}`);
|
|
@@ -7795,8 +8332,8 @@ function registerReorderProductImagesTool() {
|
|
|
7795
8332
|
name: "reorder-product-images",
|
|
7796
8333
|
title: "Reorder Product Images",
|
|
7797
8334
|
description: "Change the display order of product images. The first image (position 0) is typically the featured/hero image shown in product listings. Provide an array of move operations specifying which image IDs should move to which positions. Positions are 0-indexed. This operation runs asynchronously in Shopify's background. **Prerequisites:** get-product to obtain current image IDs and their positions.",
|
|
7798
|
-
inputSchema:
|
|
7799
|
-
outputSchema:
|
|
8335
|
+
inputSchema: inputSchema35,
|
|
8336
|
+
outputSchema: outputSchema35,
|
|
7800
8337
|
// AI Agent Optimization (Story 5.5)
|
|
7801
8338
|
category: "media",
|
|
7802
8339
|
relationships: {
|
|
@@ -7817,45 +8354,45 @@ function registerReorderProductImagesTool() {
|
|
|
7817
8354
|
}
|
|
7818
8355
|
|
|
7819
8356
|
// src/tools/set-product-metafields.ts
|
|
7820
|
-
import { z as
|
|
8357
|
+
import { z as z38 } from "zod";
|
|
7821
8358
|
var MAX_METAFIELDS_PER_CALL = 25;
|
|
7822
|
-
var metafieldInputSchema =
|
|
7823
|
-
namespace:
|
|
8359
|
+
var metafieldInputSchema = z38.object({
|
|
8360
|
+
namespace: z38.string().min(1).describe(
|
|
7824
8361
|
'Metafield namespace (grouping identifier, e.g., "custom", "seo", "my_app"). Use consistent namespaces to organize related metafields.'
|
|
7825
8362
|
),
|
|
7826
|
-
key:
|
|
8363
|
+
key: z38.string().min(1).describe(
|
|
7827
8364
|
'Metafield key (field name, e.g., "color_hex", "schema_markup"). Keys should be lowercase with underscores, unique within a namespace.'
|
|
7828
8365
|
),
|
|
7829
|
-
value:
|
|
7830
|
-
type:
|
|
8366
|
+
value: z38.string().describe("The value to store. All values are stored as strings; JSON should be stringified."),
|
|
8367
|
+
type: z38.string().min(1).describe(
|
|
7831
8368
|
'Metafield type. Required for creating new metafields. Common types: "single_line_text_field" (short text), "multi_line_text_field" (long text), "number_integer", "number_decimal", "boolean", "json", "url", "date", "date_time".'
|
|
7832
8369
|
)
|
|
7833
8370
|
});
|
|
7834
|
-
var
|
|
8371
|
+
var inputSchema36 = z38.object({
|
|
7835
8372
|
productId: productIdSchema.describe(
|
|
7836
8373
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Use get-product or list-products to find product IDs.'
|
|
7837
8374
|
),
|
|
7838
|
-
metafields:
|
|
8375
|
+
metafields: z38.array(metafieldInputSchema).min(1, "At least one metafield is required").max(
|
|
7839
8376
|
MAX_METAFIELDS_PER_CALL,
|
|
7840
8377
|
`Maximum ${MAX_METAFIELDS_PER_CALL} metafields per call. Split into multiple calls for larger batches.`
|
|
7841
8378
|
).describe(
|
|
7842
8379
|
`Array of metafields to create or update (max ${MAX_METAFIELDS_PER_CALL} per call). Existing metafields with matching namespace+key are updated; new ones are created.`
|
|
7843
8380
|
)
|
|
7844
8381
|
});
|
|
7845
|
-
var
|
|
7846
|
-
success:
|
|
7847
|
-
metafields:
|
|
7848
|
-
|
|
7849
|
-
id:
|
|
7850
|
-
namespace:
|
|
7851
|
-
key:
|
|
7852
|
-
value:
|
|
7853
|
-
type:
|
|
7854
|
-
createdAt:
|
|
7855
|
-
updatedAt:
|
|
8382
|
+
var outputSchema36 = z38.object({
|
|
8383
|
+
success: z38.boolean().describe("Whether the operation succeeded"),
|
|
8384
|
+
metafields: z38.array(
|
|
8385
|
+
z38.object({
|
|
8386
|
+
id: z38.string().describe("Metafield GID"),
|
|
8387
|
+
namespace: z38.string().describe("Metafield namespace"),
|
|
8388
|
+
key: z38.string().describe("Metafield key"),
|
|
8389
|
+
value: z38.string().describe("Metafield value"),
|
|
8390
|
+
type: z38.string().describe("Metafield type"),
|
|
8391
|
+
createdAt: z38.string().describe("Creation timestamp (ISO 8601)"),
|
|
8392
|
+
updatedAt: z38.string().describe("Last update timestamp (ISO 8601)")
|
|
7856
8393
|
})
|
|
7857
8394
|
).describe("Created or updated metafields"),
|
|
7858
|
-
count:
|
|
8395
|
+
count: z38.number().describe("Number of metafields processed")
|
|
7859
8396
|
});
|
|
7860
8397
|
var handleSetProductMetafields = async (context, params) => {
|
|
7861
8398
|
log.debug(
|
|
@@ -7891,8 +8428,8 @@ function registerSetProductMetafieldsTool() {
|
|
|
7891
8428
|
name: "set-product-metafields",
|
|
7892
8429
|
title: "Set Product Metafields",
|
|
7893
8430
|
description: `Create or update up to ${MAX_METAFIELDS_PER_CALL} metafields on a product in a single operation. Each metafield requires: namespace (grouping identifier), key (field name), value (the data), and type. Existing metafields with matching namespace+key are updated; new ones are created. Common types: single_line_text_field, multi_line_text_field, number_integer, number_decimal, boolean, json. **Typical workflow:** create-product \u2192 set-product-metafields (add custom data). **Prerequisites:** get-product to obtain product ID, optionally get-product-metafields to check existing values. **Follow-ups:** get-product-metafields to verify changes.`,
|
|
7894
|
-
inputSchema:
|
|
7895
|
-
outputSchema:
|
|
8431
|
+
inputSchema: inputSchema36,
|
|
8432
|
+
outputSchema: outputSchema36,
|
|
7896
8433
|
// AI Agent Optimization (Story 5.5)
|
|
7897
8434
|
category: "seo",
|
|
7898
8435
|
relationships: {
|
|
@@ -7914,47 +8451,47 @@ function registerSetProductMetafieldsTool() {
|
|
|
7914
8451
|
}
|
|
7915
8452
|
|
|
7916
8453
|
// src/tools/update-article.ts
|
|
7917
|
-
import { z as
|
|
7918
|
-
var
|
|
8454
|
+
import { z as z39 } from "zod";
|
|
8455
|
+
var inputSchema37 = z39.object({
|
|
7919
8456
|
id: articleIdSchema.describe(
|
|
7920
8457
|
'The article ID to update (required). Must be a valid Shopify GID format. Example: "gid://shopify/Article/12345". Use list-articles to find article IDs.'
|
|
7921
8458
|
),
|
|
7922
|
-
title:
|
|
7923
|
-
authorName:
|
|
7924
|
-
body:
|
|
7925
|
-
summary:
|
|
7926
|
-
tags:
|
|
8459
|
+
title: z39.string().optional().describe("The new title for the article. Only provided if changing the title."),
|
|
8460
|
+
authorName: z39.string().optional().describe("The new author name for the article."),
|
|
8461
|
+
body: z39.string().optional().describe("The new HTML body content of the article. Supports HTML markup for formatting."),
|
|
8462
|
+
summary: z39.string().optional().describe("A summary or excerpt of the article."),
|
|
8463
|
+
tags: z39.array(z39.string()).optional().describe(
|
|
7927
8464
|
"New tags for categorization. This replaces all existing tags. Example: ['guide', 'tutorial', 'beginner']."
|
|
7928
8465
|
),
|
|
7929
|
-
image:
|
|
7930
|
-
url:
|
|
7931
|
-
altText:
|
|
8466
|
+
image: z39.object({
|
|
8467
|
+
url: z39.string().url().describe("The URL of the featured image"),
|
|
8468
|
+
altText: z39.string().optional().describe("Alt text for accessibility")
|
|
7932
8469
|
}).optional().describe("Featured image for the article."),
|
|
7933
|
-
isPublished:
|
|
8470
|
+
isPublished: z39.boolean().optional().describe(
|
|
7934
8471
|
"Whether the article should be visible on the storefront. Set to true to publish, false to unpublish."
|
|
7935
8472
|
),
|
|
7936
|
-
publishDate:
|
|
8473
|
+
publishDate: z39.string().optional().describe(
|
|
7937
8474
|
"The date and time when the article should become visible (ISO 8601 format). Example: '2024-01-15T10:00:00Z'."
|
|
7938
8475
|
),
|
|
7939
|
-
handle:
|
|
8476
|
+
handle: z39.string().optional().describe(
|
|
7940
8477
|
"The new URL handle/slug for the article. Set redirectNewHandle to true to automatically redirect the old URL to the new one."
|
|
7941
8478
|
),
|
|
7942
|
-
templateSuffix:
|
|
8479
|
+
templateSuffix: z39.string().optional().describe(
|
|
7943
8480
|
"The suffix of the Liquid template used to render the article. For example, 'featured' would use the template 'article.featured.liquid'."
|
|
7944
8481
|
),
|
|
7945
|
-
redirectNewHandle:
|
|
8482
|
+
redirectNewHandle: z39.boolean().optional().describe(
|
|
7946
8483
|
"Whether to automatically redirect the old URL to the new handle. Set to true when changing the handle to preserve SEO and existing links."
|
|
7947
8484
|
)
|
|
7948
8485
|
});
|
|
7949
|
-
var
|
|
7950
|
-
id:
|
|
7951
|
-
title:
|
|
7952
|
-
handle:
|
|
7953
|
-
blog:
|
|
7954
|
-
id:
|
|
7955
|
-
title:
|
|
8486
|
+
var outputSchema37 = z39.object({
|
|
8487
|
+
id: z39.string().describe("Updated article GID"),
|
|
8488
|
+
title: z39.string().describe("Article title"),
|
|
8489
|
+
handle: z39.string().describe("URL handle/slug"),
|
|
8490
|
+
blog: z39.object({
|
|
8491
|
+
id: z39.string().describe("Parent blog GID"),
|
|
8492
|
+
title: z39.string().describe("Parent blog title")
|
|
7956
8493
|
}),
|
|
7957
|
-
isPublished:
|
|
8494
|
+
isPublished: z39.boolean().describe("Whether article is visible on storefront")
|
|
7958
8495
|
});
|
|
7959
8496
|
var handleUpdateArticle = async (context, params) => {
|
|
7960
8497
|
log.debug(`Updating article on shop: ${context.shopDomain}`);
|
|
@@ -8003,8 +8540,8 @@ function registerUpdateArticleTool() {
|
|
|
8003
8540
|
name: "update-article",
|
|
8004
8541
|
title: "Update Article",
|
|
8005
8542
|
description: "Update an existing article's attributes. You can update title, body content (HTML), summary, author, tags, featured image, publish status, and template suffix. Only provided fields are updated; others remain unchanged. Use redirectNewHandle: true when changing handles. Useful for: editing content, adding tags, publishing/unpublishing articles. **Typical workflow:** list-articles \u2192 update-article. **Prerequisites:** Article ID. **Follow-ups:** list-articles. Returns the updated article object.",
|
|
8006
|
-
inputSchema:
|
|
8007
|
-
outputSchema:
|
|
8543
|
+
inputSchema: inputSchema37,
|
|
8544
|
+
outputSchema: outputSchema37,
|
|
8008
8545
|
category: "content",
|
|
8009
8546
|
relationships: {
|
|
8010
8547
|
relatedTools: ["list-articles", "create-article", "delete-article"],
|
|
@@ -8024,30 +8561,30 @@ function registerUpdateArticleTool() {
|
|
|
8024
8561
|
}
|
|
8025
8562
|
|
|
8026
8563
|
// src/tools/update-blog.ts
|
|
8027
|
-
import { z as
|
|
8028
|
-
var
|
|
8564
|
+
import { z as z40 } from "zod";
|
|
8565
|
+
var inputSchema38 = z40.object({
|
|
8029
8566
|
id: blogIdSchema.describe(
|
|
8030
8567
|
'The blog ID to update (required). Must be a valid Shopify GID format. Example: "gid://shopify/Blog/12345". Use list-blogs to find blog IDs.'
|
|
8031
8568
|
),
|
|
8032
|
-
title:
|
|
8033
|
-
handle:
|
|
8569
|
+
title: z40.string().optional().describe("The new title for the blog. Only provided if changing the title."),
|
|
8570
|
+
handle: z40.string().optional().describe(
|
|
8034
8571
|
"The new URL handle/slug for the blog. Set redirectNewHandle to true to automatically redirect the old URL to the new one."
|
|
8035
8572
|
),
|
|
8036
|
-
commentPolicy:
|
|
8573
|
+
commentPolicy: z40.enum(["CLOSED", "MODERATE", "OPEN"]).optional().describe(
|
|
8037
8574
|
"Comment moderation policy for the blog. CLOSED: Comments disabled. MODERATE: Comments require approval. OPEN: Comments appear immediately."
|
|
8038
8575
|
),
|
|
8039
|
-
templateSuffix:
|
|
8576
|
+
templateSuffix: z40.string().optional().describe(
|
|
8040
8577
|
"The suffix of the Liquid template used to render the blog. For example, 'news' would use the template 'blog.news.liquid'."
|
|
8041
8578
|
),
|
|
8042
|
-
redirectNewHandle:
|
|
8579
|
+
redirectNewHandle: z40.boolean().optional().describe(
|
|
8043
8580
|
"Whether to automatically redirect the old URL to the new handle. Set to true when changing the handle to preserve SEO and existing links."
|
|
8044
8581
|
)
|
|
8045
8582
|
});
|
|
8046
|
-
var
|
|
8047
|
-
id:
|
|
8048
|
-
title:
|
|
8049
|
-
handle:
|
|
8050
|
-
commentPolicy:
|
|
8583
|
+
var outputSchema38 = z40.object({
|
|
8584
|
+
id: z40.string().describe("Updated blog GID"),
|
|
8585
|
+
title: z40.string().describe("Blog title"),
|
|
8586
|
+
handle: z40.string().describe("URL handle/slug"),
|
|
8587
|
+
commentPolicy: z40.enum(["CLOSED", "MODERATE", "OPEN"]).describe("Comment moderation policy")
|
|
8051
8588
|
});
|
|
8052
8589
|
var handleUpdateBlog = async (context, params) => {
|
|
8053
8590
|
log.debug(`Updating blog on shop: ${context.shopDomain}`);
|
|
@@ -8090,8 +8627,8 @@ function registerUpdateBlogTool() {
|
|
|
8090
8627
|
name: "update-blog",
|
|
8091
8628
|
title: "Update Blog",
|
|
8092
8629
|
description: "Update an existing blog's attributes. You can update title, handle (URL slug), comment policy (CLOSED, MODERATE, OPEN), and template suffix. Only provided fields are updated; others remain unchanged. Use redirectNewHandle: true when changing handles. Useful for: renaming blogs, changing comment settings, updating templates. **Typical workflow:** list-blogs \u2192 update-blog. **Prerequisites:** Blog ID. **Follow-ups:** list-blogs. Returns the updated blog object.",
|
|
8093
|
-
inputSchema:
|
|
8094
|
-
outputSchema:
|
|
8630
|
+
inputSchema: inputSchema38,
|
|
8631
|
+
outputSchema: outputSchema38,
|
|
8095
8632
|
category: "content",
|
|
8096
8633
|
relationships: {
|
|
8097
8634
|
relatedTools: ["list-blogs", "create-blog", "delete-blog"],
|
|
@@ -8111,21 +8648,21 @@ function registerUpdateBlogTool() {
|
|
|
8111
8648
|
}
|
|
8112
8649
|
|
|
8113
8650
|
// src/tools/update-collection.ts
|
|
8114
|
-
import { z as
|
|
8115
|
-
var
|
|
8651
|
+
import { z as z41 } from "zod";
|
|
8652
|
+
var inputSchema39 = z41.object({
|
|
8116
8653
|
collectionId: collectionIdSchema.describe(
|
|
8117
8654
|
'Collection ID to update (GID format, e.g., "gid://shopify/Collection/123"). Use list-collections or get-collection to find collection IDs.'
|
|
8118
8655
|
),
|
|
8119
|
-
title:
|
|
8120
|
-
handle:
|
|
8656
|
+
title: z41.string().min(1).optional().describe("New collection title"),
|
|
8657
|
+
handle: z41.string().optional().describe(
|
|
8121
8658
|
"New URL handle/slug. When changing, set redirectNewHandle: true to create automatic redirect from the old URL."
|
|
8122
8659
|
),
|
|
8123
|
-
descriptionHtml:
|
|
8124
|
-
seo:
|
|
8125
|
-
title:
|
|
8126
|
-
description:
|
|
8660
|
+
descriptionHtml: z41.string().optional().describe("New HTML description"),
|
|
8661
|
+
seo: z41.object({
|
|
8662
|
+
title: z41.string().optional().describe("New SEO title"),
|
|
8663
|
+
description: z41.string().optional().describe("New SEO meta description")
|
|
8127
8664
|
}).optional().describe("Updated SEO metadata"),
|
|
8128
|
-
sortOrder:
|
|
8665
|
+
sortOrder: z41.enum([
|
|
8129
8666
|
"ALPHA_ASC",
|
|
8130
8667
|
"ALPHA_DESC",
|
|
8131
8668
|
"BEST_SELLING",
|
|
@@ -8135,19 +8672,19 @@ var inputSchema35 = z37.object({
|
|
|
8135
8672
|
"PRICE_ASC",
|
|
8136
8673
|
"PRICE_DESC"
|
|
8137
8674
|
]).optional().describe("New product sort order within collection"),
|
|
8138
|
-
image:
|
|
8139
|
-
src:
|
|
8140
|
-
altText:
|
|
8675
|
+
image: z41.object({
|
|
8676
|
+
src: z41.string().url().describe("New image URL (publicly accessible)"),
|
|
8677
|
+
altText: z41.string().optional().describe("New alt text for accessibility")
|
|
8141
8678
|
}).optional().describe("New collection image"),
|
|
8142
|
-
templateSuffix:
|
|
8143
|
-
redirectNewHandle:
|
|
8679
|
+
templateSuffix: z41.string().optional().describe("New Liquid template suffix"),
|
|
8680
|
+
redirectNewHandle: z41.boolean().optional().describe(
|
|
8144
8681
|
"When changing the handle, set to true to create an automatic URL redirect from the old handle to the new one. Important for SEO to preserve link equity."
|
|
8145
8682
|
)
|
|
8146
8683
|
});
|
|
8147
|
-
var
|
|
8148
|
-
id:
|
|
8149
|
-
title:
|
|
8150
|
-
handle:
|
|
8684
|
+
var outputSchema39 = z41.object({
|
|
8685
|
+
id: z41.string().describe("Updated collection GID"),
|
|
8686
|
+
title: z41.string().describe("Collection title"),
|
|
8687
|
+
handle: z41.string().describe("Collection URL handle")
|
|
8151
8688
|
});
|
|
8152
8689
|
var handleUpdateCollection = async (context, params) => {
|
|
8153
8690
|
log.debug(`Updating collection on shop: ${context.shopDomain}`);
|
|
@@ -8186,8 +8723,8 @@ function registerUpdateCollectionTool() {
|
|
|
8186
8723
|
name: "update-collection",
|
|
8187
8724
|
title: "Update Collection",
|
|
8188
8725
|
description: "Update an existing collection's attributes. Any field can be updated including title, handle, description, SEO fields, sort order, and image. When changing the handle, set redirectNewHandle: true for automatic URL redirect (important for SEO). Only provided fields are modified; omitted fields remain unchanged. **Prerequisites:** get-collection to view current values before updating. **Follow-ups:** add-products-to-collection, remove-products-from-collection.",
|
|
8189
|
-
inputSchema:
|
|
8190
|
-
outputSchema:
|
|
8726
|
+
inputSchema: inputSchema39,
|
|
8727
|
+
outputSchema: outputSchema39,
|
|
8191
8728
|
// AI Agent Optimization (Story 5.5)
|
|
8192
8729
|
category: "collection",
|
|
8193
8730
|
relationships: {
|
|
@@ -8209,8 +8746,8 @@ function registerUpdateCollectionTool() {
|
|
|
8209
8746
|
}
|
|
8210
8747
|
|
|
8211
8748
|
// src/tools/update-inventory.ts
|
|
8212
|
-
import { z as
|
|
8213
|
-
var inventoryReasonEnum =
|
|
8749
|
+
import { z as z42 } from "zod";
|
|
8750
|
+
var inventoryReasonEnum = z42.enum([
|
|
8214
8751
|
"correction",
|
|
8215
8752
|
"cycle_count_available",
|
|
8216
8753
|
"damaged",
|
|
@@ -8229,20 +8766,20 @@ var inventoryReasonEnum = z38.enum([
|
|
|
8229
8766
|
"safety_stock",
|
|
8230
8767
|
"shrinkage"
|
|
8231
8768
|
]);
|
|
8232
|
-
var
|
|
8769
|
+
var inputSchema40 = z42.object({
|
|
8233
8770
|
inventoryItemId: inventoryItemIdSchema.describe(
|
|
8234
8771
|
'The Shopify inventory item ID (e.g., "gid://shopify/InventoryItem/456"). Get this from get-inventory tool or from get-product response.'
|
|
8235
8772
|
),
|
|
8236
8773
|
locationId: locationIdSchema.describe(
|
|
8237
8774
|
'The location ID where inventory should be updated (e.g., "gid://shopify/Location/789"). Get this from get-inventory tool.'
|
|
8238
8775
|
),
|
|
8239
|
-
setQuantity:
|
|
8776
|
+
setQuantity: z42.number().int().min(0).optional().describe(
|
|
8240
8777
|
"Set inventory to this exact quantity. Example: 100. Use for absolute stock counts after physical inventory. Cannot be used together with adjustQuantity."
|
|
8241
8778
|
),
|
|
8242
|
-
adjustQuantity:
|
|
8779
|
+
adjustQuantity: z42.number().int().optional().describe(
|
|
8243
8780
|
"Adjust inventory by this amount. Positive to add, negative to subtract. Example: -5 to reduce by 5, +10 to add 10. Use for incremental changes. Cannot be used together with setQuantity."
|
|
8244
8781
|
),
|
|
8245
|
-
name:
|
|
8782
|
+
name: z42.enum(["available", "on_hand"]).optional().default("available").describe(
|
|
8246
8783
|
'Which quantity to modify. "available" (default) for sellable stock, "on_hand" for physical count.'
|
|
8247
8784
|
),
|
|
8248
8785
|
reason: inventoryReasonEnum.optional().default("correction").describe(
|
|
@@ -8253,16 +8790,16 @@ var inputSchema36 = z38.object({
|
|
|
8253
8790
|
}).refine((data) => !(data.setQuantity !== void 0 && data.adjustQuantity !== void 0), {
|
|
8254
8791
|
message: "Cannot provide both setQuantity and adjustQuantity. Choose one."
|
|
8255
8792
|
});
|
|
8256
|
-
var
|
|
8257
|
-
success:
|
|
8258
|
-
inventoryItemId:
|
|
8259
|
-
locationId:
|
|
8260
|
-
locationName:
|
|
8261
|
-
previousQuantity:
|
|
8262
|
-
newQuantity:
|
|
8263
|
-
delta:
|
|
8264
|
-
name:
|
|
8265
|
-
reason:
|
|
8793
|
+
var outputSchema40 = z42.object({
|
|
8794
|
+
success: z42.boolean().describe("Whether the operation succeeded"),
|
|
8795
|
+
inventoryItemId: z42.string().describe("Inventory item GID"),
|
|
8796
|
+
locationId: z42.string().describe("Location GID where inventory was updated"),
|
|
8797
|
+
locationName: z42.string().describe("Human-readable location name"),
|
|
8798
|
+
previousQuantity: z42.number().describe("Quantity before the change"),
|
|
8799
|
+
newQuantity: z42.number().describe("Quantity after the change"),
|
|
8800
|
+
delta: z42.number().describe("The actual change applied (positive or negative)"),
|
|
8801
|
+
name: z42.string().describe("Which quantity was modified (available or on_hand)"),
|
|
8802
|
+
reason: z42.string().describe("Reason for the adjustment")
|
|
8266
8803
|
});
|
|
8267
8804
|
var handleUpdateInventory = async (context, params) => {
|
|
8268
8805
|
log.debug(`Updating inventory on shop: ${context.shopDomain}`);
|
|
@@ -8336,8 +8873,8 @@ function registerUpdateInventoryTool() {
|
|
|
8336
8873
|
name: "update-inventory",
|
|
8337
8874
|
title: "Update Inventory",
|
|
8338
8875
|
description: 'Update inventory quantity at a specific location. Use setQuantity for absolute values (e.g., setting stock to 50 after a count) or adjustQuantity for relative changes (e.g., +10 for received stock, -5 for shrinkage). Requires inventoryItemId (from get-inventory or get-product) and locationId (from get-inventory). Common reasons: "correction" (default), "received" (new stock), "shrinkage" (loss/theft), "damaged", "cycle_count_available" (stock take). Pre-validates that adjustments will not result in negative inventory. **Typical workflow:** get-inventory \u2192 update-inventory \u2192 get-inventory (to verify). **Prerequisites:** Inventory Item ID, Location ID. **Follow-ups:** get-inventory. Returns before/after quantities with delta.',
|
|
8339
|
-
inputSchema:
|
|
8340
|
-
outputSchema:
|
|
8876
|
+
inputSchema: inputSchema40,
|
|
8877
|
+
outputSchema: outputSchema40,
|
|
8341
8878
|
category: "inventory",
|
|
8342
8879
|
relationships: {
|
|
8343
8880
|
relatedTools: ["get-inventory", "get-bulk-inventory", "list-low-inventory"],
|
|
@@ -8356,34 +8893,93 @@ function registerUpdateInventoryTool() {
|
|
|
8356
8893
|
);
|
|
8357
8894
|
}
|
|
8358
8895
|
|
|
8896
|
+
// src/tools/update-market.ts
|
|
8897
|
+
import { z as z43 } from "zod";
|
|
8898
|
+
var inputSchema41 = z43.object({
|
|
8899
|
+
id: marketIdSchema.describe(
|
|
8900
|
+
'Shopify Market GID to update (e.g., "gid://shopify/Market/123"). Use list-markets to find market IDs.'
|
|
8901
|
+
),
|
|
8902
|
+
name: z43.string().min(1).optional().describe("New market name"),
|
|
8903
|
+
handle: z43.string().optional().describe("New URL handle/slug for the market"),
|
|
8904
|
+
enabled: z43.boolean().optional().describe("Whether the market should be enabled")
|
|
8905
|
+
});
|
|
8906
|
+
var outputSchema41 = z43.object({
|
|
8907
|
+
id: z43.string().describe("Updated market GID"),
|
|
8908
|
+
name: z43.string().describe("Market name"),
|
|
8909
|
+
handle: z43.string().describe("URL handle"),
|
|
8910
|
+
enabled: z43.boolean().describe("Whether the market is enabled")
|
|
8911
|
+
});
|
|
8912
|
+
var handleUpdateMarket = async (context, params) => {
|
|
8913
|
+
log.debug(`Updating market ${params.id} on shop: ${context.shopDomain}`);
|
|
8914
|
+
const input = {};
|
|
8915
|
+
if (params.name !== void 0) {
|
|
8916
|
+
input.name = params.name;
|
|
8917
|
+
}
|
|
8918
|
+
if (params.handle !== void 0) {
|
|
8919
|
+
input.handle = params.handle;
|
|
8920
|
+
}
|
|
8921
|
+
if (params.enabled !== void 0) {
|
|
8922
|
+
input.enabled = params.enabled;
|
|
8923
|
+
}
|
|
8924
|
+
const market = await updateMarket(params.id, input);
|
|
8925
|
+
log.debug(`Updated market: ${market.id}`);
|
|
8926
|
+
return market;
|
|
8927
|
+
};
|
|
8928
|
+
function registerUpdateMarketTool() {
|
|
8929
|
+
registerContextAwareTool(
|
|
8930
|
+
{
|
|
8931
|
+
name: "update-market",
|
|
8932
|
+
title: "Update Market",
|
|
8933
|
+
description: "Update an existing market's properties. Only provided fields are updated; omitted fields remain unchanged. Can update: name, handle, enabled status. **Prerequisites:** get-market to view current values before updating. **Follow-ups:** get-market (to verify), delete-market.",
|
|
8934
|
+
inputSchema: inputSchema41,
|
|
8935
|
+
outputSchema: outputSchema41,
|
|
8936
|
+
// AI Agent Optimization
|
|
8937
|
+
category: "market",
|
|
8938
|
+
relationships: {
|
|
8939
|
+
relatedTools: ["get-market", "list-markets"],
|
|
8940
|
+
followUps: ["get-market", "delete-market"]
|
|
8941
|
+
},
|
|
8942
|
+
// MCP Tool Annotations (Epic 9.5 - MCP Best Practices)
|
|
8943
|
+
annotations: {
|
|
8944
|
+
readOnlyHint: false,
|
|
8945
|
+
destructiveHint: false,
|
|
8946
|
+
idempotentHint: true,
|
|
8947
|
+
// Same update with same values produces same result
|
|
8948
|
+
openWorldHint: true
|
|
8949
|
+
}
|
|
8950
|
+
},
|
|
8951
|
+
handleUpdateMarket
|
|
8952
|
+
);
|
|
8953
|
+
}
|
|
8954
|
+
|
|
8359
8955
|
// src/tools/update-page.ts
|
|
8360
|
-
import { z as
|
|
8361
|
-
var
|
|
8956
|
+
import { z as z44 } from "zod";
|
|
8957
|
+
var inputSchema42 = z44.object({
|
|
8362
8958
|
id: pageIdSchema.describe(
|
|
8363
8959
|
'The page ID to update (required). Must be a valid Shopify GID format. Example: "gid://shopify/Page/123456789". Use list-pages to find page IDs.'
|
|
8364
8960
|
),
|
|
8365
|
-
title:
|
|
8366
|
-
body:
|
|
8961
|
+
title: z44.string().optional().describe("The new title for the page. Only provide if you want to change it."),
|
|
8962
|
+
body: z44.string().optional().describe(
|
|
8367
8963
|
"The new HTML body content for the page. Supports HTML markup. Only provide if you want to change it."
|
|
8368
8964
|
),
|
|
8369
|
-
handle:
|
|
8965
|
+
handle: z44.string().optional().describe(
|
|
8370
8966
|
"The new URL handle/slug for the page. Only provide if you want to change the URL. Consider setting redirectNewHandle to true when changing handles."
|
|
8371
8967
|
),
|
|
8372
|
-
isPublished:
|
|
8968
|
+
isPublished: z44.boolean().optional().describe(
|
|
8373
8969
|
"Whether the page should be visible on the storefront. Set to true to publish, false to unpublish."
|
|
8374
8970
|
),
|
|
8375
|
-
templateSuffix:
|
|
8971
|
+
templateSuffix: z44.string().optional().describe(
|
|
8376
8972
|
"The suffix of the Liquid template used to render the page. Set to empty string to use the default template."
|
|
8377
8973
|
),
|
|
8378
|
-
redirectNewHandle:
|
|
8974
|
+
redirectNewHandle: z44.boolean().optional().describe(
|
|
8379
8975
|
"Whether to create a redirect from the old handle to the new handle when changing handles. Recommended to preserve SEO value when changing page URLs."
|
|
8380
8976
|
)
|
|
8381
8977
|
});
|
|
8382
|
-
var
|
|
8383
|
-
id:
|
|
8384
|
-
title:
|
|
8385
|
-
handle:
|
|
8386
|
-
isPublished:
|
|
8978
|
+
var outputSchema42 = z44.object({
|
|
8979
|
+
id: z44.string().describe("Updated page GID"),
|
|
8980
|
+
title: z44.string().describe("Page title"),
|
|
8981
|
+
handle: z44.string().describe("URL handle/slug"),
|
|
8982
|
+
isPublished: z44.boolean().describe("Whether page is visible on storefront")
|
|
8387
8983
|
});
|
|
8388
8984
|
var handleUpdatePage = async (context, params) => {
|
|
8389
8985
|
log.debug(`Updating page on shop: ${context.shopDomain}`);
|
|
@@ -8427,8 +9023,8 @@ function registerUpdatePageTool() {
|
|
|
8427
9023
|
name: "update-page",
|
|
8428
9024
|
title: "Update Page",
|
|
8429
9025
|
description: "Update an existing page's attributes. You can update title, body content (HTML), handle (URL slug), publish status, and template suffix. Only provided fields are updated; others remain unchanged. Use redirectNewHandle: true when changing handles to preserve SEO. Useful for: editing content, publishing/unpublishing pages, changing URLs. **Typical workflow:** get-page \u2192 update-page. **Prerequisites:** Page ID. **Follow-ups:** get-page. Returns the updated page object.",
|
|
8430
|
-
inputSchema:
|
|
8431
|
-
outputSchema:
|
|
9026
|
+
inputSchema: inputSchema42,
|
|
9027
|
+
outputSchema: outputSchema42,
|
|
8432
9028
|
category: "content",
|
|
8433
9029
|
relationships: {
|
|
8434
9030
|
relatedTools: ["get-page", "list-pages"],
|
|
@@ -8448,7 +9044,7 @@ function registerUpdatePageTool() {
|
|
|
8448
9044
|
}
|
|
8449
9045
|
|
|
8450
9046
|
// src/tools/update-product-image.ts
|
|
8451
|
-
import { z as
|
|
9047
|
+
import { z as z45 } from "zod";
|
|
8452
9048
|
var FILE_UPDATE_MUTATION = `
|
|
8453
9049
|
mutation FileUpdate($files: [FileUpdateInput!]!) {
|
|
8454
9050
|
fileUpdate(files: $files) {
|
|
@@ -8468,18 +9064,18 @@ var FILE_UPDATE_MUTATION = `
|
|
|
8468
9064
|
}
|
|
8469
9065
|
}
|
|
8470
9066
|
`;
|
|
8471
|
-
var
|
|
9067
|
+
var inputSchema43 = z45.object({
|
|
8472
9068
|
imageId: imageIdSchema.describe(
|
|
8473
9069
|
'Shopify image GID (e.g., "gid://shopify/MediaImage/123"). Required. Use get-product to find image IDs in the media field.'
|
|
8474
9070
|
),
|
|
8475
|
-
altText:
|
|
9071
|
+
altText: z45.string().describe(
|
|
8476
9072
|
"New alt text for the image. Pass an empty string to clear the alt text. Alt text describes the image for screen readers and helps search engines understand image content."
|
|
8477
9073
|
)
|
|
8478
9074
|
});
|
|
8479
|
-
var
|
|
8480
|
-
id:
|
|
8481
|
-
url:
|
|
8482
|
-
altText:
|
|
9075
|
+
var outputSchema43 = z45.object({
|
|
9076
|
+
id: z45.string().describe('Image GID (e.g., "gid://shopify/MediaImage/123")'),
|
|
9077
|
+
url: z45.string().nullable().describe("Shopify CDN URL for the image"),
|
|
9078
|
+
altText: z45.string().nullable().describe("Updated alt text for the image")
|
|
8483
9079
|
});
|
|
8484
9080
|
var handleUpdateProductImage = async (context, params) => {
|
|
8485
9081
|
log.debug(`Updating image alt text on shop: ${context.shopDomain}`);
|
|
@@ -8538,8 +9134,8 @@ function registerUpdateProductImageTool() {
|
|
|
8538
9134
|
name: "update-product-image",
|
|
8539
9135
|
title: "Update Product Image",
|
|
8540
9136
|
description: "Update the alt text of a product image for SEO and accessibility. Alt text describes the image for screen readers and helps search engines understand image content. Pass an empty string to clear alt text. **Typical workflow:** add-product-image \u2192 update-product-image (set alt text). **Prerequisites:** add-product-image or get-product to find image IDs. **Follow-ups:** reorder-product-images.",
|
|
8541
|
-
inputSchema:
|
|
8542
|
-
outputSchema:
|
|
9137
|
+
inputSchema: inputSchema43,
|
|
9138
|
+
outputSchema: outputSchema43,
|
|
8543
9139
|
// AI Agent Optimization (Story 5.5)
|
|
8544
9140
|
category: "media",
|
|
8545
9141
|
relationships: {
|
|
@@ -8561,19 +9157,19 @@ function registerUpdateProductImageTool() {
|
|
|
8561
9157
|
}
|
|
8562
9158
|
|
|
8563
9159
|
// src/tools/update-product-variant.ts
|
|
8564
|
-
import { z as
|
|
8565
|
-
var
|
|
9160
|
+
import { z as z46 } from "zod";
|
|
9161
|
+
var inputSchema44 = z46.object({
|
|
8566
9162
|
productId: productIdSchema.describe(
|
|
8567
9163
|
'Shopify product GID (e.g., "gid://shopify/Product/123"). Required. Use get-product to find the product ID containing the variant.'
|
|
8568
9164
|
),
|
|
8569
9165
|
id: variantIdSchema.describe(
|
|
8570
9166
|
'Shopify variant GID (e.g., "gid://shopify/ProductVariant/456"). Required. Use get-product to find variant IDs for a product.'
|
|
8571
9167
|
),
|
|
8572
|
-
price:
|
|
8573
|
-
compareAtPrice:
|
|
9168
|
+
price: z46.string().optional().describe('New variant price as decimal string (e.g., "29.99")'),
|
|
9169
|
+
compareAtPrice: z46.string().nullable().optional().describe(
|
|
8574
9170
|
'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.'
|
|
8575
9171
|
),
|
|
8576
|
-
barcode:
|
|
9172
|
+
barcode: z46.string().nullable().optional().describe("Barcode (UPC, EAN, ISBN, etc.). Set to null to remove.")
|
|
8577
9173
|
}).refine(
|
|
8578
9174
|
(data) => {
|
|
8579
9175
|
const { productId: _productId, id: _id, ...updateFields } = data;
|
|
@@ -8581,14 +9177,14 @@ var inputSchema39 = z41.object({
|
|
|
8581
9177
|
},
|
|
8582
9178
|
{ message: "At least one field to update must be provided (price, compareAtPrice, or barcode)" }
|
|
8583
9179
|
);
|
|
8584
|
-
var
|
|
8585
|
-
id:
|
|
8586
|
-
title:
|
|
8587
|
-
price:
|
|
8588
|
-
compareAtPrice:
|
|
8589
|
-
sku:
|
|
8590
|
-
barcode:
|
|
8591
|
-
inventoryQuantity:
|
|
9180
|
+
var outputSchema44 = z46.object({
|
|
9181
|
+
id: z46.string().describe('Variant GID (e.g., "gid://shopify/ProductVariant/123")'),
|
|
9182
|
+
title: z46.string().describe('Variant title (e.g., "Red / Medium")'),
|
|
9183
|
+
price: z46.string().describe("Current price as decimal string"),
|
|
9184
|
+
compareAtPrice: z46.string().nullable().describe("Compare at price for sale display"),
|
|
9185
|
+
sku: z46.string().nullable().describe("Stock keeping unit"),
|
|
9186
|
+
barcode: z46.string().nullable().describe("Barcode (UPC, EAN, etc.)"),
|
|
9187
|
+
inventoryQuantity: z46.number().nullable().describe("Available inventory quantity")
|
|
8592
9188
|
});
|
|
8593
9189
|
var handleUpdateProductVariant = async (context, params) => {
|
|
8594
9190
|
log.debug(`Updating product variant on shop: ${context.shopDomain}`);
|
|
@@ -8617,8 +9213,8 @@ function registerUpdateProductVariantTool() {
|
|
|
8617
9213
|
name: "update-product-variant",
|
|
8618
9214
|
title: "Update Product Variant",
|
|
8619
9215
|
description: 'Update an existing product variant in the Shopify store. Requires BOTH productId and variant id (GID format). Only provided fields are updated; others remain unchanged. Supports updating: price, compareAtPrice (for sale pricing), barcode. Returns the updated variant with all current details. To show sale pricing, set compareAtPrice higher than price (e.g., compareAtPrice: "39.99", price: "24.99"). **Prerequisites:** get-product to obtain productId and variant IDs. **Note:** SKU updates require separate inventory API calls.',
|
|
8620
|
-
inputSchema:
|
|
8621
|
-
outputSchema:
|
|
9216
|
+
inputSchema: inputSchema44,
|
|
9217
|
+
outputSchema: outputSchema44,
|
|
8622
9218
|
// AI Agent Optimization (Story 5.5)
|
|
8623
9219
|
category: "product",
|
|
8624
9220
|
relationships: {
|
|
@@ -8639,25 +9235,25 @@ function registerUpdateProductVariantTool() {
|
|
|
8639
9235
|
}
|
|
8640
9236
|
|
|
8641
9237
|
// src/tools/update-product.ts
|
|
8642
|
-
import { z as
|
|
8643
|
-
var
|
|
9238
|
+
import { z as z47 } from "zod";
|
|
9239
|
+
var inputSchema45 = z47.object({
|
|
8644
9240
|
id: productIdSchema.describe(
|
|
8645
9241
|
'Shopify product ID (GID format, e.g., "gid://shopify/Product/123"). Required.'
|
|
8646
9242
|
),
|
|
8647
|
-
title:
|
|
8648
|
-
description:
|
|
8649
|
-
vendor:
|
|
8650
|
-
productType:
|
|
8651
|
-
tags:
|
|
8652
|
-
status:
|
|
8653
|
-
seo:
|
|
8654
|
-
title:
|
|
8655
|
-
description:
|
|
9243
|
+
title: z47.string().min(1).optional().describe("New product title"),
|
|
9244
|
+
description: z47.string().optional().describe("New product description (HTML supported)"),
|
|
9245
|
+
vendor: z47.string().optional().describe("New product vendor/brand name"),
|
|
9246
|
+
productType: z47.string().optional().describe("New product type for categorization"),
|
|
9247
|
+
tags: z47.array(z47.string()).optional().describe("New tags (replaces existing tags)"),
|
|
9248
|
+
status: z47.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).optional().describe("New product status: ACTIVE (visible), DRAFT (hidden), ARCHIVED (hidden)"),
|
|
9249
|
+
seo: z47.object({
|
|
9250
|
+
title: z47.string().optional().describe("SEO title for search engine results"),
|
|
9251
|
+
description: z47.string().optional().describe("SEO meta description for search engines")
|
|
8656
9252
|
}).optional().describe("SEO metadata for search engine optimization"),
|
|
8657
|
-
handle:
|
|
9253
|
+
handle: z47.string().optional().describe(
|
|
8658
9254
|
'New URL handle/slug (e.g., "my-product"). Use with redirectNewHandle for URL changes.'
|
|
8659
9255
|
),
|
|
8660
|
-
redirectNewHandle:
|
|
9256
|
+
redirectNewHandle: z47.boolean().optional().describe(
|
|
8661
9257
|
"If true, creates automatic redirect from old handle to new handle. Use when changing handle."
|
|
8662
9258
|
)
|
|
8663
9259
|
}).refine(
|
|
@@ -8667,40 +9263,40 @@ var inputSchema40 = z42.object({
|
|
|
8667
9263
|
},
|
|
8668
9264
|
{ message: "At least one field to update must be provided" }
|
|
8669
9265
|
);
|
|
8670
|
-
var
|
|
8671
|
-
id:
|
|
8672
|
-
title:
|
|
8673
|
-
handle:
|
|
8674
|
-
description:
|
|
8675
|
-
vendor:
|
|
8676
|
-
productType:
|
|
8677
|
-
status:
|
|
8678
|
-
tags:
|
|
8679
|
-
seo:
|
|
8680
|
-
title:
|
|
8681
|
-
description:
|
|
9266
|
+
var outputSchema45 = z47.object({
|
|
9267
|
+
id: z47.string().describe('Product GID (e.g., "gid://shopify/Product/123")'),
|
|
9268
|
+
title: z47.string().describe("Product title"),
|
|
9269
|
+
handle: z47.string().describe("URL handle/slug"),
|
|
9270
|
+
description: z47.string().nullable().describe("Product description (HTML)"),
|
|
9271
|
+
vendor: z47.string().describe("Vendor/brand name"),
|
|
9272
|
+
productType: z47.string().describe("Product type"),
|
|
9273
|
+
status: z47.enum(["ACTIVE", "DRAFT", "ARCHIVED"]).describe("Product status"),
|
|
9274
|
+
tags: z47.array(z47.string()).describe("Product tags"),
|
|
9275
|
+
seo: z47.object({
|
|
9276
|
+
title: z47.string().nullable().describe("SEO title for search engines"),
|
|
9277
|
+
description: z47.string().nullable().describe("SEO description/meta description")
|
|
8682
9278
|
}).describe("SEO metadata for search engine optimization"),
|
|
8683
|
-
createdAt:
|
|
8684
|
-
updatedAt:
|
|
8685
|
-
variants:
|
|
8686
|
-
|
|
8687
|
-
id:
|
|
8688
|
-
title:
|
|
8689
|
-
price:
|
|
8690
|
-
compareAtPrice:
|
|
8691
|
-
sku:
|
|
8692
|
-
barcode:
|
|
8693
|
-
inventoryQuantity:
|
|
9279
|
+
createdAt: z47.string().describe("Creation timestamp (ISO 8601)"),
|
|
9280
|
+
updatedAt: z47.string().describe("Last update timestamp (ISO 8601)"),
|
|
9281
|
+
variants: z47.array(
|
|
9282
|
+
z47.object({
|
|
9283
|
+
id: z47.string().describe("Variant GID"),
|
|
9284
|
+
title: z47.string().describe("Variant title"),
|
|
9285
|
+
price: z47.string().describe("Price"),
|
|
9286
|
+
compareAtPrice: z47.string().nullable().describe("Compare at price"),
|
|
9287
|
+
sku: z47.string().nullable().describe("SKU"),
|
|
9288
|
+
barcode: z47.string().nullable().describe("Barcode"),
|
|
9289
|
+
inventoryQuantity: z47.number().nullable().describe("Inventory quantity")
|
|
8694
9290
|
})
|
|
8695
9291
|
).describe("Product variants"),
|
|
8696
|
-
images:
|
|
8697
|
-
|
|
8698
|
-
id:
|
|
8699
|
-
url:
|
|
8700
|
-
altText:
|
|
9292
|
+
images: z47.array(
|
|
9293
|
+
z47.object({
|
|
9294
|
+
id: z47.string().describe("Image GID"),
|
|
9295
|
+
url: z47.string().describe("Image URL"),
|
|
9296
|
+
altText: z47.string().nullable().describe("Alt text")
|
|
8701
9297
|
})
|
|
8702
9298
|
).describe("Product images"),
|
|
8703
|
-
totalInventory:
|
|
9299
|
+
totalInventory: z47.number().describe("Total inventory across variants")
|
|
8704
9300
|
});
|
|
8705
9301
|
var handleUpdateProduct = async (context, params) => {
|
|
8706
9302
|
log.debug(`Updating product on shop: ${context.shopDomain}`);
|
|
@@ -8729,8 +9325,8 @@ function registerUpdateProductTool() {
|
|
|
8729
9325
|
name: "update-product",
|
|
8730
9326
|
title: "Update Product",
|
|
8731
9327
|
description: "Update an existing product in the Shopify store. Requires the product ID (GID format). Only provided fields are updated; others remain unchanged. Supports updating: title, description, vendor, productType, tags, status, SEO metadata (seo.title, seo.description), and URL handle. Use handle + redirectNewHandle=true to change URLs with automatic redirect. Returns the updated product with all current details including SEO. **Prerequisites:** get-product to view current values before updating. **Follow-ups:** add-product-image, set-product-metafields.",
|
|
8732
|
-
inputSchema:
|
|
8733
|
-
outputSchema:
|
|
9328
|
+
inputSchema: inputSchema45,
|
|
9329
|
+
outputSchema: outputSchema45,
|
|
8734
9330
|
// AI Agent Optimization (Story 5.5)
|
|
8735
9331
|
category: "product",
|
|
8736
9332
|
relationships: {
|
|
@@ -8847,6 +9443,11 @@ function registerAllTools(server) {
|
|
|
8847
9443
|
registerGetInventoryTool();
|
|
8848
9444
|
registerListLowInventoryTool();
|
|
8849
9445
|
registerUpdateInventoryTool();
|
|
9446
|
+
registerCreateMarketTool();
|
|
9447
|
+
registerDeleteMarketTool();
|
|
9448
|
+
registerGetMarketTool();
|
|
9449
|
+
registerListMarketsTool();
|
|
9450
|
+
registerUpdateMarketTool();
|
|
8850
9451
|
const toolCount = getRegisteredTools().length;
|
|
8851
9452
|
log.debug(`Tool registration complete: ${toolCount} tools registered`);
|
|
8852
9453
|
}
|