d365fo-client 0.2.3__tar.gz → 0.3.0__tar.gz

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.
Files changed (91) hide show
  1. {d365fo_client-0.2.3/src/d365fo_client.egg-info → d365fo_client-0.3.0}/PKG-INFO +1261 -810
  2. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/README.md +1255 -809
  3. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/pyproject.toml +10 -2
  4. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/__init__.py +7 -1
  5. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/auth.py +9 -21
  6. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/cli.py +25 -13
  7. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/client.py +8 -4
  8. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/config.py +52 -30
  9. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/credential_sources.py +5 -0
  10. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/main.py +1 -1
  11. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/__init__.py +3 -1
  12. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/__init__.py +5 -0
  13. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/__init__.py +30 -0
  14. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/auth.py +372 -0
  15. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/oauth_proxy.py +989 -0
  16. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/providers/__init__.py +0 -0
  17. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/providers/azure.py +325 -0
  18. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/providers/bearer.py +25 -0
  19. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/providers/jwt.py +547 -0
  20. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/auth/redirect_validation.py +65 -0
  21. d365fo_client-0.3.0/src/d365fo_client/mcp/auth_server/dependencies.py +136 -0
  22. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/client_manager.py +16 -67
  23. d365fo_client-0.3.0/src/d365fo_client/mcp/fastmcp_main.py +358 -0
  24. d365fo_client-0.3.0/src/d365fo_client/mcp/fastmcp_server.py +598 -0
  25. d365fo_client-0.3.0/src/d365fo_client/mcp/fastmcp_utils.py +431 -0
  26. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/main.py +40 -13
  27. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/__init__.py +24 -0
  28. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/base_tools_mixin.py +55 -0
  29. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/connection_tools_mixin.py +50 -0
  30. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/crud_tools_mixin.py +311 -0
  31. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/database_tools_mixin.py +685 -0
  32. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/label_tools_mixin.py +87 -0
  33. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/metadata_tools_mixin.py +565 -0
  34. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/performance_tools_mixin.py +109 -0
  35. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/profile_tools_mixin.py +713 -0
  36. d365fo_client-0.3.0/src/d365fo_client/mcp/mixins/sync_tools_mixin.py +321 -0
  37. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/prompts/action_execution.py +1 -1
  38. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/prompts/sequence_analysis.py +1 -1
  39. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/crud_tools.py +3 -3
  40. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/sync_tools.py +1 -1
  41. d365fo_client-0.3.0/src/d365fo_client/mcp/utilities/__init__.py +1 -0
  42. d365fo_client-0.3.0/src/d365fo_client/mcp/utilities/auth.py +34 -0
  43. d365fo_client-0.3.0/src/d365fo_client/mcp/utilities/logging.py +58 -0
  44. d365fo_client-0.3.0/src/d365fo_client/mcp/utilities/types.py +426 -0
  45. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/sync_manager_v2.py +2 -0
  46. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/sync_session_manager.py +7 -7
  47. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/models.py +139 -139
  48. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/output.py +2 -2
  49. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/profile_manager.py +62 -27
  50. d365fo_client-0.3.0/src/d365fo_client/profiles.py +210 -0
  51. d365fo_client-0.3.0/src/d365fo_client/settings.py +355 -0
  52. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/sync_models.py +85 -2
  53. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/utils.py +2 -1
  54. {d365fo_client-0.2.3 → d365fo_client-0.3.0/src/d365fo_client.egg-info}/PKG-INFO +1261 -810
  55. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client.egg-info/SOURCES.txt +28 -0
  56. d365fo_client-0.3.0/src/d365fo_client.egg-info/entry_points.txt +4 -0
  57. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client.egg-info/requires.txt +5 -0
  58. d365fo_client-0.2.3/src/d365fo_client/profiles.py +0 -205
  59. d365fo_client-0.2.3/src/d365fo_client.egg-info/entry_points.txt +0 -3
  60. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/LICENSE +0 -0
  61. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/setup.cfg +0 -0
  62. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/crud.py +0 -0
  63. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/exceptions.py +0 -0
  64. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/labels.py +0 -0
  65. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/models.py +0 -0
  66. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/prompts/__init__.py +0 -0
  67. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/__init__.py +0 -0
  68. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/database_handler.py +0 -0
  69. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/entity_handler.py +0 -0
  70. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/environment_handler.py +0 -0
  71. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/metadata_handler.py +0 -0
  72. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/resources/query_handler.py +0 -0
  73. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/server.py +0 -0
  74. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/__init__.py +0 -0
  75. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/connection_tools.py +0 -0
  76. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/database_tools.py +0 -0
  77. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/label_tools.py +0 -0
  78. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/metadata_tools.py +0 -0
  79. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/mcp/tools/profile_tools.py +0 -0
  80. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_api.py +0 -0
  81. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/__init__.py +0 -0
  82. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/cache_v2.py +0 -0
  83. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/database_v2.py +0 -0
  84. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/global_version_manager.py +0 -0
  85. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/label_utils.py +0 -0
  86. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/search_engine_v2.py +0 -0
  87. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/metadata_v2/version_detector.py +0 -0
  88. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/query.py +0 -0
  89. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client/session.py +0 -0
  90. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client.egg-info/dependency_links.txt +0 -0
  91. {d365fo_client-0.2.3 → d365fo_client-0.3.0}/src/d365fo_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d365fo-client
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Microsoft Dynamics 365 Finance & Operations client
5
5
  Author-email: Muhammad Afzaal <mo@thedataguy.pro>
6
6
  License-Expression: MIT
@@ -30,6 +30,11 @@ Requires-Dist: diskcache>=5.6.3
30
30
  Requires-Dist: tabulate>=0.9.0
31
31
  Requires-Dist: pyyaml>=6.0
32
32
  Requires-Dist: mcp>=1.13.0
33
+ Requires-Dist: uvicorn[standard]>=0.32.0
34
+ Requires-Dist: pydantic-settings>=2.6.0
35
+ Requires-Dist: authlib>=1.6.4
36
+ Requires-Dist: httpx>=0.28.1
37
+ Requires-Dist: rich>=14.1.0
33
38
  Provides-Extra: dev
34
39
  Requires-Dist: pytest>=8.0.0; extra == "dev"
35
40
  Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
@@ -40,1050 +45,1496 @@ Provides-Extra: all
40
45
  Requires-Dist: d365fo-client[dev]; extra == "all"
41
46
  Dynamic: license-file
42
47
 
43
- # Dynamics 365 Finance & Operations Client and MCP Server
48
+ # Dynamics 365 Finance & Operations MCP Server
44
49
 
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.
50
+ **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
51
 
47
- ## Features
52
+ **🚀 One-Click Installation for VS Code:**
48
53
 
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
54
+ [![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)
55
+ [![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)
64
56
 
65
- ## Installation
57
+ **🐳 Docker Installation for VS Code:**
66
58
 
67
- ```bash
68
- # Install from PyPI
69
- pip install d365fo-client
59
+ [![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)
60
+ [![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)
70
61
 
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
- ```
62
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/d365fo-client?label=Downloads)](https://pypi.org/project/d365fo-client/)
76
63
 
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.
64
+ **Also includes a comprehensive Python client library** for Microsoft Dynamics 365 Finance & Operations with OData endpoints, metadata operations, label management, and CLI tools.
78
65
 
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`
66
+ ## MCP Server Overview
83
67
 
84
- Please update your environment variables accordingly when upgrading.
68
+ 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:
85
69
 
86
- ## Quick Start
70
+ - **Traditional MCP SDK** (`d365fo-mcp-server`) - Original implementation with stdio support
71
+ - **FastMCP Framework** (`d365fo-fastmcp-server`) - Modern implementation with multi-transport support ⭐ **Recommended**
87
72
 
88
- ## Command Line Interface (CLI)
73
+ Both servers provide identical functionality but the FastMCP implementation offers enhanced performance and deployment flexibility.
89
74
 
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.
75
+ ### Key Features
91
76
 
92
- ### Usage
77
+ - **34 comprehensive tools** covering all major D365 F&O operations across 7 functional categories
78
+ - **12 resource types** with comprehensive metadata exposure and discovery capabilities
79
+ - **2 prompt templates** for advanced workflow assistance
80
+ - **Multi-transport support** (FastMCP): stdio, HTTP, Server-Sent Events (SSE)
81
+ - **Production-ready** implementation with proper error handling, authentication, and security validation
82
+ - **Enhanced performance** (FastMCP): 40% faster startup, 15% lower memory usage
83
+ - **Advanced profile management** supporting multiple environments with secure credential storage
84
+ - **Database analysis capabilities** with secure SQL querying and metadata insights
85
+ - **Session-based synchronization** with detailed progress tracking and multiple sync strategies
86
+ - **Multi-language support** with label resolution and localization capabilities
87
+ - **Enterprise security** with Azure AD integration, Key Vault support, and audit logging
88
+
89
+ ### New in v0.3.0
90
+
91
+ - **🔧 Pydantic Settings Model**: Type-safe environment variable management with validation for 35+ configuration options
92
+ - **📂 Custom Log File Support**: `D365FO_LOG_FILE` environment variable for flexible log file paths
93
+ - **🔄 Legacy Config Migration**: Automatic detection and migration of legacy configuration files
94
+ - **🌐 Environment Variable Standardization**: All MCP HTTP variables now use `D365FO_` prefix for consistency
95
+ - **⚡ Enhanced FastMCP Server**: Improved startup configuration, error handling, and graceful shutdown
96
+ - **🔀 MCP Return Type Standardization**: All MCP tools now return dictionaries instead of JSON strings for better type safety
97
+ - **🛠️ Enhanced Configuration**: Support for `.env` files and comprehensive environment variable documentation
98
+
99
+ ### Quick Start
100
+
101
+ #### Installation and Setup
93
102
 
94
103
  ```bash
95
- # Use the installed CLI command
96
- d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
104
+ # Install d365fo-client with MCP dependencies
105
+ pip install d365fo-client
97
106
 
98
- # Alternative: Module execution
99
- python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]
107
+ # Set up environment variables
108
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
109
+ export D365FO_CLIENT_ID="your-client-id" # Optional with default credentials
110
+ export D365FO_CLIENT_SECRET="your-client-secret" # Optional with default credentials
111
+ export D365FO_TENANT_ID="your-tenant-id" # Optional with default credentials
100
112
  ```
101
113
 
102
- ### Command Categories
114
+ #### FastMCP Server (Recommended)
115
+
116
+ The modern FastMCP implementation provides enhanced performance and multiple transport options:
103
117
 
104
- #### Entity Operations
105
118
  ```bash
