d365fo-client 0.2.2__py3-none-any.whl → 0.2.3__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.
d365fo_client/mcp/main.py CHANGED
@@ -43,28 +43,50 @@ def setup_logging(level: str = "INFO") -> None:
43
43
 
44
44
  def load_config() -> Dict[str, Any]:
45
45
  """Load configuration from environment and config files.
46
+
47
+ Handles three startup scenarios:
48
+ 1. No environment variables: Profile-only mode
49
+ 2. D365FO_BASE_URL only: Default auth mode
50
+ 3. Full variables: Client credentials mode
46
51
 
47
52
  Returns:
48
- Configuration dictionary
53
+ Configuration dictionary with startup_mode indicator
49
54
  """
50
55
  config = {}
51
-
52
- # Load from environment variables
53
- if base_url := os.getenv("D365FO_BASE_URL"):
56
+
57
+ # Get environment variables
58
+ base_url = os.getenv("D365FO_BASE_URL")
59
+ client_id = os.getenv("D365FO_CLIENT_ID")
60
+ client_secret = os.getenv("D365FO_CLIENT_SECRET")
61
+ tenant_id = os.getenv("D365FO_TENANT_ID")
62
+
63
+ # Determine startup mode based on available environment variables
64
+ if not base_url:
65
+ # Scenario 1: No environment variables - profile-only mode
66
+ config["startup_mode"] = "profile_only"
67
+ config["has_base_url"] = False
68
+ logging.info("Startup mode: profile-only (no D365FO_BASE_URL provided)")
69
+
70
+ elif base_url and not (client_id and client_secret and tenant_id):
71
+ # Scenario 2: Only base URL - default authentication
72
+ config["startup_mode"] = "default_auth"
73
+ config["has_base_url"] = True
54
74
  config.setdefault("default_environment", {})["base_url"] = base_url
55
-
56
- if client_id := os.getenv("AZURE_CLIENT_ID"):
57
- config.setdefault("default_environment", {})["client_id"] = client_id
58
- config["default_environment"]["use_default_credentials"] = False
59
-
60
- if client_secret := os.getenv("AZURE_CLIENT_SECRET"):
61
- config.setdefault("default_environment", {})["client_secret"] = client_secret
62
-
63
- if tenant_id := os.getenv("AZURE_TENANT_ID"):
64
- config.setdefault("default_environment", {})["tenant_id"] = tenant_id
65
-
66
- # Check if D365FO_BASE_URL is configured for startup behavior
67
- config["has_base_url"] = bool(os.getenv("D365FO_BASE_URL"))
75
+ config["default_environment"]["use_default_credentials"] = True
76
+ logging.info("Startup mode: default authentication (D365FO_BASE_URL provided)")
77
+
78
+ else:
79
+ # Scenario 3: Full credentials - client credentials authentication
80
+ config["startup_mode"] = "client_credentials"
81
+ config["has_base_url"] = True
82
+ config.setdefault("default_environment", {}).update({
83
+ "base_url": base_url,
84
+ "client_id": client_id,
85
+ "client_secret": client_secret,
86
+ "tenant_id": tenant_id,
87
+ "use_default_credentials": False
88
+ })
89
+ logging.info("Startup mode: client credentials (full D365FO environment variables provided)")
68
90
 
69
91
  return config
70
92
 
@@ -8,6 +8,8 @@ from typing import Any, Dict, List, Optional
8
8
  from mcp import GetPromptResult, Resource, Tool
9
9
  from mcp.server import InitializationOptions, Server
10
10
 
11
+ from d365fo_client.credential_sources import CredentialSource, EnvironmentCredentialSource
12
+
11
13
  from .. import __version__
12
14
  from ..profile_manager import ProfileManager
13
15
  from mcp.server.lowlevel.server import NotificationOptions
@@ -23,7 +25,7 @@ from .resources import (
23
25
  MetadataResourceHandler,
24
26
  QueryResourceHandler,
25
27
  )
26
- from .tools import ConnectionTools, CrudTools, DatabaseTools, LabelTools, MetadataTools, ProfileTools
28
+ from .tools import ConnectionTools, CrudTools, DatabaseTools, LabelTools, MetadataTools, ProfileTools, SyncTools
27
29
 
28
30
  logger = logging.getLogger(__name__)
29
31
 
@@ -56,6 +58,7 @@ class D365FOMCPServer:
56
58
  self.label_tools = LabelTools(self.client_manager)
