@zaapi/open-api-mcp 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/client.js +5 -0
  2. package/dist/client.js.map +1 -1
  3. package/dist/instructions.js +73 -0
  4. package/dist/instructions.js.map +1 -0
  5. package/dist/server.js +134 -12
  6. package/dist/server.js.map +1 -1
  7. package/dist/tools/accounts/list-accounts.js +8 -18
  8. package/dist/tools/accounts/list-accounts.js.map +1 -1
  9. package/dist/tools/common.js +22 -26
  10. package/dist/tools/common.js.map +1 -1
  11. package/dist/tools/contacts/create-contact.js +13 -7
  12. package/dist/tools/contacts/create-contact.js.map +1 -1
  13. package/dist/tools/contacts/get-contact-by-id.js +6 -7
  14. package/dist/tools/contacts/get-contact-by-id.js.map +1 -1
  15. package/dist/tools/contacts/list-contact-fields.js +5 -3
  16. package/dist/tools/contacts/list-contact-fields.js.map +1 -1
  17. package/dist/tools/contacts/list-contacts.js +11 -6
  18. package/dist/tools/contacts/list-contacts.js.map +1 -1
  19. package/dist/tools/contacts/search-contacts.js +20 -0
  20. package/dist/tools/contacts/search-contacts.js.map +1 -0
  21. package/dist/tools/contacts/update-contact-field.js +12 -7
  22. package/dist/tools/contacts/update-contact-field.js.map +1 -1
  23. package/dist/tools/conversations/filter-conversations.js +11 -7
  24. package/dist/tools/conversations/filter-conversations.js.map +1 -1
  25. package/dist/tools/conversations/mark-conversation-read.js +4 -6
  26. package/dist/tools/conversations/mark-conversation-read.js.map +1 -1
  27. package/dist/tools/conversations/update-conversation-labels.js +10 -9
  28. package/dist/tools/conversations/update-conversation-labels.js.map +1 -1
  29. package/dist/tools/index.js +4 -0
  30. package/dist/tools/index.js.map +1 -1
  31. package/dist/tools/labels/list-labels.js +7 -4
  32. package/dist/tools/labels/list-labels.js.map +1 -1
  33. package/dist/tools/messages/create-internal-comment.js +9 -8
  34. package/dist/tools/messages/create-internal-comment.js.map +1 -1
  35. package/dist/tools/messages/get-messages.js +9 -7
  36. package/dist/tools/messages/get-messages.js.map +1 -1
  37. package/dist/tools/messages/list-internal-comments.js +8 -8
  38. package/dist/tools/messages/list-internal-comments.js.map +1 -1
  39. package/dist/tools/messages/search-messages.js +20 -0
  40. package/dist/tools/messages/search-messages.js.map +1 -0
  41. package/dist/tools/messages/send-plain-text-message.js +9 -8
  42. package/dist/tools/messages/send-plain-text-message.js.map +1 -1
  43. package/dist/tools/responses.js +271 -0
  44. package/dist/tools/responses.js.map +1 -0
  45. package/dist/tools/teams/list-teams.js +10 -5
  46. package/dist/tools/teams/list-teams.js.map +1 -1
  47. package/dist/tools/tickets/close-ticket.js +17 -10
  48. package/dist/tools/tickets/close-ticket.js.map +1 -1
  49. package/dist/tools/tickets/get-ticket-by-id.js +8 -8
  50. package/dist/tools/tickets/get-ticket-by-id.js.map +1 -1
  51. package/dist/tools/tickets/list-ticket-fields.js +7 -4
  52. package/dist/tools/tickets/list-ticket-fields.js.map +1 -1
  53. package/dist/tools/tickets/list-tickets.js +22 -22
  54. package/dist/tools/tickets/list-tickets.js.map +1 -1
  55. package/dist/tools/tickets/update-ticket-field.js +15 -8
  56. package/dist/tools/tickets/update-ticket-field.js.map +1 -1
  57. package/dist/tools/users/list-users.js +8 -5
  58. package/dist/tools/users/list-users.js.map +1 -1
  59. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { loadConfig } from './config.js';
2
2
  const PAGE_SIZE_HEADER = 'x-pagination-page-size';
3
3
  const NEXT_CURSOR_HEADER = 'x-pagination-next-cursor';
4
+ const RETRY_AFTER_HEADER = 'retry-after';
4
5
  export class ZaapiClient {
5
6
  config;
6
7
  fetchFn;
@@ -8,6 +9,9 @@ export class ZaapiClient {
8
9
  this.config = config;
9
10
  this.fetchFn = fetchFn;
10
11
  }
12
+ get baseUrl() {
13
+ return this.config.baseUrl;
14
+ }
11
15
  static fromEnv(env = process.env, fetchFn = fetch) {
12
16
  return new ZaapiClient(loadConfig(env), fetchFn);
13
17
  }
@@ -40,6 +44,7 @@ export class ZaapiClient {
40
44
  pageSize: response.headers.get(PAGE_SIZE_HEADER) ?? undefined,
41
45
  nextCursor: response.headers.get(NEXT_CURSOR_HEADER) ?? undefined,
42
46
  },
47
+ retryAfter: response.headers.get(RETRY_AFTER_HEADER) ?? undefined,
43
48
  };