106
- # List entities with filtering
107
- d365fo-client entities list --pattern "customer" --limit 10
119
+ # Development (stdio transport - default)
120
+ d365fo-fastmcp-server
108
121
 
109
- # Get entity details and schema
110
- d365fo-client entities get CustomersV3 --properties --keys --labels
122
+ # Production HTTP API
123
+ d365fo-fastmcp-server --transport http --port 8000 --host 0.0.0.0
111
124
 
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
125
+ # Real-time Web Applications (SSE)
126
+ d365fo-fastmcp-server --transport sse --port 8001 --host 0.0.0.0
116
127
  ```
117
128
 
118
- #### Metadata Operations
119
- ```bash
120
- # Search and discover entities
121
- d365fo-client metadata entities --search "sales" --output json
122
-
123
- # Get available actions
124
- d365fo-client metadata actions --pattern "calculate" --limit 5
129
+ **Key Benefits:**
130
+ - **40% faster startup** compared to traditional MCP SDK
131
+ - **15% lower memory usage** through optimized architecture
132
+ - **Multi-transport support**: stdio, HTTP, Server-Sent Events (SSE)
133
+ - **Enhanced error handling** with better async/await support
134
+ - **Production ready** with web transports for API integration
125
135
 
126
- # Enumerate system enumerations
127
- d365fo-client metadata enums --search "status" --output table
136
+ #### Traditional MCP Server
128
137
 
129
- # Synchronize metadata cache
130
- d365fo-client metadata sync --force-refresh
131
- ```
138
+ The original MCP SDK implementation remains available for backward compatibility:
132
139
 
133
- #### Version Information
134
140
  ```bash
135
- # Get application versions
136
- d365fo-client version app
137
- d365fo-client version platform
138
- d365fo-client version build
141
+ # Start the traditional MCP server
142
+ d365fo-mcp-server
139
143
  ```
140
144
 
141
- #### Label Operations
142
- ```bash
143
- # Resolve single label
144
- d365fo-client labels resolve "@SYS13342"
145
-
146
- # Search labels by pattern
147
- d365fo-client labels search "customer" --language "en-US"
148
- ```
145
+ #### Integration with AI Assistants
149
146
 
150
- ### Global Options
147
+ ##### VS Code Integration (Recommended)
151
148
 
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)
149
+ **FastMCP Server with Default Credentials:**
150
+ Add to your VS Code `mcp.json` for GitHub Copilot with MCP:
157
151
 
158
- ### Configuration Profiles
152
+ ```json
153
+ {
154
+ "servers": {
155
+ "d365fo-fastmcp-server": {
156
+ "type": "stdio",
157
+ "command": "uvx",
158
+ "args": [
159
+ "--from",
160
+ "d365fo-client@latest",
161
+ "d365fo-fastmcp-server"
162
+ ],
163
+ "env": {
164
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
165
+ "D365FO_LOG_LEVEL": "INFO"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ ```
159
171
 
160
- Create reusable configurations in `~/.d365fo-client/config.yaml`:
172
+ **Traditional MCP Server (Alternative):**
173
+ ```json
174
+ {
175
+ "servers": {
176
+ "d365fo-mcp-server": {
177
+ "type": "stdio",
178
+ "command": "uvx",
179
+ "args": [
180
+ "--from",
181
+ "d365fo-client",
182
+ "d365fo-mcp-server"
183
+ ],
184
+ "env": {
185
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
186
+ "D365FO_LOG_LEVEL": "INFO"
187
+ }
188
+ }
189
+ }
190
+ }
191
+ ```
161
192
 
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
193
+ **Option 2: Explicit Credentials**
194
+ For environments requiring service principal authentication:
175
195
 
176
- default_profile: "development"
196
+ ```json
197
+ {
198
+ "servers": {
199
+ "d365fo-fastmcp-server": {
200
+ "type": "stdio",
201
+ "command": "uvx",
202
+ "args": [
203
+ "--from",
204
+ "d365fo-client",
205
+ "d365fo-fastmcp-server"
206
+ ],
207
+ "env": {
208
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
209
+ "D365FO_LOG_LEVEL": "DEBUG",
210
+ "D365FO_CLIENT_ID": "${input:client_id}",
211
+ "D365FO_CLIENT_SECRET": "${input:client_secret}",
212
+ "D365FO_TENANT_ID": "${input:tenant_id}"
213
+ }
214
+ }
215
+ },
216
+ "inputs": [
217
+ {
218
+ "id": "tenant_id",
219
+ "type": "promptString",
220
+ "description": "Azure AD Tenant ID for D365 F&O authentication",
221
+ "password": true
222
+ },
223
+ {
224
+ "id": "client_id",
225
+ "type": "promptString",
226
+ "description": "Azure AD Client ID for D365 F&O authentication",
227
+ "password": true
228
+ },
229
+ {
230
+ "id": "client_secret",
231
+ "type": "promptString",
232
+ "description": "Azure AD Client Secret for D365 F&O authentication",
233
+ "password": true
234
+ }
235
+ ]
236
+ }
177
237
  ```
178
238
 
179
- ### Examples
239
+ **Option 3: Docker Integration**
240
+ For containerized environments and enhanced isolation:
180
241
 
181
- ```bash
182
- # Quick entity discovery
183
- d365fo-client entities list --pattern "cust.*" --output json
242
+ ```json
243
+ {
244
+ "servers": {
245
+ "d365fo-mcp-server": {
246
+ "type": "stdio",
247
+ "command": "docker",
248
+ "args": [
249
+ "run",
250
+ "--rm",
251
+ "-i",
252
+ "-v",
253
+ "d365fo-mcp:/home/mcp_user/",
254
+ "-e",
255
+ "D365FO_CLIENT_ID=${input:client_id}",
256
+ "-e",
257
+ "D365FO_CLIENT_SECRET=${input:client_secret}",
258
+ "-e",
259
+ "D365FO_TENANT_ID=${input:tenant_id}",
260
+ "ghcr.io/mafzaal/d365fo-client:latest"
261
+ ],
262
+ "env": {
263
+ "D365FO_LOG_LEVEL": "DEBUG",
264
+ "D365FO_CLIENT_ID": "${input:client_id}",
265
+ "D365FO_CLIENT_SECRET": "${input:client_secret}",
266
+ "D365FO_TENANT_ID": "${input:tenant_id}"
267
+ }
268
+ }
269
+ },
270
+ "inputs": [
271
+ {
272
+ "id": "tenant_id",
273
+ "type": "promptString",
274
+ "description": "Azure AD Tenant ID for D365 F&O authentication",
275
+ "password": true
276
+ },
277
+ {
278
+ "id": "client_id",
279
+ "type": "promptString",
280
+ "description": "Azure AD Client ID for D365 F&O authentication",
281
+ "password": true
282
+ },
283
+ {
284
+ "id": "client_secret",
285
+ "type": "promptString",
286
+ "description": "Azure AD Client Secret for D365 F&O authentication",
287
+ "password": true
288
+ }
289
+ ]
290
+ }
291
+ ```
184
292
 
185
- # Get comprehensive entity information
186
- d365fo-client entities get CustomersV3 --properties --keys --labels --output yaml
293
+ **Benefits of Docker approach:**
294
+ - Complete environment isolation and reproducibility
295
+ - No local Python installation required
296
+ - Consistent runtime environment across different systems
297
+ - Automatic dependency management with pre-built image
298
+ - Enhanced security through containerization
299
+ - Persistent data storage via Docker volume (`d365fo-mcp`)
187
300
 
188
- # Search for calculation actions
189
- d365fo-client metadata actions --pattern "calculate|compute" --output table
301
+ **Prerequisites:**
302
+ - Docker installed and running
303
+ - Access to Docker Hub or GitHub Container Registry
304
+ - Network access for pulling the container image
190
305
 
191
- # Test environment connectivity
192
- d365fo-client version app --verbose
193
- ```
306
+ ##### Claude Desktop Integration
194
307
 
195
- For a complete command reference:
308
+ **FastMCP Server:**
309
+ Add to your Claude Desktop configuration:
196
310
 
197
- ```bash
198
- d365fo-client --help
199
- d365fo-client entities --help
200
- d365fo-client metadata --help
311
+ ```json
312
+ {
313
+ "mcpServers": {
314
+ "d365fo-fastmcp": {
315
+ "command": "uvx",
316
+ "args": [
317
+ "--from",
318
+ "d365fo-client",
319
+ "d365fo-fastmcp-server"
320
+ ],
321
+ "env": {
322
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
323
+ "D365FO_LOG_LEVEL": "INFO"
324
+ }
325
+ }
326
+ }
327
+ }
201
328
  ```
202
- ### Basic Usage
203
329
 
204
- ```python
205
- import asyncio
206
- from d365fo_client import D365FOClient, FOClientConfig
207
-
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
- )
214
-
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())
330
+ **Traditional MCP Server (Alternative):**
331
+ ```json
332
+ {
333
+ "mcpServers": {
334
+ "d365fo": {
335
+ "command": "uvx",
336
+ "args": [
337
+ "--from",
338
+ "d365fo-client",
339
+ "d365fo-mcp-server"
340
+ ],
341
+ "env": {
342
+ "D365FO_BASE_URL": "https://your-environment.dynamics.com",
343
+ "D365FO_LOG_LEVEL": "INFO"
344
+ }
345
+ }
346
+ }
347
+ }
241
348
  ```
242
349
 
243
- ### Using Convenience Function
244
-
245
- ```python
246
- from d365fo_client import create_client
350
+ **Benefits of uvx approach:**
351
+ - Always uses the latest version from the repository
352
+ - No local installation required
353
+ - Automatic dependency management
354
+ - Works across different environments
247
355
 
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)
251
- ```
356
+ #### Web Integration with FastMCP
252
357
 
253
- ## Configuration
358
+ The FastMCP server provides HTTP and SSE transports for web application integration:
254
359
 
255
- ### Authentication Options
360
+ ##### HTTP Transport for Web APIs
256
361
 
257
362
  ```python
258
- from d365fo_client import FOClientConfig
259
-
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
- )
265
-
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
- )
274
-
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
- )
363
+ import aiohttp
364
+ import json
281
365
 
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
- )
366
+ async def call_d365fo_api():
367
+ """Example: Using HTTP transport for web API integration"""
368
+
369
+ # Start FastMCP server with HTTP transport
370
+ # d365fo-fastmcp-server --transport http --port 8000
371
+
372
+ mcp_request = {
373
+ "jsonrpc": "2.0",
374
+ "id": 1,
375
+ "method": "tools/call",
376
+ "params": {
377
+ "name": "d365fo_query_entities",
378
+ "arguments": {
379
+ "entityName": "CustomersV3",
380
+ "top": 10,
381
+ "select": ["CustomerAccount", "Name"]
382
+ }
383
+ }
384
+ }
385
+
386
+ async with aiohttp.ClientSession() as session:
387
+ async with session.post(
388
+ "http://localhost:8000/mcp",
389
+ json=mcp_request,
390
+ headers={"Content-Type": "application/json"}
391
+ ) as response:
392
+ result = await response.json()
393
+ print(json.dumps(result, indent=2))
292
394
  ```
293
395
 
294
- ## Core Operations
396
+ ##### SSE Transport for Real-time Applications
295
397
 
296
- ### CRUD Operations
398
+ ```javascript
399
+ // Example: JavaScript client for real-time D365FO data
400
+ // Start FastMCP server: d365fo-fastmcp-server --transport sse --port 8001
297
401
 
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')")
402
+ const eventSource = new EventSource('http://localhost:8001/sse');
403
+
404
+ eventSource.onmessage = function(event) {
405
+ const data = JSON.parse(event.data);
406
+ console.log('Received D365FO data:', data);
310
407
 
311
- # UPDATE - Update customer with optimistic concurrency
312
- updates = {"Name": "Updated Customer Name"}
313
- updated = await client.update_data("/data/CustomersV3('US-001')", updates)
408
+ // Handle real-time updates from D365FO
409
+ if (data.method === 'notification') {
410
+ updateDashboard(data.params);
411
+ }
412
+ };
413
+
414
+ // Send MCP requests via SSE
415
+ function queryCustomers() {
416
+ const request = {
417
+ jsonrpc: "2.0",
418
+ id: Date.now(),
419
+ method: "tools/call",
420
+ params: {
421
+ name: "d365fo_search_entities",
422
+ arguments: {
423
+ pattern: "customer",
424
+ limit: 50
425
+ }
426
+ }
427
+ };
314
428
 
315
- # DELETE - Delete customer
316
- success = await client.delete_data("/data/CustomersV3('US-999')")
317
- print(f"Delete successful: {success}")
429
+ fetch('http://localhost:8001/sse/send', {
430
+ method: 'POST',
431
+ headers: {'Content-Type': 'application/json'},
432
+ body: JSON.stringify(request)
433
+ });
434
+ }
318
435
  ```
319
436
 
320
- ### Advanced Querying
437
+ #### Alternative: Programmatic Usage
321
438
 
322
439
  ```python