57
59
  self.profile_tools = ProfileTools(self.client_manager)
58
60
  self.database_tools = DatabaseTools(self.client_manager)
61
+ self.sync_tools = SyncTools(self.client_manager)
59
62
 
60
63
  # Tool registry for execution
61
64
  self.tool_registry = {}
@@ -215,6 +218,10 @@ class D365FOMCPServer:
215
218
  database_tools = self.database_tools.get_tools()
216
219
  tools.extend(database_tools)
217
220
 
221
+ # Add sync tools
222
+ sync_tools = self.sync_tools.get_tools()
223
+ tools.extend(sync_tools)
224
+
218
225
  # Register tools for execution
219
226
  for tool in tools:
220
227
  self.tool_registry[tool.name] = tool
@@ -310,6 +317,16 @@ class D365FOMCPServer:
310
317
  return await self.database_tools.execute_get_table_info(arguments)
311
318
  elif name == "d365fo_get_database_statistics":
312
319
  return await self.database_tools.execute_get_database_statistics(arguments)
320
+ elif name == "d365fo_start_sync":
321
+ return await self.sync_tools.execute_start_sync(arguments)
322
+ elif name == "d365fo_get_sync_progress":
323
+ return await self.sync_tools.execute_get_sync_progress(arguments)
324
+ elif name == "d365fo_cancel_sync":
325
+ return await self.sync_tools.execute_cancel_sync(arguments)
326
+ elif name == "d365fo_list_sync_sessions":
327
+ return await self.sync_tools.execute_list_sync_sessions(arguments)
328
+ elif name == "d365fo_get_sync_history":
329
+ return await self.sync_tools.execute_get_sync_history(arguments)
313
330
  else:
314
331
  raise ValueError(f"Unknown tool: {name}")
315
332
 
@@ -358,24 +375,34 @@ class D365FOMCPServer:
358
375
  async def _startup_initialization(self):
359
376
  """Perform startup initialization based on configuration."""
360
377
  try:
361
- # Check if D365FO_BASE_URL is configured
362
- has_base_url = self.config.get("has_base_url", False)
378
+ startup_mode = self.config.get("startup_mode", "profile_only")
363
379
 
364
- if has_base_url:
365
- logger.info("D365FO_BASE_URL environment variable detected - performing health checks and profile setup")
380
+ if startup_mode == "profile_only":
381
+ logger.info("Server started in profile-only mode")
382
+ logger.info("No environment variables configured - use profile management tools to configure D365FO connections")
383
+
384
+ elif startup_mode == "default_auth":
385
+ logger.info("Server started with default authentication mode")
386
+ logger.info("D365FO_BASE_URL configured - performing health checks and creating default profile with default auth")
366
387
 
367
- # Perform health checks
388
+ # Perform health checks and create default profile
368
389
  await self._startup_health_checks()
390
+ await self._create_default_profile_if_needed()
391
+
392
+ elif startup_mode == "client_credentials":
393
+ logger.info("Server started with client credentials authentication mode")
394
+ logger.info("Full D365FO environment variables configured - performing health checks and creating default profile with client credentials")
369
395
 
370
- # Create default profile if environment variables are configured
396
+ # Perform health checks and create default profile
397
+ await self._startup_health_checks()
371
398
  await self._create_default_profile_if_needed()
399
+
372
400
  else:
373
- logger.info("D365FO_BASE_URL not configured - server started in profile-only mode")
374
- logger.info("Use profile management tools to configure D365FO connections")
401
+ logger.warning(f"Unknown startup mode: {startup_mode}")
375
402
 
376
403
  except Exception as e:
377
404
  logger.error(f"Startup initialization failed: {e}")
378
- # Don't fail startup on initialization failures
405
+ # Don't fail startup on initialization failures - allow server to start in profile-only mode
379
406
 
380
407
  async def _create_default_profile_if_needed(self):
381
408
  """Create a default profile from environment variables if needed."""
@@ -386,20 +413,30 @@ class D365FOMCPServer:
386
413
  logger.info(f"Default profile already exists: {existing_default.name}")
387
414
  return
388
415
 
389
- # Get environment variables
416
+ # Get environment variables with correct names
390
417
  base_url = os.getenv("D365FO_BASE_URL")
