A community-driven Microsoft Dynamics 365 Finance & Operations MCP server
Production-ready Model Context Protocol (MCP) server that exposes the full capabilities of Microsoft Dynamics 365 Finance & Operations (D365 F&O) to AI assistants and other MCP-compatible tools. This enables sophisticated Dynamics 365 integration workflows through standardized protocol interactions.
๐ One-Click Installation for VS Code:
๐ณ Docker Installation for VS Code:
โ๏ธ Deploy to Azure Container Apps:
Deploy the MCP server as a secure, internet-accessible HTTP endpoint with OAuth or API Key authentication. Perfect for web integrations and remote AI assistant access.
Option 1: Using Bash Script (Recommended)
# Download and run the deployment script
curl -O https://raw.githubusercontent.com/mafzaal/d365fo-client/main/deploy-aca.sh
chmod +x deploy-aca.sh
# Set authentication (choose OAuth or API Key)
export D365FO_MCP_AUTH_CLIENT_ID="your-client-id"
export D365FO_MCP_AUTH_CLIENT_SECRET="your-client-secret"
export D365FO_MCP_AUTH_TENANT_ID="your-tenant-id"
# OR
export D365FO_MCP_API_KEY_VALUE="your-secret-key"
# Deploy
./deploy-aca.shOption 2: Using ARM Template
azure-deploy.jsonAlso includes a comprehensive Python client library for Microsoft Dynamics 365 Finance & Operations with OData endpoints, metadata operations, label management, and CLI tools.
The d365fo-client includes a production-ready Model Context Protocol (MCP) server (d365fo-fastmcp-server) built on the FastMCP framework that exposes the full capabilities of D365 Finance & Operations to AI assistants and other MCP-compatible tools.
The server provides multi-transport support (stdio, HTTP, SSE) with enhanced performance and deployment flexibility.
D365FO_LOG_FILE environment variable for flexible log file pathsD365FO_ prefix for consistency.env files and comprehensive environment variable documentation# Install d365fo-client with MCP dependencies
pip install d365fo-client
# Set up environment variables
export D365FO_BASE_URL="https://your-environment.dynamics.com"
export D365FO_CLIENT_ID="your-client-id" # Optional with default credentials
export D365FO_CLIENT_SECRET="your-client-secret" # Optional with default credentials
export D365FO_TENANT_ID="your-tenant-id" # Optional with default credentialsThe modern FastMCP implementation provides enhanced performance and multiple transport options:
# Development (stdio transport - default)
d365fo-fastmcp-server
# Production HTTP API
d365fo-fastmcp-server --transport http --port 8000 --host 0.0.0.0
# Real-time Web Applications (SSE)
d365fo-fastmcp-server --transport sse --port 8001 --host 0.0.0.0Key Benefits:
FastMCP Server with Default Credentials:
Add to your VS Code mcp.json for GitHub Copilot with MCP:
{
"servers": {
"d365fo-fastmcp-server": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"d365fo-client@latest",
"d365fo-fastmcp-server"
],
"env": {
"D365FO_BASE_URL": "https://your-environment.dynamics.com",
"D365FO_LOG_LEVEL": "INFO"
}
}
}
}Option 2: Explicit Credentials For environments requiring service principal authentication:
{
"servers": {
"d365fo-fastmcp-server": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"d365fo-client",
"d365fo-fastmcp-server"
],
"env": {
"D365FO_BASE_URL": "https://your-environment.dynamics.com",
"D365FO_LOG_LEVEL": "DEBUG",
"D365FO_CLIENT_ID": "${input:client_id}",
"D365FO_CLIENT_SECRET": "${input:client_secret}",
"D365FO_TENANT_ID": "${input:tenant_id}"
}
}
},
"inputs": [
{
"id": "tenant_id",
"type": "promptString",
"description": "Azure AD Tenant ID for D365 F&O authentication",
"password": true
},
{
"id": "client_id",
"type": "promptString",
"description": "Azure AD Client ID for D365 F&O authentication",
"password": true
},
{
"id": "client_secret",
"type": "promptString",
"description": "Azure AD Client Secret for D365 F&O authentication",
"password": true
}
]
}Option 3: Docker Integration For containerized environments and enhanced isolation:
{
"servers": {
"d365fo-fastmcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-v",
"d365fo-mcp:/home/mcp_user/",
"-e",
"D365FO_CLIENT_ID=${input:client_id}",
"-e",
"D365FO_CLIENT_SECRET=${input:client_secret}",
"-e",
"D365FO_TENANT_ID=${input:tenant_id}",
"ghcr.io/mafzaal/d365fo-client:latest"
],
"env": {
"D365FO_LOG_LEVEL": "DEBUG",
"D365FO_CLIENT_ID": "${input:client_id}",
"D365FO_CLIENT_SECRET": "${input:client_secret}",
"D365FO_TENANT_ID": "${input:tenant_id}"
}
}
},
"inputs": [
{
"id": "tenant_id",
"type": "promptString",
"description": "Azure AD Tenant ID for D365 F&O authentication",
"password": true
},
{
"id": "client_id",
"type": "promptString",
"description": "Azure AD Client ID for D365 F&O authentication",
"password": true
},
{
"id": "client_secret",
"type": "promptString",
"description": "Azure AD Client Secret for D365 F&O authentication",
"password": true
}
]
}Benefits of Docker approach:
d365fo-mcp)Prerequisites:
FastMCP Server: Add to your Claude Desktop configuration:
{
"mcpServers": {
"d365fo-fastmcp": {
"command": "uvx",
"args": [
"--from",
"d365fo-client",
"d365fo-fastmcp-server"
],
"env": {
"D365FO_BASE_URL": "https://your-environment.dynamics.com",
"D365FO_LOG_LEVEL": "INFO"
}
}
}
}Traditional MCP Server (Alternative):
{
"mcpServers": {
"d365fo": {
"command": "uvx",
"args": [
"--from",
"d365fo-client",
"d365fo-fastmcp-server"
],
"env": {
"D365FO_BASE_URL": "https://your-environment.dynamics.com",
"D365FO_LOG_LEVEL": "INFO"
}
}
}
}Benefits of uvx approach:
The FastMCP server provides HTTP and SSE transports for web application integration:
import aiohttp
import json
async def call_d365fo_api():
"""Example: Using HTTP transport for web API integration"""
# Start FastMCP server with HTTP transport
# d365fo-fastmcp-server --transport http --port 8000
mcp_request = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "d365fo_query_entities",
"arguments": {
"entityName": "CustomersV3",
"top": 10,
"select": ["CustomerAccount", "Name"]
}
}
}
async with aiohttp.ClientSession() as session:
async with session.post(
"http://localhost:8000/mcp",
json=mcp_request,
headers={"Content-Type": "application/json"}
) as response:
result = await response.json()
print(json.dumps(result, indent=2))// Example: JavaScript client for real-time D365FO data
// Start FastMCP server: d365fo-fastmcp-server --transport sse --port 8001
const eventSource = new EventSource('http://localhost:8001/sse');
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Received D365FO data:', data);
// Handle real-time updates from D365FO
if (data.method === 'notification') {
updateDashboard(data.params);
}
};
// Send MCP requests via SSE
function queryCustomers() {
const request = {
jsonrpc: "2.0",
id: Date.now(),
method: "tools/call",
params: {
name: "d365fo_search_entities",
arguments: {
pattern: "customer",
limit: 50
}
}
};
fetch('http://localhost:8001/sse/send', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(request)
});
}from d365fo_client.mcp import D365FOMCPServer
# Create and run server with custom configuration
config = {
"default_environment": {
"base_url": "https://your-environment.dynamics.com",
"use_default_credentials": True
}
}
server = D365FOMCPServer(config)
await server.run()Connect using any MCP-compatible client library:
from mcp import Client
async with Client("d365fo-fastmcp-server") as client:
# Discover available tools
tools = await client.list_tools()
# Execute operations
result = await client.call_tool(
"d365fo_query_entities",
{"entityName": "Customers", "top": 5}
)For containerized environments and production deployments:
Pull the Docker Image:
# Pull from GitHub Container Registry
docker pull ghcr.io/mafzaal/d365fo-client:latest
# Or pull a specific version
docker pull ghcr.io/mafzaal/d365fo-client:v0.2.3Standalone Docker Usage:
# Run MCP server with environment variables
docker run --rm -i \
-e D365FO_BASE_URL="https://your-environment.dynamics.com" \
-e D365FO_CLIENT_ID="your-client-id" \
-e D365FO_CLIENT_SECRET="your-client-secret" \
-e D365FO_TENANT_ID="your-tenant-id" \
-e D365FO_LOG_LEVEL="INFO" \
-v d365fo-mcp:/home/mcp_user/ \
ghcr.io/mafzaal/d365fo-client:latest
# Run CLI commands with Docker
docker run --rm -it \
-e D365FO_BASE_URL="https://your-environment.dynamics.com" \
-e D365FO_CLIENT_ID="your-client-id" \
-e D365FO_CLIENT_SECRET="your-client-secret" \
-e D365FO_TENANT_ID="your-tenant-id" \
ghcr.io/mafzaal/d365fo-client:latest \
d365fo-client entities --limit 10Docker Compose Example:
version: '3.8'
services:
d365fo-mcp:
image: ghcr.io/mafzaal/d365fo-client:latest
environment:
- D365FO_BASE_URL=https://your-environment.dynamics.com
- D365FO_CLIENT_ID=${D365FO_CLIENT_ID}
- D365FO_CLIENT_SECRET=${D365FO_CLIENT_SECRET}
- D365FO_TENANT_ID=${D365FO_TENANT_ID}
- D365FO_LOG_LEVEL=INFO
volumes:
- d365fo-mcp:/home/mcp_user/
stdin_open: true
tty: true
volumes:
d365fo-mcp:Docker Benefits:
Connection Failures
# Test connectivity
d365fo-client version app --base-url https://your-environment.dynamics.com
# Check logs
tail -f ~/.d365fo-mcp/logs/mcp-server.logAuthentication Issues
# Verify Azure CLI authentication
az account show
# Test with explicit credentials
export D365FO_CLIENT_ID="your-client-id"
# ... set other variables
d365fo-fastmcp-serverPerformance Issues
# Enable debug logging
export D365FO_LOG_LEVEL="DEBUG"
# Adjust connection settings
export D365FO_CONNECTION_TIMEOUT="120"
export D365FO_MAX_CONCURRENT_REQUESTS="5"~/.d365fo-mcp/logs/mcp-server.log for detailed error informationd365fo_get_environment_info tool to check system statusThe server provides 49 comprehensive tools organized into functional categories:
d365fo_test_connection - Test connectivity and authentication with performance metrics and error diagnosticsd365fo_get_environment_info - Get comprehensive environment details including versions, configurations, and capabilitiesd365fo_query_entities - Simplified OData querying with 'eq' filtering, wildcard patterns, field selection, and paginationd365fo_get_entity_record - Retrieve specific records by key with expansion options and ETag supportd365fo_create_entity_record - Create new entity records with validation and business logic executiond365fo_update_entity_record - Update existing records with partial updates and optimistic concurrency controld365fo_delete_entity_record - Delete entity records with referential integrity checking and cascading rulesd365fo_call_action - Execute OData actions and functions for complex business operationsd365fo_call_json_service - Call generic JSON service endpoints with parameter support and response handlingd365fo_search_entities - Search entities by pattern with category filtering and full-text search capabilitiesd365fo_get_entity_schema - Get detailed entity schemas with properties, relationships, and label resolutiond365fo_search_actions - Search available OData actions with binding type and parameter informationd365fo_search_enumerations - Search system enumerations with keyword-based filteringd365fo_get_enumeration_fields - Get detailed enumeration member information with multi-language supportd365fo_get_installed_modules - Retrieve information about installed modules and their configurationsd365fo_get_label - Get single label text by ID with multi-language support and fallback optionsd365fo_get_labels_batch - Get multiple labels efficiently with batch processing and performance optimizationd365fo_list_profiles - List all configured D365FO environment profiles with status informationd365fo_get_profile - Get detailed configuration information for specific profilesd365fo_create_profile - Create new environment profiles with comprehensive authentication optionsd365fo_update_profile - Modify existing profile configurations with partial update supportd365fo_delete_profile - Remove environment profiles with proper cleanup and validationd365fo_set_default_profile - Designate a specific profile as the default for operationsd365fo_get_default_profile - Retrieve information about the currently configured default profiled365fo_validate_profile - Validate profile configurations for completeness and security complianced365fo_test_profile_connection - Test connectivity and authentication for specific profilesd365fo_clone_profile - Clone existing profiles with customization options for new environmentsd365fo_search_profiles - Search profiles by pattern with filtering and sorting capabilitiesd365fo_get_profile_names - Get simplified list of available profile names for quick referenced365fo_import_profiles - Import profile configurations from external sources or backupsd365fo_export_profiles - Export profile configurations for backup or deployment purposesd365fo_execute_sql_query - Execute SELECT queries against metadata database with security validationd365fo_get_database_schema - Get comprehensive database schema information including relationshipsd365fo_get_table_info - Get detailed information about specific database tables with sample datad365fo_get_database_statistics - Generate database statistics and analytics for performance monitoringd365fo_start_sync - Initiate metadata synchronization with various strategies and session trackingd365fo_get_sync_progress - Monitor detailed progress of sync sessions with time estimatesd365fo_cancel_sync - Cancel running sync sessions with graceful cleanupd365fo_list_sync_sessions - List all active sync sessions with status and progress informationd365fo_get_sync_history - Get history of completed sync sessions with success/failure status and statisticsd365fo_download_srs_report - Download SQL Server Reporting Services (SRS) reports with parameter supportd365fo_download_sales_confirmation - Download sales confirmation reports in various formatsd365fo_download_purchase_order - Download purchase order documents with formatting optionsd365fo_download_customer_invoice - Download customer invoice reports with customizationd365fo_download_free_text_invoice - Download free text invoice documentsd365fo_download_debit_credit_note - Download debit and credit note reportsd365fo_get_server_performance - Get server performance metrics and statisticsd365fo_get_server_config - Get server configuration information and system settingsd365fo_reset_performance_stats - Reset performance statistics and counters for fresh monitoring๐ For detailed information about all MCP tools including usage examples and best practices, see the Comprehensive MCP Tools Introduction.
๐ค For AI agents and assistants, see the AI Agent Guide for structured workflows, best practices, and automation patterns.
The server exposes four types of resources for discovery and access:
Access entity metadata and sample data:
d365fo://entities/CustomersV3 # Customer entity with metadata and sample data
d365fo://entities/SalesOrders # Sales order entity information
d365fo://entities/Products # Product entity detailsAccess system-wide metadata:
d365fo://metadata/entities # All data entities metadata (V2 cache)
d365fo://metadata/actions # Available OData actions
d365fo://metadata/enumerations # System enumerations
d365fo://metadata/labels # System labels and translationsAccess environment status and information:
d365fo://environment/status # Environment health and connectivity
d365fo://environment/version # Version information (app, platform, build)
d365fo://environment/cache # Cache status and statistics V2Access predefined and templated queries:
d365fo://queries/customers_recent # Recent customers query template
d365fo://queries/sales_summary # Sales summary query with parametersAccess metadata database queries:
d365fo://database/entities # SQL-based entity searches with FTS5
d365fo://database/actions # Action discovery with metadata
d365fo://database/statistics # Cache and performance statistics{
"tool": "d365fo_query_entities",
"arguments": {
"entityName": "CustomersV3",
"select": ["CustomerAccount", "Name", "Email"],
"filter": "CustomerGroup eq 'VIP'",
"top": 10
}
}{
"tool": "d365fo_get_entity_schema",
"arguments": {
"entityName": "CustomersV3",
"includeProperties": true,
"resolveLabels": true,
"language": "en-US"
}
}{
"tool": "d365fo_get_environment_info",
"arguments": {}
}Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
export D365FO_BASE_URL="https://your-environment.dynamics.com"
# No additional auth environment variables needed
d365fo-fastmcp-serverFor service principal authentication:
export D365FO_BASE_URL="https://your-environment.dynamics.com"
export D365FO_CLIENT_ID="your-client-id"
export D365FO_CLIENT_SECRET="your-client-secret"
export D365FO_TENANT_ID="your-tenant-id"
d365fo-fastmcp-serverFor secure credential storage using Azure Key Vault:
export D365FO_BASE_URL="https://your-environment.dynamics.com"
export D365FO_CREDENTIAL_SOURCE="keyvault"
export D365FO_KEYVAULT_URL="https://your-keyvault.vault.azure.net/"
d365fo-fastmcp-serverNew in v0.3.0: Comprehensive environment variable management with type safety and validation using Pydantic settings.
Create a configuration file or set additional environment variables:
# === Core D365FO Connection Settings ===
export D365FO_BASE_URL="https://your-environment.dynamics.com"
export D365FO_CLIENT_ID="your-client-id"
export D365FO_CLIENT_SECRET="your-client-secret"
export D365FO_TENANT_ID="your-tenant-id"
# === Logging Configuration ===
export D365FO_LOG_LEVEL="DEBUG" # DEBUG, INFO, WARNING, ERROR, CRITICAL
export D365FO_LOG_FILE="/custom/path/server.log" # Custom log file path
# === MCP Server Transport Settings (v0.3.0+) ===
export D365FO_MCP_TRANSPORT="stdio" # stdio, sse, http, streamable-http
export D365FO_MCP_HTTP_HOST="0.0.0.0" # HTTP host (default: 127.0.0.1)
export D365FO_MCP_HTTP_PORT="8000" # HTTP port (default: 8000)
export D365FO_MCP_HTTP_STATELESS="true" # Enable stateless mode
export D365FO_MCP_HTTP_JSON="true" # Enable JSON response mode
# === Cache and Performance Settings ===
export D365FO_CACHE_DIR="/custom/cache/path" # General cache directory
export D365FO_META_CACHE_DIR="/custom/metadata/cache" # Metadata cache directory
export D365FO_LABEL_CACHE="true" # Enable label caching (default: true)
export D365FO_LABEL_EXPIRY="1440" # Label cache expiry in minutes (24 hours)
export D365FO_USE_CACHE_FIRST="true" # Use cache before API calls
# === Connection and Performance Tuning ===
export D365FO_TIMEOUT="60" # General timeout in seconds
export D365FO_MCP_MAX_CONCURRENT_REQUESTS="10" # Max concurrent requests
export D365FO_MCP_REQUEST_TIMEOUT="30" # Request timeout in seconds
export D365FO_VERIFY_SSL="true" # Verify SSL certificates
# === MCP Authentication Settings (Advanced) ===
export D365FO_MCP_AUTH_CLIENT_ID="your-mcp-client-id"
export D365FO_MCP_AUTH_CLIENT_SECRET="your-mcp-client-secret"
export D365FO_MCP_AUTH_TENANT_ID="your-mcp-tenant-id"
export D365FO_MCP_AUTH_BASE_URL="http://localhost:8000"
export D365FO_MCP_AUTH_REQUIRED_SCOPES="User.Read,email,openid,profile"
# === Debug Settings ===
export DEBUG="true" # Enable debug modeEnvironment File Support: You can also create a .env file in your project directory with these variables for development convenience.
# Install from PyPI
pip install d365fo-client
# Or install from source
git clone https://github.com/mafzaal/d365fo-client.git
cd d365fo-client
uv sync # Installs with exact dependencies from uv.lock
# Or use Docker (no local installation required)
docker pull ghcr.io/mafzaal/d365fo-client:latest
# Run with Docker
docker run --rm -it \
-e D365FO_BASE_URL="https://your-environment.dynamics.com" \
-e D365FO_CLIENT_ID="your-client-id" \
-e D365FO_CLIENT_SECRET="your-client-secret" \
-e D365FO_TENANT_ID="your-tenant-id" \
-v d365fo-mcp:/home/mcp_user/ \
ghcr.io/mafzaal/d365fo-client:latestNote: The package includes MCP (Model Context Protocol) dependencies by default, enabling AI assistant integration. Both d365fo-client CLI and d365fo-fastmcp-server commands will be available after installation.
Breaking Change in v0.2.3: Environment variable names have been updated for consistency:
AZURE_CLIENT_ID โ D365FO_CLIENT_IDAZURE_CLIENT_SECRET โ D365FO_CLIENT_SECRETAZURE_TENANT_ID โ D365FO_TENANT_IDPlease update your environment variables accordingly when upgrading.
d365fo-client provides a comprehensive CLI with hierarchical commands for interacting with Dynamics 365 Finance & Operations APIs and metadata. The CLI supports all major operations including entity management, metadata discovery, and system administration.
# Use the installed CLI command
d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
# Alternative: Module execution
python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]# List entities with filtering
d365fo-client entities list --pattern "customer" --limit 10
# Get entity details and schema
d365fo-client entities get CustomersV3 --properties --keys --labels
# CRUD operations
d365fo-client entities create Customers --data '{"CustomerAccount":"US-999","Name":"Test"}'
d365fo-client entities update Customers US-999 --data '{"Name":"Updated Name"}'
d365fo-client entities delete Customers US-999# Search and discover entities
d365fo-client metadata entities --search "sales" --output json
# Get available actions
d365fo-client metadata actions --pattern "calculate" --limit 5
# Enumerate system enumerations
d365fo-client metadata enums --search "status" --output table
# Synchronize metadata cache
d365fo-client metadata sync --force-refresh# Get application versions
d365fo-client version app
d365fo-client version platform
d365fo-client version build# Resolve single label
d365fo-client labels resolve "@SYS13342"
# Search labels by pattern
d365fo-client labels search "customer" --language "en-US"# Call SQL diagnostic services
d365fo-client service sql-diagnostic GetAxSqlExecuting
d365fo-client service sql-diagnostic GetAxSqlResourceStats --since-minutes 5
d365fo-client service sql-diagnostic GetAxSqlBlocking --output json
# Generic JSON service calls
d365fo-client service call SysSqlDiagnosticService SysSqlDiagnosticServiceOperations GetAxSqlExecuting
d365fo-client service call YourServiceGroup YourServiceName YourOperation --parameters '{"param1":"value1"}'--base-url URL โ Specify D365 F&O environment URL--profile NAME โ Use named configuration profile--output FORMAT โ Output format: json, table, csv, yaml (default: table)--verbose โ Enable verbose output for debugging--timeout SECONDS โ Request timeout (default: 30)Create reusable configurations in ~/.d365fo-client/config.yaml:
profiles:
production:
base_url: "https://prod.dynamics.com"
use_default_credentials: true
timeout: 60
development:
base_url: "https://dev.dynamics.com"
client_id: "${D365FO_CLIENT_ID}"
client_secret: "${D365FO_CLIENT_SECRET}"
tenant_id: "${D365FO_TENANT_ID}"
use_cache_first: true
default_profile: "development"# Quick entity discovery
d365fo-client entities list --pattern "cust.*" --output json
# Get comprehensive entity information
d365fo-client entities get CustomersV3 --properties --keys --labels --output yaml
# Search for calculation actions
d365fo-client metadata actions --pattern "calculate|compute" --output table
# Test environment connectivity
d365fo-client version app --verboseFor a complete command reference:
d365fo-client --help
d365fo-client entities --help
d365fo-client metadata --helpimport asyncio
from d365fo_client import D365FOClient, FOClientConfig
async def main():
# Simple configuration with default credentials
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
use_default_credentials=True # Uses Azure Default Credential
)
async with D365FOClient(config) as client:
# Test connection
if await client.test_connection():
print("โ
Connected successfully!")
# Get environment information
env_info = await client.get_environment_info()
print(f"Environment: {env_info.application_version}")
# Search for entities (uses metadata cache v2)
customer_entities = await client.search_entities("customer")
print(f"Found {len(customer_entities)} customer entities")
# Get customers with query options
from d365fo_client import QueryOptions
options = QueryOptions(
select=["CustomerAccount", "Name", "SalesCurrencyCode"],
top=10,
orderby=["Name"]
)
customers = await client.get_data("/data/CustomersV3", options)
print(f"Retrieved {len(customers['value'])} customers")
if __name__ == "__main__":
asyncio.run(main())from d365fo_client import create_client
# Quick client creation with enhanced defaults
async with create_client("https://your-fo-environment.dynamics.com") as client:
customers = await client.get_data("/data/CustomersV3", top=5)The d365fo-client now includes a comprehensive Pydantic settings model for type-safe environment variable management:
from d365fo_client import D365FOSettings, get_settings
# Get type-safe settings instance
settings = get_settings()
# Access settings with full IntelliSense support
print(f"Base URL: {settings.base_url}")
print(f"Log Level: {settings.log_level}")
print(f"Cache Directory: {settings.cache_dir}")
# Check configuration state
if settings.has_client_credentials():
print("Client credentials configured")
startup_mode = settings.get_startup_mode() # "profile_only", "default_auth", "client_credentials"
# Convert to environment dictionary for external tools
env_vars = settings.to_env_dict()Key Benefits:
.env files in developmentfrom d365fo_client import FOClientConfig
# Option 1: Default Azure credentials (recommended)
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
use_default_credentials=True
)
# Option 2: Client credentials
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
client_id="your-client-id",
client_secret="your-client-secret",
tenant_id="your-tenant-id",
use_default_credentials=False
)
# Option 3: Azure Key Vault integration (New in v0.2.3)
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
credential_source="keyvault", # Use Azure Key Vault for credentials
keyvault_url="https://your-keyvault.vault.azure.net/"
)
# Option 4: With custom settings
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
use_default_credentials=True,
verify_ssl=False, # For development environments
timeout=60, # Request timeout in seconds
metadata_cache_dir="./my_cache", # Custom cache directory
use_label_cache=True, # Enable label caching
label_cache_expiry_minutes=120 # Cache for 2 hours
)The d365fo-client automatically detects and migrates legacy configuration files:
verify_ssl, outdated field names)cache_dir โ metadata_cache_dir, auth_mode โ use_default_credentials# Legacy configurations are automatically migrated when FastMCP server starts
# No manual intervention required - migration happens transparentlyasync with D365FOClient(config) as client:
# CREATE - Create new customer (supports composite keys)
new_customer = {
"CustomerAccount": "US-999",
"Name": "Test Customer",
"SalesCurrencyCode": "USD"
}
created = await client.create_data("/data/CustomersV3", new_customer)
# READ - Get single customer by key
customer = await client.get_data("/data/CustomersV3('US-001')")
# UPDATE - Update customer with optimistic concurrency
updates = {"Name": "Updated Customer Name"}
updated = await client.update_data("/data/CustomersV3('US-001')", updates)
# DELETE - Delete customer
success = await client.delete_data("/data/CustomersV3('US-999')")
print(f"Delete successful: {success}")from d365fo_client import QueryOptions
# Complex query with multiple options
options = QueryOptions(
select=["CustomerAccount", "Name", "SalesCurrencyCode", "CustomerGroupId"],
filter="SalesCurrencyCode eq 'USD' and contains(Name, 'Corp')",
expand=["CustomerGroup"],
orderby=["Name desc", "CustomerAccount"],
top=50,
skip=10,
count=True
)
result = await client.get_data("/data/CustomersV3", options)
print(f"Total count: {result.get('@odata.count')}")# Unbound action
result = await client.post_data("/data/calculateTax", {
"amount": 1000.00,
"taxGroup": "STANDARD"
})
# Bound action on entity set
result = await client.post_data("/data/CustomersV3/calculateBalances", {
"asOfDate": "2024-12-31"
})
# Bound action on specific entity instance
result = await client.post_data("/data/CustomersV3('US-001')/calculateBalance", {
"asOfDate": "2024-12-31"
})# Basic JSON service call (no parameters)
response = await client.post_json_service(
service_group="SysSqlDiagnosticService",
service_name="SysSqlDiagnosticServiceOperations",
operation_name="GetAxSqlExecuting"
)
if response.success:
print(f"Found {len(response.data)} executing SQL statements")
print(f"Status: HTTP {response.status_code}")
else:
print(f"Error: {response.error_message}")
# JSON service call with parameters
from datetime import datetime, timezone, timedelta
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(minutes=10)
response = await client.post_json_service(
service_group="SysSqlDiagnosticService",
service_name="SysSqlDiagnosticServiceOperations",
operation_name="GetAxSqlResourceStats",
parameters={
"start": start_time.isoformat(),
"end": end_time.isoformat()
}
)
# Using JsonServiceRequest object for better structure
from d365fo_client.models import JsonServiceRequest
request = JsonServiceRequest(
service_group="SysSqlDiagnosticService",
service_name="SysSqlDiagnosticServiceOperations",
operation_name="GetAxSqlBlocking"
)
response = await client.call_json_service(request)
print(f"Service endpoint: {request.get_endpoint_path()}")
# Multiple SQL diagnostic operations
operations = ["GetAxSqlExecuting", "GetAxSqlBlocking", "GetAxSqlLockInfo"]
for operation in operations:
response = await client.post_json_service(
service_group="SysSqlDiagnosticService",
service_name="SysSqlDiagnosticServiceOperations",
operation_name=operation
)
if response.success:
count = len(response.data) if isinstance(response.data, list) else 1
print(f"{operation}: {count} records")
# Custom service call template
response = await client.post_json_service(
service_group="YourServiceGroup",
service_name="YourServiceName",
operation_name="YourOperation",
parameters={
"parameter1": "value1",
"parameter2": 123,
"parameter3": True
}
)# Intelligent metadata synchronization (v2 system)
sync_manager = await client.get_sync_manager()
await sync_manager.smart_sync()
# Search entities with enhanced filtering
sales_entities = await client.search_entities("sales")
print("Sales-related entities:", [e.name for e in sales_entities])
# Get detailed entity information with labels
entity_info = await client.get_public_entity_info("CustomersV3")
if entity_info:
print(f"Entity: {entity_info.name}")
print(f"Label: {entity_info.label_text}")
print(f"Data Service Enabled: {entity_info.data_service_enabled}")
# Search actions with caching
calc_actions = await client.search_actions("calculate")
print("Calculation actions:", [a.name for a in calc_actions])
# Get enumeration information
enum_info = await client.get_public_enumeration_info("NoYes")
if enum_info:
print(f"Enum: {enum_info.name}")
for member in enum_info.members:
print(f" {member.name} = {member.value}")# Get specific label (v2 ca