323
- from d365fo_client import QueryOptions
440
+ from d365fo_client.mcp import D365FOMCPServer
324
441
 
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
- )
442
+ # Create and run server with custom configuration
443
+ config = {
444
+ "default_environment": {
445
+ "base_url": "https://your-environment.dynamics.com",
446
+ "use_default_credentials": True
447
+ }
448
+ }
335
449
 
336
- result = await client.get_data("/data/CustomersV3", options)
337
- print(f"Total count: {result.get('@odata.count')}")
450
+ server = D365FOMCPServer(config)
451
+ await server.run()
338
452
  ```
339
453
 
340
- ### Action Execution
454
+ #### Custom MCP Clients
455
+ Connect using any MCP-compatible client library:
341
456
 
342
457
  ```python
343
- # Unbound action
344
- result = await client.post_data("/data/calculateTax", {
345
- "amount": 1000.00,
346
- "taxGroup": "STANDARD"
347
- })
348
-
349
- # Bound action on entity set
350
- result = await client.post_data("/data/CustomersV3/calculateBalances", {
351
- "asOfDate": "2024-12-31"
352
- })
458
+ from mcp import Client
353
459
 
354
- # Bound action on specific entity instance
355
- result = await client.post_data("/data/CustomersV3('US-001')/calculateBalance", {
356
- "asOfDate": "2024-12-31"
357
- })
460
+ async with Client("d365fo-mcp-server") as client:
461
+ # Discover available tools
462
+ tools = await client.list_tools()
463
+
464
+ # Execute operations
465
+ result = await client.call_tool(
466
+ "d365fo_query_entities",
467
+ {"entityName": "Customers", "top": 5}
468
+ )
358
469
  ```
359
470
 
360
- ### Metadata Operations
471
+ #### Docker Deployment
361
472
 
362
- ```python
363
- # Intelligent metadata synchronization (v2 system)
364
- sync_manager = await client.get_sync_manager()
365
- await sync_manager.smart_sync()
473
+ For containerized environments and production deployments:
366
474
 
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])
475
+ **Pull the Docker Image:**
476
+ ```bash
477
+ # Pull from GitHub Container Registry
478
+ docker pull ghcr.io/mafzaal/d365fo-client:latest
370
479
 
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}")
480
+ # Or pull a specific version
481
+ docker pull ghcr.io/mafzaal/d365fo-client:v0.2.3
482
+ ```
377
483
 
378
- # Search actions with caching
379
- calc_actions = await client.search_actions("calculate")
380
- print("Calculation actions:", [a.name for a in calc_actions])
484
+ **Standalone Docker Usage:**
485
+ ```bash
486
+ # Run MCP server with environment variables
487
+ docker run --rm -i \
488
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
489
+ -e D365FO_CLIENT_ID="your-client-id" \
490
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
491
+ -e D365FO_TENANT_ID="your-tenant-id" \
492
+ -e D365FO_LOG_LEVEL="INFO" \
493
+ -v d365fo-mcp:/home/mcp_user/ \
494
+ ghcr.io/mafzaal/d365fo-client:latest
495
+
496
+ # Run CLI commands with Docker
497
+ docker run --rm -it \
498
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
499
+ -e D365FO_CLIENT_ID="your-client-id" \
500
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
501
+ -e D365FO_TENANT_ID="your-tenant-id" \
502
+ ghcr.io/mafzaal/d365fo-client:latest \
503
+ d365fo-client entities --limit 10
504
+ ```
381
505
 
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}")
506
+ **Docker Compose Example:**
507
+ ```yaml
508
+ version: '3.8'
509
+ services:
510
+ d365fo-mcp:
511
+ image: ghcr.io/mafzaal/d365fo-client:latest
512
+ environment:
513
+ - D365FO_BASE_URL=https://your-environment.dynamics.com
514
+ - D365FO_CLIENT_ID=${D365FO_CLIENT_ID}
515
+ - D365FO_CLIENT_SECRET=${D365FO_CLIENT_SECRET}
516
+ - D365FO_TENANT_ID=${D365FO_TENANT_ID}
517
+ - D365FO_LOG_LEVEL=INFO
518
+ volumes:
519
+ - d365fo-mcp:/home/mcp_user/
520
+ stdin_open: true
521
+ tty: true
522
+
523
+ volumes:
524
+ d365fo-mcp:
388
525
  ```
389
526
 
390
- ### Label Operations
527
+ **Docker Benefits:**
528
+ - Complete environment isolation and reproducibility
529
+ - No local Python installation required
530
+ - Consistent runtime environment across different systems
531
+ - Built-in dependency management
532
+ - Enhanced security through containerization
533
+ - Persistent data storage via Docker volumes
534
+ - Easy integration with orchestration platforms (Kubernetes, Docker Swarm)
391
535
 
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}")
536
+ ### Architecture Benefits
396
537
 
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}")
538
+ #### For AI Assistants
539
+ - **Standardized Interface**: Consistent MCP protocol access to D365 F&O
540
+ - **Rich Metadata**: Self-describing entities and operations
541
+ - **Type Safety**: Schema validation for all operations
542
+ - **Error Context**: Detailed error information for troubleshooting
403
543
 
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}")
544
+ #### For Developers
545
+ - **Minimal Integration**: Standard MCP client libraries
546
+ - **Comprehensive Coverage**: Full D365 F&O functionality exposed
547
+ - **Performance Optimized**: Efficient connection and caching strategies
548
+ - **Well Documented**: Complete API documentation and examples
408
549
 
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}")
413
- ```
550
+ #### For Organizations
551
+ - **Secure Access**: Enterprise-grade authentication (Azure AD, Managed Identity)
552
+ - **Audit Logging**: Complete operation tracking and monitoring
553
+ - **Scalable Design**: Connection pooling and session management
554
+ - **Maintenance Friendly**: Clear architecture and comprehensive test coverage
414
555
 
415
- ## Error Handling
556
+ ### Troubleshooting
416
557
 
417
- ```python
418
- from d365fo_client import D365FOClientError, AuthenticationError, ConnectionError
558
+ #### Common Issues
419
559
 
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}")
560
+ **Connection Failures**
561
+ ```bash
562
+ # Test connectivity
563
+ d365fo-client version app --base-url https://your-environment.dynamics.com
564
+
565
+ # Check logs
566
+ tail -f ~/.d365fo-mcp/logs/mcp-server.log
431
567
  ```
432
568
 
433
- ## Development
569
+ **Authentication Issues**
570
+ ```bash
571
+ # Verify Azure CLI authentication
572
+ az account show
434
573
 
435
- ### Setting up Development Environment
574
+ # Test with explicit credentials
575
+ export D365FO_CLIENT_ID="your-client-id"
576
+ # ... set other variables
577
+ d365fo-mcp-server
578
+ ```
436
579
 
