How to integrate Dynamics365 MCP with OpenAI Agents SDK

Connect OpenAI Agents SDK to Dynamics365 MCP. Create a new sales lead for acme corp, list all open invoices for this quarter, and more using natural language, with authentication handled for you.

Dynamics365 logoDynamics365
Oauth2

Dynamics 365 is Microsoft's platform combining CRM, ERP, and productivity apps. It streamlines sales, marketing, service, and operations in one place.

119 Tools

Introduction

This guide walks you through connecting Dynamics365 to the OpenAI Agents SDK using the Composio tool router. By the end, you'll have a working Dynamics365 agent that can manage accounts and contacts, capture leads, track opportunities, create quotes and invoices, and resolve support cases through natural language commands.

This guide will help you understand how to give your OpenAI Agents SDK agent real control over a Dynamics365 account through Composio's Dynamics365 MCP server.

Before we dive in, let's take a quick look at the key ideas and tools involved.

Also integrate Dynamics365 with

TL;DR

Here's what you'll learn:
  • Get and set up your OpenAI and Composio API keys
  • Install the necessary dependencies
  • Initialize Composio and create a Tool Router session for Dynamics365
  • Configure an AI agent that can use Dynamics365 as a tool
  • Run a live chat session where you can ask the agent to perform Dynamics365 operations

What is OpenAI Agents SDK?

The OpenAI Agents SDK is a lightweight framework for building AI agents that can use tools and maintain conversation state. It provides a simple interface for creating agents with hosted MCP tool support.

Key features include:

  • Hosted MCP Tools: Connect to external services through hosted MCP endpoints
  • SQLite Sessions: Persist conversation history across interactions
  • Simple API: Clean interface with Agent, Runner, and tool configuration
  • Streaming Support: Real-time response streaming for interactive applications

What is the Dynamics365 MCP server, and what's possible with it?

The Dynamics 365 MCP server is an implementation of the Model Context Protocol that connects your AI agent and assistants like Claude, Cursor, etc directly to your Dynamics 365 account. It provides structured and secure access to your CRM records, so your agent can create accounts and contacts, manage leads and opportunities, handle customer cases, and process invoices and sales orders on your behalf.

  • Account and contact creation: Have your agent create new customer accounts and contact records in Dynamics 365.
  • Lead and opportunity management: Let the agent create leads and opportunities, retrieve lead details, list all leads, and update records as deals progress.
  • Customer case handling: Direct your agent to open new customer cases and update existing cases as issues move toward resolution.
  • Invoice management: Instruct your agent to create invoices, retrieve individual invoices or a full invoice list, and update invoice details.
  • Sales order processing: Have your agent create sales orders and update them when order information changes.

What is the Composio tool router, and how does it fit here?

What is Composio SDK?

Composio's Composio SDK helps agents find the right tools for a task at runtime. You can plug in multiple toolkits (like Gmail, HubSpot, and GitHub), and the agent will identify the relevant app and action to complete multi-step workflows. This can reduce token usage and improve the reliability of tool calls. Read more here: Getting started with Composio SDK

The tool router generates a secure MCP URL that your agents can access to perform actions.

How the Composio SDK works

The Composio SDK follows a three-phase workflow:

  1. Discovery: Searches for tools matching your task and returns relevant toolkits with their details.
  2. Authentication: Checks for active connections. If missing, creates an auth config and returns a connection URL via Auth Link.
  3. Execution: Executes the action using the authenticated connection.

Step-by-step Guide

Step by step09 STEPS
1

Prerequisites

Before starting, make sure you have:
  • Composio API Key and OpenAI API Key
  • Primary know-how of OpenAI Agents SDK
  • A live Dynamics365 project
  • Some knowledge of Python or Typescript
2

Getting API Keys for OpenAI and Composio

OpenAI API Key
  • Go to the OpenAI dashboard and create an API key. You'll need credits to use the models, or you can connect to another model provider.
  • Keep the API key safe.
Composio API Key
3

Install dependencies

npm install @composio/openai-agents @openai/agents dotenv

Install the Composio SDK and the OpenAI Agents SDK.

4

Set up environment variables

bash
OPENAI_API_KEY=sk-...your-api-key
COMPOSIO_API_KEY=your-api-key
USER_ID=composio_user@gmail.com

Create a .env file and add your OpenAI and Composio API keys.

5

Import dependencies

