mcp-chat-connect 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +138 -16
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -137,7 +137,7 @@ function connectWebSocket() {
|
|
|
137
137
|
if (msg.session_id === sessionState.sessionToken) return;
|
|
138
138
|
|
|
139
139
|
const senderLabel = msg.session_id
|
|
140
|
-
? `${msg.user_name?.split(' ')[0]}'s Claude`
|
|
140
|
+
? `${msg.user_name?.split(' ')[0]}'s Claude${msg.session_label ? ` (${msg.session_label})` : ''}`
|
|
141
141
|
: msg.user_name || 'unknown';
|
|
142
142
|
|
|
143
143
|
pushChannelMessage('mcp-chat', msg.content, {
|
|
@@ -146,6 +146,27 @@ function connectWebSocket() {
|
|
|
146
146
|
message_type: msg.message_type || 'info',
|
|
147
147
|
timestamp: msg.created_at || new Date().toISOString(),
|
|
148
148
|
});
|
|
149
|
+
} else if (data.type === 'session_renamed') {
|
|
150
|
+
// Only react when this session itself was renamed (e.g. from the browser)
|
|
151
|
+
if (data.session_token !== sessionState.sessionToken) return;
|
|
152
|
+
if (data.label === sessionState.sessionLabel) return;
|
|
153
|
+
sessionState.sessionLabel = data.label;
|
|
154
|
+
pushChannelMessage('mcp-chat', `This session has been named "${data.label}". Refer to yourself as "${data.label}" in #${sessionState.channelName}.`, {
|
|
155
|
+
channel: sessionState.channelName,
|
|
156
|
+
event: 'session_renamed',
|
|
157
|
+
session_label: data.label,
|
|
158
|
+
});
|
|
159
|
+
} else if (data.type === 'channel_instructions_updated') {
|
|
160
|
+
// Skip the echo of a change this session just made itself
|
|
161
|
+
if ((data.instructions || null) === sessionState.sessionInstructions) return;
|
|
162
|
+
sessionState.sessionInstructions = data.instructions || null;
|
|
163
|
+
const body = data.instructions
|
|
164
|
+
? `Channel instructions for #${sessionState.channelName} were updated${data.updated_by ? ` by ${data.updated_by}` : ''}. Follow these instructions for this channel:\n\n${data.instructions}`
|
|
165
|
+
: `Channel instructions for #${sessionState.channelName} were cleared.`;
|
|
166
|
+
pushChannelMessage('mcp-chat', body, {
|
|
167
|
+
channel: sessionState.channelName,
|
|
168
|
+
event: 'channel_instructions_updated',
|
|
169
|
+
});
|
|
149
170
|
} else if (data.type === 'presence') {
|
|
150
171
|
// Only push presence for Claude Code sessions (have session_token), not browser refreshes
|
|
151
172
|
if (!data.session_token) return;
|
|
@@ -260,6 +281,7 @@ let sessionState = {
|
|
|
260
281
|
userId: null,
|
|
261
282
|
sessionToken: null,
|
|
262
283
|
sessionLabel: null,
|
|
284
|
+
sessionInstructions: null,
|
|
263
285
|
connected: false,
|
|
264
286
|
};
|
|
265
287
|
|
|
@@ -292,15 +314,19 @@ if (envToken && envChannel) {
|
|
|
292
314
|
userId,
|
|
293
315
|
sessionToken,
|
|
294
316
|
sessionLabel: null,
|
|
317
|
+
sessionInstructions: null,
|
|
295
318
|
connected: true,
|
|
296
319
|
};
|
|
297
320
|
|
|
298
|
-
// Register session for
|
|
321
|
+
// Register session for label + channel instructions, then connect WebSocket
|
|
299
322
|
apiCall('register_session', {
|
|
300
323
|
channel_id: sessionState.channelId,
|
|
301
324
|
session_token: sessionToken,
|
|
325
|
+
label: process.env.MCP_CHAT_SESSION_NAME || undefined,
|
|
302
326
|
}, envToken).then(result => {
|
|
303
327
|
sessionState.sessionLabel = result.label || 'Session';
|
|
328
|
+
sessionState.sessionInstructions = result.instructions || null;
|
|
329
|
+
if (result.channel_name) sessionState.channelName = result.channel_name;
|
|
304
330
|
process.stderr.write(`[mcp-chat] Auto-connected to #${sessionState.channelName} as ${userName} (${sessionState.sessionLabel})\n`);
|
|
305
331
|
}).catch(() => {
|
|
306
332
|
process.stderr.write(`[mcp-chat] Auto-connected to #${sessionState.channelName} as ${userName}\n`);
|
|
@@ -324,9 +350,15 @@ function getTools() {
|
|
|
324
350
|
{
|
|
325
351
|
name: 'mcp_chat_connect',
|
|
326
352
|
description: sessionState.connected
|
|
327
|
-
? `Currently connected to #${sessionState.channelName} as ${sessionState.userName}. Live messages are being pushed into this session. Run again to switch channels.`
|
|
328
|
-
: 'Connect to MCP Chat. Opens your browser to authenticate and select a channel. Once connected, messages will be pushed into this session in real-time.',
|
|
329
|
-
inputSchema: {
|
|
353
|
+
? `Currently connected to #${sessionState.channelName} as ${sessionState.userName} (${sessionState.sessionLabel || 'Session'}). Live messages are being pushed into this session. Run again to switch channels.`
|
|
354
|
+
: 'Connect to MCP Chat. Opens your browser to authenticate and select a channel. Once connected, messages will be pushed into this session in real-time. Optionally pass a label to name this session.',
|
|
355
|
+
inputSchema: {
|
|
356
|
+
type: 'object',
|
|
357
|
+
properties: {
|
|
358
|
+
label: { type: 'string', description: 'Optional name for this session (e.g. "Backend Dev", "QA"). Defaults to a sequential "Session N".' },
|
|
359
|
+
},
|
|
360
|
+
required: [],
|
|
361
|
+
},
|
|
330
362
|
},
|
|
331
363
|
{
|
|
332
364
|
name: 'mcp_chat_send',
|
|
@@ -414,6 +446,33 @@ function getTools() {
|
|
|
414
446
|
},
|
|
415
447
|
},
|
|
416
448
|
},
|
|
449
|
+
{
|
|
450
|
+
name: 'mcp_chat_set_name',
|
|
451
|
+
description: 'Set or change the name of your own session. Other participants (and you) will see this name on every message you send.',
|
|
452
|
+
inputSchema: {
|
|
453
|
+
type: 'object',
|
|
454
|
+
properties: {
|
|
455
|
+
name: { type: 'string', description: 'The name for this session (e.g. "Backend Dev", "QA Agent").' },
|
|
456
|
+
},
|
|
457
|
+
required: ['name'],
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
name: 'mcp_chat_instructions',
|
|
462
|
+
description: 'Show the current channel instructions (a shared system prompt set for everyone in the channel).',
|
|
463
|
+
inputSchema: { type: 'object', properties: {} },
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
name: 'mcp_chat_set_instructions',
|
|
467
|
+
description: 'Set the channel instructions: a shared system prompt that every connected session in the channel sees. Pass an empty string to clear. Any channel member can set these.',
|
|
468
|
+
inputSchema: {
|
|
469
|
+
type: 'object',
|
|
470
|
+
properties: {
|
|
471
|
+
instructions: { type: 'string', description: 'The shared instructions for the channel. Empty string clears them.' },
|
|
472
|
+
},
|
|
473
|
+
required: ['instructions'],
|
|
474
|
+
},
|
|
475
|
+
},
|
|
417
476
|
];
|
|
418
477
|
}
|
|
419
478
|
|
|
@@ -442,19 +501,22 @@ async function handleToolCall(name, args) {
|
|
|
442
501
|
userId,
|
|
443
502
|
sessionToken,
|
|
444
503
|
sessionLabel: null,
|
|
504
|
+
sessionInstructions: null,
|
|
445
505
|
connected: true,
|
|
446
506
|
};
|
|
447
507
|
saveConfig({ token: result.token, userName: result.userName, userId });
|
|
448
508
|
|
|
449
|
-
// Register session to get sequential
|
|
450
|
-
let sessionLabel = 'Session';
|
|
509
|
+
// Register session to get label (custom or sequential) + channel instructions
|
|
510
|
+
let sessionLabel = args.label || 'Session';
|
|
451
511
|
try {
|
|
452
512
|
const regResult = await apiCall('register_session', {
|
|
453
513
|
channel_id: result.channelId,
|
|
454
514
|
session_token: sessionToken,
|
|
515
|
+
label: args.label || undefined,
|
|
455
516
|
}, result.token);
|
|
456
|
-
sessionLabel = regResult.label ||
|
|
517
|
+
sessionLabel = regResult.label || sessionLabel;
|
|
457
518
|
sessionState.sessionLabel = sessionLabel;
|
|
519
|
+
sessionState.sessionInstructions = regResult.instructions || null;
|
|
458
520
|
} catch {}
|
|
459
521
|
|
|
460
522
|
// Start WebSocket listener for real-time push
|
|
@@ -462,7 +524,10 @@ async function handleToolCall(name, args) {
|
|
|
462
524
|
|
|
463
525
|
// Check for package updates
|
|
464
526
|
const updateNotice = await checkForUpdate();
|
|
465
|
-
let responseText = `Connected to #${result.channelName} as ${result.userName} (${sessionLabel}). Live messages will now be pushed into this session. You can also use mcp_chat_send to send messages and mcp_chat_read to fetch history.`;
|
|
527
|
+
let responseText = `Connected to #${result.channelName} as ${result.userName} (${sessionLabel}). Your session is named "${sessionLabel}" -- this name appears on every message you send. Use mcp_chat_set_name to change it. Live messages will now be pushed into this session. You can also use mcp_chat_send to send messages and mcp_chat_read to fetch history.`;
|
|
528
|
+
if (sessionState.sessionInstructions) {
|
|
529
|
+
responseText += `\n\nChannel instructions for #${result.channelName} (apply these while in this channel):\n${sessionState.sessionInstructions}`;
|
|
530
|
+
}
|
|
466
531
|
if (updateNotice) {
|
|
467
532
|
responseText += `\n\n${updateNotice}`;
|
|
468
533
|
}
|
|
@@ -498,10 +563,11 @@ async function handleToolCall(name, args) {
|
|
|
498
563
|
channelName: channel.name,
|
|
499
564
|
sessionToken,
|
|
500
565
|
sessionLabel: null,
|
|
566
|
+
sessionInstructions: null,
|
|
501
567
|
connected: true,
|
|
502
568
|
};
|
|
503
569
|
|
|
504
|
-
// Register session to get label (custom or sequential)
|
|
570
|
+
// Register session to get label (custom or sequential) + channel instructions
|
|
505
571
|
let sessionLabel = args.label || 'Session';
|
|
506
572
|
try {
|
|
507
573
|
const regResult = await apiCall('register_session', {
|
|
@@ -511,10 +577,15 @@ async function handleToolCall(name, args) {
|
|
|
511
577
|
}, sessionState.token);
|
|
512
578
|
sessionLabel = regResult.label || sessionLabel;
|
|
513
579
|
sessionState.sessionLabel = sessionLabel;
|
|
580
|
+
sessionState.sessionInstructions = regResult.instructions || null;
|
|
514
581
|
} catch {}
|
|
515
582
|
|
|
516
583
|
connectWebSocket();
|
|
517
|
-
|
|
584
|
+
let joinText = `Joined #${channel.name} (ID: ${channelId}) as ${sessionState.userName} (${sessionLabel}). Your session is named "${sessionLabel}"; use mcp_chat_set_name to change it. Live messages are now being pushed.`;
|
|
585
|
+
if (sessionState.sessionInstructions) {
|
|
586
|
+
joinText += `\n\nChannel instructions for #${channel.name} (apply these while in this channel):\n${sessionState.sessionInstructions}`;
|
|
587
|
+
}
|
|
588
|
+
return { content: [{ type: 'text', text: joinText }] };
|
|
518
589
|
} catch (err) {
|
|
519
590
|
return { content: [{ type: 'text', text: `Failed to join channel: ${err.message}` }], isError: true };
|
|
520
591
|
}
|
|
@@ -550,9 +621,12 @@ async function handleToolCall(name, args) {
|
|
|
550
621
|
if (!result.messages || result.messages.length === 0) {
|
|
551
622
|
return { content: [{ type: 'text', text: `No messages in #${sessionState.channelName}` }] };
|
|
552
623
|
}
|
|
553
|
-
const formatted = result.messages.map(m =>
|
|
554
|
-
|
|
555
|
-
|
|
624
|
+
const formatted = result.messages.map(m => {
|
|
625
|
+
const sender = m.session_id
|
|
626
|
+
? `${m.user_name?.split(' ')[0]}'s Claude${m.session_label ? ` (${m.session_label})` : ''}`
|
|
627
|
+
: m.user_name;
|
|
628
|
+
return `[${new Date(m.created_at).toLocaleTimeString()}] ${sender}: ${m.content}`;
|
|
629
|
+
}).join('\n');
|
|
556
630
|
return { content: [{ type: 'text', text: `Messages in #${sessionState.channelName}:\n${formatted}` }] };
|
|
557
631
|
}
|
|
558
632
|
|
|
@@ -589,7 +663,11 @@ async function handleToolCall(name, args) {
|
|
|
589
663
|
return { content: [{ type: 'text', text: sessionState.token ? 'Authenticated but not connected to a channel. Run mcp_chat_connect or mcp_chat_join to pick a channel.' : 'Not connected. Run mcp_chat_connect to authenticate and select a channel.' }] };
|
|
590
664
|
}
|
|
591
665
|
const wsStatus = wsConnection?.readyState === 1 ? 'live (receiving messages)' : 'reconnecting...';
|
|
592
|
-
|
|
666
|
+
let statusText = `Connected to #${sessionState.channelName} as ${sessionState.userName} (${sessionState.sessionLabel || 'Session'})\nWebSocket: ${wsStatus}`;
|
|
667
|
+
if (sessionState.sessionInstructions) {
|
|
668
|
+
statusText += `\n\nChannel instructions:\n${sessionState.sessionInstructions}`;
|
|
669
|
+
}
|
|
670
|
+
return { content: [{ type: 'text', text: statusText }] };
|
|
593
671
|
}
|
|
594
672
|
|
|
595
673
|
case 'mcp_chat_create_channel': {
|
|
@@ -638,6 +716,50 @@ async function handleToolCall(name, args) {
|
|
|
638
716
|
return { content: [{ type: 'text', text: `Channel updated: #${result.channel.name}${result.channel.description ? ` -- ${result.channel.description}` : ''}` }] };
|
|
639
717
|
}
|
|
640
718
|
|
|
719
|
+
case 'mcp_chat_set_name': {
|
|
720
|
+
if (!sessionState.connected) {
|
|
721
|
+
return { content: [{ type: 'text', text: 'Not connected. Run mcp_chat_connect first.' }], isError: true };
|
|
722
|
+
}
|
|
723
|
+
const newName = String(args.name || '').trim().slice(0, 100);
|
|
724
|
+
if (!newName) return { content: [{ type: 'text', text: 'A name is required.' }], isError: true };
|
|
725
|
+
const result = await apiCall('rename_session', {
|
|
726
|
+
session_token: sessionState.sessionToken,
|
|
727
|
+
label: newName,
|
|
728
|
+
}, sessionState.token);
|
|
729
|
+
if (result.error) return { content: [{ type: 'text', text: `Error: ${result.error}` }], isError: true };
|
|
730
|
+
sessionState.sessionLabel = result.label || newName;
|
|
731
|
+
return { content: [{ type: 'text', text: `Your session is now named "${sessionState.sessionLabel}" in #${sessionState.channelName}. This name appears on every message you send.` }] };
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
case 'mcp_chat_instructions': {
|
|
735
|
+
if (!sessionState.connected) {
|
|
736
|
+
return { content: [{ type: 'text', text: 'Not connected. Run mcp_chat_connect first.' }], isError: true };
|
|
737
|
+
}
|
|
738
|
+
if (!sessionState.sessionInstructions) {
|
|
739
|
+
return { content: [{ type: 'text', text: `No instructions are set for #${sessionState.channelName}. Set them with mcp_chat_set_instructions.` }] };
|
|
740
|
+
}
|
|
741
|
+
return { content: [{ type: 'text', text: `Channel instructions for #${sessionState.channelName}:\n${sessionState.sessionInstructions}` }] };
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
case 'mcp_chat_set_instructions': {
|
|
745
|
+
if (!sessionState.connected) {
|
|
746
|
+
return { content: [{ type: 'text', text: 'Not connected. Run mcp_chat_connect first.' }], isError: true };
|
|
747
|
+
}
|
|
748
|
+
if (typeof args.instructions !== 'string') {
|
|
749
|
+
return { content: [{ type: 'text', text: 'instructions (string) is required. Pass an empty string to clear.' }], isError: true };
|
|
750
|
+
}
|
|
751
|
+
const instructions = args.instructions.slice(0, 10000);
|
|
752
|
+
const result = await apiCall('set_channel_instructions', {
|
|
753
|
+
channel_id: sessionState.channelId,
|
|
754
|
+
instructions,
|
|
755
|
+
}, sessionState.token);
|
|
756
|
+
if (result.error) return { content: [{ type: 'text', text: `Error: ${result.error}` }], isError: true };
|
|
757
|
+
sessionState.sessionInstructions = result.instructions || null;
|
|
758
|
+
return { content: [{ type: 'text', text: result.instructions
|
|
759
|
+
? `Channel instructions for #${sessionState.channelName} updated. All connected sessions will see them.`
|
|
760
|
+
: `Channel instructions for #${sessionState.channelName} cleared.` }] };
|
|
761
|
+
}
|
|
762
|
+
|
|
641
763
|
default:
|
|
642
764
|
return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
|
|
643
765
|
}
|
|
@@ -656,7 +778,7 @@ async function handleMessage(msg) {
|
|
|
656
778
|
tools: {},
|
|
657
779
|
experimental: { 'claude/channel': {} },
|
|
658
780
|
},
|
|
659
|
-
serverInfo: { name: 'mcp-chat-connect', version:
|
|
781
|
+
serverInfo: { name: 'mcp-chat-connect', version: LOCAL_VERSION },
|
|
660
782
|
});
|
|
661
783
|
break;
|
|
662
784
|
|
package/package.json
CHANGED