send_message
Send messages to Microsoft Copilot Studio Agents through Direct Line API to interact with custom AI assistants and manage conversation flow in VS Code.
Instructions
Send a message to the Copilot Studio Agent
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| conversationId | No | Optional conversation ID to continue existing conversation | |
| message | Yes | The message text to send |
Implementation Reference
- src/server/mcp-server.ts:224-339 (handler)Main handler function for the 'send_message' tool. Validates input, manages conversations, sends messages via DirectLineClient, polls for bot response, and returns the result.private async handleSendMessage(args: Record<string, unknown>, userContext?: UserContext) { const { message, conversationId } = validateToolArgs(SendMessageArgsSchema, args); // Validate permissions if user context exists if (userContext && conversationId) { this.validateUserConversationAccess(userContext.userId, conversationId); } try { let convId = conversationId; let convState; // Get or create conversation if (convId) { convState = this.conversationManager.getConversation(convId); if (!convState) { throw new Error(`Conversation ${convId} not found or expired`); } } else { // Create new conversation with user-specific client ID const clientId = userContext ? `user-${userContext.userId}-${Date.now()}` : `mcp-client-${Date.now()}`; convState = await this.conversationManager.createConversation(clientId); convId = convState.conversationId; // Associate conversation with user if (userContext) { this.associateConversationWithUser(userContext.userId, convId); } } // Send message to Direct Line with user metadata const activityId = await this.client.sendActivity( { conversationId: convId, activity: { type: 'message', from: { id: convState.clientId, name: userContext?.name || 'MCP User', }, text: message, timestamp: new Date().toISOString(), // Add user metadata to activity channelData: userContext ? { userId: userContext.userId, userEmail: userContext.email, tenantId: userContext.tenantId, } : undefined, }, }, convState.token ); // Poll for response const startTime = Date.now(); const timeout = 30000; let botResponse = ''; while (Date.now() - startTime < timeout) { await new Promise((resolve) => setTimeout(resolve, 1000)); const activitySet = await this.client.getActivities( { conversationId: convId, watermark: convState.watermark, }, convState.token ); if (activitySet.watermark) { this.conversationManager.updateWatermark(convId, activitySet.watermark); } const botActivities = activitySet.activities.filter( (a) => a.type === 'message' && a.from?.id !== convState.clientId ); if (botActivities.length > 0) { botActivities.forEach((activity) => { this.conversationManager.addToHistory(convId!, activity); }); const latestBot = botActivities[botActivities.length - 1]; botResponse = latestBot.text || '[No text response]'; break; } } if (!botResponse) { botResponse = '[No response received within timeout period]'; } // Audit log this.logAudit({ timestamp: Date.now(), userId: userContext?.userId, action: 'send_message', conversationId: convId, details: { activityId }, }); return createSuccessResponse({ conversationId: convId, response: botResponse, activityId, }); } catch (error) { throw new Error( `Failed to send message: ${error instanceof Error ? error.message : String(error)}` ); } }
- src/server/tool-schemas.ts:10-15 (schema)Zod schema defining input validation for send_message tool arguments: message (required string), conversationId (optional string).export const SendMessageArgsSchema = z.object({ message: z.string().min(1, 'Message cannot be empty'), conversationId: z.string().optional(), }); export type SendMessageArgs = z.infer<typeof SendMessageArgsSchema>;
- src/server/mcp-server.ts:116-133 (registration)Registration of the 'send_message' tool in the ListTools response for stdio transport, including name, description, and input schema.{ name: 'send_message', description: 'Send a message to the Copilot Studio Agent', inputSchema: { type: 'object', properties: { message: { type: 'string', description: 'The message text to send', }, conversationId: { type: 'string', description: 'Optional conversation ID to continue existing conversation', }, }, required: ['message'], }, },
- src/server/mcp-server.ts:184-216 (registration)MCP CallToolRequestHandler registration dispatching 'send_message' calls to handleSendMessage based on tool name.this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const userContext = (request as any).userContext as UserContext | undefined; console.error( `[MCP] Tool called: ${name} by user: ${userContext?.userId || 'anonymous'}`, args ); try { switch (name) { case 'send_message': return await this.handleSendMessage(args || {}, userContext); case 'start_conversation': return await this.handleStartConversation(args || {}, userContext); case 'end_conversation': return await this.handleEndConversation(args || {}, userContext); case 'get_conversation_history': return await this.handleGetConversationHistory(args || {}, userContext); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { console.error(`[MCP] Tool error: ${name}`, error); this.logAudit({ timestamp: Date.now(), userId: userContext?.userId, action: `${name}_error`, details: { error: error instanceof Error ? error.message : String(error) }, }); return transformErrorToMCPResponse(error); } });
- src/server/mcp-server.ts:689-704 (registration)Registration of the 'send_message' tool in the HTTP tools/list response.name: 'send_message', description: 'Send a message to the Copilot Studio Agent', inputSchema: { type: 'object', properties: { message: { type: 'string', description: 'The message text to send', }, conversationId: { type: 'string', description: 'Optional conversation ID to continue existing conversation', }, }, required: ['message'], },