580
+ **Performance Issues**
437
581
  ```bash
438
- # Clone the repository
439
- git clone https://github.com/mafzaal/d365fo-client.git
440
- cd d365fo-client
582
+ # Enable debug logging
583
+ export D365FO_LOG_LEVEL="DEBUG"
441
584
 
442
- # Install with development dependencies using uv
443
- uv sync --dev
585
+ # Adjust connection settings
586
+ export D365FO_CONNECTION_TIMEOUT="120"
587
+ export D365FO_MAX_CONCURRENT_REQUESTS="5"
588
+ ```
444
589
 
445
- # Run tests
446
- uv run pytest
590
+ #### Getting Help
447
591
 
448
- # Run integration tests
449
- .\tests\integration\integration-test-simple.ps1 test-sandbox
592
+ - **Logs**: Check `~/.d365fo-mcp/logs/mcp-server.log` for detailed error information
593
+ - **Environment**: Use `d365fo_get_environment_info` tool to check system status
594
+ - **Documentation**: See [MCP Implementation Summary](docs/MCP_IMPLEMENTATION_SUMMARY.md) for technical details
595
+ - **Issues**: Report problems at [GitHub Issues](https://github.com/mafzaal/d365fo-client/issues)
450
596
 
451
- # Format code
452
- uv run black .
453
- uv run isort .
597
+ ### MCP Tools
454
598
 
455
- # Type checking
456
- uv run mypy src/
599
+ The server provides **34 comprehensive tools** organized into functional categories:
600
+
601
+ #### Connection & Environment Tools (2 tools)
602
+ - **`d365fo_test_connection`** - Test connectivity and authentication with performance metrics and error diagnostics
603
+ - **`d365fo_get_environment_info`** - Get comprehensive environment details including versions, configurations, and capabilities
604
+
605
+ #### CRUD Operations Tools (6 tools)
606
+ - **`d365fo_query_entities`** - Simplified OData querying with 'eq' filtering, wildcard patterns, field selection, and pagination
607
+ - **`d365fo_get_entity_record`** - Retrieve specific records by key with expansion options and ETag support
608
+ - **`d365fo_create_entity_record`** - Create new entity records with validation and business logic execution
609
+ - **`d365fo_update_entity_record`** - Update existing records with partial updates and optimistic concurrency control
610
+ - **`d365fo_delete_entity_record`** - Delete entity records with referential integrity checking and cascading rules
611
+ - **`d365fo_call_action`** - Execute OData actions and functions for complex business operations
612
+
613
+ #### Metadata Discovery Tools (6 tools)
614
+ - **`d365fo_search_entities`** - Search entities by pattern with category filtering and full-text search capabilities
615
+ - **`d365fo_get_entity_schema`** - Get detailed entity schemas with properties, relationships, and label resolution
616
+ - **`d365fo_search_actions`** - Search available OData actions with binding type and parameter information
617
+ - **`d365fo_search_enumerations`** - Search system enumerations with keyword-based filtering
618
+ - **`d365fo_get_enumeration_fields`** - Get detailed enumeration member information with multi-language support
619
+ - **`d365fo_get_installed_modules`** - Retrieve information about installed modules and their configurations
620
+
621
+ #### Label Management Tools (2 tools)
622
+ - **`d365fo_get_label`** - Get single label text by ID with multi-language support and fallback options
623
+ - **`d365fo_get_labels_batch`** - Get multiple labels efficiently with batch processing and performance optimization
624
+
625
+ #### Profile Management Tools (10 tools)
626
+ - **`d365fo_list_profiles`** - List all configured D365FO environment profiles with status information
627
+ - **`d365fo_get_profile`** - Get detailed configuration information for specific profiles
628
+ - **`d365fo_create_profile`** - Create new environment profiles with comprehensive authentication options
629
+ - **`d365fo_update_profile`** - Modify existing profile configurations with partial update support
630
+ - **`d365fo_delete_profile`** - Remove environment profiles with proper cleanup and validation
631
+ - **`d365fo_set_default_profile`** - Designate a specific profile as the default for operations
632
+ - **`d365fo_get_default_profile`** - Retrieve information about the currently configured default profile
633
+ - **`d365fo_validate_profile`** - Validate profile configurations for completeness and security compliance
634
+ - **`d365fo_test_profile_connection`** - Test connectivity and authentication for specific profiles
635
+ - **`d365fo_get_profile_status`** - Get comprehensive status information for profiles
636
+
637
+ #### Database Analysis Tools (4 tools)
638
+ - **`d365fo_execute_sql_query`** - Execute SELECT queries against metadata database with security validation
639
+ - **`d365fo_get_database_schema`** - Get comprehensive database schema information including relationships
640
+ - **`d365fo_get_table_info`** - Get detailed information about specific database tables with sample data
641
+ - **`d365fo_get_database_statistics`** - Generate database statistics and analytics for performance monitoring
642
+
643
+ #### Synchronization Tools (4 tools)
644
+ - **`d365fo_start_sync`** - Initiate metadata synchronization with various strategies and session tracking
645
+ - **`d365fo_get_sync_progress`** - Monitor detailed progress of sync sessions with time estimates
646
+ - **`d365fo_cancel_sync`** - Cancel running sync sessions with graceful cleanup
647
+ - **`d365fo_list_sync_sessions`** - List all active sync sessions with status and progress information
648
+
649
+ **📖 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).**
457
650
 
458
- # Quality checks
459
- .\make.ps1 quality-check # Windows PowerShell
460
- # or
461
- make quality-check # Unix/Linux/macOS
462
- ```
651
+ ### MCP Resources
463
652
 
464
- ### Project Structure
653
+ The server exposes four types of resources for discovery and access:
465
654
 
655
+ #### Entity Resources
656
+ Access entity metadata and sample data:
466
657
  ```
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
658
+ d365fo://entities/CustomersV3 # Customer entity with metadata and sample data
659
+ d365fo://entities/SalesOrders # Sales order entity information
660
+ d365fo://entities/Products # Product entity details
530
661
  ```
531
662
 
532
- ## Configuration Options
663
+ #### Metadata Resources
664
+ Access system-wide metadata:
665
+ ```
666
+ d365fo://metadata/entities # All data entities metadata (V2 cache)
667
+ d365fo://metadata/actions # Available OData actions
668
+ d365fo://metadata/enumerations # System enumerations
669
+ d365fo://metadata/labels # System labels and translations
670
+ ```
533
671
 
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 |
672
+ #### Environment Resources
673
+ Access environment status and information:
674
+ ```
675
+ d365fo://environment/status # Environment health and connectivity
676
+ d365fo://environment/version # Version information (app, platform, build)
677
+ d365fo://environment/cache # Cache status and statistics V2
678
+ ```
549
679
 
550
- ### Cache Directory Behavior
680
+ #### Query Resources
681
+ Access predefined and templated queries:
682
+ ```
683
+ d365fo://queries/customers_recent # Recent customers query template
684
+ d365fo://queries/sales_summary # Sales summary query with parameters
685
+ ```
551
686
 
552
- By default, the client uses platform-appropriate user cache directories:
687
+ #### Database Resources (New in V2)
688
+ Access metadata database queries:
689
+ ```
690
+ d365fo://database/entities # SQL-based entity searches with FTS5
691
+ d365fo://database/actions # Action discovery with metadata
692
+ d365fo://database/statistics # Cache and performance statistics
693
+ ```
553
694
 
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`)
695
+ ### Usage Examples
557
696
 
558
- You can override this by explicitly setting `metadata_cache_dir`:
697
+ #### Basic Tool Execution
559
698
 
560
- ```python
561
- from d365fo_client import FOClientConfig
699
+ ```json
700
+ {
701
+ "tool": "d365fo_query_entities",
702
+ "arguments": {
703
+ "entityName": "CustomersV3",
704
+ "select": ["CustomerAccount", "Name", "Email"],
705
+ "filter": "CustomerGroup eq 'VIP'",
706
+ "top": 10
707
+ }
708
+ }
709
+ ```
562
710
 
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
- )
711
+ #### Entity Schema Discovery
568
712
 
569
- # Or get the default cache directory programmatically
570
- from d365fo_client import get_user_cache_dir
713
+ ```json
714
+ {
715
+ "tool": "d365fo_get_entity_schema",
716
+ "arguments": {
717
+ "entityName": "CustomersV3",
718
+ "includeProperties": true,
719
+ "resolveLabels": true,
720
+ "language": "en-US"
721
+ }
722
+ }
723
+ ```
571
724
 
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
- )
725
+ #### Environment Information
726
+
727
+ ```json
728
+ {
729
+ "tool": "d365fo_get_environment_info",
730
+ "arguments": {}
731
+ }
577
732
  ```
578
733
 
579
- ## Testing
734
+ ### Authentication & Configuration
580
735
 
581
- This project includes comprehensive testing at multiple levels to ensure reliability and quality.
736
+ #### Default Credentials (Recommended)
737
+ Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
582
738
 
583
- ### Unit Tests
739
+ ```bash
740
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
741
+ # No additional auth environment variables needed
742
+ d365fo-mcp-server
743
+ ```
584
744
 
585
- Run standard unit tests for core functionality:
745
+ #### Explicit Credentials
746
+ For service principal authentication:
586
747
 
587
748
  ```bash
588
- # Run all unit tests
589
- uv run pytest
749
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
750
+ export D365FO_CLIENT_ID="your-client-id"
751
+ export D365FO_CLIENT_SECRET="your-client-secret"
752
+ export D365FO_TENANT_ID="your-tenant-id"
753
+ d365fo-mcp-server
754
+ ```
590
755
 
591
- # Run with coverage
592
- uv run pytest --cov=d365fo_client --cov-report=html
756
+ #### Azure Key Vault Integration (New in v0.2.3)
757
+ For secure credential storage using Azure Key Vault:
593
758
 
594
- # Run specific test file
595
- uv run pytest tests/test_client.py -v
759
+ ```bash
760
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
761
+ export D365FO_CREDENTIAL_SOURCE="keyvault"
762
+ export D365FO_KEYVAULT_URL="https://your-keyvault.vault.azure.net/"
763
+ d365fo-mcp-server
596
764
  ```
597
765
 
598
- ### Integration Tests
766
+ #### Advanced Configuration
599
767
 
600
- The project includes a sophisticated multi-tier integration testing framework:
768
+ **New in v0.3.0**: Comprehensive environment variable management with type safety and validation using Pydantic settings.
601
769
 
602
- #### Quick Start
770
+ Create a configuration file or set additional environment variables:
603
771
 
604
772
  ```bash