44
49
  }
45
50
  buildUrl(path, query) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AAsB3D,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAClD,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAEtD,MAAM,OAAO,WAAW;IAEH;IACA;IAFnB,YACmB,MAAmB,EACnB,UAAmB,KAAK;QADxB,WAAM,GAAN,MAAM,CAAa;QACnB,YAAO,GAAP,OAAO,CAAiB;IACxC,CAAC;IAEJ,MAAM,CAAC,OAAO,CACZ,MAA2B,OAAO,CAAC,GAAG,EACtC,UAAmB,KAAK;QAExB,OAAO,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAqB;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACvD,MAAM,OAAO,GAA2B;YACtC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC/B,MAAM,EAAE,kBAAkB;SAC3B,CAAC;QAEF,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YAC7C,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,IAAI,GAAY,IAAI,CAAC;QACzB,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO;YACL,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,IAAI;YACJ,UAAU,EAAE;gBACV,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,SAAS;gBAC7D,UAAU,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS;aAClE;SACF,CAAC;IACJ,CAAC;IAEO,QAAQ,CAAC,IAAY,EAAE,KAA+B;QAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;QACxB,CAAC;QAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC1C,SAAS;YACX,CAAC;YACD,GAAG,CAAC,YAAY,CAAC,GAAG,CAClB,GAAG,EACH,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACJ,CAAC;QAED,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ export const INSTRUCTIONS = `Zaapi is a shared inbox for sellers. Customer conversations from LINE, Instagram, Facebook, WhatsApp, Shopee, Lazada, TikTok, email and the web widget land in one place, and the team works them as tickets.
2
+
3
+ This server exposes the public Zaapi Open API. The API key selects the store, so every call is already scoped to one store and there is no storeId argument anywhere.
4
+
5
+ # How the data links together
6
+
7
+ - **Account** — one connected channel inbox (a LINE OA, an Instagram account, a Shopee shop, a mailbox). \`listAccounts\`.
8
+ - **Contact** — one person. Holds name, emails, phones, addresses, and \`customFields\` keyed by contact field id. \`getContactById\`, \`searchContacts\`, \`listContacts\`.
9
+ - **Conversation** — one ongoing thread between a contact and an account, on one channel. Carries \`contactId\`, \`accountId\`, \`labelIds\`, an unread count and a last-message snippet. \`filterConversations\`.
10
+ - **Ticket** — one unit of work over a slice of a conversation's timeline, with \`ticketNumber\`, an assignee, an open/closed state, and \`ticketFields\` keyed by ticket field id. A conversation accumulates many tickets over its life and has at most one open at a time. \`listTickets\`, \`getTicketById\`.
11
+ - **Message** — one customer-facing message on a conversation. \`getMessages\`, \`searchMessages\`.
12
+ - **Internal comment** — a seller-private note on a conversation. Never delivered to the customer. \`listInternalComments\`.
13
+ - **User** — a seat on the store. **Team** — a named group of users. \`listUsers\`, \`listTeams\`.
14
+ - **Label** — a tag applied to a conversation. \`listLabels\`.
15
+ - **Ticket field / contact field** — the store's custom field definitions. \`listTicketFields\`, \`listContactFields\`.
16
+
17
+ Contact → many conversations (one per channel it writes from) → many tickets over time. A ticket also carries \`conversationId\`, \`contactId\` and \`accountId\` directly, so one \`listTickets\` call usually gives you every id the rest of the task needs.
18
+
19
+ Note what hangs off which object. **Labels, messages and internal comments belong to the conversation, not to the ticket** — labelling or reading a thread affects every ticket on it. **Ticket fields belong to the ticket**; **contact fields belong to the contact**.
20
+
21
+ # Where to start
22
+
23
+ There is no endpoint that lists conversations or messages on their own. Every read starts from one of these:
24
+
25
+ - **A queue, a person's workload, a filtered set of work** → \`listTickets\`. With no filters it returns the live queue: open, non-spam, not snoozed, newest message first. This is the default entry point.
26
+ - **A topic, a phrase, something the customer said** → \`searchMessages\`. The only way to reach a thread from its content. Every hit carries \`conversationId\`.
27
+ - **A person by name, email or phone** → \`searchContacts\`, then \`filterConversations\` with the \`contactId\` for their threads.
28
+ - **A ticket number or id already in hand** → \`getTicketById\`.
29
+
30
+ From a \`conversationId\` you can reach everything else: \`getMessages\` for the thread, \`listInternalComments\` for private notes, \`listTickets\` with \`conversationId\` for its full ticket history (set \`statuses\` or omit it to include closed ones), \`filterConversations\` for labels and the contact.
31
+
32
+ # Custom fields
33
+
34
+ \`ticketFields\` and \`customFields\` are maps keyed by **field id**, never by field name. When a request names a field in words ("order number", "loyalty tier"), call \`listTicketFields\` or \`listContactFields\` first and match on \`name\` to get the id. Those catalogs also give you \`dataType\`, \`selectOptions\` and \`regex\` — a value that does not match the definition is rejected.
35
+
36
+ Ticket fields additionally accept four system keys wherever a \`ticketFieldId\` is taken: \`isConverted\`, \`salesRevenue\`, \`aiCsat\`, \`aiSummary\`.
37
+
38
+ # Users and assignment
39
+
40
+ \`listUsers\` returns two identifiers per seat and they are not interchangeable. **\`userId\` (a UUID) is the one that matters**: it is what \`assigneeUserId\` and \`handledBy\` hold on a ticket, and what \`listTickets\` \`assigneeUserIds\` / \`handledByUserIds\`, \`closeTicket\` \`handledBy\` and \`listTeams\` \`userId\` all match on. The \`id\` beside it is the seat record and filters nothing.
41
+
42
+ There is no team filter on tickets. To scope work to a team, read its members with \`listTeams\` and pass their UUIDs as \`assigneeUserIds\`.
43
+
44
+ # Pagination
45
+
46
+ Every paged result returns \`pagination.nextCursor\`. Pass it back verbatim as \`cursor\` for the next page; its absence means you have reached the end. Most list tools take \`pageSize\` up to 100 — ask for what you need in one call instead of walking small pages. \`searchContacts\` and \`searchMessages\` are fixed at 10 per page and reject \`pageSize\`.
47
+
48
+ Results can be large. Prefer a filter over fetching pages and discarding them.
49
+
50
+ # expand
51
+
52
+ Read tools take an \`expand\` list that replaces or supplements ids with the named object in the same response — \`expand: ["account","assignee"]\` on \`listTickets\` saves a \`listAccounts\` and a \`listUsers\` call. The allowed values differ per tool and are enumerated on each \`expand\` argument; anything else is rejected with 400.
53
+
54
+ # Writing
55
+
56
+ - \`sendPlainTextMessage\` reaches a real customer on the channel and cannot be recalled. Confirm the wording with the user before sending. For something only the team should see, use \`createInternalComment\`.
57
+ - \`closeTicket\` ends the ticket fronting a conversation. Confirm before calling it.
58
+ - \`updateTicketField\` and \`updateContactField\` write **one field per call** and use optimistic concurrency: echo back the timestamp from your most recent read (\`ticketFieldsUpdatedAt\` on a ticket; \`customFieldsUpdatedAt\`, or \`updatedAt\` when that is absent, on a contact). A **409** means someone else wrote in between — re-read the record and retry with the fresh timestamp. Do not retry with the same one.
59
+ - \`createContact\` rejects a duplicate email or phone with **409**. That means the person is already on file, so search before creating. Custom fields cannot be set at creation; create, then write each field.
60
+ - \`updateConversationLabels\` only accepts label ids that already exist. Resolve names with \`listLabels\` first; it does not create labels.
61
+ - Several writes — \`sendPlainTextMessage\`, \`createInternalComment\`, \`updateContactField\`, \`updateConversationLabels\`, \`markConversationRead\` — return only an acknowledgement. Re-read the resource if you need to confirm the result.
62
+
63
+ # Results and errors
64
+
65
+ Every result is \`{ status, data, pagination? }\`, with the API envelope already unwrapped. Failures set \`isError\` and return \`{ status, error }\`, where \`error\` carries the API message, a \`requestId\` to quote to Zaapi support, and a \`hint\` when there is a specific way to recover.
66
+
67
+ - **400** — usually an invalid \`expand\` value or a filter combination the API rejects. Read the message; do not retry unchanged.
68
+ - **401 / 403** — the key is invalid or its usage plan is missing the scope that tool needs. Each tool names its scope. Not retryable; tell the user which scope to add.
69
+ - **404** — the id does not exist on this store, or (on \`markConversationRead\`) the conversation has no open ticket.
70
+ - **409** — a concurrent write. Re-read, then retry.
71
+ - **429** — throttled by the usage plan. Back off before retrying.
72
+ `;
73
+ //# sourceMappingURL=instructions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuE3B,CAAC"}
package/dist/server.js CHANGED
@@ -1,45 +1,167 @@
1
+ import { createRequire } from 'node:module';
1
2
  import { McpServer } from '@modelcontextprotocol/server';
