Skip to main content
Glama
bradcstevens

Copilot Studio Agent Direct Line MCP Server

by bradcstevens

send_message

Send messages to Microsoft Copilot Studio Agents via Direct Line API to interact with custom conversational agents directly from development environments.

Instructions

Send a message to the Copilot Studio Agent

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
messageYesThe message text to send
conversationIdNoOptional conversation ID to continue existing conversation

Implementation Reference

  • The core handler function that executes the send_message tool logic: validates input using SendMessageArgsSchema, manages or creates conversations, sends the message via DirectLineClient, polls for the bot's response, logs audit, and returns conversationId, response, and activityId.
    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 for validating send_message tool arguments: requires 'message' string (non-empty), optional 'conversationId' string. Used in handleSendMessage via validateToolArgs.
     * Schema for send_message tool arguments
     */
    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>;
  • Tool registration in the MCP server's ListToolsRequestSchema handler, defining name, description, and inputSchema for send_message.
    {
      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'],
      },
    },
  • Dispatch/registration in CallToolRequestSchema handler: routes 'send_message' calls to handleSendMessage function.
    switch (name) {
      case 'send_message':
        return await this.handleSendMessage(args || {}, userContext);
  • Duplicate tool registration for HTTP transport mode in handleHttpMessage 'tools/list' case.
    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