@channlize/mcp 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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @channlize/mcp
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Release every `@channlize/*` package under one shared version. From 0.4.0 on, core, react, mcp and skills always publish together at the same version, so matching versions work together.
8
+
9
+ ### Patch Changes
10
+
11
+ - 5663cd2: Make `@channlize/core` the single source for what the packages share.
12
+
13
+ - core exports `DEFAULT_BASE_URL`, `DEFAULT_TIMEOUT`, `EVENT_SEVERITIES`, `EVENT_KEY_PATTERN`, `isValidEventKey`, `keyKind` (widget vs. server key), `readChannlizeEnv` (the `CHANNLIZE_*` variables) and `parseApiError` (the API's error shape). `createNotifier`, the client and `@channlize/mcp` use them instead of their own copies.
14
+ - `ChannlizeError` gains `requestId` and `details` (the API's error body, e.g. `limit`, `used` and `resetAt` on a plan-limit 429). When a legacy route puts its human-readable text in `error`, it becomes the message instead of `HTTP <status>`.
15
+ - The chat types document where the API differs from them (ISO string timestamps, session summaries without `messages`).
16
+ - `@channlize/react` and `@channlize/mcp` re-export the error classes as values, so `instanceof` works without importing core.
17
+ - mcp tool errors no longer end with a doubled period when a core error message ends with one.
18
+
19
+ - Updated dependencies [5663cd2]
20
+ - Updated dependencies
21
+ - @channlize/core@0.4.0
22
+
3
23
  ## 0.3.0
4
24
 
5
25
  ### Minor Changes
package/README.md CHANGED
@@ -173,6 +173,15 @@ await server.runStdio(); // or: await server.runHttp({ port: 3333 })
173
173
  const mcp = buildServer({ serverApiKey: '…' });
174
174
  ```
175
175
 
176
+ ## Documentation
177
+
178
+ - Guide: https://channlize.com/docs/mcp
179
+ - All docs: https://channlize.com/docs (quick start, API keys, troubleshooting)
180
+
181
+ ## Changelog
182
+
183
+ [CHANGELOG.md](./CHANGELOG.md) lists every release of `@channlize/mcp`. Product updates: https://channlize.com/docs/changelog
184
+
176
185
  ## License
177
186
 
178
187
  MIT
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as node_http from 'node:http';
2
2
  import { McpServer } from '@modelcontextprotocol/server';
3
- export { AuthenticationError, ChannlizeConfig, ChannlizeError, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, FileAttachment, NotifyResponse, RateLimitError, SendMessageResponse, ValidationError } from '@channlize/core';
3
+ export { AuthenticationError, ChannlizeConfig, ChannlizeError, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, FileAttachment, KeyKind, NotifyResponse, RateLimitError, SendMessageResponse, ValidationError, keyKind } from '@channlize/core';
4
4
 
5
5
  /**
6
6
  * MCP-specific types and configuration for Channlize
@@ -54,9 +54,6 @@ interface HttpServerOptions {
54
54
  declare class ConfigError extends Error {
55
55
  constructor(message: string);
56
56
  }
57
- type KeyKind = 'widget' | 'server';
58
- /** `wk_…` is the public widget key; anything else is a server API key (`ch_live_…`). */
59
- declare function keyKind(key: string): KeyKind;
60
57
  interface ResolvedConfig {
61
58
  serverApiKey?: string;
62
59
  widgetKey?: string;
@@ -123,5 +120,5 @@ declare class ChannlizeMCPServer {
123
120
  /** Create a new Channlize MCP server. */
124
121
  declare function createMCPServer(options?: MCPServerOptions): ChannlizeMCPServer;
125
122
 
126
- export { ChannlizeMCPServer, ConfigError, ToolError, VERSION, buildServer, configFromEnv, createMCPServer, ChannlizeMCPServer as default, keyKind, resolveConfig };
127
- export type { ChannlizeMCPConfig, HttpServerOptions, KeyKind, MCPServerOptions, ResolvedConfig };
123
+ export { ChannlizeMCPServer, ConfigError, ToolError, VERSION, buildServer, configFromEnv, createMCPServer, ChannlizeMCPServer as default, resolveConfig };
124
+ export type { ChannlizeMCPConfig, HttpServerOptions, MCPServerOptions, ResolvedConfig };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as node_http from 'node:http';
2
2
  import { McpServer } from '@modelcontextprotocol/server';
3
- export { AuthenticationError, ChannlizeConfig, ChannlizeError, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, FileAttachment, NotifyResponse, RateLimitError, SendMessageResponse, ValidationError } from '@channlize/core';
3
+ export { AuthenticationError, ChannlizeConfig, ChannlizeError, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, FileAttachment, KeyKind, NotifyResponse, RateLimitError, SendMessageResponse, ValidationError, keyKind } from '@channlize/core';
4
4
 
5
5
  /**
6
6
  * MCP-specific types and configuration for Channlize
@@ -54,9 +54,6 @@ interface HttpServerOptions {
54
54
  declare class ConfigError extends Error {
55
55
  constructor(message: string);
56
56
  }
57
- type KeyKind = 'widget' | 'server';
58
- /** `wk_…` is the public widget key; anything else is a server API key (`ch_live_…`). */
59
- declare function keyKind(key: string): KeyKind;
60
57
  interface ResolvedConfig {
61
58
  serverApiKey?: string;
62
59
  widgetKey?: string;
@@ -123,5 +120,5 @@ declare class ChannlizeMCPServer {
123
120
  /** Create a new Channlize MCP server. */
124
121
  declare function createMCPServer(options?: MCPServerOptions): ChannlizeMCPServer;
125
122
 
126
- export { ChannlizeMCPServer, ConfigError, ToolError, VERSION, buildServer, configFromEnv, createMCPServer, ChannlizeMCPServer as default, keyKind, resolveConfig };
127
- export type { ChannlizeMCPConfig, HttpServerOptions, KeyKind, MCPServerOptions, ResolvedConfig };
123
+ export { ChannlizeMCPServer, ConfigError, ToolError, VERSION, buildServer, configFromEnv, createMCPServer, ChannlizeMCPServer as default, resolveConfig };
124
+ export type { ChannlizeMCPConfig, HttpServerOptions, MCPServerOptions, ResolvedConfig };
package/dist/index.js CHANGED
@@ -30,15 +30,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AuthenticationError: () => import_core4.AuthenticationError,
34
+ ChannlizeError: () => import_core4.ChannlizeError,
33
35
  ChannlizeMCPServer: () => ChannlizeMCPServer,
34
36
  ConfigError: () => ConfigError,
37
+ RateLimitError: () => import_core4.RateLimitError,
35
38
  ToolError: () => ToolError,
36
39
  VERSION: () => VERSION,
40
+ ValidationError: () => import_core4.ValidationError,
37
41
  buildServer: () => buildServer,
38
42
  configFromEnv: () => configFromEnv,
39
43
  createMCPServer: () => createMCPServer,
40
44
  default: () => index_default,
41
- keyKind: () => keyKind,
45
+ keyKind: () => import_core2.keyKind,
42
46
  resolveConfig: () => resolveConfig
43
47
  });
44
48
  module.exports = __toCommonJS(index_exports);
@@ -75,7 +79,7 @@ function toToolError(err) {
75
79
  if (err instanceof ToolError) return err;
76
80
  if (err instanceof import_core.ChannlizeError) {
77
81
  return new ToolError(
78
- err.statusCode ? hintFor(err.statusCode, err.message) : err.message,
82
+ err.statusCode ? hintFor(err.statusCode, err.message.replace(/\.$/, "")) : err.message,
79
83
  err.statusCode,
80
84
  err.code
81
85
  );
@@ -119,6 +123,7 @@ var ChannlizeApi = class {
119
123
  ...options.body !== void 0 ? { "Content-Type": "application/json" } : {},
120
124
  ...options.headers
121
125
  },
126
+ // oxlint-disable-next-line unicorn/no-invalid-fetch-options -- `method` is dynamic; GET calls never pass a body.
122
127
  body: options.body !== void 0 ? JSON.stringify(options.body) : void 0,
123
128
  signal: AbortSignal.timeout(this.config.timeout)
124
129
  });
@@ -145,13 +150,11 @@ var ChannlizeApi = class {
145
150
  }
146
151
  }
147
152
  if (!res.ok) {
148
- const body = data ?? {};
149
- const raw = Array.isArray(body.message) ? body.message.join(", ") : body.message;
150
- const apiMessage = raw || (typeof body.error === "string" && /\s/.test(body.error) ? body.error : "") || `HTTP ${res.status} ${res.statusText}`.trim();
153
+ const { message, code } = (0, import_core.parseApiError)(res.status, data, res.statusText);
151
154
  throw new ToolError(
152
- hintFor(res.status, apiMessage.replace(/\.$/, "")),
155
+ hintFor(res.status, message.replace(/\.$/, "")),
153
156
  res.status,
154
- body.code ?? (typeof body.error === "string" ? body.error : void 0)
157
+ code
155
158
  );
156
159
  }
157
160
  if (data === void 0) {
@@ -213,17 +216,13 @@ var ChannlizeApi = class {
213
216
  };
214
217
 
215
218
  // src/config.ts
216
- var DEFAULT_BASE_URL = "https://api.channlize.com";
217
- var DEFAULT_TIMEOUT = 1e4;
219
+ var import_core2 = require("@channlize/core");
218
220
  var ConfigError = class extends Error {
219
221
  constructor(message) {
220
222
  super(message);
221
223
  this.name = "ConfigError";
222
224
  }
223
225
  };
224
- function keyKind(key) {
225
- return key.startsWith("wk_") ? "widget" : "server";
226
- }
227
226
  function clean(value) {
228
227
  const v = value?.trim();
229
228
  return v ? v : void 0;
@@ -232,18 +231,18 @@ function resolveConfig(config) {
232
231
  let serverApiKey = clean(config.serverApiKey);
233
232
  let widgetKey = clean(config.widgetKey);
234
233
  const apiKey = clean(config.apiKey);
235
- if (serverApiKey && keyKind(serverApiKey) === "widget") {
234
+ if (serverApiKey && (0, import_core2.keyKind)(serverApiKey) === "widget") {
236
235
  throw new ConfigError(
237
236
  "CHANNLIZE_SERVER_API_KEY / --server-api-key holds a widget key (wk_\u2026). Widget keys are public and only work for the visitor tools: pass it as CHANNLIZE_WIDGET_KEY / --widget-key, and create a server API key (ch_live_\u2026) under SDK & Integration \u2192 API keys in the Channlize dashboard."
238
237
  );
239
238
  }
240
- if (widgetKey && keyKind(widgetKey) === "server") {
239
+ if (widgetKey && (0, import_core2.keyKind)(widgetKey) === "server") {
241
240
  throw new ConfigError(
242
241
  "CHANNLIZE_WIDGET_KEY / --widget-key holds a server API key. Pass server keys (ch_live_\u2026) as CHANNLIZE_SERVER_API_KEY / --server-api-key; widget keys start with wk_."
243
242
  );
244
243
  }
245
244
  if (apiKey) {
246
- if (keyKind(apiKey) === "widget") widgetKey ??= apiKey;
245
+ if ((0, import_core2.keyKind)(apiKey) === "widget") widgetKey ??= apiKey;
247
246
  else serverApiKey ??= apiKey;
248
247
  }
249
248
  if (!serverApiKey && !widgetKey) {
@@ -251,13 +250,13 @@ function resolveConfig(config) {
251
250
  "A Channlize key is required. Set CHANNLIZE_SERVER_API_KEY (or --server-api-key) to a server API key (ch_live_\u2026) from SDK & Integration \u2192 API keys in the Channlize dashboard. Use a read-scoped key for read-only access, or add the write scope to send events, logs and conversations."
252
251
  );
253
252
  }
254
- const timeout = config.timeout ?? DEFAULT_TIMEOUT;
253
+ const timeout = config.timeout ?? import_core2.DEFAULT_TIMEOUT;
255
254
  if (!Number.isFinite(timeout) || timeout <= 0) {
256
255
  throw new ConfigError(
257
256
  `Invalid timeout "${config.timeout}": use milliseconds, e.g. 10000`
258
257
  );
259
258
  }
260
- const baseUrl = (clean(config.baseUrl) ?? DEFAULT_BASE_URL).replace(
259
+ const baseUrl = (clean(config.baseUrl) ?? import_core2.DEFAULT_BASE_URL).replace(
261
260
  /\/+$/,
262
261
  ""
263
262
  );
@@ -265,7 +264,7 @@ function resolveConfig(config) {
265
264
  new URL(baseUrl);
266
265
  } catch {
267
266
  throw new ConfigError(
268
- `Invalid base URL "${config.baseUrl}": use e.g. ${DEFAULT_BASE_URL}`
267
+ `Invalid base URL "${config.baseUrl}": use e.g. ${import_core2.DEFAULT_BASE_URL}`
269
268
  );
270
269
  }
271
270
  return {
@@ -277,15 +276,8 @@ function resolveConfig(config) {
277
276
  };
278
277
  }
279
278
  function configFromEnv(env = process.env) {
280
- const timeout = clean(env.CHANNLIZE_TIMEOUT);
281
- return {
282
- serverApiKey: clean(env.CHANNLIZE_SERVER_API_KEY),
283
- widgetKey: clean(env.CHANNLIZE_WIDGET_KEY),
284
- apiKey: clean(env.CHANNLIZE_API_KEY),
285
- projectId: clean(env.CHANNLIZE_PROJECT_ID),
286
- baseUrl: clean(env.CHANNLIZE_BASE_URL),
287
- timeout: timeout ? Number(timeout) : void 0
288
- };
279
+ const { timeout, ...rest } = (0, import_core2.readChannlizeEnv)(env);
280
+ return { ...rest, timeout: timeout ? Number(timeout) : void 0 };
289
281
  }
290
282
 
291
283
  // src/prompts.ts
@@ -614,10 +606,9 @@ function registerResources(server, api) {
614
606
 
615
607
  // src/tools.ts
616
608
  var z2 = __toESM(require("zod/v4"));
609
+ var import_core3 = require("@channlize/core");
617
610
  var STATUSES = ["open", "pending", "resolved", "closed"];
618
611
  var PRIORITIES = ["low", "normal", "high", "urgent"];
619
- var SEVERITIES = ["info", "warning", "error"];
620
- var EVENT_KEY = /^[a-z0-9][a-z0-9._-]*$/;
621
612
  function ok(data) {
622
613
  return {
623
614
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
@@ -852,7 +843,7 @@ function registerServerTools(server, api) {
852
843
  description: 'Post an Event to Slack: the event key (e.g. "user.subscribed") picks the channel and message template set under Events in the dashboard, and `data` fills its {{placeholders}}. An unknown key is saved as a disabled draft and answered with status "skipped". Needs the write scope. Pass an idempotencyKey so a retry never posts twice.',
853
844
  inputSchema: z2.object({
854
845
  event: z2.string().max(100).regex(
855
- EVENT_KEY,
846
+ import_core3.EVENT_KEY_PATTERN,
856
847
  "lowercase letters, digits, dots, underscores or dashes"
857
848
  ).describe("Event key, e.g. user.subscribed"),
858
849
  data: record2.optional().describe(
@@ -939,7 +930,7 @@ function registerServerTools(server, api) {
939
930
  title: "Query logs",
940
931
  description: "Search log tracking (trackEvent / trackServerEvent / track_log), newest first. Filter by severity, source, text (matches the name and properties) and time range; paginate with limit/offset. Covers all projects unless projectId is given.",
941
932
  inputSchema: z2.object({
942
- severity: z2.enum(SEVERITIES).optional(),
933
+ severity: z2.enum(import_core3.EVENT_SEVERITIES).optional(),
943
934
  source: z2.enum(["client_sdk", "server_api", "system"]).optional().describe(
944
935
  "client_sdk = browser (widget key), server_api = server key"
945
936
  ),
@@ -971,7 +962,7 @@ function registerServerTools(server, api) {
971
962
  description: "Record a log line under Log tracking from a trusted server context (source server_api). Needs the write scope. For Slack messages about product events use notify_event instead.",
972
963
  inputSchema: z2.object({
973
964
  name: z2.string().min(1).max(255).describe("Log name, e.g. payment.failed"),
974
- severity: z2.enum(SEVERITIES).default("info"),
965
+ severity: z2.enum(import_core3.EVENT_SEVERITIES).default("info"),
975
966
  properties: record2.optional().describe("Extra fields")
976
967
  }),
977
968
  outputSchema: z2.object({ id: z2.string(), projectId: z2.string() }),
@@ -1191,7 +1182,8 @@ async function startHttpServer(factory, options = {}) {
1191
1182
  }
1192
1183
 
1193
1184
  // src/index.ts
1194
- var VERSION = true ? "0.3.0" : "0.0.0";
1185
+ var import_core4 = require("@channlize/core");
1186
+ var VERSION = true ? "0.4.0" : "0.0.0";
1195
1187
  var INSTRUCTIONS = `Channlize routes website conversations and app events to the team's Slack.
1196
1188
  - Inbox: list_conversations / get_conversation, then contacts. Replies and status changes happen in Slack or the dashboard.
1197
1189
  - Events (notify_event) post a Slack message per event key; list_event_definitions and list_event_deliveries explain what was sent or skipped.
@@ -1246,10 +1238,14 @@ function createMCPServer(options) {
1246
1238
  var index_default = ChannlizeMCPServer;
1247
1239
  // Annotate the CommonJS export names for ESM import in node:
1248
1240
  0 && (module.exports = {
1241
+ AuthenticationError,
1242
+ ChannlizeError,
1249
1243
  ChannlizeMCPServer,
1250
1244
  ConfigError,
1245
+ RateLimitError,
1251
1246
  ToolError,
1252
1247
  VERSION,
1248
+ ValidationError,
1253
1249
  buildServer,
1254
1250
  configFromEnv,
1255
1251
  createMCPServer,