@solumflow-app/crm-mcp-server 0.11.0 → 0.12.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 +173 -103
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
6
|
import { createClient } from "@solumflow-app/crm-client";
|
|
7
7
|
|
|
8
8
|
// package.json
|
|
9
|
-
var version = "0.
|
|
9
|
+
var version = "0.12.0";
|
|
10
10
|
|
|
11
11
|
// src/catalog-migration-tools.ts
|
|
12
12
|
import { z as z8 } from "zod";
|
|
@@ -4476,8 +4476,77 @@ function describeForm(form) {
|
|
|
4476
4476
|
return `- ${form.name} (/${form.slug}, id ${form.id}): ${form.status}`;
|
|
4477
4477
|
}
|
|
4478
4478
|
|
|
4479
|
-
// src/order-tools.ts
|
|
4479
|
+
// src/hosting-order-page-tools.ts
|
|
4480
4480
|
import { z as z16 } from "zod";
|
|
4481
|
+
function registerHostingOrderPageTools(server, client) {
|
|
4482
|
+
server.registerTool(
|
|
4483
|
+
"get_hosting_order_page",
|
|
4484
|
+
{
|
|
4485
|
+
title: "Read the hosting order page",
|
|
4486
|
+
description: 'The hosting order page: open or closed, the packages on it and the ones that could be, the quick extensions, the sites it may stand on, why it would refuse to open, its link, and the snippet that puts it on a site (or <CrmHostingOrder account="\u2026" /> from @solumflow-app/crm-client/react on a React site).',
|
|
4487
|
+
annotations: { readOnlyHint: true, idempotentHint: true }
|
|
4488
|
+
},
|
|
4489
|
+
async () => {
|
|
4490
|
+
try {
|
|
4491
|
+
const page2 = await client.getHostingOrderPage();
|
|
4492
|
+
return answer(describe(page2), page2);
|
|
4493
|
+
} catch (error) {
|
|
4494
|
+
return refusal(error, "hosting-order:manage");
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
);
|
|
4498
|
+
server.registerTool(
|
|
4499
|
+
"update_hosting_order_page",
|
|
4500
|
+
{
|
|
4501
|
+
title: "Set up the hosting order page",
|
|
4502
|
+
description: "Changes the hosting order page; only what is sent changes. `packages` is the whole list in the order the page shows it (product ids from get_hosting_order_page candidates), `allowedOrigins` the whole list of sites the snippet may stand on -- add the site before placing the snippet. `enabled: true` opens real payments. It is refused while the page cannot deliver what it sells; the refusal names what the account owner has to fix in the app themselves (a registrar login, the renewal round still in shadow mode) -- pass that on, do not retry.",
|
|
4503
|
+
inputSchema: {
|
|
4504
|
+
enabled: z16.boolean().optional(),
|
|
4505
|
+
quickTlds: z16.array(z16.string().max(30)).max(12).optional().describe("Extensions without a dot, such as nl, com, be."),
|
|
4506
|
+
defaultPeriod: z16.enum(["month", "year"]).optional(),
|
|
4507
|
+
packages: z16.array(
|
|
4508
|
+
z16.object({
|
|
4509
|
+
productId: z16.string().uuid(),
|
|
4510
|
+
service: z16.enum(["hosting", "email"]),
|
|
4511
|
+
featured: z16.boolean().optional(),
|
|
4512
|
+
badge: z16.string().max(40).nullable().optional(),
|
|
4513
|
+
highlights: z16.array(z16.string().max(80)).max(4).optional()
|
|
4514
|
+
})
|
|
4515
|
+
).max(24).optional(),
|
|
4516
|
+
allowedOrigins: z16.array(z16.string().max(255)).max(20).optional().describe(
|
|
4517
|
+
"Origins such as https://example.com: no path, lower case."
|
|
4518
|
+
)
|
|
4519
|
+
},
|
|
4520
|
+
annotations: { idempotentHint: true }
|
|
4521
|
+
},
|
|
4522
|
+
async (input) => {
|
|
4523
|
+
try {
|
|
4524
|
+
const page2 = await client.updateHostingOrderPage(input);
|
|
4525
|
+
return answer(`Saved. ${describe(page2)}`, page2);
|
|
4526
|
+
} catch (error) {
|
|
4527
|
+
return refusal(error, "hosting-order:manage");
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
);
|
|
4531
|
+
}
|
|
4532
|
+
function describe(page2) {
|
|
4533
|
+
const lines = [
|
|
4534
|
+
`${page2.enabled ? "Open" : "Closed"}: ${page2.url}`,
|
|
4535
|
+
`Packages on the page: ${page2.packages.length} of ${page2.candidates.length}.`,
|
|
4536
|
+
page2.allowedOrigins.length ? `Sites it may stand on: ${page2.allowedOrigins.join(", ")}.` : "No sites yet: add the site to allowedOrigins before placing the snippet."
|
|
4537
|
+
];
|
|
4538
|
+
if (page2.refusal) {
|
|
4539
|
+
lines.push(`It cannot open now: ${page2.refusal.message}`);
|
|
4540
|
+
}
|
|
4541
|
+
lines.push(
|
|
4542
|
+
"Snippet (the site needs its CSP to allow the app and js.stripe.com):",
|
|
4543
|
+
codeBlock(page2.embed)
|
|
4544
|
+
);
|
|
4545
|
+
return lines.join("\n");
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
// src/order-tools.ts
|
|
4549
|
+
import { z as z17 } from "zod";
|
|
4481
4550
|
function registerOrderTools(server, client) {
|
|
4482
4551
|
server.registerTool(
|
|
4483
4552
|
"get_order",
|
|
@@ -4485,7 +4554,7 @@ function registerOrderTools(server, client) {
|
|
|
4485
4554
|
title: "Read one order",
|
|
4486
4555
|
description: "One order by its number, its id or its Stripe PaymentIntent (pi_\u2026): payment status, whether it was sent, the lines and the totals. Live, never cached. It does not say who bought it or where it went, and it cannot change, ship or refund an order: that is done in the app.",
|
|
4487
4556
|
inputSchema: {
|
|
4488
|
-
ref:
|
|
4557
|
+
ref: z17.string().min(1).max(200).describe("The order number, its id, or a pi_\u2026 PaymentIntent id.")
|
|
4489
4558
|
},
|
|
4490
4559
|
annotations: { readOnlyHint: true, idempotentHint: true }
|
|
4491
4560
|
},
|
|
@@ -4514,16 +4583,16 @@ function describeOrder(order) {
|
|
|
4514
4583
|
}
|
|
4515
4584
|
|
|
4516
4585
|
// src/payment-page-tools.ts
|
|
4517
|
-
import { z as
|
|
4518
|
-
var id4 =
|
|
4519
|
-
var slug =
|
|
4586
|
+
import { z as z18 } from "zod";
|
|
4587
|
+
var id4 = z18.string().uuid();
|
|
4588
|
+
var slug = z18.string().min(2).max(64).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/).describe("Lowercase letters, digits and hyphens.");
|
|
4520
4589
|
function registerPaymentPageTools(server, client) {
|
|
4521
4590
|
server.registerTool(
|
|
4522
4591
|
"list_payment_pages",
|
|
4523
4592
|
{
|
|
4524
4593
|
title: "List payment pages",
|
|
4525
4594
|
description: "The account\u2019s payment pages, paged by id; archived ones only with archived: true.",
|
|
4526
|
-
inputSchema: { archived:
|
|
4595
|
+
inputSchema: { archived: z18.boolean().optional(), ...page },
|
|
4527
4596
|
annotations: { readOnlyHint: true, idempotentHint: true }
|
|
4528
4597
|
},
|
|
4529
4598
|
async (input) => {
|
|
@@ -4566,7 +4635,7 @@ ${blockers}`, page2);
|
|
|
4566
4635
|
title: "Make a payment page",
|
|
4567
4636
|
description: "A draft payment page for one of the account\u2019s products. Nothing is live until a person publishes it in the app. Without priceId the buyer picks from the product\u2019s active price options.",
|
|
4568
4637
|
inputSchema: {
|
|
4569
|
-
name:
|
|
4638
|
+
name: z18.string().min(1).max(120),
|
|
4570
4639
|
slug: slug.optional(),
|
|
4571
4640
|
productId: id4,
|
|
4572
4641
|
priceId: id4.optional()
|
|
@@ -4588,13 +4657,13 @@ ${blockers}`, page2);
|
|
|
4588
4657
|
description: "Only what is sent changes. content takes whole blocks: hero {headline, subheadline}, bullets {title, items}, quote {text, author, role}, guarantee {title, body}, faq {items: [{question, answer}]}, trust {items}, paymentOptions {recommendedPriceId, note}; a block left out stays. settings takes termsUrl, requireFields, excludedPaymentMethods (what is switched OFF), thankYouMode, redirectUrl, createInvoice, maxQuantity, customFields, tagOnPurchase. status goes back to draft (off the web) or archived; publishing is done in the app. A new slug breaks links already sent.",
|
|
4589
4658
|
inputSchema: {
|
|
4590
4659
|
id: id4,
|
|
4591
|
-
name:
|
|
4660
|
+
name: z18.string().min(1).max(120).optional(),
|
|
4592
4661
|
slug: slug.optional(),
|
|
4593
4662
|
productId: id4.optional(),
|
|
4594
4663
|
priceId: id4.nullable().optional(),
|
|
4595
|
-
status:
|
|
4596
|
-
content:
|
|
4597
|
-
settings:
|
|
4664
|
+
status: z18.enum(["draft", "archived"]).optional(),
|
|
4665
|
+
content: z18.record(z18.string(), z18.unknown()).optional(),
|
|
4666
|
+
settings: z18.record(z18.string(), z18.unknown()).optional()
|
|
4598
4667
|
},
|
|
4599
4668
|
annotations: { idempotentHint: true }
|
|
4600
4669
|
},
|
|
@@ -4613,9 +4682,9 @@ function describePage(page2) {
|
|
|
4613
4682
|
}
|
|
4614
4683
|
|
|
4615
4684
|
// src/placement-tools.ts
|
|
4616
|
-
import { z as
|
|
4685
|
+
import { z as z19 } from "zod";
|
|
4617
4686
|
var REACT_HINT = "On a React or Next.js site, prefer the components in `@solumflow-app/crm-client/react` (CrmForm, CrmBooking, CrmChatWidget, CrmSiteTracking) over pasting HTML.";
|
|
4618
|
-
var origin =
|
|
4687
|
+
var origin = z19.string().regex(/^https?:\/\/[a-zA-Z0-9.-]+(:[0-9]{1,5})?$/).describe("Scheme, host and optional port; no path: https://www.example.com");
|
|
4619
4688
|
function registerPlacementTools(server, client) {
|
|
4620
4689
|
server.registerTool(
|
|
4621
4690
|
"list_forms",
|
|
@@ -4688,13 +4757,13 @@ function registerPlacementTools(server, client) {
|
|
|
4688
4757
|
title: "Make or change a chat widget",
|
|
4689
4758
|
description: "Makes the chat widget at this address when there is none, or changes it. Sets its name, whether it is live, and which sites it may run on. How it looks and what it says is done in the app\u2019s builder. Sites are added and removed, never replaced. Careful: an empty list means ANY site, so adding the first origin narrows the widget to that site only, and removing an origin takes the chat off a site that may be live.",
|
|
4690
4759
|
inputSchema: {
|
|
4691
|
-
slug:
|
|
4760
|
+
slug: z19.string().regex(/^[a-z][a-z0-9-]*$/).max(100).describe(
|
|
4692
4761
|
'The widget\u2019s address on this account, such as "website-chat".'
|
|
4693
4762
|
),
|
|
4694
|
-
name:
|
|
4695
|
-
status:
|
|
4696
|
-
addAllowedOrigins:
|
|
4697
|
-
removeAllowedOrigins:
|
|
4763
|
+
name: z19.string().min(1).max(200).optional().describe("Required when the widget does not exist yet."),
|
|
4764
|
+
status: z19.enum(["draft", "published"]).optional().describe("Only a published widget answers on a site."),
|
|
4765
|
+
addAllowedOrigins: z19.array(origin).max(20).optional(),
|
|
4766
|
+
removeAllowedOrigins: z19.array(origin).max(20).optional()
|
|
4698
4767
|
},
|
|
4699
4768
|
annotations: {
|
|
4700
4769
|
readOnlyHint: false,
|
|
@@ -4742,9 +4811,9 @@ ${describeChatWidget(widget)}`,
|
|
|
4742
4811
|
title: "Set up or change the tracking script",
|
|
4743
4812
|
description: "Sets website tracking up when it is not there, adds or removes the hosts it counts visits from, and changes the consent it waits for. An empty list of hosts counts nothing, so add the host of every site the script is placed on. Hosts are added and removed, never replaced.",
|
|
4744
4813
|
inputSchema: {
|
|
4745
|
-
addAllowedHosts:
|
|
4746
|
-
removeAllowedHosts:
|
|
4747
|
-
consentSignal:
|
|
4814
|
+
addAllowedHosts: z19.array(z19.string()).max(20).optional().describe('Hosts such as "www.example.com" or "*.example.com".'),
|
|
4815
|
+
removeAllowedHosts: z19.array(z19.string()).max(20).optional(),
|
|
4816
|
+
consentSignal: z19.enum([
|
|
4748
4817
|
"ad_storage",
|
|
4749
4818
|
"analytics_storage",
|
|
4750
4819
|
"personalization_storage",
|
|
@@ -4805,14 +4874,14 @@ function describeSiteTracking(site) {
|
|
|
4805
4874
|
}
|
|
4806
4875
|
|
|
4807
4876
|
// src/record-tools.ts
|
|
4808
|
-
import { z as
|
|
4809
|
-
var recordId =
|
|
4810
|
-
var values =
|
|
4877
|
+
import { z as z20 } from "zod";
|
|
4878
|
+
var recordId = z20.string().uuid().describe("The id of the record.");
|
|
4879
|
+
var values = z20.record(z20.string(), z20.unknown()).describe(
|
|
4811
4880
|
"Field values by field slug, as list_record_lists names them. A field marked sensitive is refused."
|
|
4812
4881
|
);
|
|
4813
|
-
var tags =
|
|
4814
|
-
add:
|
|
4815
|
-
remove:
|
|
4882
|
+
var tags = z20.object({
|
|
4883
|
+
add: z20.array(z20.string().uuid()).max(50).optional(),
|
|
4884
|
+
remove: z20.array(z20.string().uuid()).max(50).optional()
|
|
4816
4885
|
}).optional().describe("Tag ids to put on or take off; list_tags names them.");
|
|
4817
4886
|
function registerRecordTools(server, client) {
|
|
4818
4887
|
server.registerTool(
|
|
@@ -4837,8 +4906,8 @@ function registerRecordTools(server, client) {
|
|
|
4837
4906
|
title: "Search the records of one list",
|
|
4838
4907
|
description: "The records of one list, by its slug, paged. q searches the name and every value but a sensitive one. Records whose processing is restricted are left out.",
|
|
4839
4908
|
inputSchema: {
|
|
4840
|
-
list:
|
|
4841
|
-
q:
|
|
4909
|
+
list: z20.string().min(1).max(64).describe("The slug of the list."),
|
|
4910
|
+
q: z20.string().max(200).optional(),
|
|
4842
4911
|
...page
|
|
4843
4912
|
},
|
|
4844
4913
|
annotations: { readOnlyHint: true, idempotentHint: true }
|
|
@@ -4878,7 +4947,7 @@ function registerRecordTools(server, client) {
|
|
|
4878
4947
|
title: "Make a record",
|
|
4879
4948
|
description: "A new record in a list (left out: a person, where the account puts new contacts). A person whose e-mail or phone is already known is not made again: the answer gives only their id (matched), nothing on them changes, and get_record reads them; use update_record to change them. Automations that start on a new record run as they do for one made in the app.",
|
|
4880
4949
|
inputSchema: {
|
|
4881
|
-
list:
|
|
4950
|
+
list: z20.string().min(1).max(64).optional(),
|
|
4882
4951
|
values,
|
|
4883
4952
|
tags
|
|
4884
4953
|
}
|
|
@@ -4904,7 +4973,7 @@ function registerRecordTools(server, client) {
|
|
|
4904
4973
|
id: recordId,
|
|
4905
4974
|
values: values.optional(),
|
|
4906
4975
|
tags,
|
|
4907
|
-
ownerId:
|
|
4976
|
+
ownerId: z20.string().uuid().nullable().optional()
|
|
4908
4977
|
},
|
|
4909
4978
|
annotations: { idempotentHint: true }
|
|
4910
4979
|
},
|
|
@@ -4968,7 +5037,7 @@ function registerRecordTools(server, client) {
|
|
|
4968
5037
|
description: "A note on a record\u2019s timeline, shown as written through the API with the name of this key.",
|
|
4969
5038
|
inputSchema: {
|
|
4970
5039
|
recordId,
|
|
4971
|
-
body:
|
|
5040
|
+
body: z20.string().min(1).max(2e4)
|
|
4972
5041
|
}
|
|
4973
5042
|
},
|
|
4974
5043
|
async ({ recordId: id7, body }) => {
|
|
@@ -4986,12 +5055,12 @@ function registerRecordTools(server, client) {
|
|
|
4986
5055
|
title: "Add a contact, or find the one already known",
|
|
4987
5056
|
description: "A person by e-mail address. Somebody already known by that address is matched rather than made twice (created: false), and the answer is their id. A field left out is never cleared on a contact already known.",
|
|
4988
5057
|
inputSchema: {
|
|
4989
|
-
email:
|
|
4990
|
-
firstName:
|
|
4991
|
-
lastName:
|
|
4992
|
-
phone:
|
|
4993
|
-
company:
|
|
4994
|
-
object:
|
|
5058
|
+
email: z20.string().email().max(320),
|
|
5059
|
+
firstName: z20.string().trim().min(1).max(200).optional(),
|
|
5060
|
+
lastName: z20.string().trim().min(1).max(200).optional(),
|
|
5061
|
+
phone: z20.string().trim().min(1).max(50).optional(),
|
|
5062
|
+
company: z20.string().trim().min(1).max(200).optional(),
|
|
5063
|
+
object: z20.string().trim().min(1).max(64).optional().describe(
|
|
4995
5064
|
"The slug of the list for people a new contact goes into; left out, the account\u2019s own choice."
|
|
4996
5065
|
)
|
|
4997
5066
|
},
|
|
@@ -5073,20 +5142,20 @@ function registerServerInfoTool(server, info) {
|
|
|
5073
5142
|
}
|
|
5074
5143
|
|
|
5075
5144
|
// src/shop-setup-tools.ts
|
|
5076
|
-
import { z as
|
|
5077
|
-
var id5 =
|
|
5078
|
-
var cents2 =
|
|
5079
|
-
var region =
|
|
5080
|
-
countryCode:
|
|
5081
|
-
postcodeFrom:
|
|
5082
|
-
postcodeTo:
|
|
5145
|
+
import { z as z21 } from "zod";
|
|
5146
|
+
var id5 = z21.string().uuid();
|
|
5147
|
+
var cents2 = z21.number().int().min(0).max(99999999);
|
|
5148
|
+
var region = z21.object({
|
|
5149
|
+
countryCode: z21.string().regex(/^[A-Z]{2}$/).describe("Two capital letters, ISO 3166 (NL, BE, DE)."),
|
|
5150
|
+
postcodeFrom: z21.string().max(20).nullable().default(null).describe("With postcodeTo: only this range of the country."),
|
|
5151
|
+
postcodeTo: z21.string().max(20).nullable().default(null)
|
|
5083
5152
|
});
|
|
5084
|
-
var discount =
|
|
5085
|
-
name:
|
|
5086
|
-
code:
|
|
5153
|
+
var discount = z21.object({
|
|
5154
|
+
name: z21.string().min(1).max(120).describe("What the team sees it as."),
|
|
5155
|
+
code: z21.string().max(40).nullable().describe(
|
|
5087
5156
|
"What a buyer types (upper-cased), or null for one that applies on its own."
|
|
5088
5157
|
),
|
|
5089
|
-
effect:
|
|
5158
|
+
effect: z21.enum([
|
|
5090
5159
|
"tier_price",
|
|
5091
5160
|
"percent_off_lines",
|
|
5092
5161
|
"amount_off_lines",
|
|
@@ -5096,19 +5165,19 @@ var discount = z20.object({
|
|
|
5096
5165
|
]).describe(
|
|
5097
5166
|
"tier_price: a lower price from tierMinQuantity of one product; *_lines: off each matching line; *_order: once off the whole order; free_shipping: no postage."
|
|
5098
5167
|
),
|
|
5099
|
-
percent:
|
|
5100
|
-
amountCents:
|
|
5101
|
-
currency:
|
|
5102
|
-
tierMinQuantity:
|
|
5103
|
-
minSubtotalCents:
|
|
5104
|
-
productIds:
|
|
5105
|
-
categoryIds:
|
|
5106
|
-
objectIds:
|
|
5107
|
-
startsAt:
|
|
5108
|
-
endsAt:
|
|
5109
|
-
maxUses:
|
|
5110
|
-
maxUsesPerEmail:
|
|
5111
|
-
combinable:
|
|
5168
|
+
percent: z21.number().nullable().describe("For a percentage: above 0, at most 100."),
|
|
5169
|
+
amountCents: z21.number().int().nullable().describe("For an amount, in currency, as the account enters prices."),
|
|
5170
|
+
currency: z21.string().regex(/^[A-Z]{3}$/).nullable().describe("Required beside amountCents (EUR)."),
|
|
5171
|
+
tierMinQuantity: z21.number().int().nullable(),
|
|
5172
|
+
minSubtotalCents: z21.number().int().nullable().describe("Only from this basket value, before discount."),
|
|
5173
|
+
productIds: z21.array(id5).max(500).describe("Empty: every product."),
|
|
5174
|
+
categoryIds: z21.array(id5).max(100),
|
|
5175
|
+
objectIds: z21.array(id5).max(20),
|
|
5176
|
+
startsAt: z21.string().datetime({ offset: true }).nullable(),
|
|
5177
|
+
endsAt: z21.string().datetime({ offset: true }).nullable(),
|
|
5178
|
+
maxUses: z21.number().int().positive().nullable(),
|
|
5179
|
+
maxUsesPerEmail: z21.number().int().positive().nullable(),
|
|
5180
|
+
combinable: z21.boolean().describe(
|
|
5112
5181
|
"Whether it may count beside another discount on the same order."
|
|
5113
5182
|
)
|
|
5114
5183
|
});
|
|
@@ -5161,8 +5230,8 @@ function registerShopSetupTools(server, client) {
|
|
|
5161
5230
|
description: "A zone is a name and the countries (or postcode ranges) it covers. Without id a new zone; with one, that zone renamed and its places replaced by these. Answers the zone id, for upsert_shipping_method.",
|
|
5162
5231
|
inputSchema: {
|
|
5163
5232
|
id: id5.optional().describe("The zone to change; leave out for a new one."),
|
|
5164
|
-
name:
|
|
5165
|
-
regions:
|
|
5233
|
+
name: z21.string().min(1).max(80),
|
|
5234
|
+
regions: z21.array(region).max(300).default([])
|
|
5166
5235
|
},
|
|
5167
5236
|
annotations: { idempotentHint: true }
|
|
5168
5237
|
},
|
|
@@ -5186,14 +5255,14 @@ function registerShopSetupTools(server, client) {
|
|
|
5186
5255
|
inputSchema: {
|
|
5187
5256
|
id: id5.optional(),
|
|
5188
5257
|
zoneId: id5,
|
|
5189
|
-
kind:
|
|
5190
|
-
name:
|
|
5191
|
-
enabled:
|
|
5258
|
+
kind: z21.enum(["flat_rate", "free_shipping", "local_pickup"]),
|
|
5259
|
+
name: z21.string().min(1).max(80).describe("What the buyer chooses."),
|
|
5260
|
+
enabled: z21.boolean().default(true),
|
|
5192
5261
|
amountCents: cents2.default(0),
|
|
5193
5262
|
noClassAmountCents: cents2.default(0),
|
|
5194
5263
|
taxRateId: id5.nullish(),
|
|
5195
5264
|
freeThresholdCents: cents2.nullish(),
|
|
5196
|
-
classRates:
|
|
5265
|
+
classRates: z21.array(z21.object({ classId: id5, amountCents: cents2 })).max(100).default([])
|
|
5197
5266
|
},
|
|
5198
5267
|
annotations: { idempotentHint: true }
|
|
5199
5268
|
},
|
|
@@ -5214,7 +5283,7 @@ function registerShopSetupTools(server, client) {
|
|
|
5214
5283
|
{
|
|
5215
5284
|
title: "List discounts",
|
|
5216
5285
|
description: "The account discounts, newest first, at most 200: codes, the ones that apply on their own, and tier prices, with every condition and how many paid orders used each. Archived ones only with archived: true.",
|
|
5217
|
-
inputSchema: { archived:
|
|
5286
|
+
inputSchema: { archived: z21.boolean().optional() },
|
|
5218
5287
|
annotations: { readOnlyHint: true, idempotentHint: true }
|
|
5219
5288
|
},
|
|
5220
5289
|
async ({ archived }) => {
|
|
@@ -5256,7 +5325,7 @@ function registerShopSetupTools(server, client) {
|
|
|
5256
5325
|
description: "Stops a discount from giving anything to a new cart or order; orders that used it keep it. archived: false brings it back. Deleting is left to a person in the app.",
|
|
5257
5326
|
inputSchema: {
|
|
5258
5327
|
id: id5,
|
|
5259
|
-
archived:
|
|
5328
|
+
archived: z21.boolean().default(true)
|
|
5260
5329
|
},
|
|
5261
5330
|
annotations: { idempotentHint: true }
|
|
5262
5331
|
},
|
|
@@ -5321,9 +5390,9 @@ function registerShopSetupTools(server, client) {
|
|
|
5321
5390
|
description: "Point the account at the site revalidation route (with the SDK: https://<site>/api/solumflow/revalidate) so its cached pages follow a product the moment it changes. Without id a new address: the answer carries its signing key once -- put it in the site environment as SOLUMFLOW_WEBHOOK_KEY, it cannot be read back. https only, never a private network.",
|
|
5322
5391
|
inputSchema: {
|
|
5323
5392
|
id: id5.optional(),
|
|
5324
|
-
name:
|
|
5325
|
-
url:
|
|
5326
|
-
events:
|
|
5393
|
+
name: z21.string().min(1).max(80),
|
|
5394
|
+
url: z21.string().url().max(2048),
|
|
5395
|
+
events: z21.array(z21.string().min(1).max(60)).min(1).max(20).describe(
|
|
5327
5396
|
"For a shop: product.changed, product.deleted, category.changed."
|
|
5328
5397
|
)
|
|
5329
5398
|
},
|
|
@@ -5359,7 +5428,7 @@ function describeDiscount(entry) {
|
|
|
5359
5428
|
}
|
|
5360
5429
|
|
|
5361
5430
|
// src/shop-test-order-tool.ts
|
|
5362
|
-
import { z as
|
|
5431
|
+
import { z as z22 } from "zod";
|
|
5363
5432
|
var PAID_POLLS = 10;
|
|
5364
5433
|
var PAID_POLL_MS = 1500;
|
|
5365
5434
|
function registerShopTestOrderTool(server, client, options = {}) {
|
|
@@ -5370,25 +5439,25 @@ function registerShopTestOrderTool(server, client, options = {}) {
|
|
|
5370
5439
|
title: "Place and pay a test order",
|
|
5371
5440
|
description: "Proves the shop end to end in Stripe test mode: puts one product in a cart, chooses postage, places the order, pays it with Stripe test card 4242, and reads the order back until it is paid (the invoice and the confirmation mail follow from there). Refused when the account is live -- no real money can move through this tool. Needs a key with shop:manage, cart:write, orders:write and orders:read. Pass `extras` (products from the product\u2019s own `extras` list) and `options` (by option key: a text, true, or a choice key) to prove a product with an extra or a surcharge option; the cart must show them, priced by the server, before the order is placed. Never send an amount.",
|
|
5372
5441
|
inputSchema: {
|
|
5373
|
-
email:
|
|
5442
|
+
email: z22.string().email().describe(
|
|
5374
5443
|
"Where the confirmation goes: the shop owner, never a customer."
|
|
5375
5444
|
),
|
|
5376
|
-
productId:
|
|
5445
|
+
productId: z22.string().uuid().optional().describe(
|
|
5377
5446
|
"The product to buy; leave out for the first one in stock."
|
|
5378
5447
|
),
|
|
5379
|
-
countryCode:
|
|
5380
|
-
postalCode:
|
|
5381
|
-
extras:
|
|
5382
|
-
|
|
5383
|
-
productId:
|
|
5384
|
-
quantity:
|
|
5448
|
+
countryCode: z22.string().regex(/^[A-Z]{2}$/).default("NL").describe("Where it is posted, for a product that is posted."),
|
|
5449
|
+
postalCode: z22.string().max(20).optional(),
|
|
5450
|
+
extras: z22.array(
|
|
5451
|
+
z22.object({
|
|
5452
|
+
productId: z22.string().uuid(),
|
|
5453
|
+
quantity: z22.number().int().min(1).max(99).default(1)
|
|
5385
5454
|
})
|
|
5386
5455
|
).max(10).optional().describe(
|
|
5387
5456
|
"Extras to take with the product, each a product from its `extras`; for one that follows its line the quantity is per piece."
|
|
5388
5457
|
),
|
|
5389
|
-
options:
|
|
5390
|
-
|
|
5391
|
-
|
|
5458
|
+
options: z22.record(
|
|
5459
|
+
z22.string().regex(/^[a-z0-9_]{1,40}$/),
|
|
5460
|
+
z22.union([z22.string().max(2e3), z22.boolean()])
|
|
5392
5461
|
).optional().describe(
|
|
5393
5462
|
"The choices for the product\u2019s options, by option key: a text, true for a ticked box, or the key of a choice."
|
|
5394
5463
|
)
|
|
@@ -5515,9 +5584,9 @@ function registerShopTestOrderTool(server, client, options = {}) {
|
|
|
5515
5584
|
}
|
|
5516
5585
|
|
|
5517
5586
|
// src/task-tools.ts
|
|
5518
|
-
import { z as
|
|
5519
|
-
var id6 =
|
|
5520
|
-
var moment2 =
|
|
5587
|
+
import { z as z23 } from "zod";
|
|
5588
|
+
var id6 = z23.string().uuid();
|
|
5589
|
+
var moment2 = z23.string().datetime({ offset: true }).describe(
|
|
5521
5590
|
"An ISO moment with its offset, such as 2026-11-01T09:00:00+01:00."
|
|
5522
5591
|
);
|
|
5523
5592
|
var OUTSIDE_PROJECTS = "Only tasks outside projects: a project\u2019s tasks are seen differently per member and are worked on in the app.";
|
|
@@ -5528,7 +5597,7 @@ function registerTaskTools(server, client) {
|
|
|
5528
5597
|
title: "List tasks",
|
|
5529
5598
|
description: `Tasks paged by id: open and in progress unless status says otherwise; recordId, dealId and assigneeId narrow them. ${OUTSIDE_PROJECTS}`,
|
|
5530
5599
|
inputSchema: {
|
|
5531
|
-
status:
|
|
5600
|
+
status: z23.enum(["open", "in_progress", "done", "all"]).optional(),
|
|
5532
5601
|
recordId: id6.optional(),
|
|
5533
5602
|
dealId: id6.optional(),
|
|
5534
5603
|
assigneeId: id6.optional(),
|
|
@@ -5574,14 +5643,14 @@ function registerTaskTools(server, client) {
|
|
|
5574
5643
|
title: "Make a task",
|
|
5575
5644
|
description: `A task on a contact (recordId), on a deal (dealId; with recordId one of that contact\u2019s deals), or on nothing, optionally due, prioritised and assigned to members. ${OUTSIDE_PROJECTS}`,
|
|
5576
5645
|
inputSchema: {
|
|
5577
|
-
title:
|
|
5578
|
-
description:
|
|
5646
|
+
title: z23.string().min(1).max(500),
|
|
5647
|
+
description: z23.string().max(2e4).nullable().optional(),
|
|
5579
5648
|
dueAt: moment2.nullable().optional(),
|
|
5580
|
-
priority:
|
|
5649
|
+
priority: z23.enum(["low", "normal", "high"]).optional(),
|
|
5581
5650
|
recordId: id6.nullable().optional(),
|
|
5582
5651
|
dealId: id6.nullable().optional(),
|
|
5583
5652
|
parentTaskId: id6.nullable().optional(),
|
|
5584
|
-
assigneeIds:
|
|
5653
|
+
assigneeIds: z23.array(id6).max(20).optional()
|
|
5585
5654
|
}
|
|
5586
5655
|
},
|
|
5587
5656
|
async (input) => {
|
|
@@ -5600,12 +5669,12 @@ function registerTaskTools(server, client) {
|
|
|
5600
5669
|
description: `Changes only what is sent; status done completes it. assigneeIds replaces who works on it. ${OUTSIDE_PROJECTS}`,
|
|
5601
5670
|
inputSchema: {
|
|
5602
5671
|
id: id6,
|
|
5603
|
-
title:
|
|
5604
|
-
description:
|
|
5672
|
+
title: z23.string().min(1).max(500).optional(),
|
|
5673
|
+
description: z23.string().max(2e4).nullable().optional(),
|
|
5605
5674
|
dueAt: moment2.nullable().optional(),
|
|
5606
|
-
priority:
|
|
5607
|
-
status:
|
|
5608
|
-
assigneeIds:
|
|
5675
|
+
priority: z23.enum(["low", "normal", "high"]).optional(),
|
|
5676
|
+
status: z23.enum(["open", "in_progress", "done"]).optional(),
|
|
5677
|
+
assigneeIds: z23.array(id6).max(20).optional()
|
|
5609
5678
|
},
|
|
5610
5679
|
annotations: { idempotentHint: true }
|
|
5611
5680
|
},
|
|
@@ -5626,7 +5695,7 @@ function registerTaskTools(server, client) {
|
|
|
5626
5695
|
inputSchema: {
|
|
5627
5696
|
from: moment2,
|
|
5628
5697
|
to: moment2,
|
|
5629
|
-
kind:
|
|
5698
|
+
kind: z23.enum(["appointment", "block", "all"]).optional(),
|
|
5630
5699
|
contactRecordId: id6.optional(),
|
|
5631
5700
|
...page
|
|
5632
5701
|
},
|
|
@@ -5675,14 +5744,14 @@ function describeAppointment(appointment) {
|
|
|
5675
5744
|
}
|
|
5676
5745
|
|
|
5677
5746
|
// src/tool-definitions-version.ts
|
|
5678
|
-
import { z as
|
|
5747
|
+
import { z as z24 } from "zod";
|
|
5679
5748
|
import { createHash } from "crypto";
|
|
5680
5749
|
function toolDefinitionsHash(tools) {
|
|
5681
5750
|
const definitions = [...tools].sort((left, right) => left.name.localeCompare(right.name)).map(({ name, config }) => ({
|
|
5682
5751
|
name,
|
|
5683
5752
|
title: config.title ?? null,
|
|
5684
5753
|
description: config.description ?? null,
|
|
5685
|
-
inputSchema: config.inputSchema ?
|
|
5754
|
+
inputSchema: config.inputSchema ? z24.toJSONSchema(z24.object(config.inputSchema), {
|
|
5686
5755
|
io: "input",
|
|
5687
5756
|
unrepresentable: "any"
|
|
5688
5757
|
}) : null,
|
|
@@ -5730,7 +5799,7 @@ function holdToolRegistrations(real) {
|
|
|
5730
5799
|
description: `${config.description ?? ""} Definitions version ${version2}: send it as schemaHash and the answer tells you when these tool definitions are older than the server.`,
|
|
5731
5800
|
inputSchema: {
|
|
5732
5801
|
...config.inputSchema,
|
|
5733
|
-
schemaHash:
|
|
5802
|
+
schemaHash: z24.string().max(64).optional().describe(
|
|
5734
5803
|
`The definitions version named in this tool's description (${version2}).`
|
|
5735
5804
|
)
|
|
5736
5805
|
}
|
|
@@ -5801,6 +5870,7 @@ async function main() {
|
|
|
5801
5870
|
registerEmailTemplateTools(held.server, client);
|
|
5802
5871
|
registerFormDefinitionTools(held.server, client);
|
|
5803
5872
|
registerConsentBannerTools(held.server, client);
|
|
5873
|
+
registerHostingOrderPageTools(held.server, client);
|
|
5804
5874
|
registerTaskTools(held.server, client);
|
|
5805
5875
|
held.publish();
|
|
5806
5876
|
await server.connect(new StdioServerTransport());
|