55"""
66
77from pathlib import Path
8+ from datetime import datetime , timezone
89from typing import Optional , Union
10+ import json
911
1012import typer
11- from rich .panel import Panel
1213from rich .progress import Progress , SpinnerColumn , TextColumn
1314
1415from mcp_agent .cli .auth import load_api_key_credentials
3536 print_configuration_header ,
3637 print_info ,
3738 print_success ,
39+ print_verbose ,
3840 LOG_VERBOSE ,
3941)
4042
@@ -121,8 +123,7 @@ def configure_app(
121123
122124 client : Union [MockMCPAppClient , MCPAppClient ]
123125 if dry_run :
124- # Use the mock api client in dry run mode
125- print_info ("Using MOCK API client for dry run" )
126+ print_verbose ("Using MOCK API client for dry run" )
126127 client = MockMCPAppClient (
127128 api_url = api_url or DEFAULT_API_BASE_URL , api_key = effective_api_key
128129 )
@@ -173,22 +174,18 @@ def configure_app(
173174
174175 if requires_secrets :
175176 if not secrets_file and secrets_output_file is None :
176- # Set default output file if not specified
177177 secrets_output_file = Path (MCP_CONFIGURED_SECRETS_FILENAME )
178- print_info (f"Using default output path: { secrets_output_file } " )
178+ print_verbose (f"Using default output path: { secrets_output_file } " )
179179
180- print_configuration_header (secrets_file , secrets_output_file , dry_run )
181-
182- print_info (
180+ print_verbose (
183181 f"App { app_server_url } requires the following ({ len (required_params )} ) user secrets: { ', ' .join (required_params )} "
184182 )
185183
186184 try :
187- print_info ("Processing user secrets..." )
185+ print_verbose ("Processing user secrets..." )
188186
189187 if dry_run :
190- # Use the mock client in dry run mode
191- print_info ("Using MOCK Secrets API client for dry run" )
188+ print_verbose ("Using MOCK Secrets API client for dry run" )
192189
193190 # Create the mock client
194191 mock_client = MockSecretsClient (
@@ -221,7 +218,7 @@ def configure_app(
221218 )
222219 )
223220
224- print_success ("User secrets processed successfully" )
221+ print_verbose ("User secrets processed successfully" )
225222
226223 except Exception as e :
227224 if LOG_VERBOSE .get ():
@@ -237,14 +234,35 @@ def configure_app(
237234 f"App { app_server_url } does not require any parameters, but a secrets file was provided: { secrets_file } "
238235 )
239236
237+ print_configuration_header (
238+ app_server_url ,
239+ required_params if requires_secrets else [],
240+ secrets_file ,
241+ secrets_output_file ,
242+ dry_run ,
243+ )
244+
245+ if not dry_run :
246+ proceed = typer .confirm ("Proceed with configuration?" , default = True )
247+ if not proceed :
248+ print_info ("Configuration cancelled." )
249+ return None
250+ else :
251+ print_info ("Running in dry run mode." )
252+
253+ start_time = datetime .now (timezone .utc ).isoformat ().replace ("+00:00" , "Z" )
254+ print_info (f"[{ start_time } ] Starting configuration process..." , highlight = False )
255+
240256 if dry_run :
241257 print_success ("Configuration completed in dry run mode." )
242258 return "dry-run-app-configuration-id"
243259
244- # Finally, configure the app for the user
260+ config = None
261+ spinner_column = SpinnerColumn (spinner_name = "aesthetic" )
245262 with Progress (
246- SpinnerColumn (spinner_name = "arrow3" ),
247- TextColumn ("[progress.description]{task.description}" ),
263+ "" ,
264+ spinner_column ,
265+ TextColumn (" [progress.description]{task.description}" ),
248266 ) as progress :
249267 task = progress .add_task ("Configuring MCP App..." , total = None )
250268
@@ -254,18 +272,52 @@ def configure_app(
254272 app_server_url = app_server_url , config_params = configured_secrets
255273 )
256274 )
257- progress .update (task , description = "✅ MCP App configured successfully!" )
258- console .print (
259- Panel (
260- f"Configured App ID: [cyan]{ config .appConfigurationId } [/cyan]\n "
261- f"Configured App Server URL: [cyan]{ config .appServerInfo .serverUrl if config .appServerInfo else '' } [/cyan]" ,
262- title = "Configuration Complete" ,
263- border_style = "green" ,
264- )
265- )
266-
267- return config .appConfigurationId
275+ spinner_column .spinner .frames = spinner_column .spinner .frames [- 2 :- 1 ]
276+ progress .update (task , description = "MCP App configured successfully!" )
268277
269278 except Exception as e :
270279 progress .update (task , description = "❌ MCP App configuration failed" )
271- raise CLIError (f"Failed to configure app { app_server_url } : { str (e )} " ) from e
280+ end_time = datetime .now (timezone .utc ).isoformat ().replace ("+00:00" , "Z" )
281+ raise CLIError (
282+ f"[{ end_time } ] Failed to configure app { app_server_url } : { str (e )} "
283+ ) from e
284+
285+ # Print results after progress context ends
286+ end_time = datetime .now (timezone .utc ).isoformat ().replace ("+00:00" , "Z" )
287+ if config .app :
288+ print_info (
289+ f"[{ end_time } ] Configuration of '{ config .app .name } ' succeeded. ID: { config .appConfigurationId } " ,
290+ highlight = False ,
291+ )
292+ else :
293+ print_info (
294+ f"[{ end_time } ] Configuration succeeded. ID: { config .appConfigurationId } " ,
295+ highlight = False ,
296+ )
297+
298+ if config .appServerInfo :
299+ server_url = config .appServerInfo .serverUrl
300+ print_info (f"App Server URL: [link={ server_url } ]{ server_url } [/link]" )
301+ print_info (
302+ f"Use this configured app as an MCP server at { server_url } /sse\n \n MCP configuration example:"
303+ )
304+
305+ # Use the app name if available, otherwise use a simple default
306+ app_name = config .app .name if config .app else "configured-app"
307+
308+ mcp_config = {
309+ "mcpServers" : {
310+ app_name : {
311+ "url" : f"{ server_url } /sse" ,
312+ "transport" : "sse" ,
313+ "headers" : {"Authorization" : f"Bearer { effective_api_key } " },
314+ }
315+ }
316+ }
317+
318+ console .print (
319+ f"[bright_black]{ json .dumps (mcp_config , indent = 2 )} [/bright_black]" ,
320+ soft_wrap = True ,
321+ )
322+
323+ return config .appConfigurationId
0 commit comments