605
- # Run sandbox integration tests (recommended)
606
- .\tests\integration\integration-test-simple.ps1 test-sandbox
607
-
608
- # Run mock server tests (no external dependencies)
609
- .\tests\integration\integration-test-simple.ps1 test-mock
773
+ # === Core D365FO Connection Settings ===
774
+ export D365FO_BASE_URL="https://your-environment.dynamics.com"
775
+ export D365FO_CLIENT_ID="your-client-id"
776
+ export D365FO_CLIENT_SECRET="your-client-secret"
777
+ export D365FO_TENANT_ID="your-tenant-id"
610
778
 
611
- # Run with verbose output
612
- .\tests\integration\integration-test-simple.ps1 test-sandbox -VerboseOutput
779
+ # === Logging Configuration ===
780
+ export D365FO_LOG_LEVEL="DEBUG" # DEBUG, INFO, WARNING, ERROR, CRITICAL
781
+ export D365FO_LOG_FILE="/custom/path/server.log" # Custom log file path
782
+
783
+ # === MCP Server Transport Settings (v0.3.0+) ===
784
+ export D365FO_MCP_TRANSPORT="stdio" # stdio, sse, http, streamable-http
785
+ export D365FO_MCP_HTTP_HOST="0.0.0.0" # HTTP host (default: 127.0.0.1)
786
+ export D365FO_MCP_HTTP_PORT="8000" # HTTP port (default: 8000)
787
+ export D365FO_MCP_HTTP_STATELESS="true" # Enable stateless mode
788
+ export D365FO_MCP_HTTP_JSON="true" # Enable JSON response mode
789
+
790
+ # === Cache and Performance Settings ===
791
+ export D365FO_CACHE_DIR="/custom/cache/path" # General cache directory
792
+ export D365FO_META_CACHE_DIR="/custom/metadata/cache" # Metadata cache directory
793
+ export D365FO_LABEL_CACHE="true" # Enable label caching (default: true)
794
+ export D365FO_LABEL_EXPIRY="1440" # Label cache expiry in minutes (24 hours)
795
+ export D365FO_USE_CACHE_FIRST="true" # Use cache before API calls
796
+
797
+ # === Connection and Performance Tuning ===
798
+ export D365FO_TIMEOUT="60" # General timeout in seconds
799
+ export D365FO_MCP_MAX_CONCURRENT_REQUESTS="10" # Max concurrent requests
800
+ export D365FO_MCP_REQUEST_TIMEOUT="30" # Request timeout in seconds
801
+ export D365FO_VERIFY_SSL="true" # Verify SSL certificates
802
+
803
+ # === MCP Authentication Settings (Advanced) ===
804
+ export D365FO_MCP_AUTH_CLIENT_ID="your-mcp-client-id"
805
+ export D365FO_MCP_AUTH_CLIENT_SECRET="your-mcp-client-secret"
806
+ export D365FO_MCP_AUTH_TENANT_ID="your-mcp-tenant-id"
807
+ export D365FO_MCP_AUTH_BASE_URL="http://localhost:8000"
808
+ export D365FO_MCP_AUTH_REQUIRED_SCOPES="User.Read,email,openid,profile"
809
+
810
+ # === Debug Settings ===
811
+ export DEBUG="true" # Enable debug mode
613
812
  ```
614
813
 
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
814
+ **Environment File Support**: You can also create a `.env` file in your project directory with these variables for development convenience.
621
815
 
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
816
+ ## Python Client Library
626
817
 
627
- 3. **Live Tests** - Optional tests against production environments
628
- - Final validation
629
- - Performance benchmarking
630
- - Use with caution
818
+ ### Features
631
819
 
632
- #### Configuration
820
+ - 🔗 **OData Client**: Full CRUD operations on D365 F&O data entities with composite key support
821
+ - 📊 **Metadata Management V2**: Enhanced caching system with intelligent synchronization and FTS5 search
822
+ - 🏷️ **Label Operations V2**: Multilingual label caching with performance improvements and async support
823
+ - 🔍 **Advanced Querying**: Support for all OData query parameters ($select, $filter, $expand, etc.)
824
+ - ⚡ **Action Execution**: Execute bound and unbound OData actions with comprehensive parameter handling
825
+ - 🔒 **Authentication**: Azure AD integration with default credentials, service principal, and Azure Key Vault support
826
+ - 💾 **Intelligent Caching**: Cross-environment cache sharing with module-based version detection
827
+ - 🌐 **Async/Await**: Modern async/await patterns with optimized session management
828
+ - 📝 **Type Hints**: Full type annotation support with enhanced data models
829
+ - 🤖 **MCP Server**: Production-ready Model Context Protocol server with 12 tools and 4 resource types
830
+ - 🖥️ **Comprehensive CLI**: Hierarchical command-line interface for all D365 F&O operations
831
+ - 🧪 **Multi-tier Testing**: Mock, sandbox, and live integration testing framework (17/17 tests passing)
832
+ - 📋 **Metadata Scripts**: PowerShell and Python utilities for entity, enumeration, and action discovery
833
+ - 🔐 **Enhanced Credential Management**: Support for Azure Key Vault and multiple credential sources
834
+ - 📊 **Advanced Sync Management**: Session-based synchronization with detailed progress tracking
835
+ - **🔧 NEW v0.3.0**: Pydantic settings model with type-safe environment variable validation
836
+ - **📂 NEW v0.3.0**: Custom log file path support and flexible logging configuration
837
+ - **🔄 NEW v0.3.0**: Automatic legacy configuration migration and compatibility layer
633
838
 
634
- Set up integration testing with environment variables:
839
+ ### Installation
635
840
 
636
841
  ```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
646
- ```
647
-
648
- #### Available Commands
842
+ # Install from PyPI
843
+ pip install d365fo-client
649
844
 
650
- ```bash
651
- # Test environment setup
652
- .\tests\integration\integration-test-simple.ps1 setup
845
+ # Or install from source
846
+ git clone https://github.com/mafzaal/d365fo-client.git
847
+ cd d365fo-client
848
+ uv sync # Installs with exact dependencies from uv.lock
653
849
 
654
- # Dependency checking
655
- .\tests\integration\integration-test-simple.ps1 deps-check
850
+ # Or use Docker (no local installation required)
851
+ docker pull ghcr.io/mafzaal/d365fo-client:latest
852
+
853
+ # Run with Docker
854
+ docker run --rm -it \
855
+ -e D365FO_BASE_URL="https://your-environment.dynamics.com" \
856
+ -e D365FO_CLIENT_ID="your-client-id" \
857
+ -e D365FO_CLIENT_SECRET="your-client-secret" \
858
+ -e D365FO_TENANT_ID="your-tenant-id" \
859
+ -v d365fo-mcp:/home/mcp_user/ \
860
+ ghcr.io/mafzaal/d365fo-client:latest
861
+ ```
656
862
 
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
863
+ **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.
661
864
 
662
- # Coverage and reporting
663
- .\tests\integration\integration-test-simple.ps1 coverage
865
+ **Breaking Change in v0.2.3**: Environment variable names have been updated for consistency:
866
+ - `AZURE_CLIENT_ID` → `D365FO_CLIENT_ID`
867
+ - `AZURE_CLIENT_SECRET` → `D365FO_CLIENT_SECRET`
868
+ - `AZURE_TENANT_ID` → `D365FO_TENANT_ID`
664
869
 
665
- # Clean up test artifacts
666
- .\tests\integration\integration-test-simple.ps1 clean
667
- ```
870
+ Please update your environment variables accordingly when upgrading.
668
871
 
669
- #### Test Coverage
872
+ ## Python Client Quick Start
670
873
 
671
- Integration tests cover:
874
+ ## Command Line Interface (CLI)
672
875
 
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
876
+ 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.
679
877
 
680
- For detailed information, see [Integration Testing Documentation](tests/integration/README.md).
878
+ ### Usage
681
879
 
682
- ### Test Results
880
+ ```bash
881
+ # Use the installed CLI command
882
+ d365fo-client [GLOBAL_OPTIONS] COMMAND [SUBCOMMAND] [OPTIONS]
683
883
 
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
884
+ # Alternative: Module execution
885
+ python -m d365fo_client.main [OPTIONS] COMMAND [ARGS]
705
886
  ```
706
887
 
707
- ## Model Context Protocol (MCP) Server
708
-
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.
710
-
711
- ### Overview
888
+ ### Command Categories
712
889
 
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
890
+ #### Entity Operations
891
+ ```bash
892
+ # List entities with filtering
893
+ d365fo-client entities list --pattern "customer" --limit 10
720
894
 
721
- ### Quick Start
895
+ # Get entity details and schema
896
+ d365fo-client entities get CustomersV3 --properties --keys --labels
722
897
 
723
- #### Installation and Setup
898
+ # CRUD operations
899
+ d365fo-client entities create Customers --data '{"CustomerAccount":"US-999","Name":"Test"}'
900
+ d365fo-client entities update Customers US-999 --data '{"Name":"Updated Name"}'
901
+ d365fo-client entities delete Customers US-999
902
+ ```
724
903
 
904
+ #### Metadata Operations
725
905
  ```bash
726
- # Install d365fo-client with MCP dependencies
727
- pip install d365fo-client
906
+ # Search and discover entities
907
+ d365fo-client metadata entities --search "sales" --output json
728
908
 
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
909
+ # Get available actions
910
+ d365fo-client metadata actions --pattern "calculate" --limit 5
734
911
 
735
- # Start the MCP server
736
- d365fo-mcp-server
737
- ```
912
+ # Enumerate system enumerations
913
+ d365fo-client metadata enums --search "status" --output table
738
914
 