3
+ import { INSTRUCTIONS } from './instructions.js';
2
4
  import { splitInput, tools } from './tools/index.js';
5
+ const FALLBACK_VERSION = '0.0.0';
6
+ export function serverVersion() {
7
+ try {
8
+ const require = createRequire(import.meta.url);
9
+ const manifest = require('../package.json');
10
+ return manifest.version ?? FALLBACK_VERSION;
11
+ }
12
+ catch {
13
+ return FALLBACK_VERSION;
14
+ }
15
+ }
3
16
  export function createZaapiServer(client) {
4
17
  const server = new McpServer({
5
18
  name: 'zaapi',
6
- version: '1.0.0',
7
- });
19
+ version: serverVersion(),
20
+ }, { instructions: INSTRUCTIONS });
8
21
  for (const tool of tools) {
9
22
  server.registerTool(tool.name, {
10
23
  title: tool.title,
11
24
  description: tool.description,
12
25
  inputSchema: tool.inputSchema,
26
+ outputSchema: tool.outputSchema,
13
27
  annotations: tool.annotations,
28
+ _meta: transportMeta(tool),
14
29
  }, createToolHandler(client, tool));
15
30
  }
16
31
  return server;
17
32
  }
33
+ export function transportMeta(tool) {
34
+ return {
35
+ 'co.zaapi/http': {
36
+ method: tool.method,
37
+ path: tool.path,
38
+ queryKeys: [...tool.queryKeys],
39
+ bodyKeys: tool.method === 'GET' ? [] : 'all other arguments',
40
+ scope: tool.scope,
41
+ },
42
+ };
43
+ }
18
44
  export function createToolHandler(client, tool) {
19
45
  return async (input) => {
20
46
  const args = input && typeof input === 'object' && !Array.isArray(input)
21
47
  ? input
22
48
  : {};
23
49
  const { query, body } = splitRequest(tool, args);
24
- const result = await client.request({
25
- method: tool.method,
26
- path: tool.path,
27
- query,
28
- body,
29
- });
50
+ let result;
51
+ try {
52
+ result = await client.request({
53
+ method: tool.method,
54
+ path: tool.path,
55
+ query,
56
+ body,
57
+ });
58
+ }
59
+ catch (error) {
60
+ return transportFailure(client, tool, error);
61
+ }
62
+ if (result.status >= 400) {
63
+ return errorResult(tool, result);
64
+ }
65
+ const pagination = {
66
+ ...(result.pagination.pageSize
67
+ ? { pageSize: result.pagination.pageSize }
68
+ : {}),
69
+ ...(result.pagination.nextCursor
70
+ ? { nextCursor: result.pagination.nextCursor }
71
+ : {}),
72
+ };
30
73
  const payload = {
31
74
  status: result.status,
32
75
  data: unwrapOpenApiEnvelope(result.body),
33
- ...(result.pagination.pageSize || result.pagination.nextCursor
34
- ? { pagination: result.pagination }
35
- : {}),
76
+ ...(Object.keys(pagination).length > 0 ? { pagination } : {}),
36
77
  };
78
+ if (tool.outputSchema && !tool.outputSchema.safeParse(payload).success) {
79
+ return textResult({
80
+ status: result.status,
81
+ error: {
82
+ message: `The Open API returned a ${tool.name} response that does not match its documented shape.`,
83
+ code: 'unexpected_response_shape',
84
+ hint: 'Treat the raw body below as untyped. Report this to Zaapi support with the requestId if it persists.',
85
+ body: result.body,
86
+ },
87
+ }, true);
88
+ }
37
89
  return {
38
90
  content: [{ type: 'text', text: JSON.stringify(payload) }],
39
- isError: result.status >= 400,
91
+ ...(tool.outputSchema ? { structuredContent: payload } : {}),
92
+ isError: false,
40
93
  };
41
94
  };
42
95
  }