import 'dotenv/config';
import { Composio } from '@composio/core';
import { OpenAIAgentsProvider } from '@composio/openai-agents';
import { Agent, hostedMcpTool, run, OpenAIConversationsSession } from '@openai/agents';
import * as readline from 'readline';
What's happening:
  • You're importing all necessary libraries.
  • The Composio and OpenAIAgentsProvider classes are imported to connect your OpenAI agent to Composio tools like Dynamics365.
6

Set up the Composio instance

dotenv.config();

const composioApiKey = process.env.COMPOSIO_API_KEY;
const userId = process.env.USER_ID;

if (!composioApiKey) {
  throw new Error('COMPOSIO_API_KEY is not set. Create a .env file with COMPOSIO_API_KEY=your_key');
}
if (!userId) {
  throw new Error('USER_ID is not set');
}

// Initialize Composio
const composio = new Composio({
  apiKey: composioApiKey,
  provider: new OpenAIAgentsProvider(),
});
What's happening:
  • dotenv.config() loads your .env file so COMPOSIO_API_KEY and USER_ID are available as environment variables.
  • Creating a Composio instance using the API Key and OpenAIAgentsProvider class.
7

Create a Tool Router session

// Create Tool Router session for Dynamics365
const session = await composio.create(userId as string, {
  toolkits: ['dynamics365'],
});
const mcpUrl = session.mcp.url;

What is happening:

  • You give the Tool Router the user id and the toolkits you want available. Here, it is only dynamics365.
  • The router checks the user's Dynamics365 connection and prepares the MCP endpoint.
  • The returned session.mcp.url is the MCP URL that your agent will use to access Dynamics365.
  • This approach keeps things lightweight and lets the agent request Dynamics365 tools only when needed during the conversation.
8

Configure the agent

// Configure agent with MCP tool
const agent = new Agent({
  name: 'Assistant',
  model: 'gpt-5',
  instructions:
    'You are a helpful assistant that can access Dynamics365. Help users perform Dynamics365 operations through natural language.',
  tools: [
    hostedMcpTool({
      serverLabel: 'tool_router',
      serverUrl: mcpUrl,
      headers: { 'x-api-key': composioApiKey },
      requireApproval: 'never',
    }),
  ],
});
What's happening:
  • We're creating an Agent instance with a name, model (gpt-5), and clear instructions about its purpose.
  • The agent's instructions tell it that it can access Dynamics365 and help with queries, inserts, updates, authentication, and fetching database information.
  • The tools array includes a hostedMcpTool that connects to the MCP server URL we created earlier.
  • The headers object includes the Composio API key for secure authentication with the MCP server.
  • requireApproval: 'never' means the agent can execute Dynamics365 operations without asking for permission each time, making interactions smoother.
9

Start chat loop and handle conversation

// Keep conversation state across turns
const conversationSession = new OpenAIConversationsSession();

// Simple CLI
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: 'You: ',
});

console.log('\nComposio Tool Router session created.');
console.log('\nChat started. Type your requests below.');
console.log("Commands: 'exit', 'quit', or 'q' to end\n");

try {
  const first = await run(agent, 'What can you help me with?', { session: conversationSession });
  console.log(`Assistant: ${first.finalOutput}\n`);
} catch (e) {
  console.error('Error:', e instanceof Error ? e.message : e, '\n');
}

rl.prompt();

rl.on('line', async (userInput) => {
  const text = userInput.trim();

  if (['exit', 'quit', 'q'].includes(text.toLowerCase())) {
    console.log('Goodbye!');
    rl.close();
    process.exit(0);
  }

  if (!text) {
    rl.prompt();
    return;
  }

  try {
    const result = await run(agent, text, { session: conversationSession });
    console.log(`\nAssistant: ${result.finalOutput}\n`);
  } catch (e) {
    console.error('Error:', e instanceof Error ? e.message : e, '\n');
  }

  rl.prompt();
});

rl.on('close', () => {
  console.log('\n👋 Session ended.');
  process.exit(0);
});
What's happening:
  • The program prints a session URL that you visit to authorize Dynamics365.
  • After authorization, the chat begins.
  • Each message you type is processed by the agent using run().
  • The responses are printed to the console.
  • Typing exit, quit, or q cleanly ends the chat.

Complete Code

Here's the complete code to get you started with Dynamics365 and OpenAI Agents SDK:

