@@ -199,10 +199,8 @@ def __init__(
199199 else :
200200 self ._has_lifespan = True
201201 # Generate random ID if no name provided
202- if name is None :
203- name = f"FastMCP-{ secrets .token_hex (4 )} "
204202 self ._mcp_server = LowLevelServer [LifespanResultT ](
205- name = name ,
203+ name = name or self . generate_name () ,
206204 version = version ,
207205 instructions = instructions ,
208206 lifespan = _lifespan_wrapper (self , lifespan ),
@@ -2205,118 +2203,14 @@ def _should_enable_component(
22052203
22062204 return True
22072205
2208- def generate_hierarchy_diagram (self , format : Literal ["mermaid" ] = "mermaid" ) -> str :
2209- """Generate a diagram showing the hierarchy of servers, mounted servers, proxies, clients and transports.
2210-
2211- Args:
2212- format: Output format, currently only "mermaid" is supported
2213-
2214- Returns:
2215- A string containing the diagram in the requested format
2216-
2217- Example:
2218- ```python
2219- server = FastMCP("MyServer")
2220- print(server.generate_hierarchy_diagram())
2221- ```
2222- """
2223- if format != "mermaid" :
2224- raise ValueError ("Only 'mermaid' format is currently supported" )
2225-
2226- def get_server_type (server : FastMCP [Any ]) -> str :
2227- """Determine the type of server for display"""
2228- from fastmcp .server .proxy import FastMCPProxy
2229-
2230- if isinstance (server , FastMCPProxy ):
2231- return "Proxy"
2232- return "Server"
2233-
2234- lines = ["graph TD" ]
2235- node_id = 0
2236-
2237- def add_node (name : str , node_type : str = "Server" ) -> str :
2238- """Add a node and return its ID"""
2239- nonlocal node_id
2240- current_id = f"N{ node_id } "
2241- node_id += 1
2242-
2243- # Choose appropriate mermaid shape based on type
2244- if node_type == "Proxy" :
2245- shape = f'{ current_id } [["{ name } <br/>({ node_type } )"]'
2246- elif node_type == "Client" :
2247- shape = f'{ current_id } ({{"{ name } <br/>({ node_type } )"}})'
2248- elif node_type == "Transport" :
2249- shape = f'{ current_id } [["{ name } <br/>({ node_type } )"]'
2250- else : # Server
2251- shape = f'{ current_id } ["{ name } <br/>({ node_type } )"]'
2252-
2253- lines .append (f" { shape } " )
2254- return current_id
2255-
2256- def add_connection (from_id : str , to_id : str , label : str = "" ) -> None :
2257- """Add a connection between nodes"""
2258- if label :
2259- lines .append (f" { from_id } -->|{ label } | { to_id } " )
2260- else :
2261- lines .append (f" { from_id } --> { to_id } " )
2262-
2263- # Add the main server
2264- main_server_id = add_node (self .name , get_server_type (self ))
2265-
2266- # Add mounted servers recursively
2267- def process_server (server : FastMCP [Any ], parent_id : str ) -> None :
2268- for mounted in server ._mounted_servers :
2269- server_type = get_server_type (mounted .server )
2270- mounted_id = add_node (mounted .server .name , server_type )
2271-
2272- # Add connection with prefix label if it exists
2273- prefix_label = (
2274- f"prefix: { mounted .prefix } " if mounted .prefix else "no prefix"
2275- )
2276- add_connection (parent_id , mounted_id , prefix_label )
2277-
2278- # Recursively process this mounted server's mounts
2279- process_server (mounted .server , mounted_id )
2280-
2281- # If this is a proxy, try to show its client info
2282- from fastmcp .server .proxy import FastMCPProxy
2283-
2284- if isinstance (mounted .server , FastMCPProxy ):
2285- try :
2286- # Add a representation of the proxy's client factory
2287- client_id = add_node ("Client Factory" , "Client" )
2288- add_connection (mounted_id , client_id , "uses" )
2289- except Exception :
2290- # In case of any issues accessing proxy internals, skip
2291- pass
2292-
2293- # Process all mounted servers
2294- process_server (self , main_server_id )
2295-
2296- # If this is a proxy server, show its client connection
2297- from fastmcp .server .proxy import FastMCPProxy
2298-
2299- if isinstance (self , FastMCPProxy ):
2300- try :
2301- client_id = add_node ("Client Factory" , "Client" )
2302- add_connection (main_server_id , client_id , "proxies to" )
2303- except Exception :
2304- # In case of any issues, skip
2305- pass
2306-
2307- # Add styling
2308- lines .extend (
2309- [
2310- "" ,
2311- " %% Styling" ,
2312- " classDef serverClass fill:#e1f5fe,stroke:#01579b,stroke-width:2px" ,
2313- " classDef proxyClass fill:#fff3e0,stroke:#e65100,stroke-width:2px" ,
2314- " classDef clientClass fill:#f3e5f5,stroke:#4a148c,stroke-width:2px" ,
2315- " classDef transportClass fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px" ,
2316- ]
2317- )
2206+ @classmethod
2207+ def generate_name (cls , name : str | None = None ) -> str :
2208+ class_name = cls .__name__
23182209
2319- return "\n " .join (lines )
2210+ if name is None :
2211+ return f"{ class_name } -{ secrets .token_hex (2 )} "
2212+ else :
2213+ return f"{ class_name } -{ name } -{ secrets .token_hex (2 )} "
23202214
23212215
23222216@dataclass
0 commit comments