739
- #### Alternative: Programmatic Usage
915
+ # Synchronize metadata cache
916
+ d365fo-client metadata sync --force-refresh
917
+ ```
740
918
 
741
- ```python
742
- from d365fo_client.mcp import D365FOMCPServer
919
+ #### Version Information
920
+ ```bash
921
+ # Get application versions
922
+ d365fo-client version app
923
+ d365fo-client version platform
924
+ d365fo-client version build
925
+ ```
743
926
 
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
- }
927
+ #### Label Operations
928
+ ```bash
929
+ # Resolve single label
930
+ d365fo-client labels resolve "@SYS13342"
751
931
 
752
- server = D365FOMCPServer(config)
753
- await server.run()
932
+ # Search labels by pattern
933
+ d365fo-client labels search "customer" --language "en-US"
754
934
  ```
755
935
 
756
- ### MCP Tools
936
+ ### Global Options
757
937
 
758
- The server provides 12 comprehensive tools organized into functional categories:
938
+ - `--base-url URL` Specify D365 F&O environment URL
939
+ - `--profile NAME` — Use named configuration profile
940
+ - `--output FORMAT` — Output format: json, table, csv, yaml (default: table)
941
+ - `--verbose` — Enable verbose output for debugging
942
+ - `--timeout SECONDS` — Request timeout (default: 30)
759
943
 
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
944
+ ### Configuration Profiles
763
945
 
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
946
+ Create reusable configurations in `~/.d365fo-client/config.yaml`:
770
947
 
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
948
+ ```yaml
949
+ profiles:
950
+ production:
951
+ base_url: "https://prod.dynamics.com"
952
+ use_default_credentials: true
953
+ timeout: 60
954
+
955
+ development:
956
+ base_url: "https://dev.dynamics.com"
957
+ client_id: "${D365FO_CLIENT_ID}"
958
+ client_secret: "${D365FO_CLIENT_SECRET}"
959
+ tenant_id: "${D365FO_TENANT_ID}"
960
+ use_cache_first: true
777
961
 
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
962
+ default_profile: "development"
963
+ ```
781
964
 
782
- ### MCP Resources
965
+ ### Examples
783
966
 
784
- The server exposes four types of resources for discovery and access:
967
+ ```bash
968
+ # Quick entity discovery
969
+ d365fo-client entities list --pattern "cust.*" --output json
785
970
 
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
- ```
971
+ # Get comprehensive entity information
972
+ d365fo-client entities get CustomersV3 --properties --keys --labels --output yaml
793
973
 
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
- ```
974
+ # Search for calculation actions
975
+ d365fo-client metadata actions --pattern "calculate|compute" --output table
802
976
 
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
977
+ # Test environment connectivity
978
+ d365fo-client version app --verbose
809
979
  ```
810
980
 
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
- ```
981
+ For a complete command reference:
817
982
 
818
- #### Database Resources (New in V2)
819
- Access metadata database queries:
820
- ```
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
983
+ ```bash
984
+ d365fo-client --help
985
+ d365fo-client entities --help
986
+ d365fo-client metadata --help
824
987
  ```
988
+ ### Basic Usage
825
989
 
826
- ### Usage Examples
990
+ ```python
991
+ import asyncio
992
+ from d365fo_client import D365FOClient, FOClientConfig
827
993
 
828
- #### Basic Tool Execution
994
+ async def main():
995
+ # Simple configuration with default credentials
996
+ config = FOClientConfig(
997
+ base_url="https://your-fo-environment.dynamics.com",
998
+ use_default_credentials=True # Uses Azure Default Credential
999
+ )
1000
+
1001
+ async with D365FOClient(config) as client:
1002
+ # Test connection
1003
+ if await client.test_connection():
1004
+ print("✅ Connected successfully!")
1005
+
1006
+ # Get environment information
1007
+ env_info = await client.get_environment_info()
1008
+ print(f"Environment: {env_info.application_version}")
1009
+
1010
+ # Search for entities (uses metadata cache v2)
1011
+ customer_entities = await client.search_entities("customer")
1012
+ print(f"Found {len(customer_entities)} customer entities")
1013
+
1014
+ # Get customers with query options
1015
+ from d365fo_client import QueryOptions
1016
+ options = QueryOptions(
1017
+ select=["CustomerAccount", "Name", "SalesCurrencyCode"],
1018
+ top=10,
1019
+ orderby=["Name"]
1020
+ )
1021
+
1022
+ customers = await client.get_data("/data/CustomersV3", options)
1023
+ print(f"Retrieved {len(customers['value'])} customers")
829
1024
 
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
- }
1025
+ if __name__ == "__main__":
1026
+ asyncio.run(main())
840
1027
  ```
841
1028
 
842
- #### Entity Schema Discovery
1029
+ ### Using Convenience Function
843
1030
 
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
- }
1031
+ ```python
1032
+ from d365fo_client import create_client
1033
+
1034
+ # Quick client creation with enhanced defaults
1035
+ async with create_client("https://your-fo-environment.dynamics.com") as client:
1036
+ customers = await client.get_data("/data/CustomersV3", top=5)
854
1037
  ```
855
1038
 
856
- #### Environment Information
1039
+ ## Configuration
857
1040
 
858
- ```json
859
- {
860
- "tool": "d365fo_get_environment_info",
861
- "arguments": {}
862
- }
1041
+ ### Environment Variable Management (New in v0.3.0)
1042
+
1043
+ The d365fo-client now includes a comprehensive **Pydantic settings model** for type-safe environment variable management:
1044
+
1045
+ ```python
1046
+ from d365fo_client import D365FOSettings, get_settings
1047
+
1048
+ # Get type-safe settings instance
1049
+ settings = get_settings()
1050
+
1051
+ # Access settings with full IntelliSense support
1052
+ print(f"Base URL: {settings.base_url}")
1053
+ print(f"Log Level: {settings.log_level}")
1054
+ print(f"Cache Directory: {settings.cache_dir}")
1055
+
1056
+ # Check configuration state
1057
+ if settings.has_client_credentials():
1058
+ print("Client credentials configured")
1059
+
1060
+ startup_mode = settings.get_startup_mode() # "profile_only", "default_auth", "client_credentials"
1061
+
1062
+ # Convert to environment dictionary for external tools
1063
+ env_vars = settings.to_env_dict()
863
1064
  ```
864
1065
 
865
- ### Authentication & Configuration
1066
+ **Key Benefits:**
1067
+ - **Type Safety**: Automatic validation and type conversion for all 35+ environment variables
1068
+ - **IDE Support**: Full IntelliSense and autocompletion for configuration options
1069
+ - **Environment Files**: Support for `.env` files in development
1070
+ - **Comprehensive Defaults**: Sensible defaults for all configuration options
1071
+ - **Validation**: Built-in validation for URLs, ports, timeouts, and other settings
866
1072
 
867
- #### Default Credentials (Recommended)
868
- Uses Azure Default Credential chain (Managed Identity, Azure CLI, etc.):
1073
+ ### Authentication Options
869
1074
 
870
- ```bash
871
- export D365FO_BASE_URL="https://your-environment.dynamics.com"
872
- # No additional auth environment variables needed
873
- d365fo-mcp-server
1075
+ ```python
1076
+ from d365fo_client import FOClientConfig
1077
+
1078
+ # Option 1: Default Azure credentials (recommended)
1079
+ config = FOClientConfig(
1080
+ base_url="https://your-fo-environment.dynamics.com",
1081
+ use_default_credentials=True
1082
+ )
1083
+
1084
+ # Option 2: Client credentials
1085
+ config = FOClientConfig(
1086
+ base_url="https://your-fo-environment.dynamics.com",
1087
+ client_id="your-client-id",
1088
+ client_secret="your-client-secret",
1089
+ tenant_id="your-tenant-id",
1090
+ use_default_credentials=False
1091
+ )
1092
+
1093
+ # Option 3: Azure Key Vault integration (New in v0.2.3)
1094
+ config = FOClientConfig(
1095
+ base_url="https://your-fo-environment.dynamics.com",
1096
+ credential_source="keyvault", # Use Azure Key Vault for credentials
1097
+ keyvault_url="https://your-keyvault.vault.azure.net/"
1098
+ )
1099
+
1100
+ # Option 4: With custom settings
1101
+ config = FOClientConfig(
1102
+ base_url="https://your-fo-environment.dynamics.com",
1103
+ use_default_credentials=True,
1104
+ verify_ssl=False, # For development environments
1105
+ timeout=60, # Request timeout in seconds
1106
+ metadata_cache_dir="./my_cache", # Custom cache directory
1107
+ use_label_cache=True, # Enable label caching
1108
+ label_cache_expiry_minutes=120 # Cache for 2 hours
1109
+ )
874
1110
  ```
875
1111
 
