1+ import json
2+ from typing import Optional , Union
3+
4+ import typer
5+ import yaml
6+ from rich .panel import Panel
7+
8+ from mcp_agent .cli .exceptions import CLIError
9+ from mcp_agent .cli .mcp_app .api_client import MCPApp , MCPAppConfiguration
10+ from ..utils import (
11+ setup_authenticated_client ,
12+ validate_output_format ,
13+ resolve_server ,
14+ handle_server_api_errors ,
15+ clean_server_status ,
16+ )
17+ from mcp_agent .cli .utils .ux import console
18+
19+
20+ @handle_server_api_errors
21+ def describe_server (
22+ id_or_url : str = typer .Argument (..., help = "Server ID or URL to describe" ),
23+ format : Optional [str ] = typer .Option ("text" , "--format" , help = "Output format (text|json|yaml)" ),
24+ ) -> None :
25+ """Describe a specific MCP Server."""
26+ validate_output_format (format )
27+ client = setup_authenticated_client ()
28+ server = resolve_server (client , id_or_url )
29+ print_server_description (server , format )
30+
31+
32+ def print_server_description (server : Union [MCPApp , MCPAppConfiguration ], output_format : str = "text" ) -> None :
33+ """Print detailed description information for a server."""
34+
35+ valid_formats = ["text" , "json" , "yaml" ]
36+ if output_format not in valid_formats :
37+ raise CLIError (f"Invalid format '{ output_format } '. Valid options are: { ', ' .join (valid_formats )} " )
38+
39+ if output_format == "json" :
40+ _print_server_json (server )
41+ elif output_format == "yaml" :
42+ _print_server_yaml (server )
43+ else :
44+ _print_server_text (server )
45+
46+
47+ def _print_server_json (server : Union [MCPApp , MCPAppConfiguration ]) -> None :
48+ """Print server in JSON format."""
49+ server_data = _server_to_dict (server )
50+ print (json .dumps (server_data , indent = 2 , default = str ))
51+
52+
53+ def _print_server_yaml (server : Union [MCPApp , MCPAppConfiguration ]) -> None :
54+ """Print server in YAML format."""
55+ server_data = _server_to_dict (server )
56+ print (yaml .dump (server_data , default_flow_style = False ))
57+
58+
59+ def _server_to_dict (server : Union [MCPApp , MCPAppConfiguration ]) -> dict :
60+ """Convert server to dictionary."""
61+ if isinstance (server , MCPApp ):
62+ server_type = "deployed"
63+ server_id = server .appId
64+ server_name = server .name
65+ server_description = server .description
66+ created_at = server .createdAt
67+ server_info = server .appServerInfo
68+ creator_id = server .creatorId
69+ underlying_app = None
70+ else :
71+ server_type = "configured"
72+ server_id = server .appConfigurationId
73+ server_name = server .app .name if server .app else "Unnamed"
74+ server_description = server .app .description if server .app else None
75+ created_at = server .createdAt
76+ server_info = server .appServerInfo
77+ creator_id = server .creatorId
78+ underlying_app = {
79+ "app_id" : server .app .appId ,
80+ "name" : server .app .name
81+ } if server .app else None
82+
83+ status_raw = server_info .status if server_info else "APP_SERVER_STATUS_OFFLINE"
84+ server_url = server_info .serverUrl if server_info else None
85+
86+ data = {
87+ "id" : server_id ,
88+ "name" : server_name ,
89+ "type" : server_type ,
90+ "status" : clean_server_status (status_raw ),
91+ "server_url" : server_url ,
92+ "description" : server_description ,
93+ "creator_id" : creator_id ,
94+ "created_at" : created_at .isoformat () if created_at else None
95+ }
96+
97+ if underlying_app :
98+ data ["underlying_app" ] = underlying_app
99+
100+ return data
101+
102+
103+
104+
105+ def _print_server_text (server : Union [MCPApp , MCPAppConfiguration ]) -> None :
106+ """Print server in text format."""
107+ if isinstance (server , MCPApp ):
108+ server_type = "Deployed Server"
109+ server_id = server .appId
110+ server_name = server .name
111+ server_description = server .description
112+ created_at = server .createdAt
113+ server_info = server .appServerInfo
114+ creator_id = server .creatorId
115+ else :
116+ server_type = "Configured Server"
117+ server_id = server .appConfigurationId
118+ server_name = server .app .name if server .app else "Unnamed"
119+ server_description = server .app .description if server .app else None
120+ created_at = server .createdAt
121+ server_info = server .appServerInfo
122+ creator_id = server .creatorId
123+
124+ status_text = "❓ Unknown"
125+ server_url = "N/A"
126+
127+ if server_info :
128+ status_text = _server_status_text (server_info .status )
129+ server_url = server_info .serverUrl
130+ content_lines = [
131+ f"Name: [cyan]{ server_name } [/cyan]" ,
132+ f"Type: [cyan]{ server_type } [/cyan]" ,
133+ f"ID: [cyan]{ server_id } [/cyan]" ,
134+ f"Status: { status_text } " ,
135+ f"Server URL: [cyan]{ server_url } [/cyan]" ,
136+ ]
137+
138+ if server_description :
139+ content_lines .append (f"Description: [cyan]{ server_description } [/cyan]" )
140+
141+ content_lines .append (f"Creator: [cyan]{ creator_id } [/cyan]" )
142+
143+ if created_at :
144+ content_lines .append (f"Created: [cyan]{ created_at .strftime ('%Y-%m-%d %H:%M:%S' )} [/cyan]" )
145+
146+ if isinstance (server , MCPAppConfiguration ) and server .app :
147+ content_lines .extend ([
148+ "" ,
149+ "[bold]Underlying App:[/bold]" ,
150+ f" App ID: [cyan]{ server .app .appId } [/cyan]" ,
151+ f" App Name: [cyan]{ server .app .name } [/cyan]" ,
152+ ])
153+
154+ console .print (
155+ Panel (
156+ "\n " .join (content_lines ),
157+ title = "Server Description" ,
158+ border_style = "blue" ,
159+ expand = False ,
160+ )
161+ )
162+
163+
164+ def _server_status_text (status : str ) -> str :
165+ """Convert server status code to emoji and text."""
166+ if status == "APP_SERVER_STATUS_ONLINE" :
167+ return "[green]🟢 Active[/green]"
168+ elif status == "APP_SERVER_STATUS_OFFLINE" :
169+ return "[red]🔴 Offline[/red]"
170+ else :
171+ return "❓ Unknown"
0 commit comments