d365fo-client 0.2.3__py3-none-any.whl → 0.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d365fo-client
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Microsoft Dynamics 365 Finance & Operations client
5
5
  Author-email: Muhammad Afzaal <mo@thedataguy.pro>
6
6
  License-Expression: MIT
@@ -40,1050 +40,1246 @@ Provides-Extra: all
40
40
  Requires-Dist: d365fo-client[dev]; extra == "all"
41
41
  Dynamic: license-file
42
42
 
43
- # Dynamics 365 Finance & Operations Client and MCP Server
43
+ # Dynamics 365 Finance & Operations MCP Server
44
44
 
45
- A comprehensive Python client library and MCP server for Microsoft Dynamics 365 Finance & Operations (D365 F&O) that provides easy access to OData endpoints, metadata operations, label management, and AI assistant integration.
45
+ **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.
46
46
 
47
- ## Features
47
+ **🚀 One-Click Installation for VS Code:**
48
48
 
49
- - 🔗 **OData Client**: Full CRUD operations on D365 F&O data entities with composite key support
50
- - 📊 **Metadata Management V2**: Enhanced caching system with intelligent synchronization and FTS5 search
51
- - 🏷️ **Label Operations V2**: Multilingual label caching with performance improvements and async support
52
- - 🔍 **Advanced Querying**: Support for all OData query parameters ($select, $filter, $expand, etc.)
53
- - ⚡ **Action Execution**: Execute bound and unbound OData actions with comprehensive parameter handling
54
- - 🔒 **Authentication**: Azure AD integration with default credentials, service principal, and Azure Key Vault support
55
- - 💾 **Intelligent Caching**: Cross-environment cache sharing with module-based version detection
56
- - 🌐 **Async/Await**: Modern async/await patterns with optimized session management
57
- - 📝 **Type Hints**: Full type annotation support with enhanced data models
58
- - 🤖 **MCP Server**: Production-ready Model Context Protocol server with 12 tools and 4 resource types
59
- - 🖥️ **Comprehensive CLI**: Hierarchical command-line interface for all D365 F&O operations
60
- - 🧪 **Multi-tier Testing**: Mock, sandbox, and live integration testing framework (17/17 tests passing)
61
- - 📋 **Metadata Scripts**: PowerShell and Python utilities for entity, enumeration, and action discovery
62
- - 🔐 **Enhanced Credential Management**: Support for Azure Key Vault and multiple credential sources
63
- - 📊 **Advanced Sync Management**: Session-based synchronization with detailed progress tracking
64
-
65
- ## Installation
49
+ [![Install with UVX in VS Code](https://img.shields.io/badge/VS_Code-Install_D365_FO_MCP_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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)
50
+ [![Install with UVX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_D365_FO_MCP_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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)
66
51
 
67
- ```bash
68
- # Install from PyPI
69
- pip install d365fo-client
70
-
71
- # Or install from source
72
- git clone https://github.com/mafzaal/d365fo-client.git
73
- cd d365fo-client
74
- uv sync # Installs with exact dependencies from uv.lock
75
- ```
76
-
77
- **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.
52
+ **🐳 Docker Installation for VS Code:**
78
53
 
79
- **Breaking Change in v0.2.3**: Environment variable names have been updated for consistency:
80
- - `AZURE_CLIENT_ID` `D365FO_CLIENT_ID`
81
- - `AZURE_CLIENT_SECRET` → `D365FO_CLIENT_SECRET`
82
- - `AZURE_TENANT_ID` → `D365FO_TENANT_ID`
54
+ [![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Install_D365_FO_MCP_Server_(Docker)-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)
55
+ [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_D365_FO_MCP_Server_(Docker)-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)
83
56
 
84
- Please update your environment variables accordingly when upgrading.
57
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/d365fo-client?label=Downloads)](https://pypi.org/project/d365fo-client/)
85
58
 
86
- ## Quick Start
59
+ **Also includes a comprehensive Python client library** for Microsoft Dynamics 365 Finance & Operations with OData endpoints, metadata operations, label management, and CLI tools.
87
60
 
88
- ## Command Line Interface (CLI)
61
+ ## MCP Server Overview
89
62
 
90
- 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.
63
+ The d365fo-client includes a **production-ready Model Context Protocol (MCP) server** that exposes the full capabilities of the D365 Finance & Operations client to AI assistants and other MCP-compatible tools. This enables sophisticated Dynamics 365 integration workflows through standardized protocol interactions.
91
64
 
92
- ### Usage
65
+ ### Key Features
93
66
 
94
- ```bash
95
- # Use the installed CLI command
96
- d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
67
+ - **34 comprehensive tools** covering all major D365 F&O operations across 7 functional categories
68
+ - **6 resource types** with comprehensive metadata exposure and discovery capabilities
69
+ - **Production-ready** implementation with proper error handling, authentication, and security validation
70
+ - **Performance optimization** with connection pooling, intelligent caching V2, and session management
71
+ - **Comprehensive testing** with 14 unit tests (100% pass rate) and multi-tier integration testing
72
+ - **Advanced profile management** supporting multiple environments with secure credential storage
73
+ - **Database analysis capabilities** with secure SQL querying and metadata insights
74
+ - **Session-based synchronization** with detailed progress tracking and multiple sync strategies
75
+ - **Multi-language support** with label resolution and localization capabilities
76
+ - **Enterprise security** with Azure AD integration, Key Vault support, and audit logging
97
77
 
98
- # Alternative: Module execution
99
- python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]
100
- ```
78
+ ### Quick Start
101
79
 
102
- ### Command Categories
80
+ #### Installation and Setup
103
81
 
104
- #### Entity Operations
105
82
  ```bash
106
- # List entities with filtering
107
- d365fo-client entities list --pattern "customer" --limit 10
83
+ # Install d365fo-client with MCP dependencies
84
+ pip install d365fo-client
108
85
 
109
- # Get entity details and schema
110
- d365fo-client entities get CustomersV3 --properties --keys --labels
86
+ # Set up environment variables
87
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
88
+ export D365FO_CLIENT_ID="your-client-id" # Optional with default credentials
89
+ export D365FO_CLIENT_SECRET="your-client-secret" # Optional with default credentials
90
+ export D365FO_TENANT_ID="your-tenant-id" # Optional with default credentials
111
91
 
112
- # CRUD operations
113
- d365fo-client entities create Customers --data '{"CustomerAccount":"US-999","Name":"Test"}'
114
- d365fo-client entities update Customers US-999 --data '{"Name":"Updated Name"}'
115
- d365fo-client entities delete Customers US-999
92
+ # Start the MCP server
93
+ d365fo-mcp-server
116
94
  ```
117
95
 
118
- #### Metadata Operations
119
- ```bash
120
- # Search and discover entities
121
- d365fo-client metadata entities --search "sales" --output json
96
+ #### Integration with AI Assistants
122
97
 
123
- # Get available actions
124
- d365fo-client metadata actions --pattern "calculate" --limit 5
98
+ ##### VS Code Integration (Recommended)
125
99
 
126
- # Enumerate system enumerations
127
- d365fo-client metadata enums --search "status" --output table
100
+ **Option 1: Default Credentials**
101
+ Add to your VS Code `mcp.json` for GitHub Copilot with MCP:
128
102
 
129
- # Synchronize metadata cache
130
- d365fo-client metadata sync --force-refresh
103
+ ```json
104
+ {
105
+ "servers": {
106
+ "d365fo-mcp-server": {
107
+ "type": "stdio",
108
+ "command": "uvx",
109
+ "args": [
110
+ "--from",
111
+ "d365fo-client",
112
+ "d365fo-mcp-server"
113
+ ],
114
+ "env": {
115
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
116
+ "D365FO_LOG_LEVEL": "INFO"
117
+ }
118
+ }
119
+ }
120
+ }
131
121
  ```
132
122
 
133
- #### Version Information
134
- ```bash
135
- # Get application versions
136
- d365fo-client version app
137
- d365fo-client version platform
138
- d365fo-client version build
123
+ **Option 2: Explicit Credentials**
124
+ For environments requiring service principal authentication:
125
+
126
+ ```json
127
+ {
128
+ "servers": {
129
+ "d365fo-mcp-server": {
130
+ "type": "stdio",
131
+ "command": "uvx",
132
+ "args": [
133
+ "--from",
134
+ "d365fo-client",
135
+ "d365fo-mcp-server"
136
+ ],
137
+ "env": {
138
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
139
+ "D365FO_LOG_LEVEL": "DEBUG",
140
+ "D365FO_CLIENT_ID": "${input:client_id}",
141
+ "D365FO_CLIENT_SECRET": "${input:client_secret}",
142
+ "D365FO_TENANT_ID": "${input:tenant_id}"
143
+ }
144
+ }
145
+ },
146
+ "inputs": [
147
+ {
148
+ "id": "tenant_id",
149
+ "type": "promptString",
150
+ "description": "Azure AD Tenant ID for D365 F&O authentication",
151
+ "password": true
152
+ },
153
+ {
154
+ "id": "client_id",
155
+ "type": "promptString",
156
+ "description": "Azure AD Client ID for D365 F&O authentication",
157
+ "password": true
158
+ },
159
+ {
160
+ "id": "client_secret",
161
+ "type": "promptString",
162
+ "description": "Azure AD Client Secret for D365 F&O authentication",
163
+ "password": true
164
+ }
165
+ ]
166
+ }
139
167
  ```
140
168
 
141
- #### Label Operations
142
- ```bash
143
- # Resolve single label
144
- d365fo-client labels resolve "@SYS13342"
169
+ **Option 3: Docker Integration**
170
+ For containerized environments and enhanced isolation:
145
171
 
146
- # Search labels by pattern
147
- d365fo-client labels search "customer" --language "en-US"
172
+ ```json
173
+ {
174
+ "servers": {
175
+ "d365fo-mcp-server": {
176
+ "type": "stdio",
177
+ "command": "docker",
178
+ "args": [
179
+ "run",
180
+ "--rm",
181
+ "-i",
182
+ "-v",
183
+ "d365fo-mcp:/home/mcp_user/",
184
+ "-e",
185
+ "D365FO_CLIENT_ID=${input:client_id}",
186
+ "-e",
187
+ "D365FO_CLIENT_SECRET=${input:client_secret}",
188
+ "-e",
189
+ "D365FO_TENANT_ID=${input:tenant_id}",
190
+ "ghcr.io/mafzaal/d365fo-client:latest"
191
+ ],
192
+ "env": {
193
+ "D365FO_LOG_LEVEL": "DEBUG",
194
+ "D365FO_CLIENT_ID": "${input:client_id}",
195
+ "D365FO_CLIENT_SECRET": "${input:client_secret}",
196
+ "D365FO_TENANT_ID": "${input:tenant_id}"
197
+ }
198
+ }
199
+ },
200
+ "inputs": [
201
+ {
202
+ "id": "tenant_id",
203
+ "type": "promptString",
204
+ "description": "Azure AD Tenant ID for D365 F&O authentication",
205
+ "password": true
206
+ },
207
+ {
208
+ "id": "client_id",
209
+ "type": "promptString",
210
+ "description": "Azure AD Client ID for D365 F&O authentication",
211
+ "password": true
212
+ },
213
+ {
214
+ "id": "client_secret",
215
+ "type": "promptString",
216
+ "description": "Azure AD Client Secret for D365 F&O authentication",
217
+ "password": true
218
+ }
219
+ ]
220
+ }
148
221
  ```
149
222
 
150
- ### Global Options
151
-
152
- - `--base-url URL` Specify D365 F&O environment URL
153
- - `--profile NAME` Use named configuration profile
154
- - `--output FORMAT` Output format: json, table, csv, yaml (default: table)
155
- - `--verbose` Enable verbose output for debugging
156
- - `--timeout SECONDS` Request timeout (default: 30)
223
+ **Benefits of Docker approach:**
224
+ - Complete environment isolation and reproducibility
225
+ - No local Python installation required
226
+ - Consistent runtime environment across different systems
227
+ - Automatic dependency management with pre-built image
228
+ - Enhanced security through containerization
229
+ - Persistent data storage via Docker volume (`d365fo-mcp`)
157
230
 
158
- ### Configuration Profiles
231
+ **Prerequisites:**
232
+ - Docker installed and running
233
+ - Access to Docker Hub or GitHub Container Registry
234
+ - Network access for pulling the container image
159
235
 
160
- Create reusable configurations in `~/.d365fo-client/config.yaml`:
236
+ ##### Claude Desktop Integration
161
237
 
162
- ```yaml
163
- profiles:
164
- production:
165
- base_url: "https://prod.dynamics.com"
166
- use_default_credentials: true
167
- timeout: 60
168
-
169
- development:
170
- base_url: "https://dev.dynamics.com"
171
- client_id: "${D365FO_CLIENT_ID}"
172
- client_secret: "${D365FO_CLIENT_SECRET}"
173
- tenant_id: "${D365FO_TENANT_ID}"
174
- use_cache_first: true
238
+ Add to your Claude Desktop configuration:
175
239
 
176
- default_profile: "development"
240
+ ```json
241
+ {
242
+ "mcpServers": {
243
+ "d365fo": {
244
+ "command": "uvx",
245
+ "args": [
246
+ "--from",
247
+ "d365fo-client",
248
+ "d365fo-mcp-server"
249
+ ],
250
+ "env": {
251
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
252
+ "D365FO_LOG_LEVEL": "INFO"
253
+ }
254
+ }
255
+ }
256
+ }
177
257
  ```
178
258
 
179
- ### Examples
259
+ **Benefits of uvx approach:**
260
+ - Always uses the latest version from the repository
261
+ - No local installation required
262
+ - Automatic dependency management
263
+ - Works across different environments
180
264
 
181
- ```bash
182
- # Quick entity discovery
183
- d365fo-client entities list --pattern "cust.*" --output json
265
+ #### Alternative: Programmatic Usage
184
266
 
185
- # Get comprehensive entity information
186
- d365fo-client entities get CustomersV3 --properties --keys --labels --output yaml
267
+ ```python
268
+ from d365fo_client.mcp import D365FOMCPServer
187
269
 
188
- # Search for calculation actions
189
- d365fo-client metadata actions --pattern "calculate|compute" --output table
270
+ # Create and run server with custom configuration
271
+ config = {
272
+ "default_environment": {
273
+ "base_url": "https://your-environment.dynamics.com",
274
+ "use_default_credentials": True
275
+ }
276
+ }
190
277
 
191
- # Test environment connectivity
192
- d365fo-client version app --verbose
278
+ server = D365FOMCPServer(config)
279
+ await server.run()
193
280
  ```
194
281
 
195
- For a complete command reference:
196
-
197
- ```bash
198
- d365fo-client --help
199
- d365fo-client entities --help
200
- d365fo-client metadata --help
201
- ```
202
- ### Basic Usage
282
+ #### Custom MCP Clients
283
+ Connect using any MCP-compatible client library:
203
284
 
204
285
  ```python
205
- import asyncio
206
- from d365fo_client import D365FOClient, FOClientConfig
286
+ from mcp import Client
207
287
 
208
- async def main():
209
- # Simple configuration with default credentials
210
- config = FOClientConfig(
211
- base_url="https://your-fo-environment.dynamics.com",
212
- use_default_credentials=True # Uses Azure Default Credential
213
- )
288
+ async with Client("d365fo-mcp-server") as client:
289
+ # Discover available tools
290
+ tools = await client.list_tools()
214
291
 
215
- async with D365FOClient(config) as client:
216
- # Test connection
217
- if await client.test_connection():
218
- print(" Connected successfully!")
219
-
220
- # Get environment information
221
- env_info = await client.get_environment_info()
222
- print(f"Environment: {env_info.application_version}")
223
-
224
- # Search for entities (uses metadata cache v2)
225
- customer_entities = await client.search_entities("customer")
226
- print(f"Found {len(customer_entities)} customer entities")
227
-
228
- # Get customers with query options
229
- from d365fo_client import QueryOptions
230
- options = QueryOptions(
231
- select=["CustomerAccount", "Name", "SalesCurrencyCode"],
232
- top=10,
233
- orderby=["Name"]
234
- )
235
-
236
- customers = await client.get_data("/data/CustomersV3", options)
237
- print(f"Retrieved {len(customers['value'])} customers")
238
-
239
- if __name__ == "__main__":
240
- asyncio.run(main())
292
+ # Execute operations
293
+ result = await client.call_tool(
294
+ "d365fo_query_entities",
295
+ {"entityName": "Customers", "top": 5}
296
+ )
241
297
  ```
242
298
 
243
- ### Using Convenience Function
299
+ #### Docker Deployment
244
300
 
245
- ```python
246
- from d365fo_client import create_client
301
+ For containerized environments and production deployments:
247
302
 
248
- # Quick client creation with enhanced defaults
249
- async with create_client("https://your-fo-environment.dynamics.com") as client:
250
- customers = await client.get_data("/data/CustomersV3", top=5)
303
+ **Pull the Docker Image:**
304
+ ```bash
305
+ # Pull from GitHub Container Registry
306
+ docker pull ghcr.io/mafzaal/d365fo-client:latest
307
+
308
+ # Or pull a specific version
309
+ docker pull ghcr.io/mafzaal/d365fo-client:v0.2.3
251
310
  ```
252
311
 
253
- ## Configuration
312
+ **Standalone Docker Usage:**
313
+ ```bash
314
+ # Run MCP server with environment variables
315
+ docker run --rm -i \
316
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
317
+ -e D365FO_CLIENT_ID="your-client-id" \
318
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
319
+ -e D365FO_TENANT_ID="your-tenant-id" \
320
+ -e D365FO_LOG_LEVEL="INFO" \
321
+ -v d365fo-mcp:/home/mcp_user/ \
322
+ ghcr.io/mafzaal/d365fo-client:latest
323
+
324
+ # Run CLI commands with Docker
325
+ docker run --rm -it \
326
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
327
+ -e D365FO_CLIENT_ID="your-client-id" \
328
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
329
+ -e D365FO_TENANT_ID="your-tenant-id" \
330
+ ghcr.io/mafzaal/d365fo-client:latest \
331
+ d365fo-client entities --limit 10
332
+ ```
254
333
 
255
- ### Authentication Options
334
+ **Docker Compose Example:**
335
+ ```yaml
336
+ version: '3.8'
337
+ services:
338
+ d365fo-mcp:
339
+ image: ghcr.io/mafzaal/d365fo-client:latest
340
+ environment:
341
+ - D365FO_BASE_URL=https://your-environment.dynamics.com
342
+ - D365FO_CLIENT_ID=${D365FO_CLIENT_ID}
343
+ - D365FO_CLIENT_SECRET=${D365FO_CLIENT_SECRET}
344
+ - D365FO_TENANT_ID=${D365FO_TENANT_ID}
345
+ - D365FO_LOG_LEVEL=INFO
346
+ volumes:
347
+ - d365fo-mcp:/home/mcp_user/
348
+ stdin_open: true
349
+ tty: true
350
+
351
+ volumes:
352
+ d365fo-mcp:
353
+ ```
256
354
 
257
- ```python
258
- from d365fo_client import FOClientConfig
355
+ **Docker Benefits:**
356
+ - Complete environment isolation and reproducibility
357
+ - No local Python installation required
358
+ - Consistent runtime environment across different systems
359
+ - Built-in dependency management
360
+ - Enhanced security through containerization
361
+ - Persistent data storage via Docker volumes
362
+ - Easy integration with orchestration platforms (Kubernetes, Docker Swarm)
259
363
 
260
- # Option 1: Default Azure credentials (recommended)
261
- config = FOClientConfig(
262
- base_url="https://your-fo-environment.dynamics.com",
263
- use_default_credentials=True
264
- )
364
+ ### Architecture Benefits
265
365
 
266
- # Option 2: Client credentials
267
- config = FOClientConfig(
268
- base_url="https://your-fo-environment.dynamics.com",
269
- client_id="your-client-id",
270
- client_secret="your-client-secret",
271
- tenant_id="your-tenant-id",
272
- use_default_credentials=False
273
- )
366
+ #### For AI Assistants
367
+ - **Standardized Interface**: Consistent MCP protocol access to D365 F&O
368
+ - **Rich Metadata**: Self-describing entities and operations
369
+ - **Type Safety**: Schema validation for all operations
370
+ - **Error Context**: Detailed error information for troubleshooting
274
371
 
275
- # Option 3: Azure Key Vault integration (New in v0.2.3)
276
- config = FOClientConfig(
277
- base_url="https://your-fo-environment.dynamics.com",
278
- credential_source="keyvault", # Use Azure Key Vault for credentials
279
- keyvault_url="https://your-keyvault.vault.azure.net/"
280
- )
372
+ #### For Developers
373
+ - **Minimal Integration**: Standard MCP client libraries
374
+ - **Comprehensive Coverage**: Full D365 F&O functionality exposed
375
+ - **Performance Optimized**: Efficient connection and caching strategies
376
+ - **Well Documented**: Complete API documentation and examples
281
377
 
282
- # Option 4: With custom settings
283
- config = FOClientConfig(
284
- base_url="https://your-fo-environment.dynamics.com",
285
- use_default_credentials=True,
286
- verify_ssl=False, # For development environments
287
- timeout=60, # Request timeout in seconds
288
- metadata_cache_dir="./my_cache", # Custom cache directory
289
- use_label_cache=True, # Enable label caching
290
- label_cache_expiry_minutes=120 # Cache for 2 hours
291
- )
292
- ```
378
+ #### For Organizations
379
+ - **Secure Access**: Enterprise-grade authentication (Azure AD, Managed Identity)
380
+ - **Audit Logging**: Complete operation tracking and monitoring
381
+ - **Scalable Design**: Connection pooling and session management
382
+ - **Maintenance Friendly**: Clear architecture and comprehensive test coverage
293
383
 
294
- ## Core Operations
384
+ ### Troubleshooting
295
385
 
296
- ### CRUD Operations
386
+ #### Common Issues
297
387
 
298
- ```python
299
- async with D365FOClient(config) as client:
300
- # CREATE - Create new customer (supports composite keys)
301
- new_customer = {
302
- "CustomerAccount": "US-999",
303
- "Name": "Test Customer",
304
- "SalesCurrencyCode": "USD"
305
- }
306
- created = await client.create_data("/data/CustomersV3", new_customer)
307
-
308
- # READ - Get single customer by key
309
- customer = await client.get_data("/data/CustomersV3('US-001')")
310
-
311
- # UPDATE - Update customer with optimistic concurrency
312
- updates = {"Name": "Updated Customer Name"}
313
- updated = await client.update_data("/data/CustomersV3('US-001')", updates)
314
-
315
- # DELETE - Delete customer
316
- success = await client.delete_data("/data/CustomersV3('US-999')")
317
- print(f"Delete successful: {success}")
388
+ **Connection Failures**
389
+ ```bash
390
+ # Test connectivity
391
+ d365fo-client version app --base-url https://your-environment.dynamics.com
392
+
393
+ # Check logs
394
+ tail -f ~/.d365fo-mcp/logs/mcp-server.log
318
395
  ```
319
396
 
320
- ### Advanced Querying
397
+ **Authentication Issues**
398
+ ```bash
399
+ # Verify Azure CLI authentication
400
+ az account show
321
401
 
322
- ```python
323
- from d365fo_client import QueryOptions
402
+ # Test with explicit credentials
403
+ export D365FO_CLIENT_ID="your-client-id"
404
+ # ... set other variables
405
+ d365fo-mcp-server
406
+ ```
324
407
 
325
- # Complex query with multiple options
326
- options = QueryOptions(
327
- select=["CustomerAccount", "Name", "SalesCurrencyCode", "CustomerGroupId"],
328
- filter="SalesCurrencyCode eq 'USD' and contains(Name, 'Corp')",
329
- expand=["CustomerGroup"],
330
- orderby=["Name desc", "CustomerAccount"],
331
- top=50,
332
- skip=10,
333
- count=True
334
- )
408
+ **Performance Issues**
409
+ ```bash
410
+ # Enable debug logging
411
+ export D365FO_LOG_LEVEL="DEBUG"
335
412
 
336
- result = await client.get_data("/data/CustomersV3", options)
337
- print(f"Total count: {result.get('@odata.count')}")
413
+ # Adjust connection settings
414
+ export D365FO_CONNECTION_TIMEOUT="120"
415
+ export D365FO_MAX_CONCURRENT_REQUESTS="5"
338
416
  ```
339
417
 
340
- ### Action Execution
418
+ #### Getting Help
341
419
 
342
- ```python
343
- # Unbound action
344
- result = await client.post_data("/data/calculateTax", {
345
- "amount": 1000.00,
346
- "taxGroup": "STANDARD"
347
- })
420
+ - **Logs**: Check `~/.d365fo-mcp/logs/mcp-server.log` for detailed error information
421
+ - **Environment**: Use `d365fo_get_environment_info` tool to check system status
422
+ - **Documentation**: See [MCP Implementation Summary](docs/MCP_IMPLEMENTATION_SUMMARY.md) for technical details
423
+ - **Issues**: Report problems at [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)
348
424
 
349
- # Bound action on entity set
350
- result = await client.post_data("/data/CustomersV3/calculateBalances", {
351
- "asOfDate": "2024-12-31"
352
- })
425
+ ### MCP Tools
353
426
 
354
- # Bound action on specific entity instance
355
- result = await client.post_data("/data/CustomersV3('US-001')/calculateBalance", {
356
- "asOfDate": "2024-12-31"
357
- })
358
- ```
427
+ The server provides **34 comprehensive tools** organized into functional categories:
428
+
429
+ #### Connection & Environment Tools (2 tools)
430
+ - **`d365fo_test_connection`** - Test connectivity and authentication with performance metrics and error diagnostics
431
+ - **`d365fo_get_environment_info`** - Get comprehensive environment details including versions, configurations, and capabilities
432
+
433
+ #### CRUD Operations Tools (6 tools)
434
+ - **`d365fo_query_entities`** - Advanced OData querying with filters, selections, pagination, and performance optimization
435
+ - **`d365fo_get_entity_record`** - Retrieve specific records by key with expansion options and ETag support
436
+ - **`d365fo_create_entity_record`** - Create new entity records with validation and business logic execution
437
+ - **`d365fo_update_entity_record`** - Update existing records with partial updates and optimistic concurrency control
438
+ - **`d365fo_delete_entity_record`** - Delete entity records with referential integrity checking and cascading rules
439
+ - **`d365fo_call_action`** - Execute OData actions and functions for complex business operations
440
+
441
+ #### Metadata Discovery Tools (6 tools)
442
+ - **`d365fo_search_entities`** - Search entities by pattern with category filtering and full-text search capabilities
443
+ - **`d365fo_get_entity_schema`** - Get detailed entity schemas with properties, relationships, and label resolution
444
+ - **`d365fo_search_actions`** - Search available OData actions with binding type and parameter information
445
+ - **`d365fo_search_enumerations`** - Search system enumerations with keyword-based filtering
446
+ - **`d365fo_get_enumeration_fields`** - Get detailed enumeration member information with multi-language support
447
+ - **`d365fo_get_installed_modules`** - Retrieve information about installed modules and their configurations
448
+
449
+ #### Label Management Tools (2 tools)
450
+ - **`d365fo_get_label`** - Get single label text by ID with multi-language support and fallback options
451
+ - **`d365fo_get_labels_batch`** - Get multiple labels efficiently with batch processing and performance optimization
452
+
453
+ #### Profile Management Tools (10 tools)
454
+ - **`d365fo_list_profiles`** - List all configured D365FO environment profiles with status information
455
+ - **`d365fo_get_profile`** - Get detailed configuration information for specific profiles
456
+ - **`d365fo_create_profile`** - Create new environment profiles with comprehensive authentication options
457
+ - **`d365fo_update_profile`** - Modify existing profile configurations with partial update support
458
+ - **`d365fo_delete_profile`** - Remove environment profiles with proper cleanup and validation
459
+ - **`d365fo_set_default_profile`** - Designate a specific profile as the default for operations
460
+ - **`d365fo_get_default_profile`** - Retrieve information about the currently configured default profile
461
+ - **`d365fo_validate_profile`** - Validate profile configurations for completeness and security compliance
462
+ - **`d365fo_test_profile_connection`** - Test connectivity and authentication for specific profiles
463
+ - **`d365fo_get_profile_status`** - Get comprehensive status information for profiles
464
+
465
+ #### Database Analysis Tools (4 tools)
466
+ - **`d365fo_execute_sql_query`** - Execute SELECT queries against metadata database with security validation
467
+ - **`d365fo_get_database_schema`** - Get comprehensive database schema information including relationships
468
+ - **`d365fo_get_table_info`** - Get detailed information about specific database tables with sample data
469
+ - **`d365fo_get_database_statistics`** - Generate database statistics and analytics for performance monitoring
470
+
471
+ #### Synchronization Tools (4 tools)
472
+ - **`d365fo_start_sync`** - Initiate metadata synchronization with various strategies and session tracking
473
+ - **`d365fo_get_sync_progress`** - Monitor detailed progress of sync sessions with time estimates
474
+ - **`d365fo_cancel_sync`** - Cancel running sync sessions with graceful cleanup
475
+ - **`d365fo_list_sync_sessions`** - List all active sync sessions with status and progress information
476
+
477
+ **📖 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).**
359
478
 
360
- ### Metadata Operations
479
+ ### MCP Resources
361
480
 
362
- ```python
363
- # Intelligent metadata synchronization (v2 system)
364
- sync_manager = await client.get_sync_manager()
365
- await sync_manager.smart_sync()
481
+ The server exposes four types of resources for discovery and access:
366
482
 
367
- # Search entities with enhanced filtering
368
- sales_entities = await client.search_entities("sales")
369
- print("Sales-related entities:", [e.name for e in sales_entities])
483
+ #### Entity Resources
484
+ Access entity metadata and sample data:
485
+ ```
486
+ d365fo://entities/CustomersV3 # Customer entity with metadata and sample data
487
+ d365fo://entities/SalesOrders # Sales order entity information
488
+ d365fo://entities/Products # Product entity details
489
+ ```
370
490
 
371
- # Get detailed entity information with labels
372
- entity_info = await client.get_public_entity_info("CustomersV3")
373
- if entity_info:
374
- print(f"Entity: {entity_info.name}")
375
- print(f"Label: {entity_info.label_text}")
376
- print(f"Data Service Enabled: {entity_info.data_service_enabled}")
491
+ #### Metadata Resources
492
+ Access system-wide metadata:
493
+ ```
494
+ d365fo://metadata/entities # All data entities metadata (V2 cache)
495
+ d365fo://metadata/actions # Available OData actions
496
+ d365fo://metadata/enumerations # System enumerations
497
+ d365fo://metadata/labels # System labels and translations
498
+ ```
377
499
 
378
- # Search actions with caching
379
- calc_actions = await client.search_actions("calculate")
380
- print("Calculation actions:", [a.name for a in calc_actions])
500
+ #### Environment Resources
501
+ Access environment status and information:
502
+ ```
503
+ d365fo://environment/status # Environment health and connectivity
504
+ d365fo://environment/version # Version information (app, platform, build)
505
+ d365fo://environment/cache # Cache status and statistics V2
506
+ ```
381
507
 
382
- # Get enumeration information
383
- enum_info = await client.get_public_enumeration_info("NoYes")
384
- if enum_info:
385
- print(f"Enum: {enum_info.name}")
386
- for member in enum_info.members:
387
- print(f" {member.name} = {member.value}")
508
+ #### Query Resources
509
+ Access predefined and templated queries:
510
+ ```
511
+ d365fo://queries/customers_recent # Recent customers query template
512
+ d365fo://queries/sales_summary # Sales summary query with parameters
388
513
  ```
389
514
 
390
- ### Label Operations
515
+ #### Database Resources (New in V2)
516
+ Access metadata database queries:
517
+ ```
518
+ d365fo://database/entities # SQL-based entity searches with FTS5
519
+ d365fo://database/actions # Action discovery with metadata
520
+ d365fo://database/statistics # Cache and performance statistics
521
+ ```
391
522
 
392
- ```python
393
- # Get specific label (v2 caching system)
394
- label_text = await client.get_label_text("@SYS13342")
395
- print(f"Label text: {label_text}")
523
+ ### Usage Examples
396
524
 
397
- # Get multiple labels efficiently
398
- labels = await client.get_labels_batch([
399
- "@SYS13342", "@SYS9490", "@GLS63332"
400
- ])
401
- for label_id, text in labels.items():
402
- print(f"{label_id}: {text}")
403
-
404
- # Enhanced entity info with resolved labels
405
- entity_info = await client.get_public_entity_info_with_labels("CustomersV3")
406
- if entity_info.label_text:
407
- print(f"Entity display name: {entity_info.label_text}")
525
+ #### Basic Tool Execution
408
526
 
409
- # Access enhanced properties with labels
410
- for prop in entity_info.enhanced_properties[:5]:
411
- if hasattr(prop, 'label_text') and prop.label_text:
412
- print(f"{prop.name}: {prop.label_text}")
527
+ ```json
528
+ {
529
+ "tool": "d365fo_query_entities",
530
+ "arguments": {
531
+ "entityName": "CustomersV3",
532
+ "select": ["CustomerAccount", "Name", "Email"],
533
+ "filter": "CustomerGroup eq 'VIP'",
534
+ "top": 10
535
+ }
536
+ }
413
537
  ```
414
538
 
415
- ## Error Handling
416
-
417
- ```python
418
- from d365fo_client import D365FOClientError, AuthenticationError, ConnectionError
539
+ #### Entity Schema Discovery
419
540
 
420
- try:
421
- async with D365FOClient(config) as client:
422
- customer = await client.get_data("/data/CustomersV3('NON-EXISTENT')")
423
- except ConnectionError as e:
424
- print(f"Connection failed: {e}")
425
- except AuthenticationError as e:
426
- print(f"Authentication failed: {e}")
427
- except D365FOClientError as e:
428
- print(f"Client operation failed: {e}")
429
- print(f"Status code: {e.status_code}")
430
- print(f"Response: {e.response_text}")
541
+ ```json
542
+ {
543
+ "tool": "d365fo_get_entity_schema",
544
+ "arguments": {
545
+ "entityName": "CustomersV3",
546
+ "includeProperties": true,
547
+ "resolveLabels": true,
548
+ "language": "en-US"
549
+ }
550
+ }
431
551
  ```
432
552
 
433
- ## Development
553
+ #### Environment Information
434
554
 
435
- ### Setting up Development Environment
555
+ ```json
556
+ {
557
+ "tool": "d365fo_get_environment_info",
558
+ "arguments": {}
559
+ }
560
+ ```
436
561
 
437
- ```bash
438
- # Clone the repository
439
- git clone https://github.com/mafzaal/d365fo-client.git
440
- cd d365fo-client
562
+ ### Authentication & Configuration
441
563
 
442
- # Install with development dependencies using uv
443
- uv sync --dev
564
+ #### Default Credentials (Recommended)
565
+ Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
444
566
 
445
- # Run tests
446
- uv run pytest
567
+ ```bash
568
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
569
+ # No additional auth environment variables needed
570
+ d365fo-mcp-server
571
+ ```
447
572
 
448
- # Run integration tests
449
- .\tests\integration\integration-test-simple.ps1 test-sandbox
573
+ #### Explicit Credentials
574
+ For service principal authentication:
450
575
 
451
- # Format code
452
- uv run black .
453
- uv run isort .
576
+ ```bash
577
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
578
+ export D365FO_CLIENT_ID="your-client-id"
579
+ export D365FO_CLIENT_SECRET="your-client-secret"
580
+ export D365FO_TENANT_ID="your-tenant-id"
581
+ d365fo-mcp-server
582
+ ```
454
583
 
455
- # Type checking
456
- uv run mypy src/
584
+ #### Azure Key Vault Integration (New in v0.2.3)
585
+ For secure credential storage using Azure Key Vault:
457
586
 
458
- # Quality checks
459
- .\make.ps1 quality-check # Windows PowerShell
460
- # or
461
- make quality-check # Unix/Linux/macOS
587
+ ```bash
588
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
589
+ export D365FO_CREDENTIAL_SOURCE="keyvault"
590
+ export D365FO_KEYVAULT_URL="https://your-keyvault.vault.azure.net/"
591
+ d365fo-mcp-server
462
592
  ```
463
593
 
464
- ### Project Structure
594
+ #### Advanced Configuration
465
595
 
466
- ```
467
- d365fo-client/
468
- ├── src/
469
- │ └── d365fo_client/
470
- │ ├── __init__.py # Public API exports
471
- │ ├── main.py # CLI entry point
472
- │ ├── cli.py # CLI command handlers
473
- │ ├── client.py # Enhanced D365FOClient class
474
- │ ├── config.py # Configuration management
475
- │ ├── auth.py # Authentication management
476
- │ ├── session.py # HTTP session management
477
- │ ├── crud.py # CRUD operations
478
- │ ├── query.py # OData query utilities
479
- │ ├── metadata.py # Legacy metadata operations
480
- │ ├── metadata_api.py # Metadata API client
481
- │ ├── metadata_cache.py # Metadata caching layer V2
482
- │ ├── metadata_sync.py # Metadata synchronization V2 with session management
483
- │ ├── sync_session.py # Enhanced sync session management (New in v0.2.3)
484
- │ ├── credential_manager.py # Credential source management (New in v0.2.3)
485
- │ ├── labels.py # Label operations V2
486
- │ ├── profiles.py # Profile data models
487
- │ ├── profile_manager.py # Profile management
488
- │ ├── models.py # Data models and configurations
489
- │ ├── output.py # Output formatting
490
- │ ├── utils.py # Utility functions
491
- │ ├── exceptions.py # Custom exceptions
492
- │ └── mcp/ # Model Context Protocol server
493
- │ ├── __init__.py # MCP server exports
494
- │ ├── main.py # MCP server entry point
495
- │ ├── server.py # Core MCP server implementation
496
- │ ├── client_manager.py# D365FO client connection pooling
497
- │ ├── models.py # MCP-specific data models
498
- │ ├── tools/ # MCP tool implementations (12 tools)
499
- │ │ ├── connection_tools.py
500
- │ │ ├── crud_tools.py
501
- │ │ ├── metadata_tools.py
502
- │ │ └── label_tools.py
503
- │ ├── resources/ # MCP resource handlers (4 types)
504
- │ │ ├── entity_handler.py
505
- │ │ ├── metadata_handler.py
506
- │ │ ├── environment_handler.py
507
- │ │ └── query_handler.py
508
- │ └── prompts/ # MCP prompt templates
509
- ├── tests/ # Comprehensive test suite
510
- │ ├── unit/ # Unit tests (pytest-based)
511
- │ ├── integration/ # Multi-tier integration testing
512
- │ │ ├── mock_server/ # Mock D365 F&O API server
513
- │ │ ├── test_mock_server.py # Mock server tests
514
- │ │ ├── test_sandbox.py # Sandbox environment tests ✅
515
- │ │ ├── test_live.py # Live environment tests
516
- │ │ ├── conftest.py # Shared pytest fixtures
517
- │ │ ├── test_runner.py # Python test execution engine
518
- │ │ └── integration-test-simple.ps1 # PowerShell automation
519
- │ └── test_mcp_server.py # MCP server unit tests ✅
520
- ├── scripts/ # Metadata discovery scripts
521
- │ ├── search_data_entities.ps1 # PowerShell entity search
522
- │ ├── get_data_entity_schema.ps1 # PowerShell schema retrieval
523
- │ ├── search_enums.py # Python enumeration search
524
- │ ├── get_enumeration_info.py # Python enumeration info
525
- │ ├── search_actions.ps1 # PowerShell action search
526
- │ └── get_action_info.py # Python action information
527
- ├── docs/ # Comprehensive documentation
528
- ├── pyproject.toml # Project configuration
529
- └── README.md # This file
530
- ```
596
+ Create a configuration file or set additional environment variables:
531
597
 
532
- ## Configuration Options
598
+ ```bash
599
+ # Optional: Logging configuration
600
+ export D365FO_LOG_LEVEL="DEBUG"
533
601
 
534
- | Option | Type | Default | Description |
535
- |--------|------|---------|-------------|
536
- | `base_url` | str | Required | D365 F&O base URL |
537
- | `client_id` | str | None | Azure AD client ID |
538
- | `client_secret` | str | None | Azure AD client secret |
539
- | `tenant_id` | str | None | Azure AD tenant ID |
540
- | `use_default_credentials` | bool | True | Use Azure Default Credential |
541
- | `credential_source` | str | "environment" | Credential source: "environment", "keyvault" |
542
- | `keyvault_url` | str | None | Azure Key Vault URL for credential storage |
543
- | `verify_ssl` | bool | False | Verify SSL certificates |
544
- | `timeout` | int | 30 | Request timeout in seconds |
545
- | `metadata_cache_dir` | str | Platform-specific user cache | Metadata cache directory |
546
- | `use_label_cache` | bool | True | Enable label caching V2 |
547
- | `label_cache_expiry_minutes` | int | 60 | Label cache expiry time |
548
- | `use_cache_first` | bool | False | Enable cache-first mode with background sync |
602
+ # Optional: Cache settings
603
+ export D365FO_CACHE_DIR="/custom/cache/path"
549
604
 
550
- ### Cache Directory Behavior
605
+ # Optional: Performance tuning
606
+ export D365FO_CONNECTION_TIMEOUT="60"
607
+ export D365FO_MAX_CONCURRENT_REQUESTS="10"
608
+ ```
551
609
 
552
- By default, the client uses platform-appropriate user cache directories:
610
+ ## Python Client Library
553
611
 
554
- - **Windows**: `%LOCALAPPDATA%\d365fo-client` (e.g., `C:\Users\username\AppData\Local\d365fo-client`)
555
- - **macOS**: `~/Library/Caches/d365fo-client` (e.g., `/Users/username/Library/Caches/d365fo-client`)
556
- - **Linux**: `~/.cache/d365fo-client` (e.g., `/home/username/.cache/d365fo-client`)
612
+ ### Features
557
613
 
558
- You can override this by explicitly setting `metadata_cache_dir`:
614
+ - 🔗 **OData Client**: Full CRUD operations on D365 F&O data entities with composite key support
615
+ - 📊 **Metadata Management V2**: Enhanced caching system with intelligent synchronization and FTS5 search
616
+ - 🏷️ **Label Operations V2**: Multilingual label caching with performance improvements and async support
617
+ - 🔍 **Advanced Querying**: Support for all OData query parameters ($select, $filter, $expand, etc.)
618
+ - ⚡ **Action Execution**: Execute bound and unbound OData actions with comprehensive parameter handling
619
+ - 🔒 **Authentication**: Azure AD integration with default credentials, service principal, and Azure Key Vault support
620
+ - 💾 **Intelligent Caching**: Cross-environment cache sharing with module-based version detection
621
+ - 🌐 **Async/Await**: Modern async/await patterns with optimized session management
622
+ - 📝 **Type Hints**: Full type annotation support with enhanced data models
623
+ - 🤖 **MCP Server**: Production-ready Model Context Protocol server with 12 tools and 4 resource types
624
+ - 🖥️ **Comprehensive CLI**: Hierarchical command-line interface for all D365 F&O operations
625
+ - 🧪 **Multi-tier Testing**: Mock, sandbox, and live integration testing framework (17/17 tests passing)
626
+ - 📋 **Metadata Scripts**: PowerShell and Python utilities for entity, enumeration, and action discovery
627
+ - 🔐 **Enhanced Credential Management**: Support for Azure Key Vault and multiple credential sources
628
+ - 📊 **Advanced Sync Management**: Session-based synchronization with detailed progress tracking
559
629
 
560
- ```python
561
- from d365fo_client import FOClientConfig
630
+ ### Installation
562
631
 
563
- # Use custom cache directory
564
- config = FOClientConfig(
565
- base_url="https://your-fo-environment.dynamics.com",
566
- metadata_cache_dir="/custom/cache/path"
567
- )
632
+ ```bash
633
+ # Install from PyPI
634
+ pip install d365fo-client
568
635
 
569
- # Or get the default cache directory programmatically
570
- from d365fo_client import get_user_cache_dir
636
+ # Or install from source
637
+ git clone https://github.com/mafzaal/d365fo-client.git
638
+ cd d365fo-client
639
+ uv sync # Installs with exact dependencies from uv.lock
571
640
 
572
- cache_dir = get_user_cache_dir("my-app") # Platform-appropriate cache dir
573
- config = FOClientConfig(
574
- base_url="https://your-fo-environment.dynamics.com",
575
- metadata_cache_dir=str(cache_dir)
576
- )
641
+ # Or use Docker (no local installation required)
642
+ docker pull ghcr.io/mafzaal/d365fo-client:latest
643
+
644
+ # Run with Docker
645
+ docker run --rm -it \
646
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
647
+ -e D365FO_CLIENT_ID="your-client-id" \
648
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
649
+ -e D365FO_TENANT_ID="your-tenant-id" \
650
+ -v d365fo-mcp:/home/mcp_user/ \
651
+ ghcr.io/mafzaal/d365fo-client:latest
577
652
  ```
578
653
 
579
- ## Testing
654
+ **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.
580
655
 
581
- This project includes comprehensive testing at multiple levels to ensure reliability and quality.
656
+ **Breaking Change in v0.2.3**: Environment variable names have been updated for consistency:
657
+ - `AZURE_CLIENT_ID` → `D365FO_CLIENT_ID`
658
+ - `AZURE_CLIENT_SECRET` → `D365FO_CLIENT_SECRET`
659
+ - `AZURE_TENANT_ID` → `D365FO_TENANT_ID`
582
660
 
583
- ### Unit Tests
661
+ Please update your environment variables accordingly when upgrading.
584
662
 
585
- Run standard unit tests for core functionality:
663
+ ## Python Client Quick Start
586
664
 
587
- ```bash
588
- # Run all unit tests
589
- uv run pytest
665
+ ## Command Line Interface (CLI)
590
666
 
591
- # Run with coverage
592
- uv run pytest --cov=d365fo_client --cov-report=html
667
+ 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.
593
668
 
594
- # Run specific test file
595
- uv run pytest tests/test_client.py -v
596
- ```
669
+ ### Usage
597
670
 
598
- ### Integration Tests
671
+ ```bash
672
+ # Use the installed CLI command
673
+ d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
599
674
 
600
- The project includes a sophisticated multi-tier integration testing framework:
675
+ # Alternative: Module execution
676
+ python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]
677
+ ```
601
678
 
602
- #### Quick Start
679
+ ### Command Categories
603
680
 
681
+ #### Entity Operations
604
682
  ```bash
605
- # Run sandbox integration tests (recommended)
606
- .\tests\integration\integration-test-simple.ps1 test-sandbox
683
+ # List entities with filtering
684
+ d365fo-client entities list --pattern "customer" --limit 10
607
685
 
608
- # Run mock server tests (no external dependencies)
609
- .\tests\integration\integration-test-simple.ps1 test-mock
686
+ # Get entity details and schema
687
+ d365fo-client entities get CustomersV3 --properties --keys --labels
610
688
 
611
- # Run with verbose output
612
- .\tests\integration\integration-test-simple.ps1 test-sandbox -VerboseOutput
689
+ # CRUD operations
690
+ d365fo-client entities create Customers --data '{"CustomerAccount":"US-999","Name":"Test"}'
691
+ d365fo-client entities update Customers US-999 --data '{"Name":"Updated Name"}'
692
+ d365fo-client entities delete Customers US-999
613
693
  ```
614
694
 
615
- #### Test Levels
616
-
617
- 1. **Mock Server Tests** - Fast, isolated tests against a simulated D365 F&O API
618
- - No external dependencies
619
- - Complete API simulation
620
- - Ideal for CI/CD pipelines
621
-
622
- 2. **Sandbox Tests** ⭐ *(Default)* - Tests against real D365 F&O test environments
623
- - Validates authentication
624
- - Tests real API behavior
625
- - Requires test environment access
695
+ #### Metadata Operations
696
+ ```bash
697
+ # Search and discover entities
698
+ d365fo-client metadata entities --search "sales" --output json
626
699
 
627
- 3. **Live Tests** - Optional tests against production environments
628
- - Final validation
629
- - Performance benchmarking
630
- - Use with caution
700
+ # Get available actions
701
+ d365fo-client metadata actions --pattern "calculate" --limit 5
631
702
 
632
- #### Configuration
703
+ # Enumerate system enumerations
704
+ d365fo-client metadata enums --search "status" --output table
633
705
 
634
- Set up integration testing with environment variables:
706
+ # Synchronize metadata cache
707
+ d365fo-client metadata sync --force-refresh
708
+ ```
635
709
 
710
+ #### Version Information
636
711
  ```bash
637
- # Copy the template and configure
638
- cp tests/integration/.env.template tests/integration/.env
639
-
640
- # Edit .env file with your settings:
641
- INTEGRATION_TEST_LEVEL=sandbox
642
- D365FO_SANDBOX_BASE_URL=https://your-test.dynamics.com
643
- D365FO_CLIENT_ID=your-client-id
644
- D365FO_CLIENT_SECRET=your-client-secret
645
- D365FO_TENANT_ID=your-tenant-id
712
+ # Get application versions
713
+ d365fo-client version app
714
+ d365fo-client version platform
715
+ d365fo-client version build
646
716
  ```
647
717
 
648
- #### Available Commands
649
-
718
+ #### Label Operations
650
719
  ```bash
651
- # Test environment setup
652
- .\tests\integration\integration-test-simple.ps1 setup
653
-
654
- # Dependency checking
655
- .\tests\integration\integration-test-simple.ps1 deps-check
656
-
657
- # Run specific test levels
658
- .\tests\integration\integration-test-simple.ps1 test-mock
659
- .\tests\integration\integration-test-simple.ps1 test-sandbox
660
- .\tests\integration\integration-test-simple.ps1 test-live
661
-
662
- # Coverage and reporting
663
- .\tests\integration\integration-test-simple.ps1 coverage
720
+ # Resolve single label
721
+ d365fo-client labels resolve "@SYS13342"
664
722
 
665
- # Clean up test artifacts
666
- .\tests\integration\integration-test-simple.ps1 clean
723
+ # Search labels by pattern
724
+ d365fo-client labels search "customer" --language "en-US"
667
725
  ```
668
726
 
669
- #### Test Coverage
727
+ ### Global Options
670
728
 
671
- Integration tests cover:
729
+ - `--base-url URL` — Specify D365 F&O environment URL
730
+ - `--profile NAME` — Use named configuration profile
731
+ - `--output FORMAT` — Output format: json, table, csv, yaml (default: table)
732
+ - `--verbose` — Enable verbose output for debugging
733
+ - `--timeout SECONDS` — Request timeout (default: 30)
672
734
 
673
- - **Connection & Authentication** - Azure AD integration, SSL/TLS validation
674
- - ✅ **Version Methods** - Application, platform, and build version retrieval
675
- - ✅ **Metadata Operations** - Entity discovery, metadata API validation
676
- - ✅ **Data Operations** - CRUD operations, OData query validation
677
- - ✅ **Error Handling** - Network failures, authentication errors, invalid requests
678
- - ✅ **Performance** - Response time validation, concurrent operations
735
+ ### Configuration Profiles
679
736
 
680
- For detailed information, see [Integration Testing Documentation](tests/integration/README.md).
737
+ Create reusable configurations in `~/.d365fo-client/config.yaml`:
681
738
 
682
- ### Test Results
739
+ ```yaml
740
+ profiles:
741
+ production:
742
+ base_url: "https://prod.dynamics.com"
743
+ use_default_credentials: true
744
+ timeout: 60
745
+
746
+ development:
747
+ base_url: "https://dev.dynamics.com"
748
+ client_id: "${D365FO_CLIENT_ID}"
749
+ client_secret: "${D365FO_CLIENT_SECRET}"
750
+ tenant_id: "${D365FO_TENANT_ID}"
751
+ use_cache_first: true
683
752
 
684
- Recent sandbox integration test results:
685
- ```
686
- ✅ 17 passed, 0 failed, 2 warnings in 37.67s
687
- ======================================================
688
- ✅ TestSandboxConnection::test_connection_success
689
- ✅ TestSandboxConnection::test_metadata_connection_success
690
- ✅ TestSandboxVersionMethods::test_get_application_version
691
- ✅ TestSandboxVersionMethods::test_get_platform_build_version
692
- ✅ TestSandboxVersionMethods::test_get_application_build_version
693
- ✅ TestSandboxVersionMethods::test_version_consistency
694
- ✅ TestSandboxMetadataOperations::test_download_metadata
695
- ✅ TestSandboxMetadataOperations::test_search_entities
696
- ✅ TestSandboxMetadataOperations::test_get_data_entities
697
- ✅ TestSandboxMetadataOperations::test_get_public_entities
698
- ✅ TestSandboxDataOperations::test_get_available_entities
699
- ✅ TestSandboxDataOperations::test_odata_query_options
700
- ✅ TestSandboxAuthentication::test_authenticated_requests
701
- ✅ TestSandboxErrorHandling::test_invalid_entity_error
702
- ✅ TestSandboxErrorHandling::test_invalid_action_error
703
- ✅ TestSandboxPerformance::test_response_times
704
- ✅ TestSandboxPerformance::test_concurrent_operations
753
+ default_profile: "development"
705
754
  ```
706
755
 
707
- ## Model Context Protocol (MCP) Server
756
+ ### Examples
708
757
 
709
- d365fo-client includes a **production-ready Model Context Protocol (MCP) server** that exposes the full capabilities of the D365 Finance & Operations client to AI assistants and other MCP-compatible tools. This enables sophisticated Dynamics 365 integration workflows through standardized protocol interactions.
758
+ ```bash
759
+ # Quick entity discovery
760
+ d365fo-client entities list --pattern "cust.*" --output json
710
761
 
711
- ### Overview
762
+ # Get comprehensive entity information
763
+ d365fo-client entities get CustomersV3 --properties --keys --labels --output yaml
712
764
 
713
- The MCP server provides:
714
- - **12 functional tools** covering all major D365 F&O operations
715
- - **4 resource types** with comprehensive metadata exposure
716
- - **Production-ready** implementation with proper error handling and authentication
717
- - **Performance optimization** with connection pooling and intelligent caching V2
718
- - **Comprehensive testing** with 14 unit tests (100% pass rate)
719
- - **Profile support** for multi-environment configurations
765
+ # Search for calculation actions
766
+ d365fo-client metadata actions --pattern "calculate|compute" --output table
720
767
 
721
- ### Quick Start
768
+ # Test environment connectivity
769
+ d365fo-client version app --verbose
770
+ ```
722
771
 
723
- #### Installation and Setup
772
+ For a complete command reference:
724
773
 
725
774
  ```bash
726
- # Install d365fo-client with MCP dependencies
727
- pip install d365fo-client
728
-
729
- # Set up environment variables
730
- export D365FO_BASE_URL="https://your-environment.dynamics.com"
731
- export D365FO_CLIENT_ID="your-client-id" # Optional with default credentials
732
- export D365FO_CLIENT_SECRET="your-client-secret" # Optional with default credentials
733
- export D365FO_TENANT_ID="your-tenant-id" # Optional with default credentials
734
-
735
- # Start the MCP server
736
- d365fo-mcp-server
775
+ d365fo-client --help
776
+ d365fo-client entities --help
777
+ d365fo-client metadata --help
737
778
  ```
738
-
739
- #### Alternative: Programmatic Usage
779
+ ### Basic Usage
740
780
 
741
781
  ```python
742
- from d365fo_client.mcp import D365FOMCPServer
782
+ import asyncio
783
+ from d365fo_client import D365FOClient, FOClientConfig
743
784
 
744
- # Create and run server with custom configuration
745
- config = {
746
- "default_environment": {
747
- "base_url": "https://your-environment.dynamics.com",
748
- "use_default_credentials": True
749
- }
750
- }
785
+ async def main():
786
+ # Simple configuration with default credentials
787
+ config = FOClientConfig(
788
+ base_url="https://your-fo-environment.dynamics.com",
789
+ use_default_credentials=True # Uses Azure Default Credential
790
+ )
791
+
792
+ async with D365FOClient(config) as client:
793
+ # Test connection
794
+ if await client.test_connection():
795
+ print("✅ Connected successfully!")
796
+
797
+ # Get environment information
798
+ env_info = await client.get_environment_info()
799
+ print(f"Environment: {env_info.application_version}")
800
+
801
+ # Search for entities (uses metadata cache v2)
802
+ customer_entities = await client.search_entities("customer")
803
+ print(f"Found {len(customer_entities)} customer entities")
804
+
805
+ # Get customers with query options
806
+ from d365fo_client import QueryOptions
807
+ options = QueryOptions(
808
+ select=["CustomerAccount", "Name", "SalesCurrencyCode"],
809
+ top=10,
810
+ orderby=["Name"]
811
+ )
812
+
813
+ customers = await client.get_data("/data/CustomersV3", options)
814
+ print(f"Retrieved {len(customers['value'])} customers")
751
815
 
752
- server = D365FOMCPServer(config)
753
- await server.run()
816
+ if __name__ == "__main__":
817
+ asyncio.run(main())
754
818
  ```
755
819
 
756
- ### MCP Tools
757
-
758
- The server provides 12 comprehensive tools organized into functional categories:
820
+ ### Using Convenience Function
759
821
 
760
- #### Connection Tools (2 tools)
761
- - **`d365fo_test_connection`** - Test environment connectivity and health
762
- - **`d365fo_get_environment_info`** - Get comprehensive environment details, versions, and statistics
822
+ ```python
823
+ from d365fo_client import create_client
763
824
 
764
- #### CRUD Operations (5 tools)
765
- - **`d365fo_query_entities`** - Advanced OData querying with filters, selections, and pagination
766
- - **`d365fo_get_entity_record`** - Retrieve specific records by key with expansion options
767
- - **`d365fo_create_entity_record`** - Create new entity records with validation
768
- - **`d365fo_update_entity_record`** - Update existing records with optimistic concurrency
769
- - **`d365fo_delete_entity_record`** - Delete entity records with conflict detection
825
+ # Quick client creation with enhanced defaults
826
+ async with create_client("https://your-fo-environment.dynamics.com") as client:
827
+ customers = await client.get_data("/data/CustomersV3", top=5)
828
+ ```
770
829
 
771
- #### Metadata Tools (5 tools)
772
- - **`d365fo_search_entities`** - Search entities by pattern with advanced filtering and FTS5 search
773
- - **`d365fo_get_entity_schema`** - Get detailed entity schemas with properties and relationships
774
- - **`d365fo_search_actions`** - Search available OData actions and functions
775
- - **`d365fo_search_enums`** - Search system enumerations with filtering
776
- - **`d365fo_get_enum_info`** - Get detailed enumeration information and values
830
+ ## Configuration
777
831
 
778
- #### Label Tools (2 tools)
779
- - **`d365fo_get_label`** - Get single label text by ID with language support
780
- - **`d365fo_get_labels_batch`** - Get multiple labels efficiently in batch operations
832
+ ### Authentication Options
781
833
 
782
- ### MCP Resources
834
+ ```python
835
+ from d365fo_client import FOClientConfig
783
836
 
784
- The server exposes four types of resources for discovery and access:
837
+ # Option 1: Default Azure credentials (recommended)
838
+ config = FOClientConfig(
839
+ base_url="https://your-fo-environment.dynamics.com",
840
+ use_default_credentials=True
841
+ )
785
842
 
786
- #### Entity Resources
787
- Access entity metadata and sample data:
788
- ```
789
- d365fo://entities/CustomersV3 # Customer entity with metadata and sample data
790
- d365fo://entities/SalesOrders # Sales order entity information
791
- d365fo://entities/Products # Product entity details
792
- ```
843
+ # Option 2: Client credentials
844
+ config = FOClientConfig(
845
+ base_url="https://your-fo-environment.dynamics.com",
846
+ client_id="your-client-id",
847
+ client_secret="your-client-secret",
848
+ tenant_id="your-tenant-id",
849
+ use_default_credentials=False
850
+ )
793
851
 
794
- #### Metadata Resources
795
- Access system-wide metadata:
796
- ```
797
- d365fo://metadata/entities # All data entities metadata (V2 cache)
798
- d365fo://metadata/actions # Available OData actions
799
- d365fo://metadata/enumerations # System enumerations
800
- d365fo://metadata/labels # System labels and translations
801
- ```
852
+ # Option 3: Azure Key Vault integration (New in v0.2.3)
853
+ config = FOClientConfig(
854
+ base_url="https://your-fo-environment.dynamics.com",
855
+ credential_source="keyvault", # Use Azure Key Vault for credentials
856
+ keyvault_url="https://your-keyvault.vault.azure.net/"
857
+ )
802
858
 
803
- #### Environment Resources
804
- Access environment status and information:
805
- ```
806
- d365fo://environment/status # Environment health and connectivity
807
- d365fo://environment/version # Version information (app, platform, build)
808
- d365fo://environment/cache # Cache status and statistics V2
859
+ # Option 4: With custom settings
860
+ config = FOClientConfig(
861
+ base_url="https://your-fo-environment.dynamics.com",
862
+ use_default_credentials=True,
863
+ verify_ssl=False, # For development environments
864
+ timeout=60, # Request timeout in seconds
865
+ metadata_cache_dir="./my_cache", # Custom cache directory
866
+ use_label_cache=True, # Enable label caching
867
+ label_cache_expiry_minutes=120 # Cache for 2 hours
868
+ )
809
869
  ```
810
870
 
811
- #### Query Resources
812
- Access predefined and templated queries:
813
- ```
814
- d365fo://queries/customers_recent # Recent customers query template
815
- d365fo://queries/sales_summary # Sales summary query with parameters
816
- ```
871
+ ## Core Operations
817
872
 
818
- #### Database Resources (New in V2)
819
- Access metadata database queries:
873
+ ### CRUD Operations
874
+
875
+ ```python
876
+ async with D365FOClient(config) as client:
877
+ # CREATE - Create new customer (supports composite keys)
878
+ new_customer = {
879
+ "CustomerAccount": "US-999",
880
+ "Name": "Test Customer",
881
+ "SalesCurrencyCode": "USD"
882
+ }
883
+ created = await client.create_data("/data/CustomersV3", new_customer)
884
+
885
+ # READ - Get single customer by key
886
+ customer = await client.get_data("/data/CustomersV3('US-001')")
887
+
888
+ # UPDATE - Update customer with optimistic concurrency
889
+ updates = {"Name": "Updated Customer Name"}
890
+ updated = await client.update_data("/data/CustomersV3('US-001')", updates)
891
+
892
+ # DELETE - Delete customer
893
+ success = await client.delete_data("/data/CustomersV3('US-999')")
894
+ print(f"Delete successful: {success}")
820
895
  ```
821
- d365fo://database/entities # SQL-based entity searches with FTS5
822
- d365fo://database/actions # Action discovery with metadata
823
- d365fo://database/statistics # Cache and performance statistics
896
+
897
+ ### Advanced Querying
898
+
899
+ ```python
900
+ from d365fo_client import QueryOptions
901
+
902
+ # Complex query with multiple options
903
+ options = QueryOptions(
904
+ select=["CustomerAccount", "Name", "SalesCurrencyCode", "CustomerGroupId"],
905
+ filter="SalesCurrencyCode eq 'USD' and contains(Name, 'Corp')",
906
+ expand=["CustomerGroup"],
907
+ orderby=["Name desc", "CustomerAccount"],
908
+ top=50,
909
+ skip=10,
910
+ count=True
911
+ )
912
+
913
+ result = await client.get_data("/data/CustomersV3", options)
914
+ print(f"Total count: {result.get('@odata.count')}")
824
915
  ```
825
916
 
826
- ### Usage Examples
917
+ ### Action Execution
827
918
 
828
- #### Basic Tool Execution
919
+ ```python
920
+ # Unbound action
921
+ result = await client.post_data("/data/calculateTax", {
922
+ "amount": 1000.00,
923
+ "taxGroup": "STANDARD"
924
+ })
829
925
 
830
- ```json
831
- {
832
- "tool": "d365fo_query_entities",
833
- "arguments": {
834
- "entityName": "CustomersV3",
835
- "select": ["CustomerAccount", "Name", "Email"],
836
- "filter": "CustomerGroup eq 'VIP'",
837
- "top": 10
838
- }
839
- }
926
+ # Bound action on entity set
927
+ result = await client.post_data("/data/CustomersV3/calculateBalances", {
928
+ "asOfDate": "2024-12-31"
929
+ })
930
+
931
+ # Bound action on specific entity instance
932
+ result = await client.post_data("/data/CustomersV3('US-001')/calculateBalance", {
933
+ "asOfDate": "2024-12-31"
934
+ })
840
935
  ```
841
936
 
842
- #### Entity Schema Discovery
937
+ ### Metadata Operations
843
938
 
844
- ```json
845
- {
846
- "tool": "d365fo_get_entity_schema",
847
- "arguments": {
848
- "entityName": "CustomersV3",
849
- "includeProperties": true,
850
- "resolveLabels": true,
851
- "language": "en-US"
852
- }
853
- }
939
+ ```python
940
+ # Intelligent metadata synchronization (v2 system)
941
+ sync_manager = await client.get_sync_manager()
942
+ await sync_manager.smart_sync()
943
+
944
+ # Search entities with enhanced filtering
945
+ sales_entities = await client.search_entities("sales")
946
+ print("Sales-related entities:", [e.name for e in sales_entities])
947
+
948
+ # Get detailed entity information with labels
949
+ entity_info = await client.get_public_entity_info("CustomersV3")
950
+ if entity_info:
951
+ print(f"Entity: {entity_info.name}")
952
+ print(f"Label: {entity_info.label_text}")
953
+ print(f"Data Service Enabled: {entity_info.data_service_enabled}")
954
+
955
+ # Search actions with caching
956
+ calc_actions = await client.search_actions("calculate")
957
+ print("Calculation actions:", [a.name for a in calc_actions])
958
+
959
+ # Get enumeration information
960
+ enum_info = await client.get_public_enumeration_info("NoYes")
961
+ if enum_info:
962
+ print(f"Enum: {enum_info.name}")
963
+ for member in enum_info.members:
964
+ print(f" {member.name} = {member.value}")
854
965
  ```
855
966
 
856
- #### Environment Information
967
+ ### Label Operations
857
968
 
858
- ```json
859
- {
860
- "tool": "d365fo_get_environment_info",
861
- "arguments": {}
862
- }
969
+ ```python
970
+ # Get specific label (v2 caching system)
971
+ label_text = await client.get_label_text("@SYS13342")
972
+ print(f"Label text: {label_text}")
973
+
974
+ # Get multiple labels efficiently
975
+ labels = await client.get_labels_batch([
976
+ "@SYS13342", "@SYS9490", "@GLS63332"
977
+ ])
978
+ for label_id, text in labels.items():
979
+ print(f"{label_id}: {text}")
980
+
981
+ # Enhanced entity info with resolved labels
982
+ entity_info = await client.get_public_entity_info_with_labels("CustomersV3")
983
+ if entity_info.label_text:
984
+ print(f"Entity display name: {entity_info.label_text}")
985
+
986
+ # Access enhanced properties with labels
987
+ for prop in entity_info.enhanced_properties[:5]:
988
+ if hasattr(prop, 'label_text') and prop.label_text:
989
+ print(f"{prop.name}: {prop.label_text}")
863
990
  ```
864
991
 
865
- ### Authentication & Configuration
992
+ ## Error Handling
866
993
 
867
- #### Default Credentials (Recommended)
868
- Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
994
+ ```python
995
+ from d365fo_client import D365FOClientError, AuthenticationError, ConnectionError
869
996
 
870
- ```bash
871
- export D365FO_BASE_URL="https://your-environment.dynamics.com"
872
- # No additional auth environment variables needed
873
- d365fo-mcp-server
997
+ try:
998
+ async with D365FOClient(config) as client:
999
+ customer = await client.get_data("/data/CustomersV3('NON-EXISTENT')")
1000
+ except ConnectionError as e:
1001
+ print(f"Connection failed: {e}")
1002
+ except AuthenticationError as e:
1003
+ print(f"Authentication failed: {e}")
1004
+ except D365FOClientError as e:
1005
+ print(f"Client operation failed: {e}")
1006
+ print(f"Status code: {e.status_code}")
1007
+ print(f"Response: {e.response_text}")
874
1008
  ```
875
1009
 
876
- #### Explicit Credentials
877
- For service principal authentication:
1010
+ ## Development
1011
+
1012
+ ### Setting up Development Environment
878
1013
 
879
1014
  ```bash
880
- export D365FO_BASE_URL="https://your-environment.dynamics.com"
881
- export D365FO_CLIENT_ID="your-client-id"
882
- export D365FO_CLIENT_SECRET="your-client-secret"
883
- export D365FO_TENANT_ID="your-tenant-id"
884
- d365fo-mcp-server
1015
+ # Clone the repository
1016
+ git clone https://github.com/mafzaal/d365fo-client.git
1017
+ cd d365fo-client
1018
+
1019
+ # Install with development dependencies using uv
1020
+ uv sync --dev
1021
+
1022
+ # Run tests
1023
+ uv run pytest
1024
+
1025
+ # Run integration tests
1026
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1027
+
1028
+ # Format code
1029
+ uv run black .
1030
+ uv run isort .
1031
+
1032
+ # Type checking
1033
+ uv run mypy src/
1034
+
1035
+ # Quality checks
1036
+ .\make.ps1 quality-check # Windows PowerShell
1037
+ # or
1038
+ make quality-check # Unix/Linux/macOS
885
1039
  ```
886
1040
 
887
- #### Azure Key Vault Integration (New in v0.2.3)
888
- For secure credential storage using Azure Key Vault:
1041
+ ### Project Structure
889
1042
 
890
- ```bash
891
- export D365FO_BASE_URL="https://your-environment.dynamics.com"
892
- export D365FO_CREDENTIAL_SOURCE="keyvault"
893
- export D365FO_KEYVAULT_URL="https://your-keyvault.vault.azure.net/"
894
- d365fo-mcp-server
895
1043
  ```
1044
+ d365fo-client/
1045
+ ├── src/
1046
+ │ └── d365fo_client/
1047
+ │ ├── __init__.py # Public API exports
1048
+ │ ├── main.py # CLI entry point
1049
+ │ ├── cli.py # CLI command handlers
1050
+ │ ├── client.py # Enhanced D365FOClient class
1051
+ │ ├── config.py # Configuration management
1052
+ │ ├── auth.py # Authentication management
1053
+ │ ├── session.py # HTTP session management
1054
+ │ ├── crud.py # CRUD operations
1055
+ │ ├── query.py # OData query utilities
1056
+ │ ├── metadata.py # Legacy metadata operations
1057
+ │ ├── metadata_api.py # Metadata API client
1058
+ │ ├── metadata_cache.py # Metadata caching layer V2
1059
+ │ ├── metadata_sync.py # Metadata synchronization V2 with session management
1060
+ │ ├── sync_session.py # Enhanced sync session management (New in v0.2.3)
1061
+ │ ├── credential_manager.py # Credential source management (New in v0.2.3)
1062
+ │ ├── labels.py # Label operations V2
1063
+ │ ├── profiles.py # Profile data models
1064
+ │ ├── profile_manager.py # Profile management
1065
+ │ ├── models.py # Data models and configurations
1066
+ │ ├── output.py # Output formatting
1067
+ │ ├── utils.py # Utility functions
1068
+ │ ├── exceptions.py # Custom exceptions
1069
+ │ └── mcp/ # Model Context Protocol server
1070
+ │ ├── __init__.py # MCP server exports
1071
+ │ ├── main.py # MCP server entry point
1072
+ │ ├── server.py # Core MCP server implementation
1073
+ │ ├── client_manager.py# D365FO client connection pooling
1074
+ │ ├── models.py # MCP-specific data models
1075
+ │ ├── tools/ # MCP tool implementations (12 tools)
1076
+ │ │ ├── connection_tools.py
1077
+ │ │ ├── crud_tools.py
1078
+ │ │ ├── metadata_tools.py
1079
+ │ │ └── label_tools.py
1080
+ │ ├── resources/ # MCP resource handlers (4 types)
1081
+ │ │ ├── entity_handler.py
1082
+ │ │ ├── metadata_handler.py
1083
+ │ │ ├── environment_handler.py
1084
+ │ │ └── query_handler.py
1085
+ │ └── prompts/ # MCP prompt templates
1086
+ ├── tests/ # Comprehensive test suite
1087
+ │ ├── unit/ # Unit tests (pytest-based)
1088
+ │ ├── integration/ # Multi-tier integration testing
1089
+ │ │ ├── mock_server/ # Mock D365 F&O API server
1090
+ │ │ ├── test_mock_server.py # Mock server tests
1091
+ │ │ ├── test_sandbox.py # Sandbox environment tests ✅
1092
+ │ │ ├── test_live.py # Live environment tests
1093
+ │ │ ├── conftest.py # Shared pytest fixtures
1094
+ │ │ ├── test_runner.py # Python test execution engine
1095
+ │ │ └── integration-test-simple.ps1 # PowerShell automation
1096
+ │ └── test_mcp_server.py # MCP server unit tests ✅
1097
+ ├── scripts/ # Metadata discovery scripts
1098
+ │ ├── search_data_entities.ps1 # PowerShell entity search
1099
+ │ ├── get_data_entity_schema.ps1 # PowerShell schema retrieval
1100
+ │ ├── search_enums.py # Python enumeration search
1101
+ │ ├── get_enumeration_info.py # Python enumeration info
1102
+ │ ├── search_actions.ps1 # PowerShell action search
1103
+ │ └── get_action_info.py # Python action information
1104
+ ├── docs/ # Comprehensive documentation
1105
+ ├── pyproject.toml # Project configuration
1106
+ └── README.md # This file
1107
+ ```
1108
+
1109
+ ## Configuration Options
1110
+
1111
+ | Option | Type | Default | Description |
1112
+ |--------|------|---------|-------------|
1113
+ | `base_url` | str | Required | D365 F&O base URL |
1114
+ | `client_id` | str | None | Azure AD client ID |
1115
+ | `client_secret` | str | None | Azure AD client secret |
1116
+ | `tenant_id` | str | None | Azure AD tenant ID |
1117
+ | `use_default_credentials` | bool | True | Use Azure Default Credential |
1118
+ | `credential_source` | str | "environment" | Credential source: "environment", "keyvault" |
1119
+ | `keyvault_url` | str | None | Azure Key Vault URL for credential storage |
1120
+ | `verify_ssl` | bool | False | Verify SSL certificates |
1121
+ | `timeout` | int | 30 | Request timeout in seconds |
1122
+ | `metadata_cache_dir` | str | Platform-specific user cache | Metadata cache directory |
1123
+ | `use_label_cache` | bool | True | Enable label caching V2 |
1124
+ | `label_cache_expiry_minutes` | int | 60 | Label cache expiry time |
1125
+ | `use_cache_first` | bool | False | Enable cache-first mode with background sync |
1126
+
1127
+ ### Cache Directory Behavior
1128
+
1129
+ By default, the client uses platform-appropriate user cache directories:
1130
+
1131
+ - **Windows**: `%LOCALAPPDATA%\d365fo-client` (e.g., `C:\Users\username\AppData\Local\d365fo-client`)
1132
+ - **macOS**: `~/Library/Caches/d365fo-client` (e.g., `/Users/username/Library/Caches/d365fo-client`)
1133
+ - **Linux**: `~/.cache/d365fo-client` (e.g., `/home/username/.cache/d365fo-client`)
896
1134
 
897
- #### Advanced Configuration
1135
+ You can override this by explicitly setting `metadata_cache_dir`:
898
1136
 
899
- Create a configuration file or set additional environment variables:
1137
+ ```python
1138
+ from d365fo_client import FOClientConfig
900
1139
 
901
- ```bash
902
- # Optional: Logging configuration
903
- export D365FO_LOG_LEVEL="DEBUG"
1140
+ # Use custom cache directory
1141
+ config = FOClientConfig(
1142
+ base_url="https://your-fo-environment.dynamics.com",
1143
+ metadata_cache_dir="/custom/cache/path"
1144
+ )
904
1145
 
905
- # Optional: Cache settings
906
- export D365FO_CACHE_DIR="/custom/cache/path"
1146
+ # Or get the default cache directory programmatically
1147
+ from d365fo_client import get_user_cache_dir
907
1148
 
908
- # Optional: Performance tuning
909
- export D365FO_CONNECTION_TIMEOUT="60"
910
- export D365FO_MAX_CONCURRENT_REQUESTS="10"
1149
+ cache_dir = get_user_cache_dir("my-app") # Platform-appropriate cache dir
1150
+ config = FOClientConfig(
1151
+ base_url="https://your-fo-environment.dynamics.com",
1152
+ metadata_cache_dir=str(cache_dir)
1153
+ )
911
1154
  ```
912
1155
 
913
- ### Integration with AI Assistants
1156
+ ## Testing
914
1157
 
915
- The MCP server seamlessly integrates with AI assistants and development tools:
1158
+ This project includes comprehensive testing at multiple levels to ensure reliability and quality.
916
1159
 
917
- #### Claude Desktop Integration
918
- Add to your Claude Desktop configuration:
1160
+ ### Unit Tests
919
1161
 
920
- ```json
921
- {
922
- "mcpServers": {
923
- "d365fo": {
924
- "command": "d365fo-mcp-server",
925
- "env": {
926
- "D365FO_BASE_URL": "https://your-environment.dynamics.com" //Optional
927
- }
928
- }
929
- }
930
- }
931
- ```
1162
+ Run standard unit tests for core functionality:
932
1163
 
933
- #### VS Code Integration
1164
+ ```bash
1165
+ # Run all unit tests
1166
+ uv run pytest
934
1167
 
935
- ##### Option 1: Default Credentials (Recommended)
936
- Add to your VS Code `mcp.json` for GitHub Copilot with MCP:
1168
+ # Run with coverage
1169
+ uv run pytest --cov=d365fo_client --cov-report=html
937
1170
 
938
- ```json
939
- {
940
- "servers": {
941
- "d365fo-mcp-server": {
942
- "type": "stdio",
943
- "command": "uvx",
944
- "args": [
945
- "--from",
946
- "d365fo-client",
947
- "d365fo-mcp-server"
948
- ],
949
- "env": {
950
- "D365FO_BASE_URL": "https://your-environment.dynamics.com",
951
- "D365FO_LOG_LEVEL": "INFO"
952
- }
953
- }
954
- }
955
- }
1171
+ # Run specific test file
1172
+ uv run pytest tests/test_client.py -v
956
1173
  ```
957
1174
 
958
- ##### Option 2: Explicit Credentials
959
- For environments requiring service principal authentication:
1175
+ ### Integration Tests
960
1176
 
961
- ```json
962
- {
963
- "servers": {
964
- "d365fo-mcp-server": {
965
- "type": "stdio",
966
- "command": "uvx",
967
- "args": [
968
- "--from",
969
- "d365fo-client",
970
- "d365fo-mcp-server"
971
- ],
972
- "env": {
973
- "D365FO_BASE_URL": "https://your-environment.dynamics.com",
974
- "D365FO_LOG_LEVEL": "DEBUG",
975
- "D365FO_CLIENT_ID": "${input:client_id}",
976
- "D365FO_CLIENT_SECRET": "${input:client_secret}",
977
- "D365FO_TENANT_ID": "${input:tenant_id}"
978
- }
979
- }
980
- },
981
- "inputs": [
982
- {
983
- "id": "tenant_id",
984
- "type": "promptString",
985
- "description": "Azure AD Tenant ID for D365 F&O authentication",
986
- "password": true
987
- },
988
- {
989
- "id": "client_id",
990
- "type": "promptString",
991
- "description": "Azure AD Client ID for D365 F&O authentication",
992
- "password": true
993
- },
994
- {
995
- "id": "client_secret",
996
- "type": "promptString",
997
- "description": "Azure AD Client Secret for D365 F&O authentication",
998
- "password": true
999
- }
1000
- ]
1001
- }
1002
- ```
1177
+ The project includes a sophisticated multi-tier integration testing framework:
1003
1178
 
1004
- **Benefits of uvx approach:**
1005
- - Always uses the latest version from the repository
1006
- - No local installation required
1007
- - Automatic dependency management
1008
- - Works across different environments
1179
+ #### Quick Start
1009
1180
 
1010
- #### Custom MCP Clients
1011
- Connect using any MCP-compatible client library:
1181
+ ```bash
1182
+ # Run sandbox integration tests (recommended)
1183
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1012
1184
 
1013
- ```python
1014
- from mcp import Client
1185
+ # Run mock server tests (no external dependencies)
1186
+ .\tests\integration\integration-test-simple.ps1 test-mock
1015
1187
 
1016
- async with Client("d365fo-mcp-server") as client:
1017
- # Discover available tools
1018
- tools = await client.list_tools()
1019
-
1020
- # Execute operations
1021
- result = await client.call_tool(
1022
- "d365fo_query_entities",
1023
- {"entityName": "Customers", "top": 5}
1024
- )
1188
+ # Run with verbose output
1189
+ .\tests\integration\integration-test-simple.ps1 test-sandbox -VerboseOutput
1025
1190
  ```
1026
1191
 
1027
- ### Architecture Benefits
1192
+ #### Test Levels
1028
1193
 
1029
- #### For AI Assistants
1030
- - **Standardized Interface**: Consistent MCP protocol access to D365 F&O
1031
- - **Rich Metadata**: Self-describing entities and operations
1032
- - **Type Safety**: Schema validation for all operations
1033
- - **Error Context**: Detailed error information for troubleshooting
1194
+ 1. **Mock Server Tests** - Fast, isolated tests against a simulated D365 F&O API
1195
+ - No external dependencies
1196
+ - Complete API simulation
1197
+ - Ideal for CI/CD pipelines
1034
1198
 
1035
- #### For Developers
1036
- - **Minimal Integration**: Standard MCP client libraries
1037
- - **Comprehensive Coverage**: Full D365 F&O functionality exposed
1038
- - **Performance Optimized**: Efficient connection and caching strategies
1039
- - **Well Documented**: Complete API documentation and examples
1199
+ 2. **Sandbox Tests** ⭐ *(Default)* - Tests against real D365 F&O test environments
1200
+ - Validates authentication
1201
+ - Tests real API behavior
1202
+ - Requires test environment access
1040
1203
 
1041
- #### For Organizations
1042
- - **Secure Access**: Enterprise-grade authentication (Azure AD, Managed Identity)
1043
- - **Audit Logging**: Complete operation tracking and monitoring
1044
- - **Scalable Design**: Connection pooling and session management
1045
- - **Maintenance Friendly**: Clear architecture and comprehensive test coverage
1204
+ 3. **Live Tests** - Optional tests against production environments
1205
+ - Final validation
1206
+ - Performance benchmarking
1207
+ - Use with caution
1046
1208
 
1047
- ### Troubleshooting
1209
+ #### Configuration
1048
1210
 
1049
- #### Common Issues
1211
+ Set up integration testing with environment variables:
1050
1212
 
1051
- **Connection Failures**
1052
1213
  ```bash
1053
- # Test connectivity
1054
- d365fo-client get-version --base-url https://your-environment.dynamics.com
1214
+ # Copy the template and configure
1215
+ cp tests/integration/.env.template tests/integration/.env
1055
1216
 
1056
- # Check logs
1057
- tail -f ~/.d365fo-mcp/logs/mcp-server.log
1217
+ # Edit .env file with your settings:
1218
+ INTEGRATION_TEST_LEVEL=sandbox
1219
+ D365FO_SANDBOX_BASE_URL=https://your-test.dynamics.com
1220
+ D365FO_CLIENT_ID=your-client-id
1221
+ D365FO_CLIENT_SECRET=your-client-secret
1222
+ D365FO_TENANT_ID=your-tenant-id
1058
1223
  ```
1059
1224
 
1060
- **Authentication Issues**
1225
+ #### Available Commands
1226
+
1061
1227
  ```bash
1062
- # Verify Azure CLI authentication
1063
- az account show
1228
+ # Test environment setup
1229
+ .\tests\integration\integration-test-simple.ps1 setup
1064
1230
 
1065
- # Test with explicit credentials
1066
- export D365FO_CLIENT_ID="your-client-id"
1067
- # ... set other variables
1068
- d365fo-mcp-server
1069
- ```
1231
+ # Dependency checking
1232
+ .\tests\integration\integration-test-simple.ps1 deps-check
1070
1233
 
1071
- **Performance Issues**
1072
- ```bash
1073
- # Enable debug logging
1074
- export D365FO_LOG_LEVEL="DEBUG"
1234
+ # Run specific test levels
1235
+ .\tests\integration\integration-test-simple.ps1 test-mock
1236
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1237
+ .\tests\integration\integration-test-simple.ps1 test-live
1075
1238
 
1076
- # Adjust connection settings
1077
- export D365FO_CONNECTION_TIMEOUT="120"
1078
- export D365FO_MAX_CONCURRENT_REQUESTS="5"
1239
+ # Coverage and reporting
1240
+ .\tests\integration\integration-test-simple.ps1 coverage
1241
+
1242
+ # Clean up test artifacts
1243
+ .\tests\integration\integration-test-simple.ps1 clean
1079
1244
  ```
1080
1245
 
1081
- #### Getting Help
1246
+ #### Test Coverage
1082
1247
 
1083
- - **Logs**: Check `~/.d365fo-mcp/logs/mcp-server.log` for detailed error information
1084
- - **Environment**: Use `d365fo_get_environment_info` tool to check system status
1085
- - **Documentation**: See [MCP Implementation Summary](docs/MCP_IMPLEMENTATION_SUMMARY.md) for technical details
1086
- - **Issues**: Report problems at [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)
1248
+ Integration tests cover:
1249
+
1250
+ - **Connection & Authentication** - Azure AD integration, SSL/TLS validation
1251
+ - **Version Methods** - Application, platform, and build version retrieval
1252
+ - ✅ **Metadata Operations** - Entity discovery, metadata API validation
1253
+ - ✅ **Data Operations** - CRUD operations, OData query validation
1254
+ - ✅ **Error Handling** - Network failures, authentication errors, invalid requests
1255
+ - ✅ **Performance** - Response time validation, concurrent operations
1256
+
1257
+ For detailed information, see [Integration Testing Documentation](tests/integration/README.md).
1258
+
1259
+ ### Test Results
1260
+
1261
+ Recent sandbox integration test results:
1262
+ ```
1263
+ ✅ 17 passed, 0 failed, 2 warnings in 37.67s
1264
+ ======================================================
1265
+ ✅ TestSandboxConnection::test_connection_success
1266
+ ✅ TestSandboxConnection::test_metadata_connection_success
1267
+ ✅ TestSandboxVersionMethods::test_get_application_version
1268
+ ✅ TestSandboxVersionMethods::test_get_platform_build_version
1269
+ ✅ TestSandboxVersionMethods::test_get_application_build_version
1270
+ ✅ TestSandboxVersionMethods::test_version_consistency
1271
+ ✅ TestSandboxMetadataOperations::test_download_metadata
1272
+ ✅ TestSandboxMetadataOperations::test_search_entities
1273
+ ✅ TestSandboxMetadataOperations::test_get_data_entities
1274
+ ✅ TestSandboxMetadataOperations::test_get_public_entities
1275
+ ✅ TestSandboxDataOperations::test_get_available_entities
1276
+ ✅ TestSandboxDataOperations::test_odata_query_options
1277
+ ✅ TestSandboxAuthentication::test_authenticated_requests
1278
+ ✅ TestSandboxErrorHandling::test_invalid_entity_error
1279
+ ✅ TestSandboxErrorHandling::test_invalid_action_error
1280
+ ✅ TestSandboxPerformance::test_response_times
1281
+ ✅ TestSandboxPerformance::test_concurrent_operations
1282
+ ```
1087
1283
 
1088
1284
  ## Contributing
1089
1285