@channlize/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js ADDED
@@ -0,0 +1,1850 @@
1
+ #!/usr/bin/env node
2
+ #!/usr/bin/env node
3
+ "use strict";
4
+
5
+ // src/index.ts
6
+ var import_server = require("@modelcontextprotocol/sdk/server/index.js");
7
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
8
+ var import_types = require("@modelcontextprotocol/sdk/types.js");
9
+
10
+ // src/resources/index.ts
11
+ var CONTACT_FORM_SCHEMA = `{
12
+ "name": "ContactFormData",
13
+ "description": "Data structure for submitting a contact form inquiry",
14
+ "type": "object",
15
+ "properties": {
16
+ "name": {
17
+ "type": "string",
18
+ "description": "Contact's full name",
19
+ "required": true
20
+ },
21
+ "email": {
22
+ "type": "string",
23
+ "format": "email",
24
+ "description": "Contact's email address",
25
+ "required": true
26
+ },
27
+ "subject": {
28
+ "type": "string",
29
+ "description": "Subject line for the inquiry"
30
+ },
31
+ "message": {
32
+ "type": "string",
33
+ "description": "Message content",
34
+ "required": true
35
+ },
36
+ "customFields": {
37
+ "type": "object",
38
+ "description": "Additional custom fields as key-value pairs",
39
+ "additionalProperties": true
40
+ },
41
+ "pageUrl": {
42
+ "type": "string",
43
+ "description": "URL of the page where form was submitted"
44
+ },
45
+ "userAgent": {
46
+ "type": "string",
47
+ "description": "User agent string of the submitter"
48
+ }
49
+ }
50
+ }`;
51
+ var CHAT_SESSION_SCHEMA = `{
52
+ "name": "ChatSession",
53
+ "description": "Real-time chat session structure",
54
+ "type": "object",
55
+ "properties": {
56
+ "id": {
57
+ "type": "string",
58
+ "description": "Unique session identifier"
59
+ },
60
+ "status": {
61
+ "type": "string",
62
+ "enum": ["active", "closed", "waiting"],
63
+ "description": "Current session status"
64
+ },
65
+ "messages": {
66
+ "type": "array",
67
+ "items": {
68
+ "$ref": "#/definitions/ChatMessage"
69
+ },
70
+ "description": "Array of messages in this session"
71
+ },
72
+ "metadata": {
73
+ "type": "object",
74
+ "description": "Custom metadata for the session"
75
+ },
76
+ "createdAt": {
77
+ "type": "string",
78
+ "format": "date-time",
79
+ "description": "Session creation timestamp"
80
+ },
81
+ "updatedAt": {
82
+ "type": "string",
83
+ "format": "date-time",
84
+ "description": "Last update timestamp"
85
+ }
86
+ },
87
+ "definitions": {
88
+ "ChatMessage": {
89
+ "type": "object",
90
+ "properties": {
91
+ "id": { "type": "string" },
92
+ "content": { "type": "string" },
93
+ "timestamp": { "type": "string", "format": "date-time" },
94
+ "author": { "type": "string", "enum": ["user", "agent"] },
95
+ "authorData": {
96
+ "type": "object",
97
+ "properties": {
98
+ "name": { "type": "string" },
99
+ "email": { "type": "string" },
100
+ "avatarUrl": { "type": "string" }
101
+ }
102
+ },
103
+ "attachments": {
104
+ "type": "array",
105
+ "items": { "$ref": "#/definitions/FileAttachment" }
106
+ }
107
+ }
108
+ },
109
+ "FileAttachment": {
110
+ "type": "object",
111
+ "properties": {
112
+ "id": { "type": "string" },
113
+ "name": { "type": "string" },
114
+ "size": { "type": "number" },
115
+ "type": { "type": "string" },
116
+ "url": { "type": "string" }
117
+ }
118
+ }
119
+ }
120
+ }`;
121
+ var API_REFERENCE = `# Channlize API Reference
122
+
123
+ ## Overview
124
+ Channlize is a developer-first support platform that routes customer conversations directly into Slack.
125
+
126
+ Base URL: \`http://api.channlize.com\` (default) or your configured API endpoint
127
+
128
+ ## Authentication
129
+ All API requests require a Widget Key (API key) in the request body or as a header.
130
+
131
+ ## Endpoints
132
+
133
+ ### Contact Forms
134
+
135
+ **POST /public/contact**
136
+ Submit a contact form inquiry.
137
+
138
+ Request Body:
139
+ \`\`\`json
140
+ {
141
+ "widgetKey": "your-widget-key",
142
+ "name": "John Doe",
143
+ "email": "john@example.com",
144
+ "subject": "Support Request",
145
+ "message": "I need help with...",
146
+ "pageUrl": "https://example.com/contact",
147
+ "userAgent": "Mozilla/5.0..."
148
+ }
149
+ \`\`\`
150
+
151
+ Response:
152
+ \`\`\`json
153
+ {
154
+ "data": {
155
+ "id": "contact_123",
156
+ "status": "received",
157
+ "slackThreadUrl": "https://slack.com/..."
158
+ }
159
+ }
160
+ \`\`\`
161
+
162
+ ### Chat Sessions
163
+
164
+ **POST /v1/chat/sessions**
165
+ Create a new chat session.
166
+
167
+ Request Body:
168
+ \`\`\`json
169
+ {
170
+ "metadata": {
171
+ "pageUrl": "https://example.com",
172
+ "userAgent": "Mozilla/5.0...",
173
+ "customField": "value"
174
+ }
175
+ }
176
+ \`\`\`
177
+
178
+ Response:
179
+ \`\`\`json
180
+ {
181
+ "data": {
182
+ "session": {
183
+ "id": "session_123",
184
+ "status": "active",
185
+ "messages": [],
186
+ "createdAt": "2025-01-15T10:00:00Z"
187
+ },
188
+ "sseEndpoint": "/v1/chat/sessions/session_123/events"
189
+ }
190
+ }
191
+ \`\`\`
192
+
193
+ **POST /v1/chat/sessions/:sessionId/messages**
194
+ Send a message in a chat session.
195
+
196
+ Request: FormData with 'content' field and optional file attachments
197
+
198
+ **GET /v1/chat/sessions/:sessionId/messages**
199
+ Get messages for a session. Query params: limit, offset
200
+
201
+ **POST /v1/chat/sessions/:sessionId/close**
202
+ Close a chat session.
203
+
204
+ ## Error Responses
205
+
206
+ Status codes:
207
+ - 400: Validation error
208
+ - 401: Authentication failed
209
+ - 429: Rate limit exceeded
210
+ - 500: Server error
211
+
212
+ Error format:
213
+ \`\`\`json
214
+ {
215
+ "error": "Error message",
216
+ "code": "ERROR_CODE",
217
+ "field": "fieldName" // for validation errors
218
+ }
219
+ \`\`\`
220
+ `;
221
+ var QUICK_START = `# Channlize Quick Start
222
+
223
+ ## Installation
224
+
225
+ \`\`\`bash
226
+ # For React applications
227
+ npm install @channlize/react
228
+
229
+ # For non-React applications
230
+ npm install @channlize/core
231
+ \`\`\`
232
+
233
+ ## React Setup
234
+
235
+ 1. Wrap your app with ChannlizeProvider:
236
+
237
+ \`\`\`tsx
238
+ import { ChannlizeProvider } from '@channlize/react';
239
+
240
+ function App() {
241
+ return (
242
+ <ChannlizeProvider
243
+ config={{
244
+ apiKey: 'your-widget-key',
245
+ projectId: 'your-project-id',
246
+ }}
247
+ >
248
+ <YourApp />
249
+ </ChannlizeProvider>
250
+ );
251
+ }
252
+ \`\`\`
253
+
254
+ 2. Use the Form component:
255
+
256
+ \`\`\`tsx
257
+ import { Form } from '@channlize/react';
258
+
259
+ function ContactPage() {
260
+ return (
261
+ <Form
262
+ onSuccess={() => console.log('Form submitted!')}
263
+ submitText="Send Message"
264
+ />
265
+ );
266
+ }
267
+ \`\`\`
268
+
269
+ 3. Add live chat:
270
+
271
+ \`\`\`tsx
272
+ import { Chat } from '@channlize/react';
273
+
274
+ function SupportPage() {
275
+ return (
276
+ <Chat
277
+ autoStart={true}
278
+ title="Customer Support"
279
+ placeholder="How can we help?"
280
+ />
281
+ );
282
+ }
283
+ \`\`\`
284
+
285
+ ## Core SDK Usage
286
+
287
+ For non-React applications:
288
+
289
+ \`\`\`typescript
290
+ import { ChannlizeClient } from '@channlize/core';
291
+
292
+ const client = new ChannlizeClient({
293
+ apiKey: 'your-widget-key',
294
+ projectId: 'your-project-id',
295
+ });
296
+
297
+ // Submit contact form
298
+ await client.submitContactForm({
299
+ name: 'John Doe',
300
+ email: 'john@example.com',
301
+ message: 'I need help!',
302
+ });
303
+
304
+ // Create chat session
305
+ const { session } = await client.createChatSession();
306
+
307
+ // Send message
308
+ await client.sendMessage(session.id, 'Hello!');
309
+ \`\`\`
310
+
311
+ ## Configuration
312
+
313
+ - \`apiKey\`: Your Channlize widget key (required)
314
+ - \`projectId\`: Your project ID (required)
315
+ - \`baseUrl\`: API base URL (optional, defaults to api.channlize.com)
316
+ - \`timeout\`: Request timeout in ms (optional, defaults to 10000)
317
+ `;
318
+ var REACT_COMPONENTS = `# Channlize React Components
319
+
320
+ ## ChannlizeProvider
321
+
322
+ Wrap your app to provide Channlize configuration to all components.
323
+
324
+ \`\`\`tsx
325
+ <ChannlizeProvider config={{ apiKey, projectId }}>
326
+ {children}
327
+ </ChannlizeProvider>
328
+ \`\`\`
329
+
330
+ ## Form
331
+
332
+ A complete contact form with validation and submission handling.
333
+
334
+ ### Props
335
+ - \`customFields?: Array<CustomField>\` - Additional form fields
336
+ - \`onSuccess?: () => void\` - Success callback
337
+ - \`onError?: (error: Error) => void\` - Error callback
338
+ - \`className?: string\` - CSS class name
339
+ - \`styles?: FormStyles\` - Custom styles object
340
+ - \`submitText?: string\` - Submit button text
341
+ - \`successMessage?: string\` - Success message text
342
+
343
+ ### Example
344
+ \`\`\`tsx
345
+ <Form
346
+ customFields={[
347
+ {
348
+ name: 'department',
349
+ label: 'Department',
350
+ type: 'select',
351
+ options: ['Sales', 'Support'],
352
+ required: true,
353
+ },
354
+ ]}
355
+ onSuccess={() => alert('Sent!')}
356
+ styles={{
357
+ button: { background: '#007bff', color: 'white' },
358
+ }}
359
+ />
360
+ \`\`\`
361
+
362
+ ## Chat
363
+
364
+ Real-time chat widget with message history and file attachments.
365
+
366
+ ### Props
367
+ - \`autoStart?: boolean\` - Auto-start chat session
368
+ - \`metadata?: Record<string, unknown>\` - Session metadata
369
+ - \`onMessage?: (message: ChatMessage) => void\` - New message callback
370
+ - \`onError?: (error: Error) => void\` - Error callback
371
+ - \`className?: string\` - CSS class name
372
+ - \`styles?: ChatStyles\` - Custom styles object
373
+ - \`title?: string\` - Chat header title
374
+ - \`placeholder?: string\` - Input placeholder text
375
+ - \`maxHeight?: string\` - Maximum container height
376
+
377
+ ### Example
378
+ \`\`\`tsx
379
+ <Chat
380
+ autoStart={true}
381
+ title="Need Help?"
382
+ placeholder="Type your message..."
383
+ onMessage={(msg) => console.log('New:', msg)}
384
+ styles={{
385
+ container: { width: '400px', height: '500px' },
386
+ header: { background: '#007bff', color: 'white' },
387
+ }}
388
+ />
389
+ \`\`\`
390
+
391
+ ## Hooks
392
+
393
+ ### useContactForm()
394
+ Hook for managing contact form state.
395
+
396
+ \`\`\`tsx
397
+ const { submit, isSubmitting, isSuccess, error, reset } = useContactForm({
398
+ onSuccess: (response) => console.log('Submitted:', response),
399
+ onError: (error) => console.error('Failed:', error),
400
+ });
401
+ \`\`\`
402
+
403
+ ### useChatSession()
404
+ Hook for managing chat sessions.
405
+
406
+ \`\`\`tsx
407
+ const {
408
+ session,
409
+ messages,
410
+ isConnecting,
411
+ isConnected,
412
+ error,
413
+ sendMessage,
414
+ startSession,
415
+ endSession,
416
+ } = useChatSession({
417
+ autoConnect: false,
418
+ metadata: { page: 'support' },
419
+ onMessage: (message) => console.log('New message:', message),
420
+ });
421
+ \`\`\`
422
+
423
+ ## Styling
424
+
425
+ All components accept \`styles\` prop for custom styling or \`className\` for CSS classes.
426
+
427
+ CSS class names:
428
+ - \`.channlize-form\`
429
+ - \`.channlize-field\`
430
+ - \`.channlize-error\`
431
+ - \`.channlize-chat-container\`
432
+ - \`.channlize-chat-header\`
433
+ - \`.channlize-chat-messages\`
434
+ - \`.channlize-message\`
435
+ - \`.channlize-message-user\`
436
+ - \`.channlize-message-agent\`
437
+ `;
438
+ var resources = [
439
+ {
440
+ uri: "channlize://schema/contact-form",
441
+ name: "Contact Form Schema",
442
+ description: "JSON schema for contact form data structure",
443
+ mimeType: "application/json",
444
+ getText: () => CONTACT_FORM_SCHEMA
445
+ },
446
+ {
447
+ uri: "channlize://schema/chat-session",
448
+ name: "Chat Session Schema",
449
+ description: "JSON schema for chat session data structure",
450
+ mimeType: "application/json",
451
+ getText: () => CHAT_SESSION_SCHEMA
452
+ },
453
+ {
454
+ uri: "channlize://docs/api-reference",
455
+ name: "API Reference",
456
+ description: "Complete Channlize API reference documentation",
457
+ mimeType: "text/markdown",
458
+ getText: () => API_REFERENCE
459
+ },
460
+ {
461
+ uri: "channlize://docs/quick-start",
462
+ name: "Quick Start Guide",
463
+ description: "Quick start guide for using Channlize SDK",
464
+ mimeType: "text/markdown",
465
+ getText: () => QUICK_START
466
+ },
467
+ {
468
+ uri: "channlize://docs/react-components",
469
+ name: "React Components Documentation",
470
+ description: "Documentation for Channlize React components and hooks",
471
+ mimeType: "text/markdown",
472
+ getText: () => REACT_COMPONENTS
473
+ }
474
+ ];
475
+ function getResource(uri) {
476
+ return resources.find((r) => r.uri === uri);
477
+ }
478
+ function listResources() {
479
+ return resources;
480
+ }
481
+
482
+ // src/tools/index.ts
483
+ var import_core = require("@channlize/core");
484
+ function createClient(context) {
485
+ return new import_core.ChannlizeClient({
486
+ apiKey: context.config.apiKey,
487
+ projectId: context.config.projectId || "",
488
+ baseUrl: context.config.baseUrl,
489
+ timeout: context.config.timeout
490
+ });
491
+ }
492
+ var tools = [
493
+ {
494
+ name: "submit_contact_form",
495
+ description: "Submit a contact form inquiry to Channlize. This creates a new conversation thread in Slack where the team can respond.",
496
+ inputSchema: {
497
+ type: "object",
498
+ properties: {
499
+ name: {
500
+ type: "string",
501
+ description: "Contact's full name"
502
+ },
503
+ email: {
504
+ type: "string",
505
+ description: "Contact's email address"
506
+ },
507
+ subject: {
508
+ type: "string",
509
+ description: "Subject line for the inquiry (optional)"
510
+ },
511
+ message: {
512
+ type: "string",
513
+ description: "The message content"
514
+ },
515
+ customFields: {
516
+ type: "object",
517
+ description: "Additional custom fields as key-value pairs (optional)",
518
+ additionalProperties: true
519
+ },
520
+ pageUrl: {
521
+ type: "string",
522
+ description: "URL of the page where form was submitted (optional)"
523
+ },
524
+ userAgent: {
525
+ type: "string",
526
+ description: "User agent string of the submitter (optional)"
527
+ }
528
+ },
529
+ required: ["name", "email", "message"]
530
+ },
531
+ handler: async (args2, context) => {
532
+ const client = createClient(context);
533
+ const response = await client.submitContactForm({
534
+ name: args2.name,
535
+ email: args2.email,
536
+ subject: args2.subject,
537
+ message: args2.message,
538
+ customFields: args2.customFields,
539
+ pageUrl: args2.pageUrl,
540
+ userAgent: args2.userAgent
541
+ });
542
+ return {
543
+ success: true,
544
+ contactId: response.id,
545
+ status: response.status,
546
+ slackThreadUrl: response.slackThreadUrl,
547
+ message: "Contact form submitted successfully"
548
+ };
549
+ }
550
+ },
551
+ {
552
+ name: "create_chat_session",
553
+ description: "Create a new chat session for real-time messaging. Returns a session ID that can be used to send and receive messages.",
554
+ inputSchema: {
555
+ type: "object",
556
+ properties: {
557
+ metadata: {
558
+ type: "object",
559
+ description: "Custom metadata to attach to the session (e.g., page URL, user info)",
560
+ additionalProperties: true
561
+ }
562
+ }
563
+ },
564
+ handler: async (args2, context) => {
565
+ const client = createClient(context);
566
+ const response = await client.createChatSession(args2.metadata);
567
+ return {
568
+ success: true,
569
+ session: {
570
+ id: response.session.id,
571
+ status: response.session.status,
572
+ createdAt: response.session.createdAt,
573
+ messageCount: response.session.messages?.length || 0
574
+ },
575
+ sseEndpoint: response.sseEndpoint,
576
+ message: "Chat session created successfully"
577
+ };
578
+ }
579
+ },
580
+ {
581
+ name: "send_message",
582
+ description: "Send a message in an existing chat session. The message will be delivered to the Slack thread and the user can see agent replies in real-time.",
583
+ inputSchema: {
584
+ type: "object",
585
+ properties: {
586
+ sessionId: {
587
+ type: "string",
588
+ description: "The chat session ID"
589
+ },
590
+ content: {
591
+ type: "string",
592
+ description: "The message content to send"
593
+ }
594
+ },
595
+ required: ["sessionId", "content"]
596
+ },
597
+ handler: async (args2, context) => {
598
+ const client = createClient(context);
599
+ const response = await client.sendMessage(args2.sessionId, args2.content);
600
+ return {
601
+ success: true,
602
+ message: {
603
+ id: response.message.id,
604
+ content: response.message.content,
605
+ timestamp: response.message.timestamp,
606
+ author: response.message.author
607
+ },
608
+ sessionStatus: response.session.status,
609
+ deliveryMessage: "Message sent successfully"
610
+ };
611
+ }
612
+ },
613
+ {
614
+ name: "get_chat_messages",
615
+ description: "Retrieve messages from a chat session. Useful for viewing conversation history.",
616
+ inputSchema: {
617
+ type: "object",
618
+ properties: {
619
+ sessionId: {
620
+ type: "string",
621
+ description: "The chat session ID"
622
+ },
623
+ limit: {
624
+ type: "number",
625
+ description: "Maximum number of messages to retrieve (default: 50)",
626
+ default: 50
627
+ },
628
+ offset: {
629
+ type: "number",
630
+ description: "Number of messages to skip (default: 0)",
631
+ default: 0
632
+ }
633
+ },
634
+ required: ["sessionId"]
635
+ },
636
+ handler: async (args2, context) => {
637
+ const client = createClient(context);
638
+ const messages = await client.getChatMessages(
639
+ args2.sessionId,
640
+ args2.limit || 50,
641
+ args2.offset || 0
642
+ );
643
+ return {
644
+ success: true,
645
+ sessionId: args2.sessionId,
646
+ messageCount: messages.length,
647
+ messages: messages.map((msg) => ({
648
+ id: msg.id,
649
+ content: msg.content,
650
+ timestamp: msg.timestamp,
651
+ author: msg.author,
652
+ authorData: msg.authorData,
653
+ hasAttachments: (msg.attachments?.length || 0) > 0
654
+ }))
655
+ };
656
+ }
657
+ },
658
+ {
659
+ name: "close_chat_session",
660
+ description: "Close an active chat session. This marks the conversation as complete and stops real-time updates.",
661
+ inputSchema: {
662
+ type: "object",
663
+ properties: {
664
+ sessionId: {
665
+ type: "string",
666
+ description: "The chat session ID to close"
667
+ }
668
+ },
669
+ required: ["sessionId"]
670
+ },
671
+ handler: async (args2, context) => {
672
+ const client = createClient(context);
673
+ const session = await client.closeChatSession(args2.sessionId);
674
+ return {
675
+ success: true,
676
+ sessionId: session.id,
677
+ status: session.status,
678
+ closedAt: session.updatedAt,
679
+ message: "Chat session closed successfully"
680
+ };
681
+ }
682
+ }
683
+ ];
684
+ function getTool(name) {
685
+ return tools.find((t) => t.name === name);
686
+ }
687
+ function listTools() {
688
+ return tools;
689
+ }
690
+
691
+ // src/prompts/index.ts
692
+ var prompts = [
693
+ {
694
+ name: "integrate-contact-form",
695
+ description: "Guide for adding a Channlize contact form to a React application",
696
+ arguments: [
697
+ {
698
+ name: "framework",
699
+ description: "The React framework being used (e.g., Next.js, Vite, CRA)",
700
+ required: false
701
+ },
702
+ {
703
+ name: "styling",
704
+ description: "The styling approach (e.g., Tailwind, CSS Modules, styled-components)",
705
+ required: false
706
+ }
707
+ ],
708
+ getPrompt: (args2) => {
709
+ const framework = args2?.framework || "React";
710
+ const styling = args2?.styling || "CSS";
711
+ return `# Integrating Channlize Contact Form in ${framework}
712
+
713
+ ## Step 1: Install Dependencies
714
+
715
+ \`\`\`bash
716
+ npm install @channlize/react
717
+ \`\`\`
718
+
719
+ ## Step 2: Configure Provider
720
+
721
+ Wrap your application with the ChannlizeProvider at the root level:
722
+
723
+ \`\`\`tsx
724
+ import { ChannlizeProvider } from '@channlize/react';
725
+
726
+ function App() {
727
+ return (
728
+ <ChannlizeProvider
729
+ config={{
730
+ apiKey: process.env.NEXT_PUBLIC_CHANNLIZE_API_KEY, // Your widget key
731
+ projectId: process.env.NEXT_PUBLIC_CHANNLIZE_PROJECT_ID,
732
+ baseUrl: process.env.NEXT_PUBLIC_CHANNLIZE_API_URL, // Optional
733
+ }}
734
+ >
735
+ <YourAppContent />
736
+ </ChannlizeProvider>
737
+ );
738
+ }
739
+ \`\`\`
740
+
741
+ ## Step 3: Add Form Component
742
+
743
+ Create a contact page or component:
744
+
745
+ \`\`\`tsx
746
+ import { Form } from '@channlize/react';
747
+
748
+ export default function ContactPage() {
749
+ return (
750
+ <div className="container mx-auto py-8">
751
+ <h1>Contact Us</h1>
752
+ <Form
753
+ onSuccess={() => {
754
+ alert('Thank you! We will get back to you soon.');
755
+ }}
756
+ onError={(error) => {
757
+ console.error('Failed to submit:', error);
758
+ }}
759
+ customFields={[
760
+ {
761
+ name: 'department',
762
+ label: 'Department',
763
+ type: 'select',
764
+ options: ['Sales', 'Support', 'Billing'],
765
+ required: true,
766
+ },
767
+ ]}
768
+ ${styling === "Tailwind" ? `className="max-w-2xl"` : ""}
769
+ styles={{
770
+ form: { maxWidth: '600px', margin: '0 auto' },
771
+ button: {
772
+ background: '#007bff',
773
+ color: 'white',
774
+ padding: '0.75rem 1.5rem',
775
+ borderRadius: '0.5rem',
776
+ },
777
+ }}
778
+ submitText="Send Message"
779
+ successMessage="Thank you! We'll respond shortly."
780
+ />
781
+ </div>
782
+ );
783
+ }
784
+ \`\`\`
785
+
786
+ ## Step 4: Environment Variables
787
+
788
+ Add to your \`.env.local\` or \`.env\`:
789
+
790
+ \`\`\`
791
+ NEXT_PUBLIC_CHANNLIZE_API_KEY=your_widget_key_here
792
+ NEXT_PUBLIC_CHANNLIZE_PROJECT_ID=your_project_id_here
793
+ NEXT_PUBLIC_CHANNLIZE_API_URL=http://api.channlize.com # Optional
794
+ \`\`\`
795
+
796
+ ## Step 5: Customize (Optional)
797
+
798
+ ### Custom Fields
799
+ Add custom fields to gather specific information:
800
+
801
+ \`\`\`tsx
802
+ customFields={[
803
+ {
804
+ name: 'company',
805
+ label: 'Company Name',
806
+ type: 'text',
807
+ required: false,
808
+ },
809
+ {
810
+ name: 'priority',
811
+ label: 'Priority',
812
+ type: 'select',
813
+ options: ['Low', 'Medium', 'High'],
814
+ required: true,
815
+ },
816
+ ]}
817
+ \`\`\`
818
+
819
+ ### Custom Styling with ${styling}
820
+ ${styling === "Tailwind" ? "Use Tailwind classes with the className prop or override styles." : "Apply custom styles using the styles prop or external CSS."}
821
+
822
+ ## Tips
823
+
824
+ - Messages are sent to your configured Slack channel instantly
825
+ - Email fallback is automatic if Slack delivery fails
826
+ - Form includes built-in validation and error handling
827
+ - All fields support accessibility features (ARIA labels, keyboard navigation)
828
+
829
+ ## Next Steps
830
+
831
+ - Set up Slack workspace integration in your Channlize dashboard
832
+ - Configure channel routing rules
833
+ - Add webhooks for custom workflows
834
+ `;
835
+ }
836
+ },
837
+ {
838
+ name: "setup-live-chat",
839
+ description: "Guide for implementing the Channlize live chat widget in a React application",
840
+ arguments: [
841
+ {
842
+ name: "placement",
843
+ description: 'Where to place the chat widget (e.g., "page", "popup", "sidebar")',
844
+ required: false
845
+ }
846
+ ],
847
+ getPrompt: (args2) => {
848
+ const placement = args2?.placement || "page";
849
+ return `# Setting Up Channlize Live Chat Widget
850
+
851
+ ## Step 1: Install Dependencies
852
+
853
+ \`\`\`bash
854
+ npm install @channlize/react
855
+ \`\`\`
856
+
857
+ ## Step 2: Configure Provider
858
+
859
+ Ensure your app is wrapped with ChannlizeProvider:
860
+
861
+ \`\`\`tsx
862
+ import { ChannlizeProvider } from '@channlize/react';
863
+
864
+ function App() {
865
+ return (
866
+ <ChannlizeProvider
867
+ config={{
868
+ apiKey: process.env.NEXT_PUBLIC_CHANNLIZE_API_KEY,
869
+ projectId: process.env.NEXT_PUBLIC_CHANNLIZE_PROJECT_ID,
870
+ }}
871
+ >
872
+ <YourAppContent />
873
+ </ChannlizeProvider>
874
+ );
875
+ }
876
+ \`\`\`
877
+
878
+ ## Step 3: Add Chat Component
879
+
880
+ ${placement === "popup" ? `
881
+ ### Popup Widget (Bottom-Right Corner)
882
+
883
+ \`\`\`tsx
884
+ import { useState } from 'react';
885
+ import { Chat } from '@channlize/react';
886
+
887
+ export function ChatWidget() {
888
+ const [isOpen, setIsOpen] = useState(false);
889
+
890
+ return (
891
+ <>
892
+ {/* Floating Button */}
893
+ {!isOpen && (
894
+ <button
895
+ onClick={() => setIsOpen(true)}
896
+ style={{
897
+ position: 'fixed',
898
+ bottom: '20px',
899
+ right: '20px',
900
+ width: '60px',
901
+ height: '60px',
902
+ borderRadius: '50%',
903
+ background: '#007bff',
904
+ color: 'white',
905
+ border: 'none',
906
+ fontSize: '24px',
907
+ cursor: 'pointer',
908
+ boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
909
+ zIndex: 1000,
910
+ }}
911
+ >
912
+ \u{1F4AC}
913
+ </button>
914
+ )}
915
+
916
+ {/* Chat Window */}
917
+ {isOpen && (
918
+ <div
919
+ style={{
920
+ position: 'fixed',
921
+ bottom: '20px',
922
+ right: '20px',
923
+ zIndex: 1000,
924
+ boxShadow: '0 4px 24px rgba(0,0,0,0.15)',
925
+ borderRadius: '12px',
926
+ overflow: 'hidden',
927
+ }}
928
+ >
929
+ <Chat
930
+ autoStart={true}
931
+ title="Customer Support"
932
+ placeholder="Type your message..."
933
+ onMessage={(message) => {
934
+ console.log('New message:', message);
935
+ }}
936
+ styles={{
937
+ container: {
938
+ width: '380px',
939
+ height: '600px',
940
+ display: 'flex',
941
+ flexDirection: 'column',
942
+ background: 'white',
943
+ },
944
+ header: {
945
+ background: '#007bff',
946
+ color: 'white',
947
+ padding: '1rem',
948
+ display: 'flex',
949
+ alignItems: 'center',
950
+ },
951
+ }}
952
+ />
953
+ <button
954
+ onClick={() => setIsOpen(false)}
955
+ style={{
956
+ position: 'absolute',
957
+ top: '10px',
958
+ right: '10px',
959
+ background: 'rgba(255,255,255,0.2)',
960
+ border: 'none',
961
+ color: 'white',
962
+ cursor: 'pointer',
963
+ fontSize: '20px',
964
+ width: '30px',
965
+ height: '30px',
966
+ borderRadius: '50%',
967
+ }}
968
+ >
969
+ \xD7
970
+ </button>
971
+ </div>
972
+ )}
973
+ </>
974
+ );
975
+ }
976
+ \`\`\`
977
+ ` : `
978
+ ### Embedded Chat
979
+
980
+ \`\`\`tsx
981
+ import { Chat } from '@channlize/react';
982
+
983
+ export default function SupportPage() {
984
+ return (
985
+ <div className="container mx-auto py-8">
986
+ <h1>Customer Support</h1>
987
+ <Chat
988
+ autoStart={true}
989
+ title="Live Chat Support"
990
+ placeholder="How can we help you today?"
991
+ onMessage={(message) => {
992
+ // Handle incoming messages
993
+ console.log('New message:', message);
994
+ }}
995
+ onError={(error) => {
996
+ console.error('Chat error:', error);
997
+ }}
998
+ styles={{
999
+ container: {
1000
+ width: '100%',
1001
+ maxWidth: '800px',
1002
+ height: '600px',
1003
+ margin: '0 auto',
1004
+ border: '1px solid #e0e0e0',
1005
+ borderRadius: '12px',
1006
+ },
1007
+ header: {
1008
+ background: '#007bff',
1009
+ color: 'white',
1010
+ },
1011
+ }}
1012
+ maxHeight="600px"
1013
+ />
1014
+ </div>
1015
+ );
1016
+ }
1017
+ \`\`\`
1018
+ `}
1019
+
1020
+ ## Step 4: Advanced Features
1021
+
1022
+ ### Custom Metadata
1023
+ Pass context about the user or page:
1024
+
1025
+ \`\`\`tsx
1026
+ <Chat
1027
+ metadata={{
1028
+ userId: user?.id,
1029
+ userName: user?.name,
1030
+ currentPage: window.location.pathname,
1031
+ plan: 'pro',
1032
+ }}
1033
+ />
1034
+ \`\`\`
1035
+
1036
+ ### Event Handlers
1037
+ React to chat events:
1038
+
1039
+ \`\`\`tsx
1040
+ <Chat
1041
+ onMessage={(message) => {
1042
+ // Track analytics
1043
+ analytics.track('chat_message_received', {
1044
+ author: message.author,
1045
+ timestamp: message.timestamp,
1046
+ });
1047
+ }}
1048
+ onError={(error) => {
1049
+ // Report errors
1050
+ errorReporting.log(error);
1051
+ }}
1052
+ />
1053
+ \`\`\`
1054
+
1055
+ ## Real-Time Features
1056
+
1057
+ - Messages are delivered instantly via Server-Sent Events (SSE)
1058
+ - Agent presence indicators show when team is active
1059
+ - File attachments supported (images, documents)
1060
+ - Automatic reconnection on connection loss
1061
+ - Message history persisted across sessions
1062
+
1063
+ ## Tips
1064
+
1065
+ - Chat sessions are automatically created on first message
1066
+ - Sessions remain active until explicitly closed
1067
+ - Messages are threaded in Slack for team collaboration
1068
+ - Supports multiple concurrent chat sessions per project
1069
+
1070
+ ## Next Steps
1071
+
1072
+ - Configure Slack notifications for new chats
1073
+ - Set up auto-responses for common questions
1074
+ - Integrate with your analytics platform
1075
+ - Add custom routing based on user context
1076
+ `;
1077
+ }
1078
+ },
1079
+ {
1080
+ name: "customize-styling",
1081
+ description: "Guide for theming and customizing Channlize components",
1082
+ getPrompt: () => `# Customizing Channlize Component Styling
1083
+
1084
+ Channlize components are designed to be highly customizable to match your brand.
1085
+
1086
+ ## Styling Approaches
1087
+
1088
+ ### 1. Inline Styles with \`styles\` Prop
1089
+
1090
+ The most direct way to customize appearance:
1091
+
1092
+ \`\`\`tsx
1093
+ <Form
1094
+ styles={{
1095
+ form: {
1096
+ maxWidth: '600px',
1097
+ margin: '0 auto',
1098
+ padding: '2rem',
1099
+ background: '#f9fafb',
1100
+ borderRadius: '8px',
1101
+ },
1102
+ field: {
1103
+ marginBottom: '1.5rem',
1104
+ },
1105
+ label: {
1106
+ display: 'block',
1107
+ marginBottom: '0.5rem',
1108
+ fontWeight: '600',
1109
+ color: '#374151',
1110
+ },
1111
+ input: {
1112
+ width: '100%',
1113
+ padding: '0.75rem',
1114
+ border: '1px solid #d1d5db',
1115
+ borderRadius: '6px',
1116
+ fontSize: '1rem',
1117
+ },
1118
+ textarea: {
1119
+ width: '100%',
1120
+ padding: '0.75rem',
1121
+ border: '1px solid #d1d5db',
1122
+ borderRadius: '6px',
1123
+ fontSize: '1rem',
1124
+ minHeight: '120px',
1125
+ },
1126
+ button: {
1127
+ background: '#3b82f6',
1128
+ color: 'white',
1129
+ padding: '0.75rem 2rem',
1130
+ border: 'none',
1131
+ borderRadius: '6px',
1132
+ fontSize: '1rem',
1133
+ fontWeight: '600',
1134
+ cursor: 'pointer',
1135
+ transition: 'background 0.2s',
1136
+ },
1137
+ error: {
1138
+ color: '#ef4444',
1139
+ fontSize: '0.875rem',
1140
+ marginTop: '0.5rem',
1141
+ },
1142
+ success: {
1143
+ background: '#ecfdf5',
1144
+ border: '1px solid #10b981',
1145
+ padding: '1.5rem',
1146
+ borderRadius: '6px',
1147
+ color: '#065f46',
1148
+ },
1149
+ }}
1150
+ />
1151
+ \`\`\`
1152
+
1153
+ ### 2. CSS Classes with \`className\` Prop
1154
+
1155
+ Use your existing CSS or CSS-in-JS solution:
1156
+
1157
+ \`\`\`tsx
1158
+ <Form className="custom-form" />
1159
+ \`\`\`
1160
+
1161
+ \`\`\`css
1162
+ /* styles.css */
1163
+ .channlize-form {
1164
+ max-width: 600px;
1165
+ margin: 0 auto;
1166
+ }
1167
+
1168
+ .channlize-field {
1169
+ margin-bottom: 1.5rem;
1170
+ }
1171
+
1172
+ .channlize-field label {
1173
+ font-weight: 600;
1174
+ color: var(--primary-text);
1175
+ }
1176
+
1177
+ .channlize-field input,
1178
+ .channlize-field textarea,
1179
+ .channlize-field select {
1180
+ border: 1px solid var(--border-color);
1181
+ border-radius: 6px;
1182
+ padding: 0.75rem;
1183
+ }
1184
+
1185
+ .channlize-form button[type="submit"] {
1186
+ background: var(--primary-color);
1187
+ color: white;
1188
+ }
1189
+ \`\`\`
1190
+
1191
+ ### 3. Tailwind CSS
1192
+
1193
+ Combine with Tailwind utility classes:
1194
+
1195
+ \`\`\`tsx
1196
+ <Form
1197
+ className="max-w-2xl mx-auto p-8"
1198
+ styles={{
1199
+ input: {
1200
+ // Tailwind styles as objects don't work well
1201
+ // Use className on wrapper or global CSS
1202
+ },
1203
+ }}
1204
+ />
1205
+ \`\`\`
1206
+
1207
+ \`\`\`css
1208
+ /* globals.css with @layer */
1209
+ @layer components {
1210
+ .channlize-field input {
1211
+ @apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500;
1212
+ }
1213
+
1214
+ .channlize-field textarea {
1215
+ @apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500;
1216
+ }
1217
+
1218
+ .channlize-form button[type="submit"] {
1219
+ @apply bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-6 rounded-lg transition;
1220
+ }
1221
+ }
1222
+ \`\`\`
1223
+
1224
+ ## Styling Chat
1225
+
1226
+ \`\`\`tsx
1227
+ <Chat
1228
+ styles={{
1229
+ container: {
1230
+ border: '1px solid #e5e7eb',
1231
+ borderRadius: '12px',
1232
+ overflow: 'hidden',
1233
+ boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
1234
+ },
1235
+ header: {
1236
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
1237
+ color: 'white',
1238
+ padding: '1rem',
1239
+ },
1240
+ messages: {
1241
+ background: '#f9fafb',
1242
+ padding: '1rem',
1243
+ },
1244
+ messageUser: {
1245
+ background: '#3b82f6',
1246
+ color: 'white',
1247
+ padding: '0.75rem',
1248
+ borderRadius: '12px 12px 4px 12px',
1249
+ maxWidth: '70%',
1250
+ marginLeft: 'auto',
1251
+ },
1252
+ messageAgent: {
1253
+ background: 'white',
1254
+ color: '#1f2937',
1255
+ padding: '0.75rem',
1256
+ borderRadius: '12px 12px 12px 4px',
1257
+ maxWidth: '70%',
1258
+ border: '1px solid #e5e7eb',
1259
+ },
1260
+ input: {
1261
+ border: '1px solid #d1d5db',
1262
+ borderRadius: '6px',
1263
+ padding: '0.75rem',
1264
+ fontSize: '1rem',
1265
+ },
1266
+ button: {
1267
+ background: '#3b82f6',
1268
+ color: 'white',
1269
+ padding: '0.75rem 1.5rem',
1270
+ borderRadius: '6px',
1271
+ border: 'none',
1272
+ cursor: 'pointer',
1273
+ },
1274
+ }}
1275
+ />
1276
+ \`\`\`
1277
+
1278
+ ## CSS Class Reference
1279
+
1280
+ All Channlize components use semantic CSS classes:
1281
+
1282
+ **Form:**
1283
+ - \`.channlize-form\` - Form container
1284
+ - \`.channlize-form-success\` - Success message container
1285
+ - \`.channlize-field\` - Field wrapper
1286
+ - \`.channlize-error\` - Error message
1287
+
1288
+ **Chat:**
1289
+ - \`.channlize-chat-container\` - Main container
1290
+ - \`.channlize-chat-header\` - Header section
1291
+ - \`.channlize-chat-messages\` - Messages container
1292
+ - \`.channlize-message\` - Individual message
1293
+ - \`.channlize-message-user\` - User message
1294
+ - \`.channlize-message-agent\` - Agent message
1295
+ - \`.channlize-chat-input-container\` - Input area
1296
+
1297
+ ## Dark Mode Example
1298
+
1299
+ \`\`\`tsx
1300
+ const darkStyles = {
1301
+ form: {
1302
+ background: '#1f2937',
1303
+ color: '#f9fafb',
1304
+ },
1305
+ input: {
1306
+ background: '#374151',
1307
+ color: '#f9fafb',
1308
+ border: '1px solid #4b5563',
1309
+ },
1310
+ button: {
1311
+ background: '#3b82f6',
1312
+ color: 'white',
1313
+ },
1314
+ };
1315
+
1316
+ <Form styles={darkStyles} />
1317
+ \`\`\`
1318
+ `
1319
+ },
1320
+ {
1321
+ name: "handle-webhooks",
1322
+ description: "Guide for integrating Channlize webhooks into custom workflows",
1323
+ getPrompt: () => `# Integrating Channlize Webhooks
1324
+
1325
+ Channlize can send webhook events to your backend for custom workflows and integrations.
1326
+
1327
+ ## Available Webhook Events
1328
+
1329
+ - \`conversation.created\` - New contact form or chat session started
1330
+ - \`message.created\` - New message in a conversation
1331
+ - \`conversation.closed\` - Conversation marked as closed
1332
+ - \`agent.assigned\` - Agent assigned to conversation
1333
+
1334
+ ## Setting Up Webhooks
1335
+
1336
+ ### 1. Configure Webhook URL
1337
+
1338
+ In your Channlize dashboard:
1339
+ 1. Navigate to Project Settings \u2192 Webhooks
1340
+ 2. Add your webhook endpoint URL
1341
+ 3. Select which events to receive
1342
+ 4. Save your secret key for verification
1343
+
1344
+ ### 2. Create Webhook Handler (Next.js API Route)
1345
+
1346
+ \`\`\`typescript
1347
+ // app/api/webhooks/channlize/route.ts
1348
+ import { NextRequest, NextResponse } from 'next/server';
1349
+ import crypto from 'crypto';
1350
+
1351
+ const WEBHOOK_SECRET = process.env.CHANNLIZE_WEBHOOK_SECRET!;
1352
+
1353
+ function verifySignature(payload: string, signature: string): boolean {
1354
+ const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
1355
+ const digest = hmac.update(payload).digest('hex');
1356
+ return crypto.timingSafeEqual(
1357
+ Buffer.from(signature),
1358
+ Buffer.from(digest)
1359
+ );
1360
+ }
1361
+
1362
+ export async function POST(req: NextRequest) {
1363
+ const signature = req.headers.get('x-channlize-signature');
1364
+ const payload = await req.text();
1365
+
1366
+ if (!signature || !verifySignature(payload, signature)) {
1367
+ return NextResponse.json(
1368
+ { error: 'Invalid signature' },
1369
+ { status: 401 }
1370
+ );
1371
+ }
1372
+
1373
+ const event = JSON.parse(payload);
1374
+
1375
+ // Handle different event types
1376
+ switch (event.type) {
1377
+ case 'conversation.created':
1378
+ await handleNewConversation(event.data);
1379
+ break;
1380
+
1381
+ case 'message.created':
1382
+ await handleNewMessage(event.data);
1383
+ break;
1384
+
1385
+ case 'conversation.closed':
1386
+ await handleConversationClosed(event.data);
1387
+ break;
1388
+
1389
+ default:
1390
+ console.log('Unhandled event type:', event.type);
1391
+ }
1392
+
1393
+ return NextResponse.json({ received: true });
1394
+ }
1395
+
1396
+ async function handleNewConversation(data: any) {
1397
+ // Example: Log to analytics
1398
+ await analytics.track('support_conversation_started', {
1399
+ conversationId: data.conversation.id,
1400
+ type: data.conversation.type, // 'contact_form' or 'chat'
1401
+ customerEmail: data.conversation.email,
1402
+ });
1403
+
1404
+ // Example: Notify sales team for high-value customers
1405
+ if (data.conversation.metadata?.customerTier === 'enterprise') {
1406
+ await notifySalesTeam({
1407
+ conversationId: data.conversation.id,
1408
+ customerEmail: data.conversation.email,
1409
+ message: data.conversation.initialMessage,
1410
+ });
1411
+ }
1412
+ }
1413
+
1414
+ async function handleNewMessage(data: any) {
1415
+ // Example: Auto-tag based on content
1416
+ const message = data.message.content.toLowerCase();
1417
+
1418
+ if (message.includes('bug') || message.includes('error')) {
1419
+ await tagConversation(data.conversation.id, 'bug');
1420
+ }
1421
+
1422
+ if (message.includes('billing') || message.includes('payment')) {
1423
+ await tagConversation(data.conversation.id, 'billing');
1424
+ await assignToDepartment(data.conversation.id, 'billing');
1425
+ }
1426
+
1427
+ // Example: Sentiment analysis
1428
+ const sentiment = await analyzeSentiment(message);
1429
+ if (sentiment === 'negative') {
1430
+ await escalateConversation(data.conversation.id, 'high');
1431
+ }
1432
+ }
1433
+
1434
+ async function handleConversationClosed(data: any) {
1435
+ // Example: Send satisfaction survey
1436
+ await sendSurveyEmail({
1437
+ to: data.conversation.email,
1438
+ conversationId: data.conversation.id,
1439
+ resolutionTime: data.metrics.resolutionTime,
1440
+ });
1441
+
1442
+ // Example: Update CRM
1443
+ await updateCRM({
1444
+ email: data.conversation.email,
1445
+ lastInteraction: new Date(),
1446
+ supportTicketId: data.conversation.id,
1447
+ resolved: true,
1448
+ });
1449
+ }
1450
+ \`\`\`
1451
+
1452
+ ### 3. Express.js Example
1453
+
1454
+ \`\`\`typescript
1455
+ import express from 'express';
1456
+ import crypto from 'crypto';
1457
+
1458
+ const app = express();
1459
+
1460
+ // Raw body needed for signature verification
1461
+ app.use('/webhooks/channlize', express.raw({ type: 'application/json' }));
1462
+
1463
+ app.post('/webhooks/channlize', (req, res) => {
1464
+ const signature = req.headers['x-channlize-signature'];
1465
+ const payload = req.body.toString();
1466
+
1467
+ // Verify signature
1468
+ const hmac = crypto.createHmac('sha256', process.env.CHANNLIZE_WEBHOOK_SECRET);
1469
+ const digest = hmac.update(payload).digest('hex');
1470
+
1471
+ if (signature !== digest) {
1472
+ return res.status(401).json({ error: 'Invalid signature' });
1473
+ }
1474
+
1475
+ const event = JSON.parse(payload);
1476
+
1477
+ // Handle event
1478
+ handleEvent(event);
1479
+
1480
+ res.json({ received: true });
1481
+ });
1482
+ \`\`\`
1483
+
1484
+ ## Webhook Event Payload Examples
1485
+
1486
+ ### conversation.created
1487
+
1488
+ \`\`\`json
1489
+ {
1490
+ "type": "conversation.created",
1491
+ "timestamp": "2025-01-15T10:00:00Z",
1492
+ "data": {
1493
+ "conversation": {
1494
+ "id": "conv_123",
1495
+ "type": "contact_form",
1496
+ "status": "open",
1497
+ "email": "customer@example.com",
1498
+ "name": "John Doe",
1499
+ "initialMessage": "I need help with...",
1500
+ "metadata": {
1501
+ "pageUrl": "https://example.com/contact",
1502
+ "userAgent": "Mozilla/5.0..."
1503
+ },
1504
+ "createdAt": "2025-01-15T10:00:00Z"
1505
+ }
1506
+ }
1507
+ }
1508
+ \`\`\`
1509
+
1510
+ ### message.created
1511
+
1512
+ \`\`\`json
1513
+ {
1514
+ "type": "message.created",
1515
+ "timestamp": "2025-01-15T10:05:00Z",
1516
+ "data": {
1517
+ "message": {
1518
+ "id": "msg_456",
1519
+ "conversationId": "conv_123",
1520
+ "content": "Thanks for reaching out!",
1521
+ "author": "agent",
1522
+ "authorData": {
1523
+ "name": "Sarah",
1524
+ "email": "sarah@example.com"
1525
+ },
1526
+ "timestamp": "2025-01-15T10:05:00Z"
1527
+ },
1528
+ "conversation": {
1529
+ "id": "conv_123",
1530
+ "status": "open"
1531
+ }
1532
+ }
1533
+ }
1534
+ \`\`\`
1535
+
1536
+ ## Use Cases
1537
+
1538
+ 1. **CRM Integration**: Sync conversations to Salesforce, HubSpot, etc.
1539
+ 2. **Analytics**: Track support metrics in your data warehouse
1540
+ 3. **Auto-routing**: Assign conversations based on content analysis
1541
+ 4. **Notifications**: Alert teams via SMS, PagerDuty for urgent issues
1542
+ 5. **AI Enhancement**: Feed messages to AI for sentiment/intent analysis
1543
+ 6. **Billing**: Track support usage for metered billing
1544
+
1545
+ ## Security Best Practices
1546
+
1547
+ - Always verify webhook signatures
1548
+ - Use HTTPS endpoints only
1549
+ - Rotate webhook secrets periodically
1550
+ - Implement rate limiting on webhook endpoints
1551
+ - Log all webhook events for audit trail
1552
+ `
1553
+ }
1554
+ ];
1555
+ function getPrompt(name) {
1556
+ return prompts.find((p) => p.name === name);
1557
+ }
1558
+ function listPrompts() {
1559
+ return prompts;
1560
+ }
1561
+
1562
+ // src/index.ts
1563
+ var ChannlizeMCPServer = class {
1564
+ server;
1565
+ config;
1566
+ constructor(options = {}) {
1567
+ this.config = options.config;
1568
+ this.server = new import_server.Server(
1569
+ {
1570
+ name: options.name || "channlize-mcp",
1571
+ version: options.version || "0.1.0"
1572
+ },
1573
+ {
1574
+ capabilities: {
1575
+ resources: {},
1576
+ tools: {},
1577
+ prompts: {}
1578
+ }
1579
+ }
1580
+ );
1581
+ this.setupHandlers();
1582
+ }
1583
+ setupHandlers() {
1584
+ this.server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => {
1585
+ const resources2 = listResources();
1586
+ return {
1587
+ resources: resources2.map((r) => ({
1588
+ uri: r.uri,
1589
+ name: r.name,
1590
+ description: r.description,
1591
+ mimeType: r.mimeType
1592
+ }))
1593
+ };
1594
+ });
1595
+ this.server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
1596
+ const resource = getResource(request.params.uri);
1597
+ if (!resource) {
1598
+ throw new Error(`Resource not found: ${request.params.uri}`);
1599
+ }
1600
+ return {
1601
+ contents: [
1602
+ {
1603
+ uri: resource.uri,
1604
+ mimeType: resource.mimeType,
1605
+ text: resource.getText()
1606
+ }
1607
+ ]
1608
+ };
1609
+ });
1610
+ this.server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
1611
+ const tools2 = listTools();
1612
+ return {
1613
+ tools: tools2.map((t) => ({
1614
+ name: t.name,
1615
+ description: t.description,
1616
+ inputSchema: t.inputSchema
1617
+ }))
1618
+ };
1619
+ });
1620
+ this.server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
1621
+ const tool = getTool(request.params.name);
1622
+ if (!tool) {
1623
+ throw new Error(`Tool not found: ${request.params.name}`);
1624
+ }
1625
+ if (!this.config?.apiKey) {
1626
+ throw new Error(
1627
+ "Channlize API key required. Please configure the MCP server with your API credentials."
1628
+ );
1629
+ }
1630
+ const context = {
1631
+ config: this.config
1632
+ };
1633
+ try {
1634
+ const result = await tool.handler(request.params.arguments || {}, context);
1635
+ return {
1636
+ content: [
1637
+ {
1638
+ type: "text",
1639
+ text: JSON.stringify(result, null, 2)
1640
+ }
1641
+ ]
1642
+ };
1643
+ } catch (error) {
1644
+ return {
1645
+ content: [
1646
+ {
1647
+ type: "text",
1648
+ text: JSON.stringify(
1649
+ {
1650
+ success: false,
1651
+ error: error.message || "Unknown error",
1652
+ code: error.code,
1653
+ statusCode: error.statusCode
1654
+ },
1655
+ null,
1656
+ 2
1657
+ )
1658
+ }
1659
+ ],
1660
+ isError: true
1661
+ };
1662
+ }
1663
+ });
1664
+ this.server.setRequestHandler(import_types.ListPromptsRequestSchema, async () => {
1665
+ const prompts2 = listPrompts();
1666
+ return {
1667
+ prompts: prompts2.map((p) => ({
1668
+ name: p.name,
1669
+ description: p.description,
1670
+ arguments: p.arguments
1671
+ }))
1672
+ };
1673
+ });
1674
+ this.server.setRequestHandler(import_types.GetPromptRequestSchema, async (request) => {
1675
+ const prompt = getPrompt(request.params.name);
1676
+ if (!prompt) {
1677
+ throw new Error(`Prompt not found: ${request.params.name}`);
1678
+ }
1679
+ const args2 = request.params.arguments;
1680
+ const text = prompt.getPrompt(args2);
1681
+ return {
1682
+ description: prompt.description,
1683
+ messages: [
1684
+ {
1685
+ role: "user",
1686
+ content: {
1687
+ type: "text",
1688
+ text
1689
+ }
1690
+ }
1691
+ ]
1692
+ };
1693
+ });
1694
+ }
1695
+ /**
1696
+ * Set or update the Channlize configuration
1697
+ */
1698
+ setConfig(config2) {
1699
+ this.config = config2;
1700
+ }
1701
+ /**
1702
+ * Get the underlying MCP server instance
1703
+ */
1704
+ getServer() {
1705
+ return this.server;
1706
+ }
1707
+ /**
1708
+ * Start the server with stdio transport
1709
+ */
1710
+ async runStdio() {
1711
+ const transport = new import_stdio.StdioServerTransport();
1712
+ await this.server.connect(transport);
1713
+ }
1714
+ /**
1715
+ * Close the server
1716
+ */
1717
+ async close() {
1718
+ await this.server.close();
1719
+ }
1720
+ };
1721
+
1722
+ // src/server.ts
1723
+ var args = process.argv.slice(2);
1724
+ var getArg = (name) => {
1725
+ const index = args.findIndex((arg) => arg === `--${name}` || arg === `-${name[0]}`);
1726
+ return index >= 0 && index + 1 < args.length ? args[index + 1] : void 0;
1727
+ };
1728
+ if (args.includes("--help") || args.includes("-h")) {
1729
+ console.log(`
1730
+ Channlize MCP Server
1731
+
1732
+ Usage: channlize-mcp [options]
1733
+
1734
+ Options:
1735
+ --api-key <key> Channlize API key (widget key) [required]
1736
+ --project-id <id> Channlize project ID
1737
+ --base-url <url> Channlize API base URL (default: https://api.channlize.com)
1738
+ --timeout <ms> Request timeout in milliseconds (default: 10000)
1739
+ -h, --help Show this help message
1740
+
1741
+ Environment Variables:
1742
+ CHANNLIZE_API_KEY Alternative to --api-key
1743
+ CHANNLIZE_PROJECT_ID Alternative to --project-id
1744
+ CHANNLIZE_BASE_URL Alternative to --base-url
1745
+ CHANNLIZE_TIMEOUT Alternative to --timeout
1746
+
1747
+ Examples:
1748
+ # Using command line arguments
1749
+ channlize-mcp --api-key wk_123abc --project-id proj_456def
1750
+
1751
+ # Using environment variables
1752
+ export CHANNLIZE_API_KEY=wk_123abc
1753
+ export CHANNLIZE_PROJECT_ID=proj_456def
1754
+ channlize-mcp
1755
+
1756
+ Configuration in MCP Clients (e.g., Claude Desktop):
1757
+ {
1758
+ "mcpServers": {
1759
+ "channlize": {
1760
+ "command": "npx",
1761
+ "args": [
1762
+ "@channlize/mcp",
1763
+ "--api-key",
1764
+ "your-api-key",
1765
+ "--project-id",
1766
+ "your-project-id"
1767
+ ]
1768
+ }
1769
+ }
1770
+ }
1771
+
1772
+ Or with environment variables:
1773
+ {
1774
+ "mcpServers": {
1775
+ "channlize": {
1776
+ "command": "npx",
1777
+ "args": ["@channlize/mcp"],
1778
+ "env": {
1779
+ "CHANNLIZE_API_KEY": "your-api-key",
1780
+ "CHANNLIZE_PROJECT_ID": "your-project-id"
1781
+ }
1782
+ }
1783
+ }
1784
+ }
1785
+
1786
+ Resources:
1787
+ channlize://schema/contact-form - Contact form JSON schema
1788
+ channlize://schema/chat-session - Chat session JSON schema
1789
+ channlize://docs/api-reference - Full API documentation
1790
+ channlize://docs/quick-start - Quick start guide
1791
+ channlize://docs/react-components - React components guide
1792
+
1793
+ Tools:
1794
+ submit_contact_form - Submit a contact form inquiry
1795
+ create_chat_session - Create a new chat session
1796
+ send_message - Send a message in a chat session
1797
+ get_chat_messages - Retrieve chat message history
1798
+ close_chat_session - Close an active chat session
1799
+
1800
+ Prompts:
1801
+ integrate-contact-form - Guide for adding contact form to React app
1802
+ setup-live-chat - Guide for implementing live chat widget
1803
+ customize-styling - Guide for theming components
1804
+ handle-webhooks - Guide for webhook integration
1805
+
1806
+ For more information, visit: https://github.com/channlize/sdk
1807
+ `);
1808
+ process.exit(0);
1809
+ }
1810
+ var config = {
1811
+ apiKey: getArg("api-key") || process.env.CHANNLIZE_API_KEY || "",
1812
+ projectId: getArg("project-id") || process.env.CHANNLIZE_PROJECT_ID,
1813
+ baseUrl: getArg("base-url") || process.env.CHANNLIZE_BASE_URL,
1814
+ timeout: parseInt(
1815
+ getArg("timeout") || process.env.CHANNLIZE_TIMEOUT || "10000",
1816
+ 10
1817
+ )
1818
+ };
1819
+ if (!config.apiKey) {
1820
+ console.error(`
1821
+ Error: Channlize API key is required
1822
+
1823
+ Please provide your API key using either:
1824
+ --api-key <key>
1825
+ or set CHANNLIZE_API_KEY environment variable
1826
+
1827
+ Get your API key from your Channlize dashboard.
1828
+
1829
+ Run 'channlize-mcp --help' for more information.
1830
+ `);
1831
+ process.exit(1);
1832
+ }
1833
+ var server = new ChannlizeMCPServer({
1834
+ name: "channlize-mcp",
1835
+ version: "0.1.0",
1836
+ config
1837
+ });
1838
+ process.on("SIGINT", async () => {
1839
+ await server.close();
1840
+ process.exit(0);
1841
+ });
1842
+ process.on("SIGTERM", async () => {
1843
+ await server.close();
1844
+ process.exit(0);
1845
+ });
1846
+ server.runStdio().catch((error) => {
1847
+ console.error("Failed to start Channlize MCP server:", error);
1848
+ process.exit(1);
1849
+ });
1850
+ //# sourceMappingURL=server.js.map