mafzaal/d365fo-client
If you are the rightful owner of d365fo-client and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The Model Context Protocol (MCP) server for Dynamics 365 Finance & Operations provides a standardized interface for AI assistants and other MCP-compatible tools to interact with D365 F&O functionalities.
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.sh
Option 2: Using ARM Template
- Download azure-deploy.json
- Go to Azure Portal โ Deploy a custom template
- Click "Build your own template in the editor"
- Paste the contents of
azure-deploy.json
- Fill in the parameters and deploy
Also includes a comprehensive Python client library for Microsoft Dynamics 365 Finance & Operations with OData endpoints, metadata operations, label management, and CLI tools.
MCP Server Overview
The d365fo-client includes two production-ready Model Context Protocol (MCP) servers that expose the full capabilities of D365 Finance & Operations to AI assistants and other MCP-compatible tools:
- Traditional MCP SDK (
d365fo-mcp-server
) - Original implementation with stdio support - FastMCP Framework (
d365fo-fastmcp-server
) - Modern implementation with multi-transport support โญ Recommended
Both servers provide identical functionality but the FastMCP implementation offers enhanced performance and deployment flexibility.
Key Features
- 34 comprehensive tools covering all major D365 F&O operations across 7 functional categories
- 12 resource types with comprehensive metadata exposure and discovery capabilities
- 2 prompt templates for advanced workflow assistance
- Multi-transport support (FastMCP): stdio, HTTP, Server-Sent Events (SSE)
- Production-ready implementation with proper error handling, authentication, and security validation
- Enhanced performance (FastMCP): 40% faster startup, 15% lower memory usage
- Advanced profile management supporting multiple environments with secure credential storage
- Database analysis capabilities with secure SQL querying and metadata insights
- Session-based synchronization with detailed progress tracking and multiple sync strategies
- Multi-language support with label resolution and localization capabilities
- Enterprise security with Azure AD integration, Key Vault support, and audit logging
New in v0.3.0
- ๐ง Pydantic Settings Model: Type-safe environment variable management with validation for 35+ configuration options
- ๐ Custom Log File Support:
D365FO_LOG_FILE
environment variable for flexible log file paths - ๐ Legacy Config Migration: Automatic detection and migration of legacy configuration files
- ๐ Environment Variable Standardization: All MCP HTTP variables now use
D365FO_
prefix for consistency - โก Enhanced FastMCP Server: Improved startup configuration, error handling, and graceful shutdown
- ๐ MCP Return Type Standardization: All MCP tools now return dictionaries instead of JSON strings for better type safety
- ๐ ๏ธ Enhanced Configuration: Support for
.env
files and comprehensive environment variable documentation
Quick Start
Installation and Setup
# 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 credentials
FastMCP Server (Recommended)
The 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.0
Key Benefits:
- 40% faster startup compared to traditional MCP SDK
- 15% lower memory usage through optimized architecture
- Multi-transport support: stdio, HTTP, Server-Sent Events (SSE)
- Enhanced error handling with better async/await support
- Production ready with web transports for API integration
Traditional MCP Server
The original MCP SDK implementation remains available for backward compatibility:
# Start the traditional MCP server
d365fo-mcp-server
Integration with AI Assistants
VS Code Integration (Recommended)
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"
}
}
}
}
Traditional MCP Server (Alternative):
{
"servers": {
"d365fo-mcp-server": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"d365fo-client",
"d365fo-mcp-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-mcp-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:
- Complete environment isolation and reproducibility
- No local Python installation required
- Consistent runtime environment across different systems
- Automatic dependency management with pre-built image
- Enhanced security through containerization
- Persistent data storage via Docker volume (
d365fo-mcp
)
Prerequisites:
- Docker installed and running
- Access to Docker Hub or GitHub Container Registry
- Network access for pulling the container image
Claude Desktop Integration
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-mcp-server"
],
"env": {
"D365FO_BASE_URL": "https://your-environment.dynamics.com",
"D365FO_LOG_LEVEL": "INFO"
}
}
}
}
Benefits of uvx approach:
- Always uses the latest version from the repository
- No local installation required
- Automatic dependency management
- Works across different environments
Web Integration with FastMCP
The FastMCP server provides HTTP and SSE transports for web application integration:
HTTP Transport for Web APIs
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))
SSE Transport for Real-time Applications
// 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)
});
}
Alternative: Programmatic Usage
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()
Custom MCP Clients
Connect using any MCP-compatible client library:
from mcp import Client
async with Client("d365fo-mcp-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}
)
Docker Deployment
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.3
Standalone 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 10
Docker 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:
- Complete environment isolation and reproducibility
- No local Python installation required
- Consistent runtime environment across different systems
- Built-in dependency management
- Enhanced security through containerization
- Persistent data storage via Docker volumes
- Easy integration with orchestration platforms (Kubernetes, Docker Swarm)
Architecture Benefits
For AI Assistants
- Standardized Interface: Consistent MCP protocol access to D365 F&O
- Rich Metadata: Self-describing entities and operations
- Type Safety: Schema validation for all operations
- Error Context: Detailed error information for troubleshooting
For Developers
- Minimal Integration: Standard MCP client libraries
- Comprehensive Coverage: Full D365 F&O functionality exposed
- Performance Optimized: Efficient connection and caching strategies
- Well Documented: Complete API documentation and examples
For Organizations
- Secure Access: Enterprise-grade authentication (Azure AD, Managed Identity)
- Audit Logging: Complete operation tracking and monitoring
- Scalable Design: Connection pooling and session management
- Maintenance Friendly: Clear architecture and comprehensive test coverage
Troubleshooting
Common Issues
Connection Failures
# Test connectivity
d365fo-client version app --base-url https://your-environment.dynamics.com
# Check logs
tail -f ~/.d365fo-mcp/logs/mcp-server.log
Authentication Issues
# Verify Azure CLI authentication
az account show
# Test with explicit credentials
export D365FO_CLIENT_ID="your-client-id"
# ... set other variables
d365fo-mcp-server
Performance Issues
# Enable debug logging
export D365FO_LOG_LEVEL="DEBUG"
# Adjust connection settings
export D365FO_CONNECTION_TIMEOUT="120"
export D365FO_MAX_CONCURRENT_REQUESTS="5"
Getting Help
- Logs: Check
~/.d365fo-mcp/logs/mcp-server.log
for detailed error information - Environment: Use
d365fo_get_environment_info
tool to check system status - Documentation: See for technical details
- Issues: Report problems at GitHub Issues
MCP Tools
The server provides 34 comprehensive tools organized into functional categories:
Connection & Environment Tools (2 tools)
d365fo_test_connection
- Test connectivity and authentication with performance metrics and error diagnosticsd365fo_get_environment_info
- Get comprehensive environment details including versions, configurations, and capabilities
CRUD Operations Tools (6 tools)
d365fo_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 operations
Metadata Discovery Tools (6 tools)
d365fo_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 configurations
Label Management Tools (2 tools)
d365fo_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 optimization
Profile Management Tools (10 tools)
d365fo_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_get_profile_status
- Get comprehensive status information for profiles
Database Analysis Tools (4 tools)
d365fo_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 monitoring
Synchronization Tools (4 tools)
d365fo_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 information
๐ For detailed information about all MCP tools including usage examples and best practices, see the .
MCP Resources
The server exposes four types of resources for discovery and access:
Entity Resources
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 details
Metadata Resources
Access 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 translations
Environment Resources
Access 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 V2
Query Resources
Access predefined and templated queries:
d365fo://queries/customers_recent # Recent customers query template
d365fo://queries/sales_summary # Sales summary query with parameters
Database Resources (New in V2)
Access 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
Usage Examples
Basic Tool Execution
{
"tool": "d365fo_query_entities",
"arguments": {
"entityName": "CustomersV3",
"select": ["CustomerAccount", "Name", "Email"],
"filter": "CustomerGroup eq 'VIP'",
"top": 10
}
}
Entity Schema Discovery
{
"tool": "d365fo_get_entity_schema",
"arguments": {
"entityName": "CustomersV3",
"includeProperties": true,
"resolveLabels": true,
"language": "en-US"
}
}
Environment Information
{
"tool": "d365fo_get_environment_info",
"arguments": {}
}
Authentication & Configuration
Default Credentials (Recommended)
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-mcp-server
Explicit Credentials
For 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-mcp-server
Azure Key Vault Integration (New in v0.2.3)
For 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-mcp-server
Advanced Configuration
New 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 mode
Environment File Support: You can also create a .env
file in your project directory with these variables for development convenience.
Python Client Library
Features
- ๐ OData Client: Full CRUD operations on D365 F&O data entities with composite key support
- ๐ Metadata Management V2: Enhanced caching system with intelligent synchronization and FTS5 search
- ๐ท๏ธ Label Operations V2: Multilingual label caching with performance improvements and async support
- ๐ Advanced Querying: Support for all OData query parameters ($select, $filter, $expand, etc.)
- โก Action Execution: Execute bound and unbound OData actions with comprehensive parameter handling
- ๐ Authentication: Azure AD integration with default credentials, service principal, and Azure Key Vault support
- ๐พ Intelligent Caching: Cross-environment cache sharing with module-based version detection
- ๐ Async/Await: Modern async/await patterns with optimized session management
- ๐ Type Hints: Full type annotation support with enhanced data models
- ๐ค MCP Server: Production-ready Model Context Protocol server with 12 tools and 4 resource types
- ๐ฅ๏ธ Comprehensive CLI: Hierarchical command-line interface for all D365 F&O operations
- ๐งช Multi-tier Testing: Mock, sandbox, and live integration testing framework (17/17 tests passing)
- ๐ Metadata Scripts: PowerShell and Python utilities for entity, enumeration, and action discovery
- ๐ Enhanced Credential Management: Support for Azure Key Vault and multiple credential sources
- ๐ Advanced Sync Management: Session-based synchronization with detailed progress tracking
- ๐ง NEW v0.3.0: Pydantic settings model with type-safe environment variable validation
- ๐ NEW v0.3.0: Custom log file path support and flexible logging configuration
- ๐ NEW v0.3.0: Automatic legacy configuration migration and compatibility layer
Installation
# 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:latest
Note: The package includes MCP (Model Context Protocol) dependencies by default, enabling AI assistant integration. Both d365fo-client
CLI and d365fo-mcp-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_ID
AZURE_CLIENT_SECRET
โD365FO_CLIENT_SECRET
AZURE_TENANT_ID
โD365FO_TENANT_ID
Please update your environment variables accordingly when upgrading.
Python Client Quick Start
Command Line Interface (CLI)
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.
Usage
# Use the installed CLI command
d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
# Alternative: Module execution
python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]
Command Categories
Entity Operations
# 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
Metadata Operations
# 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
Version Information
# Get application versions
d365fo-client version app
d365fo-client version platform
d365fo-client version build
Label Operations
# Resolve single label
d365fo-client labels resolve "@SYS13342"
# Search labels by pattern
d365fo-client labels search "customer" --language "en-US"
Global Options
--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)
Configuration Profiles
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"
Examples
# 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 --verbose
For a complete command reference:
d365fo-client --help
d365fo-client entities --help
d365fo-client metadata --help
Basic Usage
import 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())
Using Convenience Function
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)
Configuration
Environment Variable Management (New in v0.3.0)
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:
- Type Safety: Automatic validation and type conversion for all 35+ environment variables
- IDE Support: Full IntelliSense and autocompletion for configuration options
- Environment Files: Support for
.env
files in development - Comprehensive Defaults: Sensible defaults for all configuration options
- Validation: Built-in validation for URLs, ports, timeouts, and other settings
Authentication Options
from 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
)
Legacy Configuration Migration (New in v0.3.0)
The d365fo-client automatically detects and migrates legacy configuration files:
- Automatic Detection: Identifies legacy configuration patterns (missing
verify_ssl
, outdated field names) - Field Migration: Updates
cache_dir
โmetadata_cache_dir
,auth_mode
โuse_default_credentials
- Backup Creation: Creates backup of original configuration before migration
- Seamless Upgrade: Ensures smooth transition from older versions without manual intervention
# Legacy configurations are automatically migrated when FastMCP server starts
# No manual intervention required - migration happens transparently
Core Operations
CRUD Operations
async 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}")
Advanced Querying
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')}")
Action Execution
# 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"
})
Metadata Operations
# 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}")
Label Operations
# Get specific label (v2 caching system)
label_text = await client.get_label_text("@SYS13342")
print(f"Label text: {label_text}")
# Get multiple labels efficiently
labels = await client.get_labels_batch([
"@SYS13342", "@SYS9490", "@GLS63332"
])
for label_id, text in labels.items():
print(f"{label_id}: {text}")
# Enhanced entity info with resolved labels
entity_info = await client.get_public_entity_info_with_labels("CustomersV3")
if entity_info.label_text:
print(f"Entity display name: {entity_info.label_text}")
# Access enhanced properties with labels
for prop in entity_info.enhanced_properties[:5]:
if hasattr(prop, 'label_text') and prop.label_text:
print(f"{prop.name}: {prop.label_text}")
Error Handling
from d365fo_client import D365FOClientError, AuthenticationError, ConnectionError
try:
async with D365FOClient(config) as client:
customer = await client.get_data("/data/CustomersV3('NON-EXISTENT')")
except ConnectionError as e:
print(f"Connection failed: {e}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except D365FOClientError as e:
print(f"Client operation failed: {e}")
print(f"Status code: {e.status_code}")
print(f"Response: {e.response_text}")
Development
Setting up Development Environment
# Clone the repository
git clone https://github.com/mafzaal/d365fo-client.git
cd d365fo-client
# Install with development dependencies using uv
uv sync --dev
# Run tests
uv run pytest
# Run integration tests
.\tests\integration\integration-test-simple.ps1 test-sandbox
# Format code
uv run black .
uv run isort .
# Type checking
uv run mypy src/
# Quality checks
.\make.ps1 quality-check # Windows PowerShell
# or
make quality-check # Unix/Linux/macOS
Project Structure
d365fo-client/
โโโ src/
โ โโโ d365fo_client/
โ โโโ __init__.py # Public API exports
โ โโโ main.py # CLI entry point
โ โโโ cli.py # CLI command handlers
โ โโโ client.py # Enhanced D365FOClient class
โ โโโ config.py # Configuration management
โ โโโ auth.py # Authentication management
โ โโโ session.py # HTTP session management
โ โโโ crud.py # CRUD operations
โ โโโ query.py # OData query utilities
โ โโโ metadata.py # Legacy metadata operations
โ โโโ metadata_api.py # Metadata API client
โ โโโ metadata_cache.py # Metadata caching layer V2
โ โโโ metadata_sync.py # Metadata synchronization V2 with session management
โ โโโ sync_session.py # Enhanced sync session management (New in v0.2.3)
โ โโโ credential_manager.py # Credential source management (New in v0.2.3)
โ โโโ labels.py # Label operations V2
โ โโโ profiles.py # Profile data models
โ โโโ profile_manager.py # Profile management
โ โโโ models.py # Data models and configurations
โ โโโ output.py # Output formatting
โ โโโ utils.py # Utility functions
โ โโโ exceptions.py # Custom exceptions
โ โโโ mcp/ # Model Context Protocol server
โ โโโ __init__.py # MCP server exports
โ โโโ main.py # MCP server entry point
โ โโโ server.py # Core MCP server implementation
โ โโโ client_manager.py# D365FO client connection pooling
โ โโโ models.py # MCP-specific data models
โ โโโ tools/ # MCP tool implementations (12 tools)
โ โ โโโ connection_tools.py
โ โ โโโ crud_tools.py
โ โ โโโ metadata_tools.py
โ โ โโโ label_tools.py
โ โโโ resources/ # MCP resource handlers (4 types)
โ โ โโโ entity_handler.py
โ โ โโโ metadata_handler.py
โ โ โโโ environment_handler.py
โ โ โโโ query_handler.py
โ โโโ prompts/ # MCP prompt templates
โโโ tests/ # Comprehensive test suite
โ โโโ unit/ # Unit tests (pytest-based)
โ โโโ integration/ # Multi-tier integration testing
โ โ โโโ mock_server/ # Mock D365 F&O API server
โ โ โโโ test_mock_server.py # Mock server tests
โ โ โโโ test_sandbox.py # Sandbox environment tests โ
โ โ โโโ test_live.py # Live environment tests
โ โ โโโ conftest.py # Shared pytest fixtures
โ โ โโโ test_runner.py # Python test execution engine
โ โ โโโ integration-test-simple.ps1 # PowerShell automation
โ โโโ test_mcp_server.py # MCP server unit tests โ
โโโ scripts/ # Metadata discovery scripts
โ โโโ search_data_entities.ps1 # PowerShell entity search
โ โโโ get_data_entity_schema.ps1 # PowerShell schema retrieval
โ โโโ search_enums.py # Python enumeration search
โ โโโ get_enumeration_info.py # Python enumeration info
โ โโโ search_actions.ps1 # PowerShell action search
โ โโโ get_action_info.py # Python action information
โโโ docs/ # Comprehensive documentation
โโโ pyproject.toml # Project configuration
โโโ README.md # This file
Configuration Options
Option | Type | Default | Description |
---|---|---|---|
base_url | str | Required | D365 F&O base URL |
client_id | str | None | Azure AD client ID |
client_secret | str | None | Azure AD client secret |
tenant_id | str | None | Azure AD tenant ID |
use_default_credentials | bool | True | Use Azure Default Credential |
credential_source | str | "environment" | Credential source: "environment", "keyvault" |
keyvault_url | str | None | Azure Key Vault URL for credential storage |
verify_ssl | bool | False | Verify SSL certificates |
timeout | int | 30 | Request timeout in seconds |
metadata_cache_dir | str | Platform-specific user cache | Metadata cache directory |
use_label_cache | bool | True | Enable label caching V2 |
label_cache_expiry_minutes | int | 60 | Label cache expiry time |
use_cache_first | bool | False | Enable cache-first mode with background sync |
Cache Directory Behavior
By default, the client uses platform-appropriate user cache directories:
- Windows:
%LOCALAPPDATA%\d365fo-client
(e.g.,C:\Users\username\AppData\Local\d365fo-client
) - macOS:
~/Library/Caches/d365fo-client
(e.g.,/Users/username/Library/Caches/d365fo-client
) - Linux:
~/.cache/d365fo-client
(e.g.,/home/username/.cache/d365fo-client
)
You can override this by explicitly setting metadata_cache_dir
:
from d365fo_client import FOClientConfig
# Use custom cache directory
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
metadata_cache_dir="/custom/cache/path"
)
# Or get the default cache directory programmatically
from d365fo_client import get_user_cache_dir
cache_dir = get_user_cache_dir("my-app") # Platform-appropriate cache dir
config = FOClientConfig(
base_url="https://your-fo-environment.dynamics.com",
metadata_cache_dir=str(cache_dir)
)
Testing
This project includes comprehensive testing at multiple levels to ensure reliability and quality.
Unit Tests
Run standard unit tests for core functionality:
# Run all unit tests
uv run pytest
# Run with coverage
uv run pytest --cov=d365fo_client --cov-report=html
# Run specific test file
uv run pytest tests/test_client.py -v
Integration Tests
The project includes a sophisticated multi-tier integration testing framework:
Quick Start
# Run sandbox integration tests (recommended)
.\tests\integration\integration-test-simple.ps1 test-sandbox
# Run mock server tests (no external dependencies)
.\tests\integration\integration-test-simple.ps1 test-mock
# Run with verbose output
.\tests\integration\integration-test-simple.ps1 test-sandbox -VerboseOutput
Test Levels
-
Mock Server Tests - Fast, isolated tests against a simulated D365 F&O API
- No external dependencies
- Complete API simulation
- Ideal for CI/CD pipelines
-
Sandbox Tests โญ (Default) - Tests against real D365 F&O test environments
- Validates authentication
- Tests real API behavior
- Requires test environment access
-
Live Tests - Optional tests against production environments
- Final validation
- Performance benchmarking
- Use with caution
Configuration
Set up integration testing with environment variables:
# Copy the template and configure
cp tests/integration/.env.template tests/integration/.env
# Edit .env file with your settings:
INTEGRATION_TEST_LEVEL=sandbox
D365FO_SANDBOX_BASE_URL=https://your-test.dynamics.com
D365FO_CLIENT_ID=your-client-id
D365FO_CLIENT_SECRET=your-client-secret
D365FO_TENANT_ID=your-tenant-id
Available Commands
# Test environment setup
.\tests\integration\integration-test-simple.ps1 setup
# Dependency checking
.\tests\integration\integration-test-simple.ps1 deps-check
# Run specific test levels
.\tests\integration\integration-test-simple.ps1 test-mock
.\tests\integration\integration-test-simple.ps1 test-sandbox
.\tests\integration\integration-test-simple.ps1 test-live
# Coverage and reporting
.\tests\integration\integration-test-simple.ps1 coverage
# Clean up test artifacts
.\tests\integration\integration-test-simple.ps1 clean
Test Coverage
Integration tests cover:
- โ Connection & Authentication - Azure AD integration, SSL/TLS validation
- โ Version Methods - Application, platform, and build version retrieval
- โ Metadata Operations - Entity discovery, metadata API validation
- โ Data Operations - CRUD operations, OData query validation
- โ Error Handling - Network failures, authentication errors, invalid requests
- โ Performance - Response time validation, concurrent operations
For detailed information, see .
Test Results
Recent sandbox integration test results:
โ
17 passed, 0 failed, 2 warnings in 37.67s
======================================================
โ
TestSandboxConnection::test_connection_success
โ
TestSandboxConnection::test_metadata_connection_success
โ
TestSandboxVersionMethods::test_get_application_version
โ
TestSandboxVersionMethods::test_get_platform_build_version
โ
TestSandboxVersionMethods::test_get_application_build_version
โ
TestSandboxVersionMethods::test_version_consistency
โ
TestSandboxMetadataOperations::test_download_metadata
โ
TestSandboxMetadataOperations::test_search_entities
โ
TestSandboxMetadataOperations::test_get_data_entities
โ
TestSandboxMetadataOperations::test_get_public_entities
โ
TestSandboxDataOperations::test_get_available_entities
โ
TestSandboxDataOperations::test_odata_query_options
โ
TestSandboxAuthentication::test_authenticated_requests
โ
TestSandboxErrorHandling::test_invalid_entity_error
โ
TestSandboxErrorHandling::test_invalid_action_error
โ
TestSandboxPerformance::test_response_times
โ
TestSandboxPerformance::test_concurrent_operations
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Make your changes
- Run tests (
uv run pytest
) - Run integration tests (
.\tests\integration\integration-test-simple.ps1 test-sandbox
) - Format code (
uv run black . && uv run isort .
) - Commit changes (
git commit -m 'Add amazing feature'
) - Push to branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the MIT License - see the file for details.
Changelog
See for a list of changes and version history.
Support
- ๐ง Email: mo@thedataguy.pro
- ๐ Issues: GitHub Issues
Related Projects
- Microsoft Dynamics 365
- OData
- Azure Identity
- Model Context Protocol (MCP) - For AI assistant integration