876
- #### Explicit Credentials
877
- For service principal authentication:
1112
+ ### Legacy Configuration Migration (New in v0.3.0)
1113
+
1114
+ The d365fo-client automatically detects and migrates legacy configuration files:
1115
+
1116
+ - **Automatic Detection**: Identifies legacy configuration patterns (missing `verify_ssl`, outdated field names)
1117
+ - **Field Migration**: Updates `cache_dir` → `metadata_cache_dir`, `auth_mode` → `use_default_credentials`
1118
+ - **Backup Creation**: Creates backup of original configuration before migration
1119
+ - **Seamless Upgrade**: Ensures smooth transition from older versions without manual intervention
1120
+
1121
+ ```python
1122
+ # Legacy configurations are automatically migrated when FastMCP server starts
1123
+ # No manual intervention required - migration happens transparently
1124
+ ```
1125
+
1126
+ ## Core Operations
1127
+
1128
+ ### CRUD Operations
1129
+
1130
+ ```python
1131
+ async with D365FOClient(config) as client:
1132
+ # CREATE - Create new customer (supports composite keys)
1133
+ new_customer = {
1134
+ "CustomerAccount": "US-999",
1135
+ "Name": "Test Customer",
1136
+ "SalesCurrencyCode": "USD"
1137
+ }
1138
+ created = await client.create_data("/data/CustomersV3", new_customer)
1139
+
1140
+ # READ - Get single customer by key
1141
+ customer = await client.get_data("/data/CustomersV3('US-001')")
1142
+
1143
+ # UPDATE - Update customer with optimistic concurrency
1144
+ updates = {"Name": "Updated Customer Name"}
1145
+ updated = await client.update_data("/data/CustomersV3('US-001')", updates)
1146
+
1147
+ # DELETE - Delete customer
1148
+ success = await client.delete_data("/data/CustomersV3('US-999')")
1149
+ print(f"Delete successful: {success}")
1150
+ ```
1151
+
1152
+ ### Advanced Querying
1153
+
1154
+ ```python
1155
+ from d365fo_client import QueryOptions
1156
+
1157
+ # Complex query with multiple options
1158
+ options = QueryOptions(
1159
+ select=["CustomerAccount", "Name", "SalesCurrencyCode", "CustomerGroupId"],
1160
+ filter="SalesCurrencyCode eq 'USD' and contains(Name, 'Corp')",
1161
+ expand=["CustomerGroup"],
1162
+ orderby=["Name desc", "CustomerAccount"],
1163
+ top=50,
1164
+ skip=10,
1165
+ count=True
1166
+ )
1167
+
1168
+ result = await client.get_data("/data/CustomersV3", options)
1169
+ print(f"Total count: {result.get('@odata.count')}")
1170
+ ```
1171
+
1172
+ ### Action Execution
1173
+
1174
+ ```python
1175
+ # Unbound action
1176
+ result = await client.post_data("/data/calculateTax", {
1177
+ "amount": 1000.00,
1178
+ "taxGroup": "STANDARD"
1179
+ })
1180
+
1181
+ # Bound action on entity set
1182
+ result = await client.post_data("/data/CustomersV3/calculateBalances", {
1183
+ "asOfDate": "2024-12-31"
1184
+ })
1185
+
1186
+ # Bound action on specific entity instance
1187
+ result = await client.post_data("/data/CustomersV3('US-001')/calculateBalance", {
1188
+ "asOfDate": "2024-12-31"
1189
+ })
1190
+ ```
1191
+
1192
+ ### Metadata Operations
1193
+
1194
+ ```python
1195
+ # Intelligent metadata synchronization (v2 system)
1196
+ sync_manager = await client.get_sync_manager()
1197
+ await sync_manager.smart_sync()
1198
+
1199
+ # Search entities with enhanced filtering
1200
+ sales_entities = await client.search_entities("sales")
1201
+ print("Sales-related entities:", [e.name for e in sales_entities])
1202
+
1203
+ # Get detailed entity information with labels
1204
+ entity_info = await client.get_public_entity_info("CustomersV3")
1205
+ if entity_info:
1206
+ print(f"Entity: {entity_info.name}")
1207
+ print(f"Label: {entity_info.label_text}")
1208
+ print(f"Data Service Enabled: {entity_info.data_service_enabled}")
1209
+
1210
+ # Search actions with caching
1211
+ calc_actions = await client.search_actions("calculate")
1212
+ print("Calculation actions:", [a.name for a in calc_actions])
1213
+
1214
+ # Get enumeration information
1215
+ enum_info = await client.get_public_enumeration_info("NoYes")
1216
+ if enum_info:
1217
+ print(f"Enum: {enum_info.name}")
1218
+ for member in enum_info.members:
1219
+ print(f" {member.name} = {member.value}")
1220
+ ```
1221
+
1222
+ ### Label Operations
1223
+
1224
+ ```python
1225
+ # Get specific label (v2 caching system)
1226
+ label_text = await client.get_label_text("@SYS13342")
1227
+ print(f"Label text: {label_text}")
1228
+
1229
+ # Get multiple labels efficiently
1230
+ labels = await client.get_labels_batch([
1231
+ "@SYS13342", "@SYS9490", "@GLS63332"
1232
+ ])
1233
+ for label_id, text in labels.items():
1234
+ print(f"{label_id}: {text}")
1235
+
1236
+ # Enhanced entity info with resolved labels
1237
+ entity_info = await client.get_public_entity_info_with_labels("CustomersV3")
1238
+ if entity_info.label_text:
1239
+ print(f"Entity display name: {entity_info.label_text}")
1240
+
1241
+ # Access enhanced properties with labels
1242
+ for prop in entity_info.enhanced_properties[:5]:
1243
+ if hasattr(prop, 'label_text') and prop.label_text:
1244
+ print(f"{prop.name}: {prop.label_text}")
1245
+ ```
1246
+
1247
+ ## Error Handling
1248
+
1249
+ ```python
1250
+ from d365fo_client import D365FOClientError, AuthenticationError, ConnectionError
1251
+
1252
+ try:
1253
+ async with D365FOClient(config) as client:
1254
+ customer = await client.get_data("/data/CustomersV3('NON-EXISTENT')")
1255
+ except ConnectionError as e:
1256
+ print(f"Connection failed: {e}")
1257
+ except AuthenticationError as e:
1258
+ print(f"Authentication failed: {e}")
1259
+ except D365FOClientError as e:
1260
+ print(f"Client operation failed: {e}")
1261
+ print(f"Status code: {e.status_code}")
1262
+ print(f"Response: {e.response_text}")
1263
+ ```
1264
+
1265
+ ## Development
1266
+
1267
+ ### Setting up Development Environment
878
1268
 
879
1269
  ```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
1270
+ # Clone the repository
1271
+ git clone https://github.com/mafzaal/d365fo-client.git
1272
+ cd d365fo-client
1273
+
1274
+ # Install with development dependencies using uv
1275
+ uv sync --dev
1276
+
1277
+ # Run tests
1278
+ uv run pytest
1279
+
1280
+ # Run integration tests
1281
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1282
+
1283
+ # Format code
1284
+ uv run black .
1285
+ uv run isort .
1286
+
1287
+ # Type checking
1288
+ uv run mypy src/
1289
+
1290
+ # Quality checks
1291
+ .\make.ps1 quality-check # Windows PowerShell
1292
+ # or
1293
+ make quality-check # Unix/Linux/macOS
885
1294
  ```
886
1295
 
887
- #### Azure Key Vault Integration (New in v0.2.3)
888
- For secure credential storage using Azure Key Vault:
1296
+ ### Project Structure
1297
+
1298
+ ```
1299
+ d365fo-client/
1300
+ ├── src/
1301
+ │ └── d365fo_client/
1302
+ │ ├── __init__.py # Public API exports
1303
+ │ ├── main.py # CLI entry point
1304
+ │ ├── cli.py # CLI command handlers
1305
+ │ ├── client.py # Enhanced D365FOClient class
1306
+ │ ├── config.py # Configuration management
1307
+ │ ├── auth.py # Authentication management
1308
+ │ ├── session.py # HTTP session management
1309
+ │ ├── crud.py # CRUD operations
1310
+ │ ├── query.py # OData query utilities
1311
+ │ ├── metadata.py # Legacy metadata operations
1312
+ │ ├── metadata_api.py # Metadata API client
1313
+ │ ├── metadata_cache.py # Metadata caching layer V2
1314
+ │ ├── metadata_sync.py # Metadata synchronization V2 with session management
1315
+ │ ├── sync_session.py # Enhanced sync session management (New in v0.2.3)
1316
+ │ ├── credential_manager.py # Credential source management (New in v0.2.3)
1317
+ │ ├── labels.py # Label operations V2
1318
+ │ ├── profiles.py # Profile data models
1319
+ │ ├── profile_manager.py # Profile management
1320
+ │ ├── models.py # Data models and configurations
1321
+ │ ├── output.py # Output formatting
1322
+ │ ├── utils.py # Utility functions
1323
+ │ ├── exceptions.py # Custom exceptions
1324
+ │ └── mcp/ # Model Context Protocol server
1325
+ │ ├── __init__.py # MCP server exports
1326
+ │ ├── main.py # MCP server entry point
1327
+ │ ├── server.py # Core MCP server implementation
1328
+ │ ├── client_manager.py# D365FO client connection pooling
1329
+ │ ├── models.py # MCP-specific data models
1330
+ │ ├── tools/ # MCP tool implementations (12 tools)
1331
+ │ │ ├── connection_tools.py
1332
+ │ │ ├── crud_tools.py
1333
+ │ │ ├── metadata_tools.py
1334
+ │ │ └── label_tools.py
1335
+ │ ├── resources/ # MCP resource handlers (4 types)
1336
+ │ │ ├── entity_handler.py
1337
+ │ │ ├── metadata_handler.py
1338
+ │ │ ├── environment_handler.py
1339
+ │ │ └── query_handler.py
1340
+ │ └── prompts/ # MCP prompt templates
1341
+ ├── tests/ # Comprehensive test suite
1342
+ │ ├── unit/ # Unit tests (pytest-based)
1343
+ │ ├── integration/ # Multi-tier integration testing
1344
+ │ │ ├── mock_server/ # Mock D365 F&O API server
1345
+ │ │ ├── test_mock_server.py # Mock server tests
1346
+ │ │ ├── test_sandbox.py # Sandbox environment tests ✅
1347
+ │ │ ├── test_live.py # Live environment tests
1348
+ │ │ ├── conftest.py # Shared pytest fixtures
1349
+ │ │ ├── test_runner.py # Python test execution engine
1350
+ │ │ └── integration-test-simple.ps1 # PowerShell automation
1351
+ │ └── test_mcp_server.py # MCP server unit tests ✅
1352
+ ├── scripts/ # Metadata discovery scripts
1353
+ │ ├── search_data_entities.ps1 # PowerShell entity search
1354
+ │ ├── get_data_entity_schema.ps1 # PowerShell schema retrieval
1355
+ │ ├── search_enums.py # Python enumeration search
1356
+ │ ├── get_enumeration_info.py # Python enumeration info
1357
+ │ ├── search_actions.ps1 # PowerShell action search
1358
+ │ └── get_action_info.py # Python action information
1359
+ ├── docs/ # Comprehensive documentation
1360
+ ├── pyproject.toml # Project configuration
1361
+ └── README.md # This file
1362
+ ```
1363
+
1364
+ ## Configuration Options
1365
+
1366
+ | Option | Type | Default | Description |
1367
+ |--------|------|---------|-------------|
1368
+ | `base_url` | str | Required | D365 F&O base URL |
1369
+ | `client_id` | str | None | Azure AD client ID |
1370
+ | `client_secret` | str | None | Azure AD client secret |
1371
+ | `tenant_id` | str | None | Azure AD tenant ID |
1372
+ | `use_default_credentials` | bool | True | Use Azure Default Credential |
1373
+ | `credential_source` | str | "environment" | Credential source: "environment", "keyvault" |
1374
+ | `keyvault_url` | str | None | Azure Key Vault URL for credential storage |
1375
+ | `verify_ssl` | bool | False | Verify SSL certificates |
1376
+ | `timeout` | int | 30 | Request timeout in seconds |
1377
+ | `metadata_cache_dir` | str | Platform-specific user cache | Metadata cache directory |
1378
+ | `use_label_cache` | bool | True | Enable label caching V2 |
1379
+ | `label_cache_expiry_minutes` | int | 60 | Label cache expiry time |
1380
+ | `use_cache_first` | bool | False | Enable cache-first mode with background sync |
1381
+
1382
+ ### Cache Directory Behavior
1383
+
1384
+ By default, the client uses platform-appropriate user cache directories:
889
1385
 
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
- ```
1386
+ - **Windows**: `%LOCALAPPDATA%\d365fo-client` (e.g., `C:\Users\username\AppData\Local\d365fo-client`)
1387
+ - **macOS**: `~/Library/Caches/d365fo-client` (e.g., `/Users/username/Library/Caches/d365fo-client`)
1388
+ - **Linux**: `~/.cache/d365fo-client` (e.g., `/home/username/.cache/d365fo-client`)
896
1389
 
897
- #### Advanced Configuration
1390
+ You can override this by explicitly setting `metadata_cache_dir`:
898
1391
 
899
- Create a configuration file or set additional environment variables:
1392
+ ```python
1393
+ from d365fo_client import FOClientConfig
900
1394
 
