Skip to main content
Glama
bradcstevens

Copilot Studio Agent Direct Line MCP Server

by bradcstevens

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
NameRequiredDescriptionDefault
conversationIdNoOptional conversation ID to continue existing conversation
messageYesThe message text to send

Implementation Reference

  • 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)}` ); } }
  • 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>;
  • 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'], }, },
  • 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); } });
  • 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'], },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bradcstevens/copilot-studio-agent-direct-line-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server