Skip to main content
Glama
bradcstevens

Copilot Studio Agent Direct Line MCP Server

by bradcstevens

start_conversation

Initiate a new conversation with a Microsoft Copilot Studio Agent to interact with custom AI assistants through Direct Line 3.0 API integration.

Instructions

Start a new conversation with the Copilot Studio Agent

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
initialMessageNoOptional first message to send

Implementation Reference

  • Core handler function that executes the start_conversation tool: validates args, creates conversation via ConversationManager, optionally sends initial message and polls for bot response.
    private async handleStartConversation( args: Record<string, unknown>, userContext?: UserContext ) { const { initialMessage } = validateToolArgs(StartConversationArgsSchema, args); try { // Create new conversation with user-specific client ID const clientId = userContext ? `user-${userContext.userId}-${Date.now()}` : `mcp-client-${Date.now()}`; const convState = await this.conversationManager.createConversation(clientId); // Associate conversation with user if (userContext) { this.associateConversationWithUser(userContext.userId, convState.conversationId); } let result: { conversationId: string; status: string; response?: string; activityId?: string; } = { conversationId: convState.conversationId, status: 'started', }; // If initial message provided, send it if (initialMessage && typeof initialMessage === 'string') { const activityId = await this.client.sendActivity( { conversationId: convState.conversationId, activity: { type: 'message', from: { id: clientId, name: userContext?.name || 'MCP User' }, text: initialMessage, timestamp: new Date().toISOString(), channelData: userContext ? { userId: userContext.userId, userEmail: userContext.email, tenantId: userContext.tenantId, } : undefined, }, }, convState.token ); // Poll for response (same logic as send_message) 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: convState.conversationId, watermark: convState.watermark, }, convState.token ); if (activitySet.watermark) { this.conversationManager.updateWatermark(convState.conversationId, activitySet.watermark); } const botActivities = activitySet.activities.filter( (a) => a.type === 'message' && a.from?.id !== clientId ); if (botActivities.length > 0) { botActivities.forEach((activity) => { this.conversationManager.addToHistory(convState.conversationId, activity); }); const latestBot = botActivities[botActivities.length - 1]; botResponse = latestBot.text || '[No text response]'; break; } } result.response = botResponse || '[No response received within timeout period]'; result.activityId = activityId; } // Audit log this.logAudit({ timestamp: Date.now(), userId: userContext?.userId, action: 'start_conversation', conversationId: convState.conversationId, }); return createSuccessResponse(result); } catch (error) { throw new Error( `Failed to start conversation: ${error instanceof Error ? error.message : String(error)}` ); } }
  • Zod schema defining input validation for start_conversation tool arguments (optional initialMessage).
    export const StartConversationArgsSchema = z.object({ initialMessage: z.string().min(1, 'Initial message cannot be empty').optional(), }); export type StartConversationArgs = z.infer<typeof StartConversationArgsSchema>;
  • Tool registration in ListToolsRequestHandler for stdio transport, defining name, description, and input schema.
    name: 'start_conversation', description: 'Start a new conversation with the Copilot Studio Agent', inputSchema: { type: 'object', properties: { initialMessage: { type: 'string', description: 'Optional first message to send', }, }, }, },
  • Tool registration in HTTP transport handler for tools/list method.
    name: 'start_conversation', description: 'Start a new conversation with the Copilot Studio Agent', inputSchema: { type: 'object', properties: { initialMessage: { type: 'string', description: 'Optional first message to send', }, }, },
  • Helper method called by handler to create and manage conversation state, delegating actual DirectLine start to client.
    async createConversation(clientId: string): Promise<ConversationState> { // Get token from token manager const token = await this.tokenManager.getToken(clientId); // Start conversation with Direct Line const conversation = await this.client.startConversation(token); // Create state const state: ConversationState = { conversationId: conversation.conversationId, token: conversation.token, clientId, watermark: undefined, createdAt: Date.now(), lastActivity: Date.now(), messageHistory: [], }; // Store state this.conversations.set(conversation.conversationId, state); // Update metrics this.metrics.totalCreated++; this.metrics.activeCount = this.conversations.size; // Schedule cleanup this.scheduleCleanup(conversation.conversationId); console.error(`[ConversationManager] Created conversation ${conversation.conversationId} for client ${clientId}`); return state; }

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