96
+ function textResult(payload, isError) {
97
+ return {
98
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
99
+ isError,
100
+ };
101
+ }
102
+ function transportFailure(client, tool, error) {
103
+ const cause = error instanceof Error ? error : undefined;
104
+ const detail = cause?.cause instanceof Error ? cause.cause.message : undefined;
105
+ return textResult({
106
+ status: 0,
107
+ error: {
108
+ message: `Could not reach the Zaapi Open API at ${client.baseUrl}${tool.path}: ${cause?.message ?? String(error)}${detail ? ` (${detail})` : ''}`,
109
+ code: 'transport_error',
110
+ baseUrl: client.baseUrl,
111
+ path: tool.path,
112
+ hint: 'The request never reached the API, so nothing was changed. Check network access and that ZAAPI_BASE_URL points at the right host, then retry.',
113
+ },
114
+ }, true);
115
+ }
116
+ function errorResult(tool, result) {
117
+ const envelope = result.body &&
118
+ typeof result.body === 'object' &&
119
+ !Array.isArray(result.body)
120
+ ? result.body
121
+ : undefined;
122
+ const inner = envelope && typeof envelope.error === 'object' && envelope.error !== null
123
+ ? envelope.error
124
+ : undefined;
125
+ const message = (typeof inner?.message === 'string' ? inner.message : undefined) ??
126
+ (typeof envelope?.message === 'string' ? envelope.message : undefined) ??
127
+ (typeof result.body === 'string' && result.body
128
+ ? result.body
129
+ : undefined) ??
130
+ `Request failed with status ${result.status}.`;
131
+ const requestId = typeof envelope?.requestId === 'string' ? envelope.requestId : undefined;
132
+ const hint = remediation(tool, result.status, result.retryAfter);
133
+ return textResult({
134
+ status: result.status,
135
+ error: {
136
+ message,
137
+ statusCode: result.status,
138
+ ...(requestId ? { requestId } : {}),
139
+ ...(hint ? { hint } : {}),
140
+ },
141
+ }, true);
142
+ }
143
+ function remediation(tool, status, retryAfter) {
144
+ switch (status) {
145
+ case 400:
146
+ return 'The arguments were rejected. Check any expand values against the ones this tool lists, and check filter combinations. Do not retry unchanged.';
147
+ case 401:
148
+ return 'ZAAPI_API_KEY is missing, malformed, or not a key for this host. Keys start with zaapi_. Not retryable.';
149
+ case 403:
150
+ return `The key's usage plan is missing the ${tool.scope} scope, or the key does not cover this store. Not retryable — ask the user to grant ${tool.scope} in Settings → Developers.`;
151
+ case 404:
152
+ return 'No such record on this store. Re-read the id from the list or search tool that produced it.';
153
+ case 409:
154
+ return 'A concurrent write. Re-read the record and retry with the timestamp from that fresh read — retrying with the same one will fail again.';
155
+ case 429:
156
+ return retryAfter
157
+ ? `Throttled by the usage plan. Wait ${retryAfter} seconds before retrying.`
158
+ : 'Throttled by the usage plan. Back off before retrying.';
159
+ default:
160
+ return status >= 500
161
+ ? 'The Open API failed. Retry once after a short pause; if it persists, quote the requestId to Zaapi support.'
162
+ : undefined;
163
+ }
164
+ }
43
165
  function unwrapOpenApiEnvelope(body) {
44
166
  if (body === null || typeof body !== 'object' || Array.isArray(body)) {
45
167
  return body;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -1,32 +1,22 @@
1
1
  import { z } from 'zod';
2
- import { describeHttpRequest, paginationFields, } from '../common.js';
2
+ import { paginationFields } from '../common.js';
3
+ import { account, channel, envelope } from '../responses.js';
3
4
  const queryKeys = ['channel', 'pageSize', 'cursor'];
4
5
  export const listAccounts = {
5
6
  name: 'listAccounts',
6
7
  title: 'List accounts',
7
- description: `Required scope: accounts:read. ${describeHttpRequest('GET', '/v1/accounts', queryKeys)} Page through the channel accounts connected to the store. Only active accounts are returned. Filter to a single channel when needed. Each account includes a status of healthy, unhealthy, or disconnected.`,
8
+ description: 'Page through the channel inboxes connected to the store — the LINE, Instagram, Shopee, email and other accounts that conversations arrive on. Only active accounts are returned, oldest first. Each carries a status of healthy, unhealthy or disconnected; sending on anything other than healthy may fail at the channel, so check here first when a send does not land. Requires the accounts:read scope.',
9
+ scope: 'accounts:read',
8
10
  method: 'GET',
9
11
  path: '/v1/accounts',
10
12
  queryKeys,
11
13
  inputSchema: z.object({
12
- channel: z
13
- .enum([
14
- 'line',
15
- 'instagram',
16
- 'facebook',
17
- 'lazada',
18
- 'shopee',
19
- 'tiktok',
20
- 'drunken_lullabies',
21
- 'whatsapp',
22
- 'widget',
23
- 'gmail',
24
- 'outlook',
25
- ])
14
+ channel: channel
26
15
  .optional()
27
- .describe('Query parameter. Return only the accounts on this channel.'),
16
+ .describe('Return only the accounts on this channel.'),
28
17
  ...paginationFields,
29
18
  }),
30
- annotations: { readOnlyHint: true },
19
+ outputSchema: envelope(z.array(account), 'A page of connected channel accounts.', { paginated: true }),
20
+ annotations: { readOnlyHint: true, openWorldHint: true },
31
21
  };
32
22
  //# sourceMappingURL=list-accounts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-accounts.js","sourceRoot":"","sources":["../../../src/tools/accounts/list-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAEjB,MAAM,cAAc,CAAC;AAEtB,MAAM,SAAS,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,kCAAkC,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,8MAA8M;IAClT,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,OAAO,EAAE,CAAC;aACP,IAAI,CAAC;YACJ,MAAM;YACN,WAAW;YACX,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,QAAQ;YACR,mBAAmB;YACnB,UAAU;YACV,QAAQ;YACR,OAAO;YACP,SAAS;SACV,CAAC;aACD,QAAQ,EAAE;aACV,QAAQ,CAAC,4DAA4D,CAAC;QACzE,GAAG,gBAAgB;KACpB,CAAC;IACF,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;CACpC,CAAC"}
1
+ {"version":3,"file":"list-accounts.js","sourceRoot":"","sources":["../../../src/tools/accounts/list-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAqB,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,SAAS,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAU,CAAC;AAE7D,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,8YAA8Y;IAChZ,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,OAAO,EAAE,OAAO;aACb,QAAQ,EAAE;aACV,QAAQ,CAAC,2CAA2C,CAAC;QACxD,GAAG,gBAAgB;KACpB,CAAC;IACF,YAAY,EAAE,QAAQ,CACpB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAChB,uCAAuC,EACvC,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB;IACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;CACzD,CAAC"}
@@ -1,33 +1,27 @@
1
1
  import { z } from 'zod';
2
- export function describeHttpRequest(method, path, queryKeys) {
3
- const query = queryKeys.length > 0
4
- ? `Query parameters: ${queryKeys.join(', ')}.`
5
- : 'There are no query parameters.';
6
- const body = method === 'GET'
7
- ? 'There is no JSON body.'
8
- : queryKeys.length === 0
9
- ? 'All arguments are sent as a JSON body.'
10
- : 'All other arguments are sent as a JSON body.';
11
- return `${method} ${path}. ${query} ${body}`;
12
- }
13
2
  export const pageSize = z
14
3
  .number()
15
4
  .int()
16
5
  .min(1)
17
6
  .max(100)
18
7
  .optional()
19
- .describe('Query parameter. Items per page. Defaults to 20. Maximum 100.');
8
+ .describe('Items per page. Defaults to 20. Maximum 100.');
20
9
  export const messagePageSize = z
21
10
  .number()
22
11
  .int()
23
12
  .min(1)
24
13
  .max(100)
25
14
  .optional()
26
- .describe('Query parameter. Items per page. Defaults to 15. Maximum 100.');
15
+ .describe('Items per page. Defaults to 15. Maximum 100.');
27
16
  export const cursor = z
28
17
  .string()
29
18
  .optional()
30
- .describe('Query parameter. Opaque token from the previous page x-pagination-next-cursor header.');
19
+ .describe('Opaque token from the previous page. Pass back pagination.nextCursor from the last result, verbatim.');
20
+ export const searchQuery = z
21
+ .string()
22
+ .min(1)
23
+ .max(150)
24
+ .describe('Free-text search query. 1 to 150 characters.');
31
25
  export const fieldValue = z.union([
32
26
  z.string(),
33
27
  z.number(),
@@ -36,18 +30,20 @@ export const fieldValue = z.union([
36
30
  z.array(z.string()),
37
31
  z.array(z.number()),
38
32
  ]);
39
- export const expand = (description) => z
40
- .preprocess((value) => {
41
- if (typeof value !== 'string') {
42
- return value;
43
- }
44
- return value
45
- .split(',')
46
- .map((name) => name.trim())
47
- .filter(Boolean);
48
- }, z.array(z.string()))
49
- .optional()
50
- .describe(`Query parameter. ${description}`);
33
+ export function expand(values, description) {
34
+ return z
35
+ .preprocess((value) => {
36
+ if (typeof value !== 'string') {
37
+ return value;
38
+ }
39
+ return value
40
+ .split(',')
41
+ .map((name) => name.trim())
42
+ .filter(Boolean);
43
+ }, z.array(z.enum(values)))
44
+ .optional()
45
+ .describe(`${description} Any other value is rejected with 400.`);
46
+ }
51
47
  export const paginationQueryKeys = ['pageSize', 'cursor', 'expand'];
52
48
  export const paginationFields = {
53
49
  pageSize,
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/tools/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkBxB,MAAM,UAAU,mBAAmB,CACjC,MAAkB,EAClB,IAAY,EACZ,SAA4B;IAE5B,MAAM,KAAK,GACT,SAAS,CAAC,MAAM,GAAG,CAAC;QAClB,CAAC,CAAC,qBAAqB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;QAC9C,CAAC,CAAC,gCAAgC,CAAC;IACvC,MAAM,IAAI,GACR,MAAM,KAAK,KAAK;QACd,CAAC,CAAC,wBAAwB;QAC1B,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YACtB,CAAC,CAAC,wCAAwC;YAC1C,CAAC,CAAC,8CAA8C,CAAC;IACvD,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,GAAG,CAAC;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,+DAA+D,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,EAAE;KACR,GAAG,EAAE;KACL,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,GAAG,CAAC;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,+DAA+D,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC;KACpB,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CACP,uFAAuF,CACxF,CAAC;AAEJ,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC;IAChC,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,OAAO,EAAE;IACX,CAAC,CAAC,IAAI,EAAE;IACR,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,WAAmB,EAAE,EAAE,CAC5C,CAAC;KACE,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE;IACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;KACtB,QAAQ,EAAE;KACV,QAAQ,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;AAEjD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAE7E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ;IACR,MAAM;CACP,CAAC"}
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/tools/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0BxB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,GAAG,CAAC;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,8CAA8C,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,EAAE;KACR,GAAG,EAAE;KACL,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,GAAG,CAAC;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,8CAA8C,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC;KACpB,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CACP,sGAAsG,CACvG,CAAC;AAEJ,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC;KACzB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,GAAG,CAAC;KACR,QAAQ,CAAC,8CAA8C,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC;IAChC,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,MAAM,EAAE;IACV,CAAC,CAAC,OAAO,EAAE;IACX,CAAC,CAAC,IAAI,EAAE;IACR,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACpB,CAAC,CAAC;AAOH,MAAM,UAAU,MAAM,CACpB,MAAS,EACT,WAAmB;IAEnB,OAAO,CAAC;SACL,UAAU,CACT,CAAC,KAAK,EAAE,EAAE;QACR,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,KAAK;aACT,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC,EACD,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CACxB;SACA,QAAQ,EAAE;SACV,QAAQ,CAAC,GAAG,WAAW,wCAAwC,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAE7E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ;IACR,MAAM;CACP,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import { z } from 'zod';
2
- import { describeHttpRequest } from '../common.js';
2
+ import { contact, envelope } from '../responses.js';
3
3
  const queryKeys = [];
4
4
  export const createContact = {
5
5
  name: 'createContact',
6
6
  title: 'Create a contact',
7
- description: `Required scope: contacts:write. ${describeHttpRequest('POST', '/v1/contacts', queryKeys)} Create a contact. A contact whose email or phone already exists on the store is rejected with 409.`,
7
+ description: 'Create a contact on the store. Search first with searchContacts: an email or phone that already exists is rejected with 409, and that 409 means the person is already on file rather than that the call was malformed. Custom fields cannot be set here — create the contact, then write each one with updateContactField. Requires the contacts:write scope.',
8
+ scope: 'contacts:write',
8
9
  method: 'POST',
9
10
  path: '/v1/contacts',
10
11
  queryKeys,
@@ -13,24 +14,29 @@ export const createContact = {
13
14
  .string()
14
15
  .min(1)
15
16
  .max(50)
16
- .describe('JSON body. First name of the contact. Maximum 50 characters.'),
17
+ .describe('First name of the contact. Maximum 50 characters.'),
17
18
  lastName: z
18
19
  .string()
19
20
  .max(50)
20
21
  .optional()
21
- .describe('JSON body. Last name of the contact. Maximum 50 characters.'),
22
+ .describe('Last name of the contact. Maximum 50 characters.'),
22
23
  email: z
23
24
  .string()
24
25
  .email()
25
26
  .max(100)
26
27
  .optional()
27
- .describe('JSON body. Primary email address. Maximum 100 characters.'),
28
+ .describe('Primary email address. Maximum 100 characters. Must be unique on the store.'),
28
29
  phone: z
29
30
  .string()
30
31
  .max(15)
31
32
  .optional()
32
- .describe('JSON body. Primary phone number in E.164 format. Maximum 15 characters.'),
33
+ .describe('Primary phone number in E.164 format. Maximum 15 characters. Must be unique on the store.'),
33
34
  }),
34
- annotations: { readOnlyHint: false, destructiveHint: false },
35
+ outputSchema: envelope(contact, 'The contact that was created.'),
36
+ annotations: {
37
+ readOnlyHint: false,
38
+ destructiveHint: false,
39
+ openWorldHint: true,
40
+ },
35
41
  };
36
42
  //# sourceMappingURL=create-contact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-contact.js","sourceRoot":"","sources":["../../../src/tools/contacts/create-contact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAqB,MAAM,cAAc,CAAC;AAEtE,MAAM,SAAS,GAAG,EAAW,CAAC;AAE9B,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,mCAAmC,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,CAAC,qGAAqG;IAC3M,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CAAC,8DAA8D,CAAC;QAC3E,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,6DAA6D,CAAC;QAC1E,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,KAAK,EAAE;aACP,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2DAA2D,CAAC;QACxE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CACP,yEAAyE,CAC1E;KACJ,CAAC;IACF,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE;CAC7D,CAAC"}
1
+ {"version":3,"file":"create-contact.js","sourceRoot":"","sources":["../../../src/tools/contacts/create-contact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,SAAS,GAAG,EAAW,CAAC;AAE9B,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,+VAA+V;IACjW,KAAK,EAAE,gBAAgB;IACvB,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CAAC,mDAAmD,CAAC;QAChE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,KAAK,EAAE;aACP,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,6EAA6E,CAC9E;QACH,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CACP,2FAA2F,CAC5F;KACJ,CAAC;IACF,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,+BAA+B,CAAC;IAChE,WAAW,EAAE;QACX,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,KAAK;QACtB,aAAa,EAAE,IAAI;KACpB;CACF,CAAC"}
@@ -1,19 +1,18 @@
1
1
  import { z } from 'zod';
2
- import { describeHttpRequest } from '../common.js';
2
+ import { contact, envelope } from '../responses.js';
3
3
  const queryKeys = ['contactId'];
4
4
  export const getContactById = {
5
5
  name: 'getContactById',
6
6
  title: 'Get a contact by ID',
7
- description: `Required scope: contacts:read. ${describeHttpRequest('GET', '/v1/contacts', queryKeys)} Fetch a single contact, including custom field values.`,
7
+ description: 'Fetch one contact in full, including custom field values and the customFieldsUpdatedAt that updateContactField must echo back. Read this before writing a field. To see the contact’s threads, pass the same id to filterConversations. Requires the contacts:read scope.',
8
+ scope: 'contacts:read',
8
9
  method: 'GET',
9
10
  path: '/v1/contacts',
10
11
  queryKeys,
11
12
  inputSchema: z.object({
12
- contactId: z
13
- .string()
14
- .min(1)
15
- .describe('Query parameter. The ID of the contact.'),
13
+ contactId: z.string().min(1).describe('The ID of the contact.'),
16
14
  }),
17
- annotations: { readOnlyHint: true },
15
+ outputSchema: envelope(contact, 'The contact.'),
16
+ annotations: { readOnlyHint: true, openWorldHint: true },
18
17
  };
19
18
  //# sourceMappingURL=get-contact-by-id.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-contact-by-id.js","sourceRoot":"","sources":["../../../src/tools/contacts/get-contact-by-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAqB,MAAM,cAAc,CAAC;AAEtE,MAAM,SAAS,GAAG,CAAC,WAAW,CAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EAAE,kCAAkC,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,CAAC,yDAAyD;IAC7J,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,yCAAyC,CAAC;KACvD,CAAC;IACF,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;CACpC,CAAC"}
1
+ {"version":3,"file":"get-contact-by-id.js","sourceRoot":"","sources":["../../../src/tools/contacts/get-contact-by-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,SAAS,GAAG,CAAC,WAAW,CAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EACT,2QAA2Q;IAC7Q,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,cAAc;IACpB,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KAChE,CAAC;IACF,YAAY,EAAE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAC/C,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;CACzD,CAAC"}
@@ -1,14 +1,16 @@
1
1
  import { z } from 'zod';
2
- import { describeHttpRequest } from '../common.js';
2
+ import { contactField, envelope } from '../responses.js';
3
3
  const queryKeys = [];
4
4
  export const listContactFields = {
5
5
  name: 'listContactFields',
6
6
  title: 'List contact fields',
7
- description: `Required scope: contacts:read. ${describeHttpRequest('GET', '/v1/contacts/fields', queryKeys)} Full catalog of contact field definitions for the store. Not paginated.`,
7
+ description: "Full catalog of the store's contact field definitions. Not paginated. Call this first whenever a request names a field by its label — the ids, data types and select options here are what updateContactField takes, and what the customFields map on a contact is keyed by. Requires the contacts:read scope.",
8
+ scope: 'contacts:read',
8
9
  method: 'GET',
9
10
  path: '/v1/contacts/fields',
10
11
  queryKeys,
11
12
  inputSchema: z.object({}),
12
- annotations: { readOnlyHint: true },
13
+ outputSchema: envelope(z.array(contactField), 'Every contact field definition on the store.'),
14
+ annotations: { readOnlyHint: true, openWorldHint: true },
13
15
  };
14
16
  //# sourceMappingURL=list-contact-fields.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-contact-fields.js","sourceRoot":"","sources":["../../../src/tools/contacts/list-contact-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAqB,MAAM,cAAc,CAAC;AAEtE,MAAM,SAAS,GAAG,EAAW,CAAC;AAE9B,MAAM,CAAC,MAAM,iBAAiB,GAAiB;IAC7C,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EAAE,kCAAkC,mBAAmB,CAAC,KAAK,EAAE,qBAAqB,EAAE,SAAS,CAAC,0EAA0E;IACrL,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,qBAAqB;IAC3B,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACzB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;CACpC,CAAC"}
1
+ {"version":3,"file":"list-contact-fields.js","sourceRoot":"","sources":["../../../src/tools/contacts/list-contact-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,SAAS,GAAG,EAAW,CAAC;AAE9B,MAAM,CAAC,MAAM,iBAAiB,GAAiB;IAC7C,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EACT,gTAAgT;IAClT,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,qBAAqB;IAC3B,SAAS;IACT,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACzB,YAAY,EAAE,QAAQ,CACpB,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,EACrB,8CAA8C,CAC/C;IACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;CACzD,CAAC"}
@@ -1,10 +1,12 @@
1
1
  import { z } from 'zod';
2
- import { describeHttpRequest, paginationFields, } from '../common.js';
2
+ import { paginationFields } from '../common.js';
3
+ import { contact, envelope } from '../responses.js';
3
4
  const queryKeys = ['pageSize', 'cursor'];
4
5
  export const listContacts = {
5
6
  name: 'listContacts',
6
7
  title: 'List contacts',
7
- description: `Required scope: contacts:read. ${describeHttpRequest('POST', '/v1/contacts/list', queryKeys)} Search and page through contacts, most recently updated first.`,
8
+ description: 'Page through contacts, optionally filtered by a free-text search or an updated-at window. Ordered by most recently updated, or by relevance then recency when search is set; a whitespace-only search is treated as omitted. Use this to walk or sync the book; for ranked lookup of one person by name, email or phone, searchContacts is the better tool. Requires the contacts:read scope.',
9
+ scope: 'contacts:read',
8
10
  method: 'POST',
9
11
  path: '/v1/contacts/list',
10
12
  queryKeys,
@@ -14,16 +16,19 @@ export const listContacts = {
14
16
  .string()
15
17
  .max(100)
16
18
  .optional()
17
- .describe('JSON body. Free-text search across name, email, and phone. Maximum 100 characters.'),
19
+ .describe('Free-text match across name, email and phone. Maximum 100 characters.'),
18
20
  updatedAfter: z
19
21
  .string()
20
22
  .optional()
21
- .describe('JSON body. ISO 8601 date-time. Return only contacts updated on or after this time.'),
23
+ .describe('ISO 8601 date-time. Only contacts updated on or after this time.'),
22
24
  updatedBefore: z
23
25
  .string()
24
26
  .optional()
25
- .describe('JSON body. ISO 8601 date-time. Return only contacts updated before this time.'),
27
+ .describe('ISO 8601 date-time. Only contacts updated before this time.'),
26
28
  }),
27
- annotations: { readOnlyHint: true },
29
+ outputSchema: envelope(z.array(contact), 'A page of contacts.', {
30
+ paginated: true,
31
+ }),
32
+ annotations: { readOnlyHint: true, openWorldHint: true },
28
33
  };
29
34
  //# sourceMappingURL=list-contacts.js.map