update_user
Send updates to Slack or Discord for a captured message by specifying its ID and the new content to share. Ensures coordinated communication between AI agents via the Beep Boop MCP server.
Instructions
Sends a follow-up update back to the platform (Slack/Discord) for a captured message.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | ID of the captured message to respond to | |
| updateContent | Yes | Message content to send as an update |
Implementation Reference
- src/tools.ts:699-761 (handler)Core handler function for the 'update_user' MCP tool. Retrieves message from inbox store and posts update to Slack/Discord thread/channel, with delegation to HTTP listener if enabled.export async function handleUpdateUser(params: UpdateUserParams): Promise<ToolResponse> { try { const { messageId, updateContent } = params; const config = loadConfig(); // If central listener is enabled, delegate synchronously and return its response if (config.listenerEnabled) { try { const { listenerClient } = await import('./http-listener-client.js'); const payload = { messageId, updateContent }; const res = await listenerClient.post('/mcp/update_user', payload); if (res.ok) { const text = typeof res.data?.text === 'string' ? res.data.text : `✅ Update sent for message ${messageId}`; return { content: [{ type: 'text', text }] }; } return { content: [{ type: 'text', text: `❌ Listener error (${res.status}): ${res.error || 'unknown error'}` }], isError: true }; } catch (e) { return { content: [{ type: 'text', text: `❌ Listener call failed: ${e}` }], isError: true }; } } // Fallback to local platform posting const inbox = new (await import('./ingress/inbox.js')).InboxStore(config); // Trigger auto-cleanup (non-blocking) inbox.autoCleanup(); const msg = await inbox.read(messageId); if (!msg) { return { content: [{ type: 'text', text: `❌ Message ${messageId} not found` }], isError: true }; } if (msg.platform === 'slack') { if (!config.slackBotToken) { return { content: [{ type: 'text', text: '❌ Slack bot token not configured' }], isError: true }; } const { WebClient } = await import('@slack/web-api'); const web = new WebClient(config.slackBotToken); const channel = msg.context.channelId as string; const thread_ts = msg.context.threadTs as string | undefined; await web.chat.postMessage({ channel, thread_ts, text: updateContent }); } else if (msg.platform === 'discord') { if (!config.discordBotToken) { return { content: [{ type: 'text', text: '❌ Discord bot token not configured' }], isError: true }; } const { REST, Routes } = await import('discord.js'); const rest = new (REST as any)({ version: '10' }).setToken(config.discordBotToken); const threadId = (msg.context as any).threadId as string | undefined; if (threadId) { await rest.post((Routes as any).channelMessages(threadId), { body: { content: updateContent } }); } else { const channelId = msg.context.channelId as string; await rest.post((Routes as any).channelMessages(channelId), { body: { content: updateContent, message_reference: { message_id: (msg.context as any).messageId } } }); } } else { return { content: [{ type: 'text', text: `❌ Unsupported platform: ${(msg as any).platform}` }], isError: true }; } return { content: [{ type: 'text', text: `✅ Update sent for message ${messageId}` }] }; } catch (error) { return { content: [{ type: 'text', text: `❌ Failed to send update: ${error}` }], isError: true }; } }
- src/tools.ts:70-74 (schema)Zod input schema for validating 'update_user' tool parameters: messageId (string) and updateContent (string). Used in tool registration./** Schema for update_user tool parameters */ export const UpdateUserSchema = z.object({ messageId: z.string().describe('ID of the captured message to respond to'), updateContent: z.string().describe('Message content to send as an update') });
- src/index.ts:96-110 (registration)MCP server registration of the 'update_user' tool, specifying title, description, input schema imported from tools.js, and handler function.* Tool: update_user * Sends a follow-up update back to the platform thread/user tied to a captured message */ server.registerTool( 'update_user', { title: 'Update User', description: 'Sends a follow-up update back to the platform (Slack/Discord) for a captured message.', inputSchema: (await import('./tools.js')).UpdateUserSchema.shape }, async (params) => { const { handleUpdateUser } = await import('./tools.js'); return await handleUpdateUser(params); } );
- src/types.ts:143-148 (schema)TypeScript interface defining the UpdateUserParams type used by the update_user handler function.export interface UpdateUserParams { /** ID of the captured message in the inbox store */ messageId: string; /** Message content to send as an update */ updateContent: string; }
- src/ingress/index.ts:157-216 (helper)HTTP endpoint (/mcp/update_user) in ingress server that the tool handler delegates to when listenerEnabled=true. Implements the same Slack/Discord posting logic.if (req.method === 'POST' && url.pathname === '/mcp/update_user') { try { const body = await readJsonBody<any>(req); const { messageId, updateContent } = body || {}; if (!messageId || !updateContent) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'messageId and updateContent are required' })); return; } const msg = await inbox.read(messageId); if (!msg) { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: `Message ${messageId} not found` })); return; } if (msg.platform === 'slack') { const cfg = loadConfig(); if (!cfg.slackBotToken) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Slack bot token not configured' })); return; } const { WebClient } = await import('@slack/web-api'); const web = new WebClient(cfg.slackBotToken); const channel = msg.context.channelId as string; const thread_ts = (msg.context as any).threadTs as string | undefined; await web.chat.postMessage({ channel, thread_ts, text: updateContent }); } else if (msg.platform === 'discord') { const cfg = loadConfig(); if (!cfg.discordBotToken) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Discord bot token not configured' })); return; } const { REST, Routes } = await import('discord.js'); const rest = new (REST as any)({ version: '10' }).setToken(cfg.discordBotToken); const threadId = (msg.context as any).threadId as string | undefined; if (threadId) { await rest.post((Routes as any).channelMessages(threadId), { body: { content: updateContent } }); } else { const channelId = msg.context.channelId as string; await rest.post((Routes as any).channelMessages(channelId), { body: { content: updateContent, message_reference: { message_id: (msg.context as any).messageId } } }); } } else { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: `Unsupported platform: ${(msg as any).platform}` })); return; } res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ text: `✅ Update sent for message ${messageId}` })); return; } catch (e) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: `Failed to send update: ${e}` })); return; } }