A lightweight message bus for coordinating conversations between participants in Discord threads.
npm install @meldscience/message-bus
Messages are the fundamental unit of communication. Each message has:
interface Message {
id: string; // Unique message identifier
from: string; // Sender ID (e.g. Discord user ID)
to: string[]; // Target participants (for @mentions)
channelId: string; // Discord channel or thread ID
content: {
type: 'text' | 'thought' | 'action';
data: string | ActionData;
};
metadata?: {
protocolId: string; // Active protocol
threadId?: string; // For threaded conversations
[key: string]: unknown; // Protocol-specific metadata
};
timestamp: number; // Unix timestamp
}
Protocols define how messages are handled in specific conversation contexts. Each protocol:
- Has a unique ID and metadata
- Can process incoming messages
- Can maintain thread-specific state
- Receives lifecycle events (initialization, cleanup)
class MyProtocol extends BaseProtocol {
constructor() {
super(
'my-protocol', // Unique ID
'My Protocol', // Display name
'Protocol description' // Description
);
}
async onMessage(msg: Message): Promise<Message | null> {
// Process message
return msg;
}
}
The message bus:
- Routes messages between participants
- Manages protocol registration
- Handles thread lifecycle
- Maintains thread state
const messageBus = new MessageBus(discordClient);
// Register protocols
await messageBus.registerProtocol(new QandAProtocol({
id: 'qanda',
allowedQuestioners: ['user1', 'user2'],
toolPermissions: { /* ... */ }
}));
// Create thread with protocol
const threadId = await messageBus.createThread(channelId, 'qanda');
// Route message
await messageBus.routeMessage({
id: 'msg1',
from: 'user1',
to: ['claude1'],
channelId: threadId,
content: {
type: 'text',
data: 'Hello Claude!'
},
timestamp: Date.now()
});
Manages question-and-answer interactions:
- Controls who can ask questions
- Manages tool permissions
- Routes questions to appropriate participants
const qandaProtocol = new QandAProtocol({
id: 'qanda',
name: 'Q&A Protocol',
description: 'Question and answer coordination',
allowedQuestioners: ['user1', 'user2'],
toolPermissions: {
'role1': ['tool1', 'tool2']
}
});
Coordinates meetings in Discord threads:
- Parses meeting goals from initial message
- Manages participant roles
- Tracks meeting state
const meetingProtocol = new MeetingProtocol();
The message bus emits events for key operations:
messageBus.on('message', (msg: Message) => {
// Handle message event
});
messageBus.on('threadCreate', ({ threadId, protocolId }) => {
// Handle thread creation
});
messageBus.on('error', (error: Error) => {
// Handle errors
});
When integrating with mcp-discord, ensure:
-
Messages include required fields:
-
id
: Unique message identifier -
timestamp
: Unix timestamp -
metadata.protocolId
: Active protocol ID
-
-
Protocol configuration uses the new constructor format:
new QandAProtocol({ id: 'protocol-id', // Required name: 'Protocol Name', // Optional description: '...', // Optional // Protocol-specific config... });
-
Use thread state management instead of config:
// Set thread state await messageBus.setThreadState(threadId, { // Thread-specific state... }); // Get thread state const state = await messageBus.getThreadState(threadId);
-
Implement event handlers for better state management:
messageBus.on('message', handleMessage); messageBus.on('threadCreate', handleThreadCreate); messageBus.on('error', handleError);
MIT