391
- client_id = os.getenv("AZURE_CLIENT_ID")
392
- client_secret = os.getenv("AZURE_CLIENT_SECRET")
393
- tenant_id = os.getenv("AZURE_TENANT_ID")
418
+ client_id = os.getenv("D365FO_CLIENT_ID")
419
+ client_secret = os.getenv("D365FO_CLIENT_SECRET")
420
+ tenant_id = os.getenv("D365FO_TENANT_ID")
394
421
 
395
422
  if not base_url:
396
423
  logger.warning("Cannot create default profile - D365FO_BASE_URL not set")
397
424
  return
398
425
 
399
- # Determine authentication mode
400
- auth_mode = "default"
401
- if client_id and client_secret and tenant_id:
426
+ # Determine authentication mode based on startup mode
427
+ startup_mode = self.config.get("startup_mode", "profile_only")
428
+
429
+ if startup_mode == "client_credentials":
402
430
  auth_mode = "client_credentials"
431
+ if not all([client_id, client_secret, tenant_id]):
432
+ logger.error("Client credentials mode requires D365FO_CLIENT_ID, D365FO_CLIENT_SECRET, and D365FO_TENANT_ID")
433
+ return
434
+ else:
435
+ auth_mode = "default"
436
+ # Clear client credentials for default auth mode
437
+ client_id = None
438
+ client_secret = None
439
+ tenant_id = None
403
440
 
404
441
  # Create default profile with unique name
405
442
  profile_name = "default-from-env"
@@ -411,17 +448,22 @@ class D365FOMCPServer:
411
448
  self.profile_manager.set_default_profile(profile_name)
412
449
  return
413
450
 
451
+ credential_source = None
452
+ if startup_mode == "client_credentials":
453
+ credential_source = EnvironmentCredentialSource()
454
+
414
455
  success = self.profile_manager.create_profile(
415
456
  name=profile_name,
416
457
  base_url=base_url,
417
458
  auth_mode=auth_mode,
418
- client_id=client_id,
419
- client_secret=client_secret,
420
- tenant_id=tenant_id,
421
- description="Auto-created from environment variables at startup",
459
+ client_id=None, #use from env var
460
+ client_secret=None, #use from env var
461
+ tenant_id=None, #use from env var
462
+ description=f"Auto-created from environment variables at startup (mode: {startup_mode})",
422
463
  use_label_cache=True,
423
464
  timeout=60,
424
- verify_ssl=True
465
+ verify_ssl=True,
466
+ credential_source=credential_source
425
467
  )
426
468
 
427
469
  if success:
@@ -430,6 +472,11 @@ class D365FOMCPServer:
430
472
  logger.info(f"Created and set default profile: {profile_name}")
431
473
  logger.info(f"Profile configured for: {base_url}")
432
474
  logger.info(f"Authentication mode: {auth_mode}")
475
+
476
+ if auth_mode == "client_credentials":
477
+ logger.info(f"Client ID: {client_id}")
478
+ logger.info(f"Tenant ID: {tenant_id}")
479
+
433
480
  else:
434
481
  logger.warning(f"Failed to create default profile: {profile_name}")
435
482
 
@@ -6,6 +6,7 @@ from .database_tools import DatabaseTools
6
6
  from .label_tools import LabelTools
7
7
  from .metadata_tools import MetadataTools
8
8
  from .profile_tools import ProfileTools
9
+ from .sync_tools import SyncTools
9
10
 
10
11
  __all__ = [
11
12
  "ConnectionTools",
@@ -14,4 +15,5 @@ __all__ = [
14
15
  "LabelTools",
15
16
  "ProfileTools",
16
17
  "DatabaseTools",
18
+ "SyncTools",
17
19
  ]
@@ -96,6 +96,81 @@ class ProfileTools:
96
96
  "type": "string",
97
97
  "description": "Azure tenant ID (for client_credentials auth)",
98
98
  },
