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.
Files changed (2) hide show
  1. package/index.js +138 -16
  2. 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 sequential label, then connect WebSocket
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: { type: 'object', properties: {}, required: [] },
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 label
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 || 'Session';
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
- return { content: [{ type: 'text', text: `Joined #${channel.name} (ID: ${channelId}) as ${sessionState.userName} (${sessionLabel}). Live messages are now being pushed.` }] };
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
- `[${new Date(m.created_at).toLocaleTimeString()}] ${m.user_name}: ${m.content}`
555
- ).join('\n');
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
- return { content: [{ type: 'text', text: `Connected to #${sessionState.channelName} as ${sessionState.userName} (${sessionState.sessionLabel || 'Session'})\nWebSocket: ${wsStatus}` }] };
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: '1.1.0' },
781
+ serverInfo: { name: 'mcp-chat-connect', version: LOCAL_VERSION },
660
782
  });
661
783
  break;
662
784
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-chat-connect",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "MCP server with channels support for connecting Claude Code sessions to MCP Chat -- real-time team messaging for AI-assisted development",
5
5
  "main": "index.js",
6
6
  "bin": {