# 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:**
[](https://vscode.dev/redirect/mcp/install?name=d365fo&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22d365fo-client%40latest%22%2C%22d365fo-mcp-server%22%5D%2C%22env%22%3A%7B%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20tenant%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20secret%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%5D)
[](https://insiders.vscode.dev/redirect/mcp/install?name=d365fo&quality=insiders&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22d365fo-client%40latest%22%2C%22d365fo-mcp-server%22%5D%2C%22env%22%3A%7B%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20tenant%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20secret%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%5D)
**๐ณ Docker Installation for VS Code:**
[-2496ED?style=flat-square&logo=docker&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=d365fo-docker&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22d365fo-mcp%3A%2Fhome%2Fmcp_user%2F%22%2C%22-e%22%2C%22D365FO_CLIENT_ID%3D%24%7Binput%3Aclient_id%7D%22%2C%22-e%22%2C%22D365FO_CLIENT_SECRET%3D%24%7Binput%3Aclient_secret%7D%22%2C%22-e%22%2C%22D365FO_TENANT_ID%3D%24%7Binput%3Atenant_id%7D%22%2C%22ghcr.io%2Fmafzaal%2Fd365fo-client%3Alatest%22%5D%2C%22env%22%3A%7B%22D365FO_LOG_LEVEL%22%3A%22DEBUG%22%2C%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Tenant%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20Secret%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%5D)
[-2496ED?style=flat-square&logo=docker&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=d365fo-docker&quality=insiders&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22d365fo-mcp%3A%2Fhome%2Fmcp_user%2F%22%2C%22-e%22%2C%22D365FO_CLIENT_ID%3D%24%7Binput%3Aclient_id%7D%22%2C%22-e%22%2C%22D365FO_CLIENT_SECRET%3D%24%7Binput%3Aclient_secret%7D%22%2C%22-e%22%2C%22D365FO_TENANT_ID%3D%24%7Binput%3Atenant_id%7D%22%2C%22ghcr.io%2Fmafzaal%2Fd365fo-client%3Alatest%22%5D%2C%22env%22%3A%7B%22D365FO_LOG_LEVEL%22%3A%22DEBUG%22%2C%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Tenant%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20Secret%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%5D)
**โ๏ธ 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)**
```bash
# 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**
1. Download [azure-deploy.json](https://raw.githubusercontent.com/mafzaal/d365fo-client/main/azure-deploy.json)
2. Go to [Azure Portal โ Deploy a custom template](https://portal.azure.com/#create/Microsoft.Template)
3. Click "Build your own template in the editor"
4. Paste the contents of `azure-deploy.json`
5. Fill in the parameters and deploy
[](https://pypi.org/project/d365fo-client/)
**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
```bash
# 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:
```bash
# 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:
```bash
# 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:
```json
{
"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):**
```json
{
"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:
```json
{
"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:
```json
{
"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:
```json
{
"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):**
```json
{
"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
```python
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
```javascript
// 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
```python
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:
```python
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:**
```bash
# 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:**
```bash
# 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:**
```yaml
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**
```bash
# 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**
```bash
# 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**
```bash
# 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 [MCP Implementation Summary](docs/MCP_IMPLEMENTATION_SUMMARY.md) for technical details
- **Issues**: Report problems at [GitHub Issues](https://github.com/mafzaal/d365fo-client/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 diagnostics
- **`d365fo_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 pagination
- **`d365fo_get_entity_record`** - Retrieve specific records by key with expansion options and ETag support
- **`d365fo_create_entity_record`** - Create new entity records with validation and business logic execution
- **`d365fo_update_entity_record`** - Update existing records with partial updates and optimistic concurrency control
- **`d365fo_delete_entity_record`** - Delete entity records with referential integrity checking and cascading rules
- **`d365fo_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 capabilities
- **`d365fo_get_entity_schema`** - Get detailed entity schemas with properties, relationships, and label resolution
- **`d365fo_search_actions`** - Search available OData actions with binding type and parameter information
- **`d365fo_search_enumerations`** - Search system enumerations with keyword-based filtering
- **`d365fo_get_enumeration_fields`** - Get detailed enumeration member information with multi-language support
- **`d365fo_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 options
- **`d365fo_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 information
- **`d365fo_get_profile`** - Get detailed configuration information for specific profiles
- **`d365fo_create_profile`** - Create new environment profiles with comprehensive authentication options
- **`d365fo_update_profile`** - Modify existing profile configurations with partial update support
- **`d365fo_delete_profile`** - Remove environment profiles with proper cleanup and validation
- **`d365fo_set_default_profile`** - Designate a specific profile as the default for operations
- **`d365fo_get_default_profile`** - Retrieve information about the currently configured default profile
- **`d365fo_validate_profile`** - Validate profile configurations for completeness and security compliance
- **`d365fo_test_profile_connection`** - Test connectivity and authentication for specific profiles
- **`d365fo_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 validation
- **`d365fo_get_database_schema`** - Get comprehensive database schema information including relationships
- **`d365fo_get_table_info`** - Get detailed information about specific database tables with sample data
- **`d365fo_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 tracking
- **`d365fo_get_sync_progress`** - Monitor detailed progress of sync sessions with time estimates
- **`d365fo_cancel_sync`** - Cancel running sync sessions with graceful cleanup
- **`d365fo_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 [Comprehensive MCP Tools Introduction](docs/MCP_TOOLS_COMPREHENSIVE_INTRODUCTION.md).**
### 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
```json
{
"tool": "d365fo_query_entities",
"arguments": {
"entityName": "CustomersV3",
"select": ["CustomerAccount", "Name", "Email"],
"filter": "CustomerGroup eq 'VIP'",
"top": 10
}
}
```
#### Entity Schema Discovery
```json
{
"tool": "d365fo_get_entity_schema",
"arguments": {
"entityName": "CustomersV3",
"includeProperties": true,
"resolveLabels": true,
"language": "en-US"
}
}
```
#### Environment Information
```json
{
"tool": "d365fo_get_environment_info",
"arguments": {}
}
```
### Authentication & Configuration
#### Default Credentials (Recommended)
Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
```bash
export D365FO_BASE_URL="https://your-environment.dynamics.com"
# No additional auth environment variables needed
d365fo-mcp-server
```
#### Explicit Credentials
For service principal authentication:
```bash
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:
```bash
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:
```bash
# === 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
- ๏ฟฝ๏ธ **JSON Services**: Generic access to D365 F&O JSON service endpoints (/api/services pattern)
- ๏ฟฝ๐ **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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# Get application versions
d365fo-client version app
d365fo-client version platform
d365fo-client version build
```
#### Label Operations
```bash
# Resolve single label
d365fo-client labels resolve "@SYS13342"
# Search labels by pattern
d365fo-client labels search "customer" --language "en-US"
```
#### JSON Service Operations
```bash
# 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"}'
```
### 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`:
```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
```bash
# 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:
```bash
d365fo-client --help
d365fo-client entities --help
d365fo-client metadata --help
```
### Basic Usage
```python
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
```python
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:
```python
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
```python
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
```python
# Legacy configurations are automatically migrated when FastMCP server starts
# No manual intervention required - migration happens transparently
```
## Core Operations
### CRUD Operations
```python
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
```python
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
```python
# 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"
})
```
### JSON Service Operations
```python
# 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
}
)
```
### Metadata Operations
```python
# 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
```python
# 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
```python
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
```bash
# 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`:
```python
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:
```bash
# 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
```bash
# 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
1. **Mock Server Tests** - Fast, isolated tests against a simulated D365 F&O API
- No external dependencies
- Complete API simulation
- Ideal for CI/CD pipelines
2. **Sandbox Tests** โญ *(Default)* - Tests against real D365 F&O test environments
- Validates authentication
- Tests real API behavior
- Requires test environment access
3. **Live Tests** - Optional tests against production environments
- Final validation
- Performance benchmarking
- Use with caution
#### Configuration
Set up integration testing with environment variables:
```bash
# 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
```bash
# 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 [Integration Testing Documentation](tests/integration/README.md).
### 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
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Run tests (`uv run pytest`)
5. Run integration tests (`.\tests\integration\integration-test-simple.ps1 test-sandbox`)
6. Format code (`uv run black . && uv run isort .`)
7. Commit changes (`git commit -m 'Add amazing feature'`)
8. Push to branch (`git push origin feature/amazing-feature`)
9. Open a Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.
## Support
- ๐ง Email: mo@thedataguy.pro
- ๐ Issues: [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)
## Related Projects
- [Microsoft Dynamics 365](https://dynamics.microsoft.com/)
- [OData](https://www.odata.org/)
- [Azure Identity](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity)
- [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol/python-sdk) - For AI assistant integration
Raw data
{
"_id": null,
"home_page": null,
"name": "d365fo-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": null,
"keywords": "dynamics365, d365, finance, operations, erp, microsoft",
"author": null,
"author_email": "Muhammad Afzaal <mo@thedataguy.pro>",
"download_url": "https://files.pythonhosted.org/packages/d5/dd/796e78590be4943d42043b8b3201974cfde5207f25e95f1657e9ecec8054/d365fo_client-0.3.3.tar.gz",
"platform": null,
"description": "# Dynamics 365 Finance & Operations MCP Server\n\n**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.\n\n**\ud83d\ude80 One-Click Installation for VS Code:**\n\n[](https://vscode.dev/redirect/mcp/install?name=d365fo&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22d365fo-client%40latest%22%2C%22d365fo-mcp-server%22%5D%2C%22env%22%3A%7B%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20tenant%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20secret%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%5D)\n[](https://insiders.vscode.dev/redirect/mcp/install?name=d365fo&quality=insiders&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22d365fo-client%40latest%22%2C%22d365fo-mcp-server%22%5D%2C%22env%22%3A%7B%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20tenant%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20ID%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22The%20secret%20of%20the%20client%20to%20connect%20to%22%2C%22password%22%3Atrue%7D%5D)\n\n**\ud83d\udc33 Docker Installation for VS Code:**\n\n[-2496ED?style=flat-square&logo=docker&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=d365fo-docker&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22d365fo-mcp%3A%2Fhome%2Fmcp_user%2F%22%2C%22-e%22%2C%22D365FO_CLIENT_ID%3D%24%7Binput%3Aclient_id%7D%22%2C%22-e%22%2C%22D365FO_CLIENT_SECRET%3D%24%7Binput%3Aclient_secret%7D%22%2C%22-e%22%2C%22D365FO_TENANT_ID%3D%24%7Binput%3Atenant_id%7D%22%2C%22ghcr.io%2Fmafzaal%2Fd365fo-client%3Alatest%22%5D%2C%22env%22%3A%7B%22D365FO_LOG_LEVEL%22%3A%22DEBUG%22%2C%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Tenant%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20Secret%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%5D)\n[-2496ED?style=flat-square&logo=docker&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=d365fo-docker&quality=insiders&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22d365fo-mcp%3A%2Fhome%2Fmcp_user%2F%22%2C%22-e%22%2C%22D365FO_CLIENT_ID%3D%24%7Binput%3Aclient_id%7D%22%2C%22-e%22%2C%22D365FO_CLIENT_SECRET%3D%24%7Binput%3Aclient_secret%7D%22%2C%22-e%22%2C%22D365FO_TENANT_ID%3D%24%7Binput%3Atenant_id%7D%22%2C%22ghcr.io%2Fmafzaal%2Fd365fo-client%3Alatest%22%5D%2C%22env%22%3A%7B%22D365FO_LOG_LEVEL%22%3A%22DEBUG%22%2C%22D365FO_CLIENT_ID%22%3A%22%24%7Binput%3Aclient_id%7D%22%2C%22D365FO_CLIENT_SECRET%22%3A%22%24%7Binput%3Aclient_secret%7D%22%2C%22D365FO_TENANT_ID%22%3A%22%24%7Binput%3Atenant_id%7D%22%7D%7D&inputs=%5B%7B%22id%22%3A%22tenant_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Tenant%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_id%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20ID%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%2C%7B%22id%22%3A%22client_secret%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Azure%20AD%20Client%20Secret%20for%20D365%20F%26O%20authentication%22%2C%22password%22%3Atrue%7D%5D)\n\n**\u2601\ufe0f Deploy to Azure Container Apps:**\n\nDeploy 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.\n\n**Option 1: Using Bash Script (Recommended)**\n```bash\n# Download and run the deployment script\ncurl -O https://raw.githubusercontent.com/mafzaal/d365fo-client/main/deploy-aca.sh\nchmod +x deploy-aca.sh\n\n# Set authentication (choose OAuth or API Key)\nexport D365FO_MCP_AUTH_CLIENT_ID=\"your-client-id\"\nexport D365FO_MCP_AUTH_CLIENT_SECRET=\"your-client-secret\"\nexport D365FO_MCP_AUTH_TENANT_ID=\"your-tenant-id\"\n# OR\nexport D365FO_MCP_API_KEY_VALUE=\"your-secret-key\"\n\n# Deploy\n./deploy-aca.sh\n```\n\n**Option 2: Using ARM Template**\n1. Download [azure-deploy.json](https://raw.githubusercontent.com/mafzaal/d365fo-client/main/azure-deploy.json)\n2. Go to [Azure Portal \u2192 Deploy a custom template](https://portal.azure.com/#create/Microsoft.Template)\n3. Click \"Build your own template in the editor\"\n4. Paste the contents of `azure-deploy.json`\n5. Fill in the parameters and deploy\n\n[](https://pypi.org/project/d365fo-client/)\n\n**Also includes a comprehensive Python client library** for Microsoft Dynamics 365 Finance & Operations with OData endpoints, metadata operations, label management, and CLI tools.\n\n## MCP Server Overview\n\nThe 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:\n\n- **Traditional MCP SDK** (`d365fo-mcp-server`) - Original implementation with stdio support\n- **FastMCP Framework** (`d365fo-fastmcp-server`) - Modern implementation with multi-transport support \u2b50 **Recommended**\n\nBoth servers provide identical functionality but the FastMCP implementation offers enhanced performance and deployment flexibility.\n\n### Key Features\n\n- **34 comprehensive tools** covering all major D365 F&O operations across 7 functional categories\n- **12 resource types** with comprehensive metadata exposure and discovery capabilities\n- **2 prompt templates** for advanced workflow assistance\n- **Multi-transport support** (FastMCP): stdio, HTTP, Server-Sent Events (SSE)\n- **Production-ready** implementation with proper error handling, authentication, and security validation\n- **Enhanced performance** (FastMCP): 40% faster startup, 15% lower memory usage\n- **Advanced profile management** supporting multiple environments with secure credential storage\n- **Database analysis capabilities** with secure SQL querying and metadata insights\n- **Session-based synchronization** with detailed progress tracking and multiple sync strategies\n- **Multi-language support** with label resolution and localization capabilities\n- **Enterprise security** with Azure AD integration, Key Vault support, and audit logging\n\n### New in v0.3.0\n\n- **\ud83d\udd27 Pydantic Settings Model**: Type-safe environment variable management with validation for 35+ configuration options\n- **\ud83d\udcc2 Custom Log File Support**: `D365FO_LOG_FILE` environment variable for flexible log file paths\n- **\ud83d\udd04 Legacy Config Migration**: Automatic detection and migration of legacy configuration files\n- **\ud83c\udf10 Environment Variable Standardization**: All MCP HTTP variables now use `D365FO_` prefix for consistency\n- **\u26a1 Enhanced FastMCP Server**: Improved startup configuration, error handling, and graceful shutdown\n- **\ud83d\udd00 MCP Return Type Standardization**: All MCP tools now return dictionaries instead of JSON strings for better type safety\n- **\ud83d\udee0\ufe0f Enhanced Configuration**: Support for `.env` files and comprehensive environment variable documentation\n\n### Quick Start\n\n#### Installation and Setup\n\n```bash\n# Install d365fo-client with MCP dependencies\npip install d365fo-client\n\n# Set up environment variables\nexport D365FO_BASE_URL=\"https://your-environment.dynamics.com\"\nexport D365FO_CLIENT_ID=\"your-client-id\" # Optional with default credentials\nexport D365FO_CLIENT_SECRET=\"your-client-secret\" # Optional with default credentials \nexport D365FO_TENANT_ID=\"your-tenant-id\" # Optional with default credentials\n```\n\n#### FastMCP Server (Recommended)\n\nThe modern FastMCP implementation provides enhanced performance and multiple transport options:\n\n```bash\n# Development (stdio transport - default)\nd365fo-fastmcp-server\n\n# Production HTTP API\nd365fo-fastmcp-server --transport http --port 8000 --host 0.0.0.0\n\n# Real-time Web Applications (SSE)\nd365fo-fastmcp-server --transport sse --port 8001 --host 0.0.0.0\n```\n\n**Key Benefits:**\n- **40% faster startup** compared to traditional MCP SDK\n- **15% lower memory usage** through optimized architecture\n- **Multi-transport support**: stdio, HTTP, Server-Sent Events (SSE)\n- **Enhanced error handling** with better async/await support\n- **Production ready** with web transports for API integration\n\n#### Traditional MCP Server\n\nThe original MCP SDK implementation remains available for backward compatibility:\n\n```bash\n# Start the traditional MCP server\nd365fo-mcp-server\n```\n\n#### Integration with AI Assistants\n\n##### VS Code Integration (Recommended)\n\n**FastMCP Server with Default Credentials:**\nAdd to your VS Code `mcp.json` for GitHub Copilot with MCP:\n\n```json\n{\n \"servers\": {\n \"d365fo-fastmcp-server\": {\n \"type\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\n \"--from\",\n \"d365fo-client@latest\",\n \"d365fo-fastmcp-server\"\n ],\n \"env\": {\n \"D365FO_BASE_URL\": \"https://your-environment.dynamics.com\",\n \"D365FO_LOG_LEVEL\": \"INFO\"\n }\n }\n }\n}\n```\n\n**Traditional MCP Server (Alternative):**\n```json\n{\n \"servers\": {\n \"d365fo-mcp-server\": {\n \"type\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\n \"--from\",\n \"d365fo-client\",\n \"d365fo-mcp-server\"\n ],\n \"env\": {\n \"D365FO_BASE_URL\": \"https://your-environment.dynamics.com\",\n \"D365FO_LOG_LEVEL\": \"INFO\"\n }\n }\n }\n}\n```\n\n**Option 2: Explicit Credentials**\nFor environments requiring service principal authentication:\n\n```json\n{\n \"servers\": {\n \"d365fo-fastmcp-server\": {\n \"type\": \"stdio\", \n \"command\": \"uvx\",\n \"args\": [\n \"--from\",\n \"d365fo-client\",\n \"d365fo-fastmcp-server\"\n ],\n \"env\": {\n \"D365FO_BASE_URL\": \"https://your-environment.dynamics.com\",\n \"D365FO_LOG_LEVEL\": \"DEBUG\",\n \"D365FO_CLIENT_ID\": \"${input:client_id}\",\n \"D365FO_CLIENT_SECRET\": \"${input:client_secret}\",\n \"D365FO_TENANT_ID\": \"${input:tenant_id}\"\n }\n }\n },\n \"inputs\": [\n {\n \"id\": \"tenant_id\",\n \"type\": \"promptString\",\n \"description\": \"Azure AD Tenant ID for D365 F&O authentication\",\n \"password\": true\n },\n {\n \"id\": \"client_id\", \n \"type\": \"promptString\",\n \"description\": \"Azure AD Client ID for D365 F&O authentication\",\n \"password\": true\n },\n {\n \"id\": \"client_secret\",\n \"type\": \"promptString\", \n \"description\": \"Azure AD Client Secret for D365 F&O authentication\",\n \"password\": true\n }\n ]\n}\n```\n\n**Option 3: Docker Integration**\nFor containerized environments and enhanced isolation:\n\n```json\n{\n \"servers\": {\n \"d365fo-mcp-server\": {\n \"type\": \"stdio\",\n \"command\": \"docker\",\n \"args\": [\n \"run\",\n \"--rm\",\n \"-i\",\n \"-v\",\n \"d365fo-mcp:/home/mcp_user/\",\n \"-e\",\n \"D365FO_CLIENT_ID=${input:client_id}\",\n \"-e\",\n \"D365FO_CLIENT_SECRET=${input:client_secret}\",\n \"-e\",\n \"D365FO_TENANT_ID=${input:tenant_id}\",\n \"ghcr.io/mafzaal/d365fo-client:latest\"\n ],\n \"env\": {\n \"D365FO_LOG_LEVEL\": \"DEBUG\",\n \"D365FO_CLIENT_ID\": \"${input:client_id}\",\n \"D365FO_CLIENT_SECRET\": \"${input:client_secret}\",\n \"D365FO_TENANT_ID\": \"${input:tenant_id}\"\n }\n }\n },\n \"inputs\": [\n {\n \"id\": \"tenant_id\",\n \"type\": \"promptString\",\n \"description\": \"Azure AD Tenant ID for D365 F&O authentication\",\n \"password\": true\n },\n {\n \"id\": \"client_id\",\n \"type\": \"promptString\",\n \"description\": \"Azure AD Client ID for D365 F&O authentication\",\n \"password\": true\n },\n {\n \"id\": \"client_secret\",\n \"type\": \"promptString\",\n \"description\": \"Azure AD Client Secret for D365 F&O authentication\",\n \"password\": true\n }\n ]\n}\n```\n\n**Benefits of Docker approach:**\n- Complete environment isolation and reproducibility\n- No local Python installation required\n- Consistent runtime environment across different systems\n- Automatic dependency management with pre-built image\n- Enhanced security through containerization\n- Persistent data storage via Docker volume (`d365fo-mcp`)\n\n**Prerequisites:**\n- Docker installed and running\n- Access to Docker Hub or GitHub Container Registry\n- Network access for pulling the container image\n\n##### Claude Desktop Integration\n\n**FastMCP Server:**\nAdd to your Claude Desktop configuration:\n\n```json\n{\n \"mcpServers\": {\n \"d365fo-fastmcp\": {\n \"command\": \"uvx\",\n \"args\": [\n \"--from\",\n \"d365fo-client\",\n \"d365fo-fastmcp-server\"\n ],\n \"env\": {\n \"D365FO_BASE_URL\": \"https://your-environment.dynamics.com\",\n \"D365FO_LOG_LEVEL\": \"INFO\"\n }\n }\n }\n}\n```\n\n**Traditional MCP Server (Alternative):**\n```json\n{\n \"mcpServers\": {\n \"d365fo\": {\n \"command\": \"uvx\",\n \"args\": [\n \"--from\",\n \"d365fo-client\",\n \"d365fo-mcp-server\"\n ],\n \"env\": {\n \"D365FO_BASE_URL\": \"https://your-environment.dynamics.com\",\n \"D365FO_LOG_LEVEL\": \"INFO\"\n }\n }\n }\n}\n```\n\n**Benefits of uvx approach:**\n- Always uses the latest version from the repository\n- No local installation required \n- Automatic dependency management\n- Works across different environments\n\n#### Web Integration with FastMCP\n\nThe FastMCP server provides HTTP and SSE transports for web application integration:\n\n##### HTTP Transport for Web APIs\n\n```python\nimport aiohttp\nimport json\n\nasync def call_d365fo_api():\n \"\"\"Example: Using HTTP transport for web API integration\"\"\"\n \n # Start FastMCP server with HTTP transport\n # d365fo-fastmcp-server --transport http --port 8000\n \n mcp_request = {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"d365fo_query_entities\",\n \"arguments\": {\n \"entityName\": \"CustomersV3\",\n \"top\": 10,\n \"select\": [\"CustomerAccount\", \"Name\"]\n }\n }\n }\n \n async with aiohttp.ClientSession() as session:\n async with session.post(\n \"http://localhost:8000/mcp\",\n json=mcp_request,\n headers={\"Content-Type\": \"application/json\"}\n ) as response:\n result = await response.json()\n print(json.dumps(result, indent=2))\n```\n\n##### SSE Transport for Real-time Applications\n\n```javascript\n// Example: JavaScript client for real-time D365FO data\n// Start FastMCP server: d365fo-fastmcp-server --transport sse --port 8001\n\nconst eventSource = new EventSource('http://localhost:8001/sse');\n\neventSource.onmessage = function(event) {\n const data = JSON.parse(event.data);\n console.log('Received D365FO data:', data);\n \n // Handle real-time updates from D365FO\n if (data.method === 'notification') {\n updateDashboard(data.params);\n }\n};\n\n// Send MCP requests via SSE\nfunction queryCustomers() {\n const request = {\n jsonrpc: \"2.0\",\n id: Date.now(),\n method: \"tools/call\",\n params: {\n name: \"d365fo_search_entities\",\n arguments: {\n pattern: \"customer\",\n limit: 50\n }\n }\n };\n \n fetch('http://localhost:8001/sse/send', {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(request)\n });\n}\n```\n\n#### Alternative: Programmatic Usage\n\n```python\nfrom d365fo_client.mcp import D365FOMCPServer\n\n# Create and run server with custom configuration\nconfig = {\n \"default_environment\": {\n \"base_url\": \"https://your-environment.dynamics.com\",\n \"use_default_credentials\": True\n }\n}\n\nserver = D365FOMCPServer(config)\nawait server.run()\n```\n\n#### Custom MCP Clients\nConnect using any MCP-compatible client library:\n\n```python\nfrom mcp import Client\n\nasync with Client(\"d365fo-mcp-server\") as client:\n # Discover available tools\n tools = await client.list_tools()\n \n # Execute operations\n result = await client.call_tool(\n \"d365fo_query_entities\",\n {\"entityName\": \"Customers\", \"top\": 5}\n )\n```\n\n#### Docker Deployment\n\nFor containerized environments and production deployments:\n\n**Pull the Docker Image:**\n```bash\n# Pull from GitHub Container Registry\ndocker pull ghcr.io/mafzaal/d365fo-client:latest\n\n# Or pull a specific version\ndocker pull ghcr.io/mafzaal/d365fo-client:v0.2.3\n```\n\n**Standalone Docker Usage:**\n```bash\n# Run MCP server with environment variables\ndocker run --rm -i \\\n -e D365FO_BASE_URL=\"https://your-environment.dynamics.com\" \\\n -e D365FO_CLIENT_ID=\"your-client-id\" \\\n -e D365FO_CLIENT_SECRET=\"your-client-secret\" \\\n -e D365FO_TENANT_ID=\"your-tenant-id\" \\\n -e D365FO_LOG_LEVEL=\"INFO\" \\\n -v d365fo-mcp:/home/mcp_user/ \\\n ghcr.io/mafzaal/d365fo-client:latest\n\n# Run CLI commands with Docker\ndocker run --rm -it \\\n -e D365FO_BASE_URL=\"https://your-environment.dynamics.com\" \\\n -e D365FO_CLIENT_ID=\"your-client-id\" \\\n -e D365FO_CLIENT_SECRET=\"your-client-secret\" \\\n -e D365FO_TENANT_ID=\"your-tenant-id\" \\\n ghcr.io/mafzaal/d365fo-client:latest \\\n d365fo-client entities --limit 10\n```\n\n**Docker Compose Example:**\n```yaml\nversion: '3.8'\nservices:\n d365fo-mcp:\n image: ghcr.io/mafzaal/d365fo-client:latest\n environment:\n - D365FO_BASE_URL=https://your-environment.dynamics.com\n - D365FO_CLIENT_ID=${D365FO_CLIENT_ID}\n - D365FO_CLIENT_SECRET=${D365FO_CLIENT_SECRET}\n - D365FO_TENANT_ID=${D365FO_TENANT_ID}\n - D365FO_LOG_LEVEL=INFO\n volumes:\n - d365fo-mcp:/home/mcp_user/\n stdin_open: true\n tty: true\n\nvolumes:\n d365fo-mcp:\n```\n\n**Docker Benefits:**\n- Complete environment isolation and reproducibility\n- No local Python installation required\n- Consistent runtime environment across different systems\n- Built-in dependency management\n- Enhanced security through containerization\n- Persistent data storage via Docker volumes\n- Easy integration with orchestration platforms (Kubernetes, Docker Swarm)\n\n### Architecture Benefits\n\n#### For AI Assistants\n- **Standardized Interface**: Consistent MCP protocol access to D365 F&O\n- **Rich Metadata**: Self-describing entities and operations\n- **Type Safety**: Schema validation for all operations\n- **Error Context**: Detailed error information for troubleshooting\n\n#### For Developers \n- **Minimal Integration**: Standard MCP client libraries\n- **Comprehensive Coverage**: Full D365 F&O functionality exposed\n- **Performance Optimized**: Efficient connection and caching strategies\n- **Well Documented**: Complete API documentation and examples\n\n#### For Organizations\n- **Secure Access**: Enterprise-grade authentication (Azure AD, Managed Identity)\n- **Audit Logging**: Complete operation tracking and monitoring\n- **Scalable Design**: Connection pooling and session management\n- **Maintenance Friendly**: Clear architecture and comprehensive test coverage\n\n### Troubleshooting\n\n#### Common Issues\n\n**Connection Failures**\n```bash\n# Test connectivity\nd365fo-client version app --base-url https://your-environment.dynamics.com\n\n# Check logs\ntail -f ~/.d365fo-mcp/logs/mcp-server.log\n```\n\n**Authentication Issues**\n```bash\n# Verify Azure CLI authentication\naz account show\n\n# Test with explicit credentials\nexport D365FO_CLIENT_ID=\"your-client-id\"\n# ... set other variables\nd365fo-mcp-server\n```\n\n**Performance Issues**\n```bash\n# Enable debug logging\nexport D365FO_LOG_LEVEL=\"DEBUG\"\n\n# Adjust connection settings\nexport D365FO_CONNECTION_TIMEOUT=\"120\"\nexport D365FO_MAX_CONCURRENT_REQUESTS=\"5\"\n```\n\n#### Getting Help\n\n- **Logs**: Check `~/.d365fo-mcp/logs/mcp-server.log` for detailed error information\n- **Environment**: Use `d365fo_get_environment_info` tool to check system status\n- **Documentation**: See [MCP Implementation Summary](docs/MCP_IMPLEMENTATION_SUMMARY.md) for technical details\n- **Issues**: Report problems at [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)\n\n### MCP Tools\n\nThe server provides **34 comprehensive tools** organized into functional categories:\n\n#### Connection & Environment Tools (2 tools)\n- **`d365fo_test_connection`** - Test connectivity and authentication with performance metrics and error diagnostics\n- **`d365fo_get_environment_info`** - Get comprehensive environment details including versions, configurations, and capabilities\n\n#### CRUD Operations Tools (6 tools)\n- **`d365fo_query_entities`** - Simplified OData querying with 'eq' filtering, wildcard patterns, field selection, and pagination\n- **`d365fo_get_entity_record`** - Retrieve specific records by key with expansion options and ETag support\n- **`d365fo_create_entity_record`** - Create new entity records with validation and business logic execution\n- **`d365fo_update_entity_record`** - Update existing records with partial updates and optimistic concurrency control\n- **`d365fo_delete_entity_record`** - Delete entity records with referential integrity checking and cascading rules\n- **`d365fo_call_action`** - Execute OData actions and functions for complex business operations\n\n#### Metadata Discovery Tools (6 tools)\n- **`d365fo_search_entities`** - Search entities by pattern with category filtering and full-text search capabilities\n- **`d365fo_get_entity_schema`** - Get detailed entity schemas with properties, relationships, and label resolution\n- **`d365fo_search_actions`** - Search available OData actions with binding type and parameter information\n- **`d365fo_search_enumerations`** - Search system enumerations with keyword-based filtering\n- **`d365fo_get_enumeration_fields`** - Get detailed enumeration member information with multi-language support\n- **`d365fo_get_installed_modules`** - Retrieve information about installed modules and their configurations\n\n#### Label Management Tools (2 tools)\n- **`d365fo_get_label`** - Get single label text by ID with multi-language support and fallback options\n- **`d365fo_get_labels_batch`** - Get multiple labels efficiently with batch processing and performance optimization\n\n#### Profile Management Tools (10 tools)\n- **`d365fo_list_profiles`** - List all configured D365FO environment profiles with status information\n- **`d365fo_get_profile`** - Get detailed configuration information for specific profiles\n- **`d365fo_create_profile`** - Create new environment profiles with comprehensive authentication options\n- **`d365fo_update_profile`** - Modify existing profile configurations with partial update support\n- **`d365fo_delete_profile`** - Remove environment profiles with proper cleanup and validation\n- **`d365fo_set_default_profile`** - Designate a specific profile as the default for operations\n- **`d365fo_get_default_profile`** - Retrieve information about the currently configured default profile\n- **`d365fo_validate_profile`** - Validate profile configurations for completeness and security compliance\n- **`d365fo_test_profile_connection`** - Test connectivity and authentication for specific profiles\n- **`d365fo_get_profile_status`** - Get comprehensive status information for profiles\n\n#### Database Analysis Tools (4 tools)\n- **`d365fo_execute_sql_query`** - Execute SELECT queries against metadata database with security validation\n- **`d365fo_get_database_schema`** - Get comprehensive database schema information including relationships\n- **`d365fo_get_table_info`** - Get detailed information about specific database tables with sample data\n- **`d365fo_get_database_statistics`** - Generate database statistics and analytics for performance monitoring\n\n#### Synchronization Tools (4 tools)\n- **`d365fo_start_sync`** - Initiate metadata synchronization with various strategies and session tracking\n- **`d365fo_get_sync_progress`** - Monitor detailed progress of sync sessions with time estimates\n- **`d365fo_cancel_sync`** - Cancel running sync sessions with graceful cleanup\n- **`d365fo_list_sync_sessions`** - List all active sync sessions with status and progress information\n\n**\ud83d\udcd6 For detailed information about all MCP tools including usage examples and best practices, see the [Comprehensive MCP Tools Introduction](docs/MCP_TOOLS_COMPREHENSIVE_INTRODUCTION.md).**\n\n### MCP Resources\n\nThe server exposes four types of resources for discovery and access:\n\n#### Entity Resources\nAccess entity metadata and sample data:\n```\nd365fo://entities/CustomersV3 # Customer entity with metadata and sample data\nd365fo://entities/SalesOrders # Sales order entity information\nd365fo://entities/Products # Product entity details\n```\n\n#### Metadata Resources\nAccess system-wide metadata:\n```\nd365fo://metadata/entities # All data entities metadata (V2 cache)\nd365fo://metadata/actions # Available OData actions \nd365fo://metadata/enumerations # System enumerations\nd365fo://metadata/labels # System labels and translations\n```\n\n#### Environment Resources\nAccess environment status and information:\n```\nd365fo://environment/status # Environment health and connectivity\nd365fo://environment/version # Version information (app, platform, build)\nd365fo://environment/cache # Cache status and statistics V2\n```\n\n#### Query Resources\nAccess predefined and templated queries:\n```\nd365fo://queries/customers_recent # Recent customers query template\nd365fo://queries/sales_summary # Sales summary query with parameters\n```\n\n#### Database Resources (New in V2)\nAccess metadata database queries:\n```\nd365fo://database/entities # SQL-based entity searches with FTS5\nd365fo://database/actions # Action discovery with metadata\nd365fo://database/statistics # Cache and performance statistics\n```\n\n### Usage Examples\n\n#### Basic Tool Execution\n\n```json\n{\n \"tool\": \"d365fo_query_entities\",\n \"arguments\": {\n \"entityName\": \"CustomersV3\",\n \"select\": [\"CustomerAccount\", \"Name\", \"Email\"],\n \"filter\": \"CustomerGroup eq 'VIP'\",\n \"top\": 10\n }\n}\n```\n\n#### Entity Schema Discovery\n\n```json\n{\n \"tool\": \"d365fo_get_entity_schema\", \n \"arguments\": {\n \"entityName\": \"CustomersV3\",\n \"includeProperties\": true,\n \"resolveLabels\": true,\n \"language\": \"en-US\"\n }\n}\n```\n\n#### Environment Information\n\n```json\n{\n \"tool\": \"d365fo_get_environment_info\",\n \"arguments\": {}\n}\n```\n\n### Authentication & Configuration\n\n#### Default Credentials (Recommended)\nUses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):\n\n```bash\nexport D365FO_BASE_URL=\"https://your-environment.dynamics.com\"\n# No additional auth environment variables needed\nd365fo-mcp-server\n```\n\n#### Explicit Credentials\nFor service principal authentication:\n\n```bash\nexport D365FO_BASE_URL=\"https://your-environment.dynamics.com\"\nexport D365FO_CLIENT_ID=\"your-client-id\"\nexport D365FO_CLIENT_SECRET=\"your-client-secret\"\nexport D365FO_TENANT_ID=\"your-tenant-id\"\nd365fo-mcp-server\n```\n\n#### Azure Key Vault Integration (New in v0.2.3)\nFor secure credential storage using Azure Key Vault:\n\n```bash\nexport D365FO_BASE_URL=\"https://your-environment.dynamics.com\"\nexport D365FO_CREDENTIAL_SOURCE=\"keyvault\"\nexport D365FO_KEYVAULT_URL=\"https://your-keyvault.vault.azure.net/\"\nd365fo-mcp-server\n```\n\n#### Advanced Configuration\n\n**New in v0.3.0**: Comprehensive environment variable management with type safety and validation using Pydantic settings.\n\nCreate a configuration file or set additional environment variables:\n\n```bash\n# === Core D365FO Connection Settings ===\nexport D365FO_BASE_URL=\"https://your-environment.dynamics.com\"\nexport D365FO_CLIENT_ID=\"your-client-id\"\nexport D365FO_CLIENT_SECRET=\"your-client-secret\"\nexport D365FO_TENANT_ID=\"your-tenant-id\"\n\n# === Logging Configuration ===\nexport D365FO_LOG_LEVEL=\"DEBUG\" # DEBUG, INFO, WARNING, ERROR, CRITICAL\nexport D365FO_LOG_FILE=\"/custom/path/server.log\" # Custom log file path\n\n# === MCP Server Transport Settings (v0.3.0+) ===\nexport D365FO_MCP_TRANSPORT=\"stdio\" # stdio, sse, http, streamable-http\nexport D365FO_MCP_HTTP_HOST=\"0.0.0.0\" # HTTP host (default: 127.0.0.1)\nexport D365FO_MCP_HTTP_PORT=\"8000\" # HTTP port (default: 8000)\nexport D365FO_MCP_HTTP_STATELESS=\"true\" # Enable stateless mode\nexport D365FO_MCP_HTTP_JSON=\"true\" # Enable JSON response mode\n\n# === Cache and Performance Settings ===\nexport D365FO_CACHE_DIR=\"/custom/cache/path\" # General cache directory\nexport D365FO_META_CACHE_DIR=\"/custom/metadata/cache\" # Metadata cache directory\nexport D365FO_LABEL_CACHE=\"true\" # Enable label caching (default: true)\nexport D365FO_LABEL_EXPIRY=\"1440\" # Label cache expiry in minutes (24 hours)\nexport D365FO_USE_CACHE_FIRST=\"true\" # Use cache before API calls\n\n# === Connection and Performance Tuning ===\nexport D365FO_TIMEOUT=\"60\" # General timeout in seconds\nexport D365FO_MCP_MAX_CONCURRENT_REQUESTS=\"10\" # Max concurrent requests\nexport D365FO_MCP_REQUEST_TIMEOUT=\"30\" # Request timeout in seconds\nexport D365FO_VERIFY_SSL=\"true\" # Verify SSL certificates\n\n# === MCP Authentication Settings (Advanced) ===\nexport D365FO_MCP_AUTH_CLIENT_ID=\"your-mcp-client-id\"\nexport D365FO_MCP_AUTH_CLIENT_SECRET=\"your-mcp-client-secret\"\nexport D365FO_MCP_AUTH_TENANT_ID=\"your-mcp-tenant-id\"\nexport D365FO_MCP_AUTH_BASE_URL=\"http://localhost:8000\"\nexport D365FO_MCP_AUTH_REQUIRED_SCOPES=\"User.Read,email,openid,profile\"\n\n# === Debug Settings ===\nexport DEBUG=\"true\" # Enable debug mode\n```\n\n**Environment File Support**: You can also create a `.env` file in your project directory with these variables for development convenience.\n\n## Python Client Library\n\n### Features\n\n- \ud83d\udd17 **OData Client**: Full CRUD operations on D365 F&O data entities with composite key support\n- \ud83d\udcca **Metadata Management V2**: Enhanced caching system with intelligent synchronization and FTS5 search\n- \ud83c\udff7\ufe0f **Label Operations V2**: Multilingual label caching with performance improvements and async support\n- \ud83d\udd0d **Advanced Querying**: Support for all OData query parameters ($select, $filter, $expand, etc.)\n- \u26a1 **Action Execution**: Execute bound and unbound OData actions with comprehensive parameter handling\n- \ufffd\ufe0f **JSON Services**: Generic access to D365 F&O JSON service endpoints (/api/services pattern)\n- \ufffd\ud83d\udd12 **Authentication**: Azure AD integration with default credentials, service principal, and Azure Key Vault support\n- \ud83d\udcbe **Intelligent Caching**: Cross-environment cache sharing with module-based version detection\n- \ud83c\udf10 **Async/Await**: Modern async/await patterns with optimized session management\n- \ud83d\udcdd **Type Hints**: Full type annotation support with enhanced data models\n- \ud83e\udd16 **MCP Server**: Production-ready Model Context Protocol server with 12 tools and 4 resource types\n- \ud83d\udda5\ufe0f **Comprehensive CLI**: Hierarchical command-line interface for all D365 F&O operations\n- \ud83e\uddea **Multi-tier Testing**: Mock, sandbox, and live integration testing framework (17/17 tests passing)\n- \ud83d\udccb **Metadata Scripts**: PowerShell and Python utilities for entity, enumeration, and action discovery\n- \ud83d\udd10 **Enhanced Credential Management**: Support for Azure Key Vault and multiple credential sources\n- \ud83d\udcca **Advanced Sync Management**: Session-based synchronization with detailed progress tracking\n- **\ud83d\udd27 NEW v0.3.0**: Pydantic settings model with type-safe environment variable validation\n- **\ud83d\udcc2 NEW v0.3.0**: Custom log file path support and flexible logging configuration\n- **\ud83d\udd04 NEW v0.3.0**: Automatic legacy configuration migration and compatibility layer\n\n### Installation\n\n```bash\n# Install from PyPI\npip install d365fo-client\n\n# Or install from source\ngit clone https://github.com/mafzaal/d365fo-client.git\ncd d365fo-client\nuv sync # Installs with exact dependencies from uv.lock\n\n# Or use Docker (no local installation required)\ndocker pull ghcr.io/mafzaal/d365fo-client:latest\n\n# Run with Docker\ndocker run --rm -it \\\n -e D365FO_BASE_URL=\"https://your-environment.dynamics.com\" \\\n -e D365FO_CLIENT_ID=\"your-client-id\" \\\n -e D365FO_CLIENT_SECRET=\"your-client-secret\" \\\n -e D365FO_TENANT_ID=\"your-tenant-id\" \\\n -v d365fo-mcp:/home/mcp_user/ \\\n ghcr.io/mafzaal/d365fo-client:latest\n```\n\n**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.\n\n**Breaking Change in v0.2.3**: Environment variable names have been updated for consistency:\n- `AZURE_CLIENT_ID` \u2192 `D365FO_CLIENT_ID`\n- `AZURE_CLIENT_SECRET` \u2192 `D365FO_CLIENT_SECRET` \n- `AZURE_TENANT_ID` \u2192 `D365FO_TENANT_ID`\n\nPlease update your environment variables accordingly when upgrading.\n\n## Python Client Quick Start\n\n## Command Line Interface (CLI)\n\nd365fo-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.\n\n### Usage\n\n```bash\n# Use the installed CLI command\nd365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]\n\n# Alternative: Module execution\npython -m d365fo_client.main [OPTIONS] COMMAND [ARGS]\n```\n\n### Command Categories\n\n#### Entity Operations\n```bash\n# List entities with filtering\nd365fo-client entities list --pattern \"customer\" --limit 10\n\n# Get entity details and schema\nd365fo-client entities get CustomersV3 --properties --keys --labels\n\n# CRUD operations\nd365fo-client entities create Customers --data '{\"CustomerAccount\":\"US-999\",\"Name\":\"Test\"}'\nd365fo-client entities update Customers US-999 --data '{\"Name\":\"Updated Name\"}'\nd365fo-client entities delete Customers US-999\n```\n\n#### Metadata Operations\n```bash\n# Search and discover entities\nd365fo-client metadata entities --search \"sales\" --output json\n\n# Get available actions\nd365fo-client metadata actions --pattern \"calculate\" --limit 5\n\n# Enumerate system enumerations\nd365fo-client metadata enums --search \"status\" --output table\n\n# Synchronize metadata cache\nd365fo-client metadata sync --force-refresh\n```\n\n#### Version Information\n```bash\n# Get application versions\nd365fo-client version app\nd365fo-client version platform \nd365fo-client version build\n```\n\n#### Label Operations\n```bash\n# Resolve single label\nd365fo-client labels resolve \"@SYS13342\"\n\n# Search labels by pattern\nd365fo-client labels search \"customer\" --language \"en-US\"\n```\n\n#### JSON Service Operations\n```bash\n# Call SQL diagnostic services \nd365fo-client service sql-diagnostic GetAxSqlExecuting\nd365fo-client service sql-diagnostic GetAxSqlResourceStats --since-minutes 5\nd365fo-client service sql-diagnostic GetAxSqlBlocking --output json\n\n# Generic JSON service calls\nd365fo-client service call SysSqlDiagnosticService SysSqlDiagnosticServiceOperations GetAxSqlExecuting\nd365fo-client service call YourServiceGroup YourServiceName YourOperation --parameters '{\"param1\":\"value1\"}'\n```\n\n### Global Options\n\n- `--base-url URL` \u2014 Specify D365 F&O environment URL\n- `--profile NAME` \u2014 Use named configuration profile \n- `--output FORMAT` \u2014 Output format: json, table, csv, yaml (default: table)\n- `--verbose` \u2014 Enable verbose output for debugging\n- `--timeout SECONDS` \u2014 Request timeout (default: 30)\n\n### Configuration Profiles\n\nCreate reusable configurations in `~/.d365fo-client/config.yaml`:\n\n```yaml\nprofiles:\n production:\n base_url: \"https://prod.dynamics.com\"\n use_default_credentials: true\n timeout: 60\n \n development:\n base_url: \"https://dev.dynamics.com\" \n client_id: \"${D365FO_CLIENT_ID}\"\n client_secret: \"${D365FO_CLIENT_SECRET}\"\n tenant_id: \"${D365FO_TENANT_ID}\"\n use_cache_first: true\n\ndefault_profile: \"development\"\n```\n\n### Examples\n\n```bash\n# Quick entity discovery\nd365fo-client entities list --pattern \"cust.*\" --output json\n\n# Get comprehensive entity information\nd365fo-client entities get CustomersV3 --properties --keys --labels --output yaml\n\n# Search for calculation actions\nd365fo-client metadata actions --pattern \"calculate|compute\" --output table\n\n# Test environment connectivity\nd365fo-client version app --verbose\n```\n\nFor a complete command reference:\n\n```bash\nd365fo-client --help\nd365fo-client entities --help\nd365fo-client metadata --help\n```\n### Basic Usage\n\n```python\nimport asyncio\nfrom d365fo_client import D365FOClient, FOClientConfig\n\nasync def main():\n # Simple configuration with default credentials\n config = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n use_default_credentials=True # Uses Azure Default Credential\n )\n \n async with D365FOClient(config) as client:\n # Test connection\n if await client.test_connection():\n print(\"\u2705 Connected successfully!\")\n \n # Get environment information\n env_info = await client.get_environment_info()\n print(f\"Environment: {env_info.application_version}\")\n \n # Search for entities (uses metadata cache v2)\n customer_entities = await client.search_entities(\"customer\")\n print(f\"Found {len(customer_entities)} customer entities\")\n \n # Get customers with query options\n from d365fo_client import QueryOptions\n options = QueryOptions(\n select=[\"CustomerAccount\", \"Name\", \"SalesCurrencyCode\"],\n top=10,\n orderby=[\"Name\"]\n )\n \n customers = await client.get_data(\"/data/CustomersV3\", options)\n print(f\"Retrieved {len(customers['value'])} customers\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Using Convenience Function\n\n```python\nfrom d365fo_client import create_client\n\n# Quick client creation with enhanced defaults\nasync with create_client(\"https://your-fo-environment.dynamics.com\") as client:\n customers = await client.get_data(\"/data/CustomersV3\", top=5)\n```\n\n## Configuration\n\n### Environment Variable Management (New in v0.3.0)\n\nThe d365fo-client now includes a comprehensive **Pydantic settings model** for type-safe environment variable management:\n\n```python\nfrom d365fo_client import D365FOSettings, get_settings\n\n# Get type-safe settings instance\nsettings = get_settings()\n\n# Access settings with full IntelliSense support\nprint(f\"Base URL: {settings.base_url}\")\nprint(f\"Log Level: {settings.log_level}\")\nprint(f\"Cache Directory: {settings.cache_dir}\")\n\n# Check configuration state\nif settings.has_client_credentials():\n print(\"Client credentials configured\")\n\nstartup_mode = settings.get_startup_mode() # \"profile_only\", \"default_auth\", \"client_credentials\"\n\n# Convert to environment dictionary for external tools\nenv_vars = settings.to_env_dict()\n```\n\n**Key Benefits:**\n- **Type Safety**: Automatic validation and type conversion for all 35+ environment variables\n- **IDE Support**: Full IntelliSense and autocompletion for configuration options\n- **Environment Files**: Support for `.env` files in development\n- **Comprehensive Defaults**: Sensible defaults for all configuration options\n- **Validation**: Built-in validation for URLs, ports, timeouts, and other settings\n\n### Authentication Options\n\n```python\nfrom d365fo_client import FOClientConfig\n\n# Option 1: Default Azure credentials (recommended)\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n use_default_credentials=True\n)\n\n# Option 2: Client credentials\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n client_id=\"your-client-id\",\n client_secret=\"your-client-secret\", \n tenant_id=\"your-tenant-id\",\n use_default_credentials=False\n)\n\n# Option 3: Azure Key Vault integration (New in v0.2.3)\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n credential_source=\"keyvault\", # Use Azure Key Vault for credentials\n keyvault_url=\"https://your-keyvault.vault.azure.net/\"\n)\n\n# Option 4: With custom settings\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n use_default_credentials=True,\n verify_ssl=False, # For development environments\n timeout=60, # Request timeout in seconds\n metadata_cache_dir=\"./my_cache\", # Custom cache directory\n use_label_cache=True, # Enable label caching\n label_cache_expiry_minutes=120 # Cache for 2 hours\n)\n```\n\n### Legacy Configuration Migration (New in v0.3.0)\n\nThe d365fo-client automatically detects and migrates legacy configuration files:\n\n- **Automatic Detection**: Identifies legacy configuration patterns (missing `verify_ssl`, outdated field names)\n- **Field Migration**: Updates `cache_dir` \u2192 `metadata_cache_dir`, `auth_mode` \u2192 `use_default_credentials`\n- **Backup Creation**: Creates backup of original configuration before migration\n- **Seamless Upgrade**: Ensures smooth transition from older versions without manual intervention\n\n```python\n# Legacy configurations are automatically migrated when FastMCP server starts\n# No manual intervention required - migration happens transparently\n```\n\n## Core Operations\n\n### CRUD Operations\n\n```python\nasync with D365FOClient(config) as client:\n # CREATE - Create new customer (supports composite keys)\n new_customer = {\n \"CustomerAccount\": \"US-999\",\n \"Name\": \"Test Customer\",\n \"SalesCurrencyCode\": \"USD\"\n }\n created = await client.create_data(\"/data/CustomersV3\", new_customer)\n \n # READ - Get single customer by key\n customer = await client.get_data(\"/data/CustomersV3('US-001')\")\n \n # UPDATE - Update customer with optimistic concurrency\n updates = {\"Name\": \"Updated Customer Name\"}\n updated = await client.update_data(\"/data/CustomersV3('US-001')\", updates)\n \n # DELETE - Delete customer\n success = await client.delete_data(\"/data/CustomersV3('US-999')\")\n print(f\"Delete successful: {success}\")\n```\n\n### Advanced Querying\n\n```python\nfrom d365fo_client import QueryOptions\n\n# Complex query with multiple options\noptions = QueryOptions(\n select=[\"CustomerAccount\", \"Name\", \"SalesCurrencyCode\", \"CustomerGroupId\"],\n filter=\"SalesCurrencyCode eq 'USD' and contains(Name, 'Corp')\",\n expand=[\"CustomerGroup\"],\n orderby=[\"Name desc\", \"CustomerAccount\"],\n top=50,\n skip=10,\n count=True\n)\n\nresult = await client.get_data(\"/data/CustomersV3\", options)\nprint(f\"Total count: {result.get('@odata.count')}\")\n```\n\n### Action Execution\n\n```python\n# Unbound action\nresult = await client.post_data(\"/data/calculateTax\", {\n \"amount\": 1000.00,\n \"taxGroup\": \"STANDARD\"\n})\n\n# Bound action on entity set\nresult = await client.post_data(\"/data/CustomersV3/calculateBalances\", {\n \"asOfDate\": \"2024-12-31\"\n})\n\n# Bound action on specific entity instance \nresult = await client.post_data(\"/data/CustomersV3('US-001')/calculateBalance\", {\n \"asOfDate\": \"2024-12-31\"\n})\n```\n\n### JSON Service Operations\n\n```python\n# Basic JSON service call (no parameters)\nresponse = await client.post_json_service(\n service_group=\"SysSqlDiagnosticService\",\n service_name=\"SysSqlDiagnosticServiceOperations\",\n operation_name=\"GetAxSqlExecuting\"\n)\n\nif response.success:\n print(f\"Found {len(response.data)} executing SQL statements\")\n print(f\"Status: HTTP {response.status_code}\")\nelse:\n print(f\"Error: {response.error_message}\")\n\n# JSON service call with parameters\nfrom datetime import datetime, timezone, timedelta\n\nend_time = datetime.now(timezone.utc)\nstart_time = end_time - timedelta(minutes=10)\n\nresponse = await client.post_json_service(\n service_group=\"SysSqlDiagnosticService\",\n service_name=\"SysSqlDiagnosticServiceOperations\",\n operation_name=\"GetAxSqlResourceStats\",\n parameters={\n \"start\": start_time.isoformat(),\n \"end\": end_time.isoformat()\n }\n)\n\n# Using JsonServiceRequest object for better structure\nfrom d365fo_client.models import JsonServiceRequest\n\nrequest = JsonServiceRequest(\n service_group=\"SysSqlDiagnosticService\",\n service_name=\"SysSqlDiagnosticServiceOperations\",\n operation_name=\"GetAxSqlBlocking\"\n)\n\nresponse = await client.call_json_service(request)\nprint(f\"Service endpoint: {request.get_endpoint_path()}\")\n\n# Multiple SQL diagnostic operations\noperations = [\"GetAxSqlExecuting\", \"GetAxSqlBlocking\", \"GetAxSqlLockInfo\"]\nfor operation in operations:\n response = await client.post_json_service(\n service_group=\"SysSqlDiagnosticService\",\n service_name=\"SysSqlDiagnosticServiceOperations\",\n operation_name=operation\n )\n \n if response.success:\n count = len(response.data) if isinstance(response.data, list) else 1\n print(f\"{operation}: {count} records\")\n\n# Custom service call template\nresponse = await client.post_json_service(\n service_group=\"YourServiceGroup\",\n service_name=\"YourServiceName\",\n operation_name=\"YourOperation\",\n parameters={\n \"parameter1\": \"value1\",\n \"parameter2\": 123,\n \"parameter3\": True\n }\n)\n```\n\n### Metadata Operations\n\n```python\n# Intelligent metadata synchronization (v2 system)\nsync_manager = await client.get_sync_manager()\nawait sync_manager.smart_sync()\n\n# Search entities with enhanced filtering\nsales_entities = await client.search_entities(\"sales\")\nprint(\"Sales-related entities:\", [e.name for e in sales_entities])\n\n# Get detailed entity information with labels\nentity_info = await client.get_public_entity_info(\"CustomersV3\")\nif entity_info:\n print(f\"Entity: {entity_info.name}\")\n print(f\"Label: {entity_info.label_text}\")\n print(f\"Data Service Enabled: {entity_info.data_service_enabled}\")\n\n# Search actions with caching\ncalc_actions = await client.search_actions(\"calculate\")\nprint(\"Calculation actions:\", [a.name for a in calc_actions])\n\n# Get enumeration information\nenum_info = await client.get_public_enumeration_info(\"NoYes\")\nif enum_info:\n print(f\"Enum: {enum_info.name}\")\n for member in enum_info.members:\n print(f\" {member.name} = {member.value}\")\n```\n\n### Label Operations\n\n```python\n# Get specific label (v2 caching system)\nlabel_text = await client.get_label_text(\"@SYS13342\")\nprint(f\"Label text: {label_text}\")\n\n# Get multiple labels efficiently\nlabels = await client.get_labels_batch([\n \"@SYS13342\", \"@SYS9490\", \"@GLS63332\"\n])\nfor label_id, text in labels.items():\n print(f\"{label_id}: {text}\")\n\n# Enhanced entity info with resolved labels\nentity_info = await client.get_public_entity_info_with_labels(\"CustomersV3\")\nif entity_info.label_text:\n print(f\"Entity display name: {entity_info.label_text}\")\n\n# Access enhanced properties with labels\nfor prop in entity_info.enhanced_properties[:5]:\n if hasattr(prop, 'label_text') and prop.label_text:\n print(f\"{prop.name}: {prop.label_text}\")\n```\n\n## Error Handling\n\n```python\nfrom d365fo_client import D365FOClientError, AuthenticationError, ConnectionError\n\ntry:\n async with D365FOClient(config) as client:\n customer = await client.get_data(\"/data/CustomersV3('NON-EXISTENT')\")\nexcept ConnectionError as e:\n print(f\"Connection failed: {e}\")\nexcept AuthenticationError as e:\n print(f\"Authentication failed: {e}\")\nexcept D365FOClientError as e:\n print(f\"Client operation failed: {e}\")\n print(f\"Status code: {e.status_code}\")\n print(f\"Response: {e.response_text}\")\n```\n\n## Development\n\n### Setting up Development Environment\n\n```bash\n# Clone the repository\ngit clone https://github.com/mafzaal/d365fo-client.git\ncd d365fo-client\n\n# Install with development dependencies using uv\nuv sync --dev\n\n# Run tests\nuv run pytest\n\n# Run integration tests\n.\\tests\\integration\\integration-test-simple.ps1 test-sandbox\n\n# Format code\nuv run black .\nuv run isort .\n\n# Type checking\nuv run mypy src/\n\n# Quality checks\n.\\make.ps1 quality-check # Windows PowerShell\n# or\nmake quality-check # Unix/Linux/macOS\n```\n\n### Project Structure\n\n```\nd365fo-client/\n\u251c\u2500\u2500 src/\n\u2502 \u2514\u2500\u2500 d365fo_client/\n\u2502 \u251c\u2500\u2500 __init__.py # Public API exports\n\u2502 \u251c\u2500\u2500 main.py # CLI entry point \n\u2502 \u251c\u2500\u2500 cli.py # CLI command handlers\n\u2502 \u251c\u2500\u2500 client.py # Enhanced D365FOClient class\n\u2502 \u251c\u2500\u2500 config.py # Configuration management\n\u2502 \u251c\u2500\u2500 auth.py # Authentication management\n\u2502 \u251c\u2500\u2500 session.py # HTTP session management\n\u2502 \u251c\u2500\u2500 crud.py # CRUD operations\n\u2502 \u251c\u2500\u2500 query.py # OData query utilities\n\u2502 \u251c\u2500\u2500 metadata.py # Legacy metadata operations\n\u2502 \u251c\u2500\u2500 metadata_api.py # Metadata API client\n\u2502 \u251c\u2500\u2500 metadata_cache.py # Metadata caching layer V2\n\u2502 \u251c\u2500\u2500 metadata_sync.py # Metadata synchronization V2 with session management\n\u2502 \u251c\u2500\u2500 sync_session.py # Enhanced sync session management (New in v0.2.3)\n\u2502 \u251c\u2500\u2500 credential_manager.py # Credential source management (New in v0.2.3)\n\u2502 \u251c\u2500\u2500 labels.py # Label operations V2\n\u2502 \u251c\u2500\u2500 profiles.py # Profile data models\n\u2502 \u251c\u2500\u2500 profile_manager.py # Profile management\n\u2502 \u251c\u2500\u2500 models.py # Data models and configurations\n\u2502 \u251c\u2500\u2500 output.py # Output formatting\n\u2502 \u251c\u2500\u2500 utils.py # Utility functions\n\u2502 \u251c\u2500\u2500 exceptions.py # Custom exceptions\n\u2502 \u2514\u2500\u2500 mcp/ # Model Context Protocol server\n\u2502 \u251c\u2500\u2500 __init__.py # MCP server exports\n\u2502 \u251c\u2500\u2500 main.py # MCP server entry point\n\u2502 \u251c\u2500\u2500 server.py # Core MCP server implementation\n\u2502 \u251c\u2500\u2500 client_manager.py# D365FO client connection pooling\n\u2502 \u251c\u2500\u2500 models.py # MCP-specific data models\n\u2502 \u251c\u2500\u2500 tools/ # MCP tool implementations (12 tools)\n\u2502 \u2502 \u251c\u2500\u2500 connection_tools.py\n\u2502 \u2502 \u251c\u2500\u2500 crud_tools.py\n\u2502 \u2502 \u251c\u2500\u2500 metadata_tools.py\n\u2502 \u2502 \u2514\u2500\u2500 label_tools.py\n\u2502 \u251c\u2500\u2500 resources/ # MCP resource handlers (4 types)\n\u2502 \u2502 \u251c\u2500\u2500 entity_handler.py\n\u2502 \u2502 \u251c\u2500\u2500 metadata_handler.py\n\u2502 \u2502 \u251c\u2500\u2500 environment_handler.py\n\u2502 \u2502 \u2514\u2500\u2500 query_handler.py\n\u2502 \u2514\u2500\u2500 prompts/ # MCP prompt templates\n\u251c\u2500\u2500 tests/ # Comprehensive test suite\n\u2502 \u251c\u2500\u2500 unit/ # Unit tests (pytest-based)\n\u2502 \u251c\u2500\u2500 integration/ # Multi-tier integration testing\n\u2502 \u2502 \u251c\u2500\u2500 mock_server/ # Mock D365 F&O API server\n\u2502 \u2502 \u251c\u2500\u2500 test_mock_server.py # Mock server tests\n\u2502 \u2502 \u251c\u2500\u2500 test_sandbox.py # Sandbox environment tests \u2705\n\u2502 \u2502 \u251c\u2500\u2500 test_live.py # Live environment tests\n\u2502 \u2502 \u251c\u2500\u2500 conftest.py # Shared pytest fixtures\n\u2502 \u2502 \u251c\u2500\u2500 test_runner.py # Python test execution engine\n\u2502 \u2502 \u2514\u2500\u2500 integration-test-simple.ps1 # PowerShell automation\n\u2502 \u2514\u2500\u2500 test_mcp_server.py # MCP server unit tests \u2705\n\u251c\u2500\u2500 scripts/ # Metadata discovery scripts\n\u2502 \u251c\u2500\u2500 search_data_entities.ps1 # PowerShell entity search\n\u2502 \u251c\u2500\u2500 get_data_entity_schema.ps1 # PowerShell schema retrieval\n\u2502 \u251c\u2500\u2500 search_enums.py # Python enumeration search\n\u2502 \u251c\u2500\u2500 get_enumeration_info.py # Python enumeration info\n\u2502 \u251c\u2500\u2500 search_actions.ps1 # PowerShell action search\n\u2502 \u2514\u2500\u2500 get_action_info.py # Python action information\n\u251c\u2500\u2500 docs/ # Comprehensive documentation\n\u251c\u2500\u2500 pyproject.toml # Project configuration\n\u2514\u2500\u2500 README.md # This file\n```\n\n## Configuration Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `base_url` | str | Required | D365 F&O base URL |\n| `client_id` | str | None | Azure AD client ID |\n| `client_secret` | str | None | Azure AD client secret |\n| `tenant_id` | str | None | Azure AD tenant ID |\n| `use_default_credentials` | bool | True | Use Azure Default Credential |\n| `credential_source` | str | \"environment\" | Credential source: \"environment\", \"keyvault\" |\n| `keyvault_url` | str | None | Azure Key Vault URL for credential storage |\n| `verify_ssl` | bool | False | Verify SSL certificates |\n| `timeout` | int | 30 | Request timeout in seconds |\n| `metadata_cache_dir` | str | Platform-specific user cache | Metadata cache directory |\n| `use_label_cache` | bool | True | Enable label caching V2 |\n| `label_cache_expiry_minutes` | int | 60 | Label cache expiry time |\n| `use_cache_first` | bool | False | Enable cache-first mode with background sync |\n\n### Cache Directory Behavior\n\nBy default, the client uses platform-appropriate user cache directories:\n\n- **Windows**: `%LOCALAPPDATA%\\d365fo-client` (e.g., `C:\\Users\\username\\AppData\\Local\\d365fo-client`)\n- **macOS**: `~/Library/Caches/d365fo-client` (e.g., `/Users/username/Library/Caches/d365fo-client`)\n- **Linux**: `~/.cache/d365fo-client` (e.g., `/home/username/.cache/d365fo-client`)\n\nYou can override this by explicitly setting `metadata_cache_dir`:\n\n```python\nfrom d365fo_client import FOClientConfig\n\n# Use custom cache directory\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\",\n metadata_cache_dir=\"/custom/cache/path\"\n)\n\n# Or get the default cache directory programmatically\nfrom d365fo_client import get_user_cache_dir\n\ncache_dir = get_user_cache_dir(\"my-app\") # Platform-appropriate cache dir\nconfig = FOClientConfig(\n base_url=\"https://your-fo-environment.dynamics.com\", \n metadata_cache_dir=str(cache_dir)\n)\n```\n\n## Testing\n\nThis project includes comprehensive testing at multiple levels to ensure reliability and quality.\n\n### Unit Tests\n\nRun standard unit tests for core functionality:\n\n```bash\n# Run all unit tests\nuv run pytest\n\n# Run with coverage\nuv run pytest --cov=d365fo_client --cov-report=html\n\n# Run specific test file\nuv run pytest tests/test_client.py -v\n```\n\n### Integration Tests\n\nThe project includes a sophisticated multi-tier integration testing framework:\n\n#### Quick Start\n\n```bash\n# Run sandbox integration tests (recommended)\n.\\tests\\integration\\integration-test-simple.ps1 test-sandbox\n\n# Run mock server tests (no external dependencies)\n.\\tests\\integration\\integration-test-simple.ps1 test-mock\n\n# Run with verbose output\n.\\tests\\integration\\integration-test-simple.ps1 test-sandbox -VerboseOutput\n```\n\n#### Test Levels\n\n1. **Mock Server Tests** - Fast, isolated tests against a simulated D365 F&O API\n - No external dependencies\n - Complete API simulation\n - Ideal for CI/CD pipelines\n\n2. **Sandbox Tests** \u2b50 *(Default)* - Tests against real D365 F&O test environments\n - Validates authentication\n - Tests real API behavior\n - Requires test environment access\n\n3. **Live Tests** - Optional tests against production environments\n - Final validation\n - Performance benchmarking\n - Use with caution\n\n#### Configuration\n\nSet up integration testing with environment variables:\n\n```bash\n# Copy the template and configure\ncp tests/integration/.env.template tests/integration/.env\n\n# Edit .env file with your settings:\nINTEGRATION_TEST_LEVEL=sandbox\nD365FO_SANDBOX_BASE_URL=https://your-test.dynamics.com\nD365FO_CLIENT_ID=your-client-id\nD365FO_CLIENT_SECRET=your-client-secret\nD365FO_TENANT_ID=your-tenant-id\n```\n\n#### Available Commands\n\n```bash\n# Test environment setup\n.\\tests\\integration\\integration-test-simple.ps1 setup\n\n# Dependency checking\n.\\tests\\integration\\integration-test-simple.ps1 deps-check\n\n# Run specific test levels\n.\\tests\\integration\\integration-test-simple.ps1 test-mock\n.\\tests\\integration\\integration-test-simple.ps1 test-sandbox\n.\\tests\\integration\\integration-test-simple.ps1 test-live\n\n# Coverage and reporting\n.\\tests\\integration\\integration-test-simple.ps1 coverage\n\n# Clean up test artifacts\n.\\tests\\integration\\integration-test-simple.ps1 clean\n```\n\n#### Test Coverage\n\nIntegration tests cover:\n\n- \u2705 **Connection & Authentication** - Azure AD integration, SSL/TLS validation\n- \u2705 **Version Methods** - Application, platform, and build version retrieval\n- \u2705 **Metadata Operations** - Entity discovery, metadata API validation\n- \u2705 **Data Operations** - CRUD operations, OData query validation\n- \u2705 **Error Handling** - Network failures, authentication errors, invalid requests\n- \u2705 **Performance** - Response time validation, concurrent operations\n\nFor detailed information, see [Integration Testing Documentation](tests/integration/README.md).\n\n### Test Results\n\nRecent sandbox integration test results:\n```\n\u2705 17 passed, 0 failed, 2 warnings in 37.67s\n====================================================== \n\u2705 TestSandboxConnection::test_connection_success\n\u2705 TestSandboxConnection::test_metadata_connection_success \n\u2705 TestSandboxVersionMethods::test_get_application_version\n\u2705 TestSandboxVersionMethods::test_get_platform_build_version\n\u2705 TestSandboxVersionMethods::test_get_application_build_version\n\u2705 TestSandboxVersionMethods::test_version_consistency\n\u2705 TestSandboxMetadataOperations::test_download_metadata\n\u2705 TestSandboxMetadataOperations::test_search_entities\n\u2705 TestSandboxMetadataOperations::test_get_data_entities\n\u2705 TestSandboxMetadataOperations::test_get_public_entities\n\u2705 TestSandboxDataOperations::test_get_available_entities\n\u2705 TestSandboxDataOperations::test_odata_query_options\n\u2705 TestSandboxAuthentication::test_authenticated_requests\n\u2705 TestSandboxErrorHandling::test_invalid_entity_error\n\u2705 TestSandboxErrorHandling::test_invalid_action_error\n\u2705 TestSandboxPerformance::test_response_times\n\u2705 TestSandboxPerformance::test_concurrent_operations\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes\n4. Run tests (`uv run pytest`)\n5. Run integration tests (`.\\tests\\integration\\integration-test-simple.ps1 test-sandbox`)\n6. Format code (`uv run black . && uv run isort .`)\n7. Commit changes (`git commit -m 'Add amazing feature'`)\n8. Push to branch (`git push origin feature/amazing-feature`)\n9. Open a Pull Request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.\n\n## Support\n\n- \ud83d\udce7 Email: mo@thedataguy.pro\n- \ud83d\udc1b Issues: [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)\n\n\n## Related Projects\n\n- [Microsoft Dynamics 365](https://dynamics.microsoft.com/)\n- [OData](https://www.odata.org/)\n- [Azure Identity](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity)\n- [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol/python-sdk) - For AI assistant integration\n",
"bugtrack_url": null,
"license": null,
"summary": "Microsoft Dynamics 365 Finance & Operations client",
"version": "0.3.3",
"project_urls": {
"Changelog": "https://github.com/mafzaal/d365fo-client/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/mafzaal/d365fo-client",
"Homepage": "https://github.com/mafzaal/d365fo-client",
"Issues": "https://github.com/mafzaal/d365fo-client/issues",
"Repository": "https://github.com/mafzaal/d365fo-client"
},
"split_keywords": [
"dynamics365",
" d365",
" finance",
" operations",
" erp",
" microsoft"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d9de065ee8bd17d091edcb31c4cae67443ff4ebbd7e5a82034cfedb4db497a52",
"md5": "91d5a2eb1a3eec226463b28ccb607cb0",
"sha256": "db57f463e133c6dff67b78cf7cc8755b9f78ee74f8913736fe97cee4956b644c"
},
"downloads": -1,
"filename": "d365fo_client-0.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "91d5a2eb1a3eec226463b28ccb607cb0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 276292,
"upload_time": "2025-10-19T05:38:50",
"upload_time_iso_8601": "2025-10-19T05:38:50.834044Z",
"url": "https://files.pythonhosted.org/packages/d9/de/065ee8bd17d091edcb31c4cae67443ff4ebbd7e5a82034cfedb4db497a52/d365fo_client-0.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "d5dd796e78590be4943d42043b8b3201974cfde5207f25e95f1657e9ecec8054",
"md5": "1ddbec4fb0610ac541010da0e59953f0",
"sha256": "59edff7320617f30265cc58221e485583f4f363c0b2811babb1c38ca8786c67e"
},
"downloads": -1,
"filename": "d365fo_client-0.3.3.tar.gz",
"has_sig": false,
"md5_digest": "1ddbec4fb0610ac541010da0e59953f0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 270295,
"upload_time": "2025-10-19T05:38:52",
"upload_time_iso_8601": "2025-10-19T05:38:52.614396Z",
"url": "https://files.pythonhosted.org/packages/d5/dd/796e78590be4943d42043b8b3201974cfde5207f25e95f1657e9ecec8054/d365fo_client-0.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-19 05:38:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mafzaal",
"github_project": "d365fo-client",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "d365fo-client"
}