d365fo-client 0.1.0__py3-none-any.whl

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