mcp-dynamics-365
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-dynamics-365 list my top 10 active accounts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Dynamics 365 CRM MCP Server
A comprehensive Model Context Protocol (MCP) server for interacting with Microsoft Dynamics 365 CRM. This server provides AI agents with the ability to perform CRUD operations, query data, fetch schemas, and execute custom operations on Dynamics 365 entities.
Remote Server (HTTP Transport)
This connects to a running HTTP server instance. First, start the server:
# Start server on default port (3300) for local access
pnpm run dev:http
# Or start server for remote access (binds to all interfaces)
pnpm run start:http-remoteFor VS Code
Add to your mcp.json:
{
"servers": {
"dynamics365-crm-http": {
"url": "http://localhost:3300/mcp"
}
},
"inputs": []
}Or, if you need to use OAuth authentication (for protected servers):
{
"servers": {
"dynamics365-crm-http": {
"url": "http://localhost:3300/mcp",
"oauth": {
"client_id": "your_github_client_id",
"client_secret": "your_github_client_secret"
}
}
},
"inputs": []
}For remote servers, replace localhost with the server's IP address or hostname:
{
"servers": {
"dynamics365-crm-http": {
"url": "http://your-server-ip:3300/mcp"
}
},
"inputs": []
}For Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"dynamics365-crm-http": {
"url": "http://localhost:3300/mcp"
}
}
}Or, if you need to use OAuth authentication (for protected servers):
{
"mcpServers": {
"dynamics365-crm-http": {
"url": "http://localhost:3300/mcp",
"oauth": {
"client_id": "your_github_client_id",
"client_secret": "your_github_client_secret"
}
}
}
}Note: When using HTTP transport, the server must be running separately and environment variables must be configured on the server side (not in the client configuration).
Note: Environment variables must be explicitly specified in the MCP configuration. The server does not automatically load .env files when run via MCP clients.
⚠️ Disclaimer: This project was generated with the assistance of AI as a side project. While functional, it may not receive regular maintenance or updates. Use at your own discretion and consider forking if you need ongoing support.
Features
Generic Entity Operations: Query, create, update, and delete any Dynamics 365 entity
Schema Discovery: Fetch entity metadata and available entity sets
Flexible Querying: Support for OData query parameters (select, filter, orderby, top, skip, expand)
Custom OData Queries: Execute direct OData queries for complex scenarios
Function Execution: Call Dynamics 365 functions and actions
Authentication: Secure OAuth 2.0 client credentials flow
Error Handling: Comprehensive error handling and logging
Related MCP server: Dataverse MCP Server
Prerequisites
Node.js 18+
pnpm (recommended package manager)
Dynamics 365 CRM instance
Azure AD app registration with appropriate permissions
Package Manager Usage
This project uses pnpm for local development and npm for registry operations:
Use pnpm:
pnpm install,pnpm run build,pnpm run dev,pnpm run testUse npm:
npm publish,npm install -g @dav3/mcp-dynamics365-server
Azure AD App Registration
Go to Azure Portal > Azure Active Directory > App registrations
Create a new registration or use existing one
Note down:
Application (client) ID
Directory (tenant) ID
Create a client secret and note it down
Grant the following API permissions:
Dynamics CRM > user_impersonation
Or create custom permissions based on your needs
Installation
Install dependencies:
pnpm installCopy the environment template:
cp .env.example .envConfigure your environment variables in
.env(see consolidated snippet below):
# Dynamics 365 CRM (Backend API)
D365_BASE_URL=https://your-org.crm.dynamics.com # Your Dynamics 365 organization URL
D365_CLIENT_ID=your-client-id # Azure AD application client ID
D365_CLIENT_SECRET=your-client-secret # Azure AD application client secret
D365_TENANT_ID=your-tenant-id # Azure AD tenant ID
D365_RESOURCE=https://your-org.crm.dynamics.com # Resource URL for Dynamics 365 API
# MCP OAuth Resource & Provider (Authentication)
# Only required for HTTP transport (not needed for stdio transport)
OAUTH_MCP_RESOURCE=http://localhost:3300
OAUTH_AUTH_URL=https://github.com/login/oauth/authorize
OAUTH_TOKEN_URL=https://github.com/login/oauth/access_token
OAUTH_JWKS_URL=https://api.github.com/meta # GitHub does not provide JWKS, so use a placeholder
OAUTH_BASE_URL=https://github.com
OAUTH_FLOW=opaque # Supported values: 'jwt' (for JWT validation), 'opaque' (for API token validation)
OAUTH_OPAQUE_USER_API=https://api.github.com/user # Optional: endpoint for opaque token validation
OAUTH_TOKEN_CACHE_DURATION_MS=86400000 # Optional: token validation cache duration in milliseconds (default: 24 hours)
# HTTP Transport Configuration (Optional)
MCP_HTTP_PORT=3300 # Port for HTTP transport (default: 3300)
MCP_HTTP_HOST=localhost # Host for HTTP transport (default: localhost)Variable Explanations
Dynamics 365 CRM (Backend API):
D365_BASE_URL: Your Dynamics 365 organization URLD365_CLIENT_ID: Azure AD application client IDD365_CLIENT_SECRET: Azure AD application client secretD365_TENANT_ID: Azure AD tenant IDD365_RESOURCE: Resource URL for Dynamics 365 API
MCP OAuth Resource & Provider (Authentication):
OAUTH_MCP_RESOURCE: The resource identifier exposed to MCP clients (used for OAuth audience)OAUTH_AUTH_URL: OAuth 2.0 authorization endpointOAUTH_TOKEN_URL: OAuth 2.0 token endpointOAUTH_JWKS_URL: JWKS endpoint for public key discovery (required for JWT flow)OAUTH_BASE_URL: OAuth provider base URLOAUTH_FLOW: Selects the token validation flow. Use'jwt'for JWT validation (with JWKS),'opaque'for API token validation (e.g., GitHub, generic OAuth providers)opaquewas tested with githubjwtwas NOT untested yet
OAUTH_OPAQUE_USER_API: (Optional) API endpoint for validating opaque tokens (default: GitHub user API)
HTTP Transport Configuration (Optional):
MCP_HTTP_PORT: Port for HTTP transport (default: 3300)MCP_HTTP_HOST: Host for HTTP transport (default: localhost)
Authentication Modes
If all OAuth MCP variables are set, the server enforces OAuth authentication for HTTP transport.
If any are missing, the server runs in unauthenticated mode (no token required).
The protected resource metadata endpoint (
/mcp/.well-known/oauth-protected-resource) is only available in authenticated mode.
Usage
Development
pnpm devProduction
pnpm build
pnpm startTransport Options
The server supports two transport methods:
1. Stdio Transport (Default)
For direct integration with MCP clients:
# Default transport
node dist/index.js
# Explicitly specify stdio
node dist/index.js --transport=stdio2. HTTP Transport
For remote access and web-based integrations:
# Default HTTP port (3300)
node dist/index.js --transport=http
# Custom port
node dist/index.js --transport=http --port=8080HTTP transport features:
Streamable HTTP protocol compatible with MCP SDK
CORS support for browser-based clients
Session management with UUID-based session IDs
Default port: 3300
Endpoint:
/mcp
Command Line Options
# Show help
node dist/index.js --help
# Available options:
--transport=<stdio|http> Transport type (default: stdio)
--port=<number> Port for HTTP transport (default: 3300, or MCP_HTTP_PORT env var)
--host=<ip-address> Host for HTTP transport (default: localhost, or MCP_HTTP_HOST env var)
--help, -h Show help messageEnvironment Variables: Default values for --port and --host can be configured using MCP_HTTP_PORT and MCP_HTTP_HOST environment variables in your .env file.
Testing HTTP Transport
Test the HTTP transport using the included test script:
# Start server with HTTP transport
node dist/index.js --transport=http
# In another terminal, run the test
node tests/integration/test-streamable-http.jsMCP Integration
Prerequisites
Install the MCP server globally:
npm install -g @dav3/mcp-dynamics365-server
Option 1: Manual Configuration (Recommended)
The standard approach is to add the server to your MCP client configuration:
Add to your MCP client configuration (see examples below)
Option 2: VS Code Extension (Recommended for VS Code Users)
🚀 For the best VS Code experience, use the dedicated extension:
Install the VS Code extension:
dav3.mcp-dynamics365-extensionConfigure credentials: Use the "Configure MCP Dynamics 365 Server" command
Start HTTP server: Use "Start HTTP Server" command (automatic for production, local dev mode for developers)
📖 Full extension documentation: See vscode-extension/README.md for:
Development vs Production command modes
Auto-detection features
Advanced configuration options
Troubleshooting guides
Note: The extension uses HTTP transport by default and provides intelligent command visibility based on your environment (development vs production).
Configuration Examples
You can connect to the MCP server in two ways:
Local Server (Stdio Transport)
This runs the server locally and connects via stdio (standard input/output):
For VS Code
Add to your mcp.json or settings.json:
mcp.json (personally tested)
{
"servers": {
"dynamics365-crm": {
"command": "npx",
"args": ["@dav3/mcp-dynamics365-server"],
"env": {
"D365_CLIENT_ID": "your_client_id",
"D365_CLIENT_SECRET": "your_client_secret",
"D365_TENANT_ID": "your_tenant_id",
"D365_BASE_URL": "https://your-org.crm.dynamics.com",
"D365_RESOURCE": "https://your-org.crm.dynamics.com"
}
}
},
"inputs": []
}settings.json (untested)
{
"mcp.servers": {
"dynamics365": {
"command": "npx",
"args": ["@dav3/mcp-dynamics365-server"],
"env": {
"D365_CLIENT_ID": "your_client_id",
"D365_CLIENT_SECRET": "your_client_secret",
"D365_TENANT_ID": "your_tenant_id",
"D365_BASE_URL": "https://your-org.crm.dynamics.com",
"D365_RESOURCE": "https://your-org.crm.dynamics.com"
}
}
}
}For Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"dynamics365-crm": {
"command": "npx",
"args": ["@dav3/mcp-dynamics365-server"],
"env": {
"D365_BASE_URL": "https://your-org.crm.dynamics.com",
"D365_CLIENT_ID": "your-client-id",
"D365_CLIENT_SECRET": "your-client-secret",
"D365_TENANT_ID": "your-tenant-id",
"D365_RESOURCE": "https://your-org.crm.dynamics.com"
}
}
}
}Note: Environment variables must be explicitly specified in the MCP configuration. The server does not automatically load .env files when run via MCP clients.
Available Tools
📋 Naming Convention:
Metadata operations (
get_entity_schema,get_attribute_schema): Use singular entity logical names (e.g.,"contact","account")Data operations (
query_entities,get_entity,create_entity, etc.): Use plural entity set names (e.g.,"contacts","accounts")
1. get_entity_schema
Get the schema/metadata for a specific Dynamics 365 entity.
Parameters:
entityName(string): The entity logical name in singular form (e.g., "contact", "account")
Example:
{
"entityName": "contact"
}2. list_entities
List all available entity sets in Dynamics 365.
Parameters:
includeSystem(boolean, optional): Whether to include system entities
Example:
{
"includeSystem": false
}3. query_entities
Query entities with flexible filtering, sorting, and selection options.
Parameters:
entitySet(string): The entity set nameselect(array, optional): Fields to selectfilter(string, optional): OData filter expressionorderby(string, optional): OData orderby expressiontop(number, optional): Maximum number of recordsskip(number, optional): Number of records to skipexpand(string, optional): Related entities to expand
Example:
{
"entitySet": "contacts",
"select": ["firstname", "lastname", "emailaddress1"],
"filter": "firstname eq 'John'",
"orderby": "createdon desc",
"top": 10
}4. get_entity
Get a specific entity record by ID.
Parameters:
entitySet(string): The entity set nameid(string): The entity ID (GUID)select(array, optional): Specific fields to retrieve
Example:
{
"entitySet": "contacts",
"id": "12345678-1234-1234-1234-123456789abc",
"select": ["firstname", "lastname"]
}5. create_entity
Create a new entity record.
Parameters:
entitySet(string): The entity set namedata(object): The entity data to create
Example:
{
"entitySet": "contacts",
"data": {
"firstname": "John",
"lastname": "Doe",
"emailaddress1": "john.doe@example.com"
}
}6. update_entity
Update an existing entity record.
Parameters:
entitySet(string): The entity set nameid(string): The entity ID (GUID)data(object): The entity data to update
Example:
{
"entitySet": "contacts",
"id": "12345678-1234-1234-1234-123456789abc",
"data": {
"emailaddress1": "john.doe.updated@example.com"
}
}7. delete_entity
Delete an entity record.
Parameters:
entitySet(string): The entity set nameid(string): The entity ID (GUID)
Example:
{
"entitySet": "contacts",
"id": "12345678-1234-1234-1234-123456789abc"
}8. execute_odata_query
Execute a custom OData query directly.
Parameters:
query(string): The OData query string
Example:
{
"query": "contacts?$filter=firstname eq 'John' and lastname eq 'Doe'&$select=contactid,fullname"
}9. execute_function
Execute a Dynamics 365 function or action.
Parameters:
functionName(string): The function or action nameparameters(object, optional): Function parametersmethod(string, optional): HTTP method (GET, POST, PATCH, DELETE)
Example:
{
"functionName": "WhoAmI",
"method": "GET"
}Common Entity Sets
accounts- Account recordscontacts- Contact recordsleads- Lead recordsopportunities- Opportunity recordscases- Case recordstasks- Task recordsappointments- Appointment recordsemails- Email recordsphonecalls- Phone call records
OData Query Examples
Basic Filtering
contacts?$filter=firstname eq 'John'Multiple Conditions
contacts?$filter=firstname eq 'John' and lastname eq 'Doe'Selecting Specific Fields
contacts?$select=firstname,lastname,emailaddress1Ordering Results
contacts?$orderby=createdon descLimiting Results
contacts?$top=10&$skip=20Expanding Related Records
contacts?$expand=parentcustomeridError Handling
The server provides comprehensive error handling:
Authentication errors are logged and returned with appropriate messages
API errors include status codes and detailed error descriptions
Validation errors for missing required parameters
Network and timeout errors are handled gracefully
Security Considerations
Store sensitive credentials in environment variables
Use least-privilege principle for Azure AD app permissions
Implement IP restrictions if needed
Monitor and log access patterns
Rotate client secrets regularly
Contributing
For detailed development guidelines and conventions, see copilot-instructions.md.
Fork the repository
Create a feature branch
Make your changes
Add tests if applicable
Submit a pull request
Development Setup
# Install dependencies
pnpm install
# Build the project
pnpm run build
# Run tests
pnpm run test:read-tools
# Type checking
pnpm run typecheckSupport
For issues and questions:
Check the troubleshooting section below
Review Dynamics 365 Web API documentation
Create an issue in the repository
Troubleshooting
Authentication Issues
Verify client ID, secret, and tenant ID
Check Azure AD app permissions
Ensure the app has been granted admin consent
Verify the resource URL matches your Dynamics 365 instance
Connection Issues
Check the base URL format
Verify network connectivity
Check firewall and proxy settings
Validate SSL certificates
Query Issues
Review OData syntax
Check entity and field names (case sensitive)
Verify entity permissions
Contributing & Support
This project was generated with AI assistance as a side project. While contributions are welcome, please note:
Limited Maintenance: This project may not receive regular updates or active maintenance
Community Driven: The community is encouraged to fork and maintain their own versions
Best Effort Support: Issues will be addressed on a best-effort basis when time permits
Pull Requests: Well-documented PRs are welcome, but review times may vary
If you need reliable, maintained software for production use, consider:
Forking this repository and maintaining your own version
Contributing to make this project more robust
Looking for alternative commercial solutions
AI Generation Notice
This project was created with the assistance of AI tools. While the code has been reviewed and tested, users should:
Thoroughly test in their own environments
Review code for security implications
Understand the functionality before production use
License
MIT License - see LICENSE file for details.
Available Tools
10 toolscreate_entityC
Create a new entity record in Dynamics 365
Inputs: data (required), entitySet (required).
delete_entityC
Delete an entity record from Dynamics 365
Inputs: entityId (required), entitySet (required).
execute_functionC
Execute a custom Dynamics 365 function or action
Inputs: functionName (required), parameters.
execute_odata_queryB
Execute a custom OData query against Dynamics 365 Web API
Inputs: query (required).
get_attribute_schemaB
Get detailed schema/metadata for a specific attribute of a Dynamics 365 entity, including options for picklists
Inputs: entityName (required), attributeName (required).
get_entityB
Get a specific entity record by ID from Dynamics 365
Inputs: entityId (required), entitySet (required), select.
get_entity_schemaC
Get detailed schema information for a specific Dynamics 365 entity
Inputs: entityName (required).
list_entitiesB
List all available Dynamics 365 entities with their basic information
Inputs: no named parameters.
query_entitiesC
Query entities from Dynamics 365 with optional filtering, sorting, and pagination
Inputs: entitySet (required), top, filter, select, +1 more.
update_entityC
Update an existing entity record in Dynamics 365
Inputs: data (required), entityId (required), entitySet (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Most tools have distinct purposes (e.g., create/update/delete and execute_odata_query vs query_entities). However, query_entities and execute_odata_query could be confused by an agent when deciding between structured querying and raw OData. Also get_entity_schema and get_attribute_schema are clearly different, but get_entity and get_entity_schema share the 'get_entity' prefix, potentially causing slight naming ambiguity.
All tool names follow a consistent snake_case verb_noun pattern (e.g., get_entity_schema, list_entities, create_entity). The verbs are standard and the naming is predictable throughout.
10 tools is well-scoped for a Dynamics 365 API wrapper, covering essential CRUD, metadata, and query operations without being excessive. Each tool has a clear, non-redundant role.
The surface provides comprehensive CRUD and query capabilities, including schema introspection and custom function execution. However, it lacks tools for bulk operations, association management (e.g., associate/disassociate records), and batch requests, which are common in Dynamics 365.
Maintenance
Related MCP Connectors
Operate the Plixana CRM from any AI: contacts, deals, quotes, WhatsApp and metrics.
Query and update Teable records, manage tables, and access the Teable API with AI agents.
Open-source CRM for AI agents: humans, orgs, interactions, deals, tasks, links and an activity log.
Connect AI agents to Prosyo to query pipeline metrics, search B2B prospects, and manage multichannel LinkedIn and cold email outreach.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables AI agents to query, inspect, and manage Microsoft Dataverse records, metadata, schema, forms, views, and Power Platform environments via the Dataverse OData Web API.9720 PyPI3MIT
- FlicenseAqualityDmaintenanceEnables direct interaction with Microsoft Dataverse from Claude Desktop, supporting full CRUD, bulk operations, FetchXML queries, actions, and metadata discovery.20-
- AlicenseAqualityDmaintenanceProvides intelligent access to PowerPlatform/Dataverse entities and records, enabling entity metadata exploration, OData querying, relationship mapping, and AI-assisted query building through MCP.893 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables interaction with Microsoft Dataverse and Dynamics 365 data through natural language, including CRUD operations, metadata exploration, and saved views.MIT