901
- ```bash
902
- # Optional: Logging configuration
903
- export D365FO_LOG_LEVEL="DEBUG"
1395
+ # Use custom cache directory
1396
+ config = FOClientConfig(
1397
+ base_url="https://your-fo-environment.dynamics.com",
1398
+ metadata_cache_dir="/custom/cache/path"
1399
+ )
904
1400
 
905
- # Optional: Cache settings
906
- export D365FO_CACHE_DIR="/custom/cache/path"
1401
+ # Or get the default cache directory programmatically
1402
+ from d365fo_client import get_user_cache_dir
907
1403
 
908
- # Optional: Performance tuning
909
- export D365FO_CONNECTION_TIMEOUT="60"
910
- export D365FO_MAX_CONCURRENT_REQUESTS="10"
1404
+ cache_dir = get_user_cache_dir("my-app") # Platform-appropriate cache dir
1405
+ config = FOClientConfig(
1406
+ base_url="https://your-fo-environment.dynamics.com",
1407
+ metadata_cache_dir=str(cache_dir)
1408
+ )
911
1409
  ```
912
1410
 
913
- ### Integration with AI Assistants
1411
+ ## Testing
914
1412
 
915
- The MCP server seamlessly integrates with AI assistants and development tools:
1413
+ This project includes comprehensive testing at multiple levels to ensure reliability and quality.
916
1414
 
917
- #### Claude Desktop Integration
918
- Add to your Claude Desktop configuration:
1415
+ ### Unit Tests
919
1416
 
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
- ```
1417
+ Run standard unit tests for core functionality:
932
1418
 
933
- #### VS Code Integration
1419
+ ```bash
1420
+ # Run all unit tests
1421
+ uv run pytest
934
1422
 
935
- ##### Option 1: Default Credentials (Recommended)
936
- Add to your VS Code `mcp.json` for GitHub Copilot with MCP:
1423
+ # Run with coverage
1424
+ uv run pytest --cov=d365fo_client --cov-report=html
937
1425
 
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
- }
1426
+ # Run specific test file
1427
+ uv run pytest tests/test_client.py -v
956
1428
  ```
957
1429
 
958
- ##### Option 2: Explicit Credentials
959
- For environments requiring service principal authentication:
1430
+ ### Integration Tests
960
1431
 
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
- ```
1432
+ The project includes a sophisticated multi-tier integration testing framework:
1003
1433
 
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
1434
+ #### Quick Start
1009
1435
 
1010
- #### Custom MCP Clients
1011
- Connect using any MCP-compatible client library:
1436
+ ```bash
1437
+ # Run sandbox integration tests (recommended)
1438
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1012
1439
 
1013
- ```python
1014
- from mcp import Client
1440
+ # Run mock server tests (no external dependencies)
1441
+ .\tests\integration\integration-test-simple.ps1 test-mock
1015
1442
 
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
- )
1443
+ # Run with verbose output
1444
+ .\tests\integration\integration-test-simple.ps1 test-sandbox -VerboseOutput
1025
1445
  ```
1026
1446
 
1027
- ### Architecture Benefits
1447
+ #### Test Levels
1028
1448
 
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
1449
+ 1. **Mock Server Tests** - Fast, isolated tests against a simulated D365 F&O API
1450
+ - No external dependencies
1451
+ - Complete API simulation
1452
+ - Ideal for CI/CD pipelines
1034
1453
 
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
1454
+ 2. **Sandbox Tests** ⭐ *(Default)* - Tests against real D365 F&O test environments
1455
+ - Validates authentication
1456
+ - Tests real API behavior
1457
+ - Requires test environment access
1040
1458
 
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
1459
+ 3. **Live Tests** - Optional tests against production environments
1460
+ - Final validation
1461
+ - Performance benchmarking
1462
+ - Use with caution
1046
1463
 
1047
- ### Troubleshooting
1464
+ #### Configuration
1048
1465
 
1049
- #### Common Issues
1466
+ Set up integration testing with environment variables:
1050
1467
 
1051
- **Connection Failures**
1052
1468
  ```bash
1053
- # Test connectivity
1054
- d365fo-client get-version --base-url https://your-environment.dynamics.com
1469
+ # Copy the template and configure
1470
+ cp tests/integration/.env.template tests/integration/.env
1055
1471
 
1056
- # Check logs
1057
- tail -f ~/.d365fo-mcp/logs/mcp-server.log
1472
+ # Edit .env file with your settings:
1473
+ INTEGRATION_TEST_LEVEL=sandbox
1474
+ D365FO_SANDBOX_BASE_URL=https://your-test.dynamics.com
1475
+ D365FO_CLIENT_ID=your-client-id
1476
+ D365FO_CLIENT_SECRET=your-client-secret
1477
+ D365FO_TENANT_ID=your-tenant-id
1058
1478
  ```
1059
1479
 
1060
- **Authentication Issues**
1480
+ #### Available Commands
1481
+
1061
1482
  ```bash
1062
- # Verify Azure CLI authentication
1063
- az account show
1483
+ # Test environment setup
1484
+ .\tests\integration\integration-test-simple.ps1 setup
1064
1485
 
1065
- # Test with explicit credentials
1066
- export D365FO_CLIENT_ID="your-client-id"
1067
- # ... set other variables
1068
- d365fo-mcp-server
1069
- ```
1486
+ # Dependency checking
1487
+ .\tests\integration\integration-test-simple.ps1 deps-check
1070
1488
 
1071
- **Performance Issues**
1072
- ```bash
1073
- # Enable debug logging
1074
- export D365FO_LOG_LEVEL="DEBUG"
1489
+ # Run specific test levels
1490
+ .\tests\integration\integration-test-simple.ps1 test-mock
1491
+ .\tests\integration\integration-test-simple.ps1 test-sandbox
1492
+ .\tests\integration\integration-test-simple.ps1 test-live
1075
1493
 
1076
- # Adjust connection settings
1077
- export D365FO_CONNECTION_TIMEOUT="120"
1078
- export D365FO_MAX_CONCURRENT_REQUESTS="5"
1494
+ # Coverage and reporting
1495
+ .\tests\integration\integration-test-simple.ps1 coverage
1496
+
1497
+ # Clean up test artifacts
1498
+ .\tests\integration\integration-test-simple.ps1 clean
1079
1499
  ```
1080
1500
 
1081
- #### Getting Help
1501
+ #### Test Coverage
1082
1502
 
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)
1503
+ Integration tests cover:
1504
+
1505
+ - **Connection & Authentication** - Azure AD integration, SSL/TLS validation
1506
+ - **Version Methods** - Application, platform, and build version retrieval
1507
+ - ✅ **Metadata Operations** - Entity discovery, metadata API validation
1508
+ - ✅ **Data Operations** - CRUD operations, OData query validation
1509
+ - ✅ **Error Handling** - Network failures, authentication errors, invalid requests
1510
+ - ✅ **Performance** - Response time validation, concurrent operations
1511
+
1512
+ For detailed information, see [Integration Testing Documentation](tests/integration/README.md).
1513
+
1514
+ ### Test Results
1515
+
1516
+ Recent sandbox integration test results:
1517
+ ```
1518
+ ✅ 17 passed, 0 failed, 2 warnings in 37.67s
1519
+ ======================================================
1520
+ ✅ TestSandboxConnection::test_connection_success
1521
+ ✅ TestSandboxConnection::test_metadata_connection_success
1522
+ ✅ TestSandboxVersionMethods::test_get_application_version
1523
+ ✅ TestSandboxVersionMethods::test_get_platform_build_version
1524
+ ✅ TestSandboxVersionMethods::test_get_application_build_version
1525
+ ✅ TestSandboxVersionMethods::test_version_consistency
1526
+ ✅ TestSandboxMetadataOperations::test_download_metadata
1527
+ ✅ TestSandboxMetadataOperations::test_search_entities
1528
+ ✅ TestSandboxMetadataOperations::test_get_data_entities
1529
+ ✅ TestSandboxMetadataOperations::test_get_public_entities
1530
+ ✅ TestSandboxDataOperations::test_get_available_entities
1531
+ ✅ TestSandboxDataOperations::test_odata_query_options
1532
+ ✅ TestSandboxAuthentication::test_authenticated_requests
1533
+ ✅ TestSandboxErrorHandling::test_invalid_entity_error
1534
+ ✅ TestSandboxErrorHandling::test_invalid_action_error
1535
+ ✅ TestSandboxPerformance::test_response_times
1536
+ ✅ TestSandboxPerformance::test_concurrent_operations
1537
+ ```
1087
1538
 
1088
1539
  ## Contributing
1089
1540