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