| Crates.io | d365-odata-mcp |
| lib.rs | d365-odata-mcp |
| version | 0.4.2 |
| created_at | 2026-01-03 20:55:26.433712+00 |
| updated_at | 2026-01-11 15:14:37.639908+00 |
| description | MCP Server for Microsoft Dynamics 365 OData API (Dataverse & Finance/Operations) |
| homepage | https://github.com/FlintsLabs/d365-odata-mcp |
| repository | https://github.com/FlintsLabs/d365-odata-mcp |
| max_upload_size | |
| id | 2020772 |
| size | 140,345 |
An MCP (Model Context Protocol) server that enables AI assistants to query Microsoft Dynamics 365 data via OData API. Supports both Dataverse and Finance & Operations (F&O).
$filter, $select, $orderby, $top, $skip, $expand, $countcargo install d365-odata-mcp
cargo install d365-odata-mcp --force
D365 MCP)Dynamics CRM → user_impersonationDynamics ERP → CustomService.FullAccessChoose your AI client below:
Edit ~/.codex/config.toml:
[mcp_servers.d365]
command = "d365-odata-mcp"
[mcp_servers.d365.env]
TENANT_ID = "your-tenant-id"
CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret"
ENDPOINT = "https://your-org.crm.dynamics.com/api/data/v9.2/"
PRODUCT = "dataverse"
For F&O:
[mcp_servers.d365]
command = "d365-odata-mcp"
[mcp_servers.d365.env]
TENANT_ID = "your-tenant-id"
CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret"
ENDPOINT = "https://your-org.sandbox.operations.dynamics.com/data/"
PRODUCT = "finops"
Verify installation:
codex mcp list
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"d365": {
"command": "d365-odata-mcp",
"env": {
"TENANT_ID": "your-tenant-id",
"CLIENT_ID": "your-client-id",
"CLIENT_SECRET": "your-client-secret",
"ENDPOINT": "https://your-org.crm.dynamics.com/api/data/v9.2/",
"PRODUCT": "dataverse"
}
}
}
}
Add workflow file .agent/workflows/d365-query.md to your project:
---
description: How to query D365 Finance & Operations data via d365-odata-mcp
---
# D365 OData Query
Query D365 data via command line:
\```bash
export TENANT_ID="your-tenant-id"
export CLIENT_ID="your-client-id"
export CLIENT_SECRET="your-client-secret"
export ENDPOINT="https://your-org.sandbox.operations.dynamics.com/data/"
export PRODUCT="finops"
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_entity","arguments":{"entity":"CustomersV3","top":"10"}}}' | d365-odata-mcp 2>/dev/null | jq '.result.content[0].text' -r
\```
list_entitiesList all available D365 entities:
"List all D365 entities"
query_entityQuery data with full OData support:
| Parameter | Description | Required |
|---|---|---|
entity |
Entity name, e.g., CustomersV3 |
✅ |
filter |
OData filter, e.g., dataAreaId eq 'bc' |
❌ |
select |
Fields to return, e.g., Name,Id |
❌ |
orderby |
Sort order, e.g., CreatedDate desc |
❌ |
top |
Max records (default: 50, max: 1000) | ❌ |
skip |
Records to skip (pagination) | ❌ |
expand |
Navigation properties to expand | ❌ |
cross_company |
true for cross-company (F&O only) |
❌ |
count |
true to include total count |
❌ |
Examples:
"Query CustomersV3, show first 10 records"
"Query SalesOrderHeaders where dataAreaId is 'bc', order by SalesOrderNumber desc"
"Get inventory where warehouse is 'WH01' with count"
get_entity_schemaGet available fields for an entity:
"Show schema for SalesOrderHeaders"
get_recordGet a single record by ID:
"Get customer record with ID 'CUS-001'"
get_environment_infoGet D365 environment information:
"Show D365 environment info"
| Variable | Description | Required |
|---|---|---|
TENANT_ID |
Azure AD Tenant ID (or adfs for ADFS) |
✅ |
CLIENT_ID |
Azure AD/ADFS Application ID | ✅ |
CLIENT_SECRET |
Azure AD/ADFS Client Secret | ✅ |
ENDPOINT |
D365 OData endpoint URL | ✅ |
PRODUCT |
dataverse or finops |
✅ |
AUTH_TYPE |
azure (default) or adfs |
❌ |
TOKEN_URL |
Custom token URL (ADFS only) | ❌ |
RESOURCE |
Resource/audience (ADFS only) | ❌ |
For D365 F&O on-premise with ADFS authentication:
# ~/.codex/config.toml
[mcp_servers.d365_onprem]
command = "d365-odata-mcp"
[mcp_servers.d365_onprem.env]
AUTH_TYPE = "adfs"
TENANT_ID = "adfs"
CLIENT_ID = "your-adfs-client-id"
CLIENT_SECRET = "your-adfs-secret"
TOKEN_URL = "https://your-adfs-server.com/adfs/oauth2/token"
RESOURCE = "https://your-d365-onprem.com"
ENDPOINT = "https://your-d365-onprem.com/namespaces/AXSF/data/"
PRODUCT = "finops"
| Entity | Description |
|---|---|
CustomersV3 |
Customer master data |
VendorsV2 |
Vendor master data |
ProductsV2 |
Product master data |
SalesOrderHeaders |
Sales order headers |
SalesOrderLines |
Sales order lines |
PurchaseOrderHeaders |
Purchase order headers |
PurchaseOrderLines |
Purchase order lines |
InventoryOnHandAggregatedByWarehouse |
Inventory on hand |
| Operator | Example |
|---|---|
eq |
Status eq 'Open' |
ne |
Status ne 'Closed' |
gt / ge |
Amount gt 1000 |
lt / le |
Amount lt 100 |
and / or |
Status eq 'Open' and Amount gt 100 |
contains |
contains(Name, 'Corp') |
startswith |
startswith(Name, 'ABC') |
Test the server directly:
export TENANT_ID="..." CLIENT_ID="..." CLIENT_SECRET="..." ENDPOINT="..." PRODUCT="finops"
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | d365-odata-mcp
MIT License - see LICENSE for details.
Contributions welcome! Please open an issue or submit a PR.