99
+ "credentialSource": {
100
+ "type": "object",
101
+ "description": "Credential source configuration",
102
+ "properties": {
103
+ "sourceType": {
104
+ "type": "string",
105
+ "description": "Type of credential source",
106
+ "enum": ["environment", "keyvault"]
107
+ },
108
+ "clientIdVar": {
109
+ "type": "string",
110
+ "description": "Environment variable name for client ID (environment source)",
111
+ "default": "D365FO_CLIENT_ID"
112
+ },
113
+ "clientSecretVar": {
114
+ "type": "string",
115
+ "description": "Environment variable name for client secret (environment source)",
116
+ "default": "D365FO_CLIENT_SECRET"
117
+ },
118
+ "tenantIdVar": {
119
+ "type": "string",
120
+ "description": "Environment variable name for tenant ID (environment source)",
121
+ "default": "D365FO_TENANT_ID"
122
+ },
123
+ "vaultUrl": {
124
+ "type": "string",
125
+ "description": "Azure Key Vault URL (keyvault source)"
126
+ },
127
+ "clientIdSecretName": {
128
+ "type": "string",
129
+ "description": "Key Vault secret name for client ID (keyvault source)",
130
+ "default": "D365FO_CLIENT_ID"
131
+ },
132
+ "clientSecretSecretName": {
133
+ "type": "string",
134
+ "description": "Key Vault secret name for client secret (keyvault source)",
135
+ "default": "D365FO_CLIENT_SECRET"
136
+ },
137
+ "tenantIdSecretName": {
138
+ "type": "string",
139
+ "description": "Key Vault secret name for tenant ID (keyvault source)",
140
+ "default": "D365FO_TENANT_ID"
141
+ },
142
+ "keyvaultAuthMode": {
143
+ "type": "string",
144
+ "description": "Key Vault authentication mode",
145
+ "enum": ["default", "client_secret"],
146
+ "default": "default"
147
+ },
148
+ "keyvaultClientId": {
149
+ "type": "string",
150
+ "description": "Client ID for Key Vault authentication (client_secret mode)"
151
+ },
152
+ "keyvaultClientSecret": {
153
+ "type": "string",
154
+ "description": "Client secret for Key Vault authentication (client_secret mode)"
155
+ },
156
+ "keyvaultTenantId": {
157
+ "type": "string",
158
+ "description": "Tenant ID for Key Vault authentication (client_secret mode)"
159
+ }
160
+ },
161
+ "required": ["sourceType"],
162
+ "anyOf": [
163
+ {
164
+ "properties": {"sourceType": {"const": "environment"}},
165
+ "additionalProperties": True
166
+ },
167
+ {
168
+ "properties": {"sourceType": {"const": "keyvault"}},
169
+ "required": ["vaultUrl"],
170
+ "additionalProperties": True
171
+ }
172
+ ]
173
+ },
99
174
  "verifySsl": {
100
175
  "type": "boolean",
101
176
  "description": "Whether to verify SSL certificates",
@@ -163,6 +238,81 @@ class ProfileTools:
163
238
  "description": "Azure client secret",
164
239
  },
165
240
  "tenantId": {"type": "string", "description": "Azure tenant ID"},
241
+ "credentialSource": {
242
+ "type": "object",
243
+ "description": "Credential source configuration",
244
+ "properties": {
245
+ "sourceType": {
246
+ "type": "string",
247
+ "description": "Type of credential source",
248
+ "enum": ["environment", "keyvault"]
249
+ },
250
+ "clientIdVar": {
251
+ "type": "string",
252
+ "description": "Environment variable name for client ID (environment source)",
253
+ "default": "D365FO_CLIENT_ID"
254
+ },
255
+ "clientSecretVar": {
256
+ "type": "string",
257
+ "description": "Environment variable name for client secret (environment source)",
258
+ "default": "D365FO_CLIENT_SECRET"
259
+ },
260
+ "tenantIdVar": {
261
+ "type": "string",
262
+ "description": "Environment variable name for tenant ID (environment source)",
263
+ "default": "D365FO_TENANT_ID"
264
+ },
265
+ "vaultUrl": {
266
+ "type": "string",
267
+ "description": "Azure Key Vault URL (keyvault source)"
268
+ },
269
+ "clientIdSecretName": {
270
+ "type": "string",
271
+ "description": "Key Vault secret name for client ID (keyvault source)",
272
+ "default": "D365FO_CLIENT_ID"
273
+ },
274
+ "clientSecretSecretName": {
275
+ "type": "string",
276
+ "description": "Key Vault secret name for client secret (keyvault source)",
277
+ "default": "D365FO_CLIENT_SECRET"
278
+ },
279
+ "tenantIdSecretName": {
280
+ "type": "string",
281
+ "description": "Key Vault secret name for tenant ID (keyvault source)",
282
+ "default": "D365FO_TENANT_ID"
283
+ },
284
+ "keyvaultAuthMode": {
285
+ "type": "string",
286
+ "description": "Key Vault authentication mode",
287
+ "enum": ["default", "client_secret"],
288
+ "default": "default"
289
+ },
290
+ "keyvaultClientId": {
291
+ "type": "string",
292
+ "description": "Client ID for Key Vault authentication (client_secret mode)"
293
+ },
294
+ "keyvaultClientSecret": {
295
+ "type": "string",
296
+ "description": "Client secret for Key Vault authentication (client_secret mode)"
297
+ },
298
+ "keyvaultTenantId": {
299
+ "type": "string",
300
+ "description": "Tenant ID for Key Vault authentication (client_secret mode)"
301
+ }
302
+ },
303
+ "required": ["sourceType"],
304
+ "anyOf": [
305
+ {
306
+ "properties": {"sourceType": {"const": "environment"}},
307
+ "additionalProperties": True
308
+ },
309
+ {
310
+ "properties": {"sourceType": {"const": "keyvault"}},
311
+ "required": ["vaultUrl"],
312
+ "additionalProperties": True
313
+ }
314
+ ]
315
+ },
166
316
  "verifySsl": {
167
317
  "type": "boolean",
168
318
  "description": "Whether to verify SSL certificates",
@@ -299,6 +449,11 @@ class ProfileTools:
299
449
  "isDefault": default_profile and default_profile.name == name,
300
450
  "description": profile.description,
301
451
  }