import 'dotenv/config';
import { Composio } from '@composio/core';
import { OpenAIAgentsProvider } from '@composio/openai-agents';
import { Agent, hostedMcpTool, run, OpenAIConversationsSession } from '@openai/agents';
import * as readline from 'readline';

const composioApiKey = process.env.COMPOSIO_API_KEY;
const userId = process.env.USER_ID;

if (!composioApiKey) {
  throw new Error('COMPOSIO_API_KEY is not set. Create a .env file with COMPOSIO_API_KEY=your_key');
}
if (!userId) {
  throw new Error('USER_ID is not set');
}

// Initialize Composio
const composio = new Composio({
  apiKey: composioApiKey,
  provider: new OpenAIAgentsProvider(),
});

async function main() {
  // Create Tool Router session
  const session = await composio.create(userId as string, {
    toolkits: ['dynamics365'],
  });
  const mcpUrl = session.mcp.url;

  // Configure agent with MCP tool
  const agent = new Agent({
    name: 'Assistant',
    model: 'gpt-5',
    instructions:
      'You are a helpful assistant that can access Dynamics365. Help users perform Dynamics365 operations through natural language.',
    tools: [
      hostedMcpTool({
        serverLabel: 'tool_router',
        serverUrl: mcpUrl,
        headers: { 'x-api-key': composioApiKey },
        requireApproval: 'never',
      }),
    ],
  });

  // Keep conversation state across turns
  const conversationSession = new OpenAIConversationsSession();

  // Simple CLI
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: 'You: ',
  });

  console.log('\nComposio Tool Router session created.');
  console.log('\nChat started. Type your requests below.');
  console.log("Commands: 'exit', 'quit', or 'q' to end\n");

  try {
    const first = await run(agent, 'What can you help me with?', { session: conversationSession });
    console.log(`Assistant: ${first.finalOutput}\n`);
  } catch (e) {
    console.error('Error:', e instanceof Error ? e.message : e, '\n');
  }

  rl.prompt();

  rl.on('line', async (userInput) => {
    const text = userInput.trim();

    if (['exit', 'quit', 'q'].includes(text.toLowerCase())) {
      console.log('Goodbye!');
      rl.close();
      process.exit(0);
    }

    if (!text) {
      rl.prompt();
      return;
    }

    try {
      const result = await run(agent, text, { session: conversationSession });
      console.log(`\nAssistant: ${result.finalOutput}\n`);
    } catch (e) {
      console.error('Error:', e instanceof Error ? e.message : e, '\n');
    }

    rl.prompt();
  });

  rl.on('close', () => {
    console.log('\nSession ended.');
    process.exit(0);
  });
}

main().catch((err) => {
  console.error('Fatal error:', err);
  process.exit(1);
});

Conclusion

This was a starter code for integrating Dynamics365 MCP with OpenAI Agents SDK to build a functional AI agent that can interact with Dynamics365.

Key features:

  • Hosted MCP tool integration through Composio's Tool Router
  • SQLite session persistence for conversation history
  • Simple async chat loop for interactive testing
You can extend this by adding more toolkits, implementing custom business logic, or building a web interface around the agent.
TOOLS

Supported Tools

Every Dynamics365 action and event your agent gets out of the box.

Add Contact to Account

Associate an existing contact with an existing account in Dynamics 365.

Assign User Security Role

Assign a security role to a system user in the connected Dataverse environment.

Associate Contact Account

Sets an existing contact's parent account, replacing any current parent customer.

Clear Account Description

Clear an existing account's description to null without deleting the account.

Create Annotation

Create a text or attachment note, optionally linked to a supported record.

Create appointment

Create a Dataverse appointment from writable logical column values and return the created row.

Create Email Activity

Create and store a draft email activity without sending it.

Create invoice line item

Create a Dataverse invoice line item from writable logical column values and return the created row.

Create opportunity line item

Create a Dataverse opportunity line item from writable logical column values and return the created row.

Create Phone Call

Record a CRM phone-call activity; this does not place a telephone call.

Create price list

Create a Dataverse price list from writable logical column values and return the created row.

Create Product

Create a Dataverse catalog product and return its selected representation.

Create Product Price List Item

Add an existing product and unit to an existing Dynamics price list.

Create quote

Create a Dataverse quote from writable logical column values and return the created row.

Create quote line item