452
+
453
+ # Add credential source type if available
454
+ if profile.credential_source:
455
+ profile_info["credentialSourceType"] = profile.credential_source.source_type
456
+
302
457
  profile_list.append(profile_info)
303
458
 
304
459
  response = {
@@ -356,6 +511,37 @@ class ProfileTools:
356
511
  if profile.tenant_id:
357
512
  profile_dict["tenantId"] = profile.tenant_id
358
513
 
514
+ # Add credential source information if available
515
+ if profile.credential_source:
516
+ cred_source_dict = profile.credential_source.to_dict()
517
+ # Convert to camelCase for JSON response
518
+ credential_source = {
519
+ "sourceType": cred_source_dict.get("source_type"),
520
+ }
521
+
522
+ if cred_source_dict.get("source_type") == "environment":
523
+ credential_source.update({
524
+ "clientIdVar": cred_source_dict.get("client_id_var"),
525
+ "clientSecretVar": cred_source_dict.get("client_secret_var"),
526
+ "tenantIdVar": cred_source_dict.get("tenant_id_var"),
527
+ })
528
+ elif cred_source_dict.get("source_type") == "keyvault":
529
+ credential_source.update({
530
+ "vaultUrl": cred_source_dict.get("vault_url"),
531
+ "clientIdSecretName": cred_source_dict.get("client_id_secret_name"),
532
+ "clientSecretSecretName": cred_source_dict.get("client_secret_secret_name"),
533
+ "tenantIdSecretName": cred_source_dict.get("tenant_id_secret_name"),
534
+ "keyvaultAuthMode": cred_source_dict.get("keyvault_auth_mode"),
535
+ })
536
+ # Only include auth details if using client_secret mode
537
+ if cred_source_dict.get("keyvault_auth_mode") == "client_secret":
538
+ credential_source.update({
539
+ "keyvaultClientId": cred_source_dict.get("keyvault_client_id"),
540
+ "keyvaultTenantId": cred_source_dict.get("keyvault_tenant_id"),
541
+ })
542
+
543
+ profile_dict["credentialSource"] = credential_source
544
+
359
545
  return [TextContent(type="text", text=json.dumps(profile_dict, indent=2))]
360
546
 
361
547
  except Exception as e:
@@ -393,6 +579,42 @@ class ProfileTools:
393
579
  description = arguments.get("description")
394
580
  set_as_default = arguments.get("setAsDefault", False)
395
581
 
582
+ # Handle credential source
583
+ credential_source = None
584
+ if "credentialSource" in arguments:
585
+ from ...credential_sources import create_credential_source
586
+ cred_source_data = arguments["credentialSource"]
587
+
588
+ # Convert camelCase to snake_case for the factory function
589
+ source_type = cred_source_data["sourceType"]
590
+ kwargs = {}
591
+
592
+ if source_type == "environment":
593
+ if "clientIdVar" in cred_source_data:
594
+ kwargs["client_id_var"] = cred_source_data["clientIdVar"]
595
+ if "clientSecretVar" in cred_source_data:
596
+ kwargs["client_secret_var"] = cred_source_data["clientSecretVar"]
597
+ if "tenantIdVar" in cred_source_data:
598
+ kwargs["tenant_id_var"] = cred_source_data["tenantIdVar"]
599
+ elif source_type == "keyvault":
600
+ kwargs["vault_url"] = cred_source_data["vaultUrl"]
601
+ if "clientIdSecretName" in cred_source_data:
602
+ kwargs["client_id_secret_name"] = cred_source_data["clientIdSecretName"]
603
+ if "clientSecretSecretName" in cred_source_data:
604
+ kwargs["client_secret_secret_name"] = cred_source_data["clientSecretSecretName"]
605
+ if "tenantIdSecretName" in cred_source_data:
606
+ kwargs["tenant_id_secret_name"] = cred_source_data["tenantIdSecretName"]
607
+ if "keyvaultAuthMode" in cred_source_data:
608
+ kwargs["keyvault_auth_mode"] = cred_source_data["keyvaultAuthMode"]
609
+ if "keyvaultClientId" in cred_source_data:
610
+ kwargs["keyvault_client_id"] = cred_source_data["keyvaultClientId"]
611
+ if "keyvaultClientSecret" in cred_source_data:
612
+ kwargs["keyvault_client_secret"] = cred_source_data["keyvaultClientSecret"]
613
+ if "keyvaultTenantId" in cred_source_data:
614
+ kwargs["keyvault_tenant_id"] = cred_source_data["keyvaultTenantId"]
615
+
616
+ credential_source = create_credential_source(source_type, **kwargs)
617
+
396
618
  # Create profile
397
619
  success = self.profile_manager.create_profile(
398
620
  name=name,
@@ -408,6 +630,7 @@ class ProfileTools:
408
630
  language=language,
409
631
  cache_dir=cache_dir,
410
632
  description=description,
633
+ credential_source=credential_source,
411
634
  )
412
635
 
413
636
  if not success:
@@ -477,8 +700,44 @@ class ProfileTools:
477
700
 
478
701
  mapped_params = {}
479
702
  for key, value in update_params.items():
480
- mapped_key = param_mapping.get(key, key)
481
- mapped_params[mapped_key] = value
703
+ if key == "credentialSource":
704
+ # Handle credential source
705
+ from ...credential_sources import create_credential_source
706
+ cred_source_data = value
707
+
708
+ # Convert camelCase to snake_case for the factory function
709
+ source_type = cred_source_data["sourceType"]
710
+ kwargs = {}
711
+
712
+ if source_type == "environment":
713
+ if "clientIdVar" in cred_source_data:
714
+ kwargs["client_id_var"] = cred_source_data["clientIdVar"]
715
+ if "clientSecretVar" in cred_source_data:
716
+ kwargs["client_secret_var"] = cred_source_data["clientSecretVar"]
717
+ if "tenantIdVar" in cred_source_data:
718
+ kwargs["tenant_id_var"] = cred_source_data["tenantIdVar"]
719
+ elif source_type == "keyvault":
720
+ kwargs["vault_url"] = cred_source_data["vaultUrl"]
721
+ if "clientIdSecretName" in cred_source_data:
722
+ kwargs["client_id_secret_name"] = cred_source_data["clientIdSecretName"]
723
+ if "clientSecretSecretName" in cred_source_data:
724
+ kwargs["client_secret_secret_name"] = cred_source_data["clientSecretSecretName"]
725
+ if "tenantIdSecretName" in cred_source_data:
726
+ kwargs["tenant_id_secret_name"] = cred_source_data["tenantIdSecretName"]
727
+ if "keyvaultAuthMode" in cred_source_data:
728
+ kwargs["keyvault_auth_mode"] = cred_source_data["keyvaultAuthMode"]
729
+ if "keyvaultClientId" in cred_source_data:
730
+ kwargs["keyvault_client_id"] = cred_source_data["keyvaultClientId"]
731
+ if "keyvaultClientSecret" in cred_source_data:
732
+ kwargs["keyvault_client_secret"] = cred_source_data["keyvaultClientSecret"]
733
+ if "keyvaultTenantId" in cred_source_data:
734
+ kwargs["keyvault_tenant_id"] = cred_source_data["keyvaultTenantId"]
735
+
736
+ credential_source = create_credential_source(source_type, **kwargs)
737
+ mapped_params["credential_source"] = credential_source
738
+ else:
739
+ mapped_key = param_mapping.get(key, key)
740
+ mapped_params[mapped_key] = value
482
741
 
483
742
  success = self.profile_manager.update_profile(name, **mapped_params)
484
743