Create a Dataverse quote line item from writable logical column values and return the created row.

Create sales order line item

Create a Dataverse sales order line item from writable logical column values and return the created row.

Create Social Activity

Create a Dataverse social activity and return its stored representation.

Create system user

Create a Dataverse system user from writable logical column values and return the created row.

Create Task

Create a Dataverse task activity and return its selected representation.

Create transaction currency

Create a Dataverse transaction currency from writable logical column values and return the created row.

Delete account

Delete a Dataverse account by GUID.

Delete appointment

Delete a Dataverse appointment by GUID.

Delete case

Delete a Dataverse case by GUID.

Delete contact

Delete a Dataverse contact by GUID.

Delete email activity

Delete a Dataverse email activity by GUID.

Delete invoice

Delete a Dataverse invoice by GUID.

Delete invoice line item

Delete a Dataverse invoice line item by GUID.

Delete lead

Delete a Dataverse lead by GUID.

Delete note

Delete a Dataverse note by GUID.

Delete opportunity

Delete a Dataverse opportunity by GUID.

Delete opportunity line item

Delete a Dataverse opportunity line item by GUID.

Delete price list

Delete a Dataverse price list by GUID.

Delete product

Delete a Dataverse product by GUID.

Delete quote

Delete a Dataverse quote by GUID.

Delete quote line item

Delete a Dataverse quote line item by GUID.

Delete sales order

Delete a Dataverse sales order by GUID.

Delete sales order line item

Delete a Dataverse sales order line item by GUID.

Delete system user

Request deletion of a Dataverse system user by GUID.

Delete task

Delete a Dataverse task by GUID.

Delete transaction currency

Delete a Dataverse transaction currency by GUID.

Disassociate Contact Account

Remove a contact's parent account relationship without deleting either record.

Create Account

Creates a new account entity record in Dynamics CRM using the Web API.

Create Case

Creates a new case (incident) in Dynamics CRM using the Web API.

Create Contact

Creates a new contact entity record in Dynamics CRM using the Web API.

Create Invoice

Creates a new invoice entity record in Dynamics CRM using the Web API.

Create Lead

Creates a new lead entity record in Dynamics CRM using the Web API.

Create Opportunity

Creates a new opportunity entity record in Dynamics CRM using the Web API.

Create Sales Order

Creates a new sales order entity record in Dynamics CRM using the Web API.

Dynamicscrm get a invoice

Retrieve a Dynamics CRM invoice by ID, returning selected invoice details such as its number, dates, billing and shipping addresses, amounts and status.

Dynamicscrm get a lead

Dynamicscrm get a lead

Dynamicscrm get all leads

Retrieve one page of Dynamics CRM leads with optional OData query options.

Update Case

Updates a case (incident) in Dynamics CRM using the Web API.

Update Invoice

Update a Dynamics CRM invoice by ID using the Web API.

Update Lead

Updates an existing Dynamics CRM lead using the Web API.

Update Opportunity

Updates an existing Dynamics CRM opportunity using the Web API.

Update Sales Order

Updates an existing Dynamics CRM sales order using the Web API.

Execute Batch

Execute a Dataverse multipart batch, optionally containing atomic change sets.

Get account

Retrieve a Dataverse account by its GUID, optionally selecting columns and expanding relationships.

Get all invoices action

Retrieve one page of Dynamics 365 invoices with optional OData query options.

Get appointment

Retrieve a Dataverse appointment by its GUID, optionally selecting columns and expanding relationships.

Get Attribute Metadata

Retrieve one Dataverse attribute definition by its metadata IDs.

Get case

Retrieve a Dataverse case by its GUID, optionally selecting columns and expanding relationships.

Get contact

Retrieve a Dataverse contact by its GUID, optionally selecting columns and expanding relationships.

Get email activity

Retrieve a Dataverse email activity by its GUID, optionally selecting columns and expanding relationships.

Get invoice line item

Retrieve a Dataverse invoice line item by its GUID, optionally selecting columns and expanding relationships.

Get note

Retrieve a Dataverse note by its GUID, optionally selecting columns and expanding relationships.

Get opportunity

Retrieve a Dataverse opportunity by its GUID, optionally selecting columns and expanding relationships.

Get opportunity line item

Retrieve a Dataverse opportunity line item by its GUID, optionally selecting columns and expanding relationships.

Get price list

Retrieve a Dataverse price list by its GUID, optionally selecting columns and expanding relationships.

Get product

Retrieve a Dataverse product by its GUID, optionally selecting columns and expanding relationships.

Get quote

Retrieve a Dataverse quote by its GUID, optionally selecting columns and expanding relationships.

Get quote line item

Retrieve a Dataverse quote line item by its GUID, optionally selecting columns and expanding relationships.

Get sales order

Retrieve a Dataverse sales order by its GUID, optionally selecting columns and expanding relationships.

Get sales order line item

Retrieve a Dataverse sales order line item by its GUID, optionally selecting columns and expanding relationships.

Get system user

Retrieve a Dataverse system user by its GUID, optionally selecting columns and expanding relationships.

Get task

Retrieve a Dataverse task by its GUID, optionally selecting columns and expanding relationships.

Get transaction currency

Retrieve a Dataverse transaction currency by its GUID, optionally selecting columns and expanding relationships.

List appointments

List one page of Dataverse appointments.

List Entity Definitions

Discover Dataverse table definitions and return caller-selected metadata.

List entity sets

List available Dataverse entity sets and their resource URLs, not table rows.

List invoice line items

List one page of Dataverse invoice line items.

List notes

List one page of Dataverse notes.

List opportunity line items

List one page of Dataverse opportunity line items.

List price lists

List one page of Dataverse price lists.

List products

List one page of Dataverse products.

List quote line items

List one page of Dataverse quote line items.

List quotes

List one page of Dataverse quotes.

List sales orders

List one page of Dataverse sales orders.

List system users

List one page of Dataverse system users.

List transaction currencies

List one page of Dataverse transaction currencies.

Query accounts

List or filter Dynamics accounts with projection, ordering, and bounded results.

Query campaigns

List, filter, expand, or aggregate Dynamics campaigns.

Query cases

Return one bounded page of cases; pass next_link back to fetch the next page.

Query contacts

List or filter Dynamics contacts with selected fields and ordering.

Query email activities

Return one bounded page of email activities; pass next_link back to fetch the next page.

Query Entity Data

Query contacts, incidents, phone calls, activity pointers, opportunities, or sales order details and return one page with its next link.

Query opportunities

Return one bounded page of opportunities; pass next_link back to fetch the next page.

Query phone calls

Return one bounded page of phone-call activities; pass next_link back to fetch the next page.

Query social activities

Return one bounded page of social activities; pass next_link back to fetch the next page.

Query tasks

Return one bounded page of tasks; pass next_link back to fetch the next page.

Remove Contact from Account

Remove an existing contact from an account without deleting either record.

Resolve Case

Resolve an active case by creating its incident-resolution activity.

Update account

Update only the supplied writable columns of an existing Dataverse account and return the updated row.

Update Account Name

Updates only the name of an existing Dynamics 365 account.

Update appointment

Update only the supplied writable columns of an existing Dataverse appointment and return the updated row.

Update contact

Update only the supplied writable columns of an existing Dataverse contact and return the updated row.

Update email activity

Update only the supplied writable columns of an existing Dataverse email activity and return the updated row.

Update invoice line item

Update only the supplied writable columns of an existing Dataverse invoice line item and return the updated row.

Update note

Update only the supplied writable columns of an existing Dataverse note and return the updated row.

Update opportunity line item

Update only the supplied writable columns of an existing Dataverse opportunity line item and return the updated row.

Update price list

Update only the supplied writable columns of an existing Dataverse price list and return the updated row.

Update product

Update only the supplied writable columns of an existing Dataverse product and return the updated row.

Update quote

Update only the supplied writable columns of an existing Dataverse quote and return the updated row.

Update quote line item

Update only the supplied writable columns of an existing Dataverse quote line item and return the updated row.

Update sales order line item

Update only the supplied writable columns of an existing Dataverse sales order line item and return the updated row.

Update system user

Update only the supplied writable columns of an existing Dataverse system user and return the updated row.

Update task

Update only the supplied writable columns of an existing Dataverse task and return the updated row.

Update transaction currency

Update only the supplied writable columns of an existing Dataverse transaction currency and return the updated row.

Get Caller Identity

Return the connected Dataverse caller's identity IDs.

FAQ

Frequently asked questions

Start with Dynamics365.It takes 30 seconds.

Managed auth, hosted MCP servers, and every Dynamics365 tool your agent needs.Free to start.

Start building