+
    Q(ir                       a  R4 t/0 t R t^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	H
t
 ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RIHtHt ^ RIHt ^ R	IHt ^ R
IHt ]! R4      t]! 4       t0 R5mtR R lt R R lt!R R lt"R R lt#R R lt$R R lt%R R lt&R R  lt'RRRRRRRRRRR!R!R"R"/t(] ^ k R# R$ lt)R% R& lt*R' R( lt+R) R* lt,R6R+R,R-RR.RR/R,/R0 R1 lllt-R2 R3 lt.R# )7zDGenerate a standalone CLI script and agent skill from an MCP server.N)Path)	AnnotatedAny)urlparse)McpError)Console)_build_clientresolve_server_spec)ClientTransport)StdioTransport)
get_loggerzcli.generatestringintegernumberbooleannullc                R    V ^8  d   QhR\         \        \        3,          R\        /#    schemareturn)dictstrr   bool)formats   "Z/Users/agent/.openclaw/workspace/venv/lib/python3.14/site-packages/fastmcp/cli/generate.py__annotate__r       s"     ( (DcN (t (    c                    V P                  R4      p\        V\        4      '       d5   \        ;QJ d    R V 4       F  '       d   K   R# 	  R# ! R V 4       4      # V\        9   # )z9Check if a schema represents a simple (non-complex) type.typec              3   2   "   T F  q\         9   x  K  	  R # 5iN)_SIMPLE_TYPES).0ts   & r   	<genexpr>"_is_simple_type.<locals>.<genexpr>%   s     ;{!%{s   FT)get
isinstancelistallr"   )r   schema_types   & r   _is_simple_typer,       sQ    **V$K+t$$s;{;ss;s;s;{;;;-''r   c                    V ^8  d   QhR\         \        \        3,          R\        \        \        R,          3,          /# )r   r   r   Nr   r   r   tupler   )r   s   "r   r   r   )   s0      T#s(^ dC$J6F0G r   c                   V P                  R4      R8w  d   R# V P                  R/ 4      p\        V4      '       g   R# VP                  RR4      p\        V\        4      '       d   R# RRRRRR	R
R/pVP                  V4      pVf   R# RV3# )zXCheck if schema is an array of simple types.

Returns (is_simple_array, item_type_str).
r   arrayitemsr   r   r   intr   floatr   r   T)FN)r'   r,   r(   r)   )r   r2   	item_typetype_mappy_types   &    r   _is_simple_arrayr8   )   s    
 zz&W$JJw#E5!! 		&(+I)T""%5'6	H ll9%G=r   c                t    V ^8  d   QhR\         \        \        3,          R\        \        \        3,          /# r   r.   )r   s   "r   r   r   E   s+     # #4S> #eCI6F #r   c           
     z   \        V 4      w  rV'       d	   RV R2R3# \        V 4      '       d   V P                  RR4      p\        V\        4      '       d@   RRRRR	R
RRRR/pV Uu. uF  qTP                  VR4      NK  	  ppRP                  V4      R3# RRRRR	R
RRRR/pVP                  VR4      R3# R# u upi )zcConvert a JSON Schema to a Python type annotation.

Returns (type_annotation, needs_json_parsing).
list[]Fr   r   r   r   r3   r   r4   r   r   r   None | )r   T)r8   r,   r'   r(   r)   join)r   is_simple_arrr5   r+   r6   r$   partss   &      r   _schema_to_python_typerB   E   s      07Myk#U** vjj2k4(( %5'6H 6AA[\\!U+[EA::e$e++ eugvF
 ||K/66  Bs   'B8c                R    V ^8  d   QhR\         \        \        3,          R\        /# r   r   r   r   )r   s   "r   r   r   k   s"     & &DcN &s &r   c                    \         P                  ! V ^R7      P                  4       pVP                  R4      pRP	                  V4      pRV 2# )z.Format a JSON schema for display in help text.)indent
z
                          zJSON Schema: )pydantic_coreto_jsondecodesplitr?   )r   
schema_strlinesindenteds   &   r   _format_schema_for_helprO   k   sL     &&va8??AJT"E-2259H8*%%r   c                    V ^8  d   QhR\         \        \         \        3,          ,          \        ,          R\        \         \
        \         ,          3,          /# )r   resolvedr   )r   r   r   r
   r/   set)r   s   "r   r   r   z   s;     ! !DcN"_4!
3C=!r   c                >   \        V \        4      '       d   \        V 4      \        4       3# \        V \        4      '       d   RV P
                  : 2RV P                  : 2.pV P                  '       d    VP                  RV P                  : 24       V P                  '       d    VP                  RV P                  : 24       RRP                  V4       R2pR0pW#3# \        V \        4      '       d   \        V 4      \        4       3# \        V 4      \        4       3# )	zSerialize a resolved transport to a Python expression string.

Returns ``(expression, extra_imports)`` where *extra_imports* is a set of
import lines needed by the expression.
zcommand=zargs=zenv=zcwd=zStdioTransport(, )z4from fastmcp.client.transports import StdioTransport)r(   r   reprrR   r   commandargsenvappendcwdr?   r   )rQ   rA   exprimportss   &   r   serialize_transportr^   z   s     (C  H~su$$(N++H,,/0E(--9J2KL<<<LL4/01<<<LL4/01 5!1 2!4IJ}(D!!H~su$$ >35  r   c                0    V ^8  d   QhR\         R\         /# )r   namer   r   )r   s   "r   r   r      s        r   c                    \         P                  ! RRV 4      pV'       d#   V^ ,          P                  4       '       d   RV 2pT;'       g    Rp\        P                  ! V4      '       d   V R2pV# )z1Sanitize a string into a valid Python identifier.z[^a-zA-Z0-9_]__unnamed)resubisdigitkeyword	iskeyword)r`   safes   & r   _to_python_identifierrk      sa    66"C.DQ!!4&z:DqzKr   c                X    V ^8  d   QhR\         P                  P                  R\        /# )r   toolr   mcptypesToolr   )r   s   "r   r   r      s&     m m		 m3 mr   c                  a V P                   pVP                  R/ 4      p\        VP                  R. 4      4      p. p. p. p/ pVP                  4        EF  w  op\	        V4      w  rVP                  RR4      pSV9   p\        S4      pW9   d   \        RS RW},           RV R24      hSW}&   V
'       d0   \        V4      pV'       d   V R	V 2MTpVP                  SV34       VP                  R
R4      P                  RR4      P                  RR	4      pV'       d#   RV	 RV R2pVP                  RV RV R24       MVP                  R4      pVe   V
'       dQ   \        P                  ! V\        R7      P                  4       pRV	 RV R2pVP                  RV RV RV: R24       MRV	 RV R2pVP                  RV RV RV: R24       MZV	P                  R4      '       d#   RV	 RV R2pVP                  RV RV R24       M!RV	 RV R2pVP                  RV RV R24       VP                  S: RV 24       EK  	  \        V P                  4      pV P                   ;'       g    RP                  R
R4      P                  RR4      p. pVP                  R4       VP                  RV P                  : R24       VP                  RV R 24       V'       d#   VP                  R!4       VP#                  V4       VP                  R"4       VP                  R#V R$24       V'       dL   VP                  R%4       V F#  w  ppVP                  RV R&V R'V R(V 24       K%  	  VP                  R4       . pVP                  4        F  w  op\        S4      p\$        ;QJ d    V3R) lV 4       F  '       g   K   R*M	  R+M! V3R) lV 4       4      '       d   VP                  S: RV R,24       Kk  VP                  S: RV 24       K  	  R-P'                  V4      pVP                  R.V P                  : R/V R024       VP                  R4       RP'                  V4      # )1zEGenerate the source for a single ``@call_tool_app.command`` function.
propertiesrequireddescription zParameter name collision: 'z' and 'z' both sanitize to ''z\n\\\"\"rG   z
Annotated[z, cyclopts.Parameter(help="z")]z    z: ,default)fallbackz = r;   z = [],z" | None, cyclopts.Parameter(help="z = None,z\'z@call_tool_app.command(name=rU   z
async def (z    *,z
) -> None:z    '''z'''z    # Parse JSON parametersz_parsed = json.loads(z) if isinstance(z, str) else c              3   2   <"   T F  w  rVS8H  x  K  	  R # 5ir!    )r#   pnrc   	prop_names   &  r   r%   (_tool_function_source.<locals>.<genexpr>
  s     8K52rYKs   TF_parsedrT   z    await _call_tool(z, {z}))inputSchemar'   rR   r2   rB   rk   
ValueErrorrO   rZ   replacerH   rI   r   rJ   
startswithr`   ru   extendanyr?   )rm   r   rs   rt   param_lines	call_argsjson_params
seen_namesprop_schemar7   
needs_json	help_textis_required	safe_nameschema_helphelp_escaped
annotationr}   default_strfn_nameru   rM   
_prop_namecall_arg_partsrc   
dict_itemsr   s   &                         @r   _tool_function_sourcer      s   F!'L"!=J6::j"-.H  KI)+K!#J","2"2"4	;4[AOOM26	8+))4	 "-i[
@U?V W%%.Kq2  !*
 1+>K:C9+S6I	956 dF+33C?GGeT 	
 WI%@cR  i[:,a@A!ooi0G""/"7"7#"N"U"U"WK#-gY6QR^Q__b!cJ&&ykJ<s;/K $.gY6QR^Q__b!cJ&&i[:,c'TU'VW %%g..#-gY6QR^Q__b!cJ&&i[:,f'MN#-gY6XYeXffi!jJ&&i[:,h'OPI=9+67k #5p $DII.G ##))r224@HHeTKE	LL 
LL/		}A>?	LL:gYa()X[!	LL	LL7;-s+, 23%0!J	LLyk!6ykAQR[Q\\hirhst &1 	R N"((*	1))4	38K83338K888!!YMI;g"FG!!YMI;"?@ + >*J	LL(T*SIJ	LL99Ur   c                    V ^8  d   QhR\         R\         R\         R\        \         ,          R\        \        P                  P
                  ,          R\         /# )r   server_nameserver_spectransport_codeextra_importstoolsr   )r   rR   r)   ro   rp   rq   )r   s   "r   r   r     s]     k kkk k s8	k
 		k 	kr   c                (   V P                  RR4      P                  4       P                  RR4      P                  RR4      p. pVP                  R4       VP                  RV  R	24       VP                  R
4       VP                  RV 24       VP                  R4       VP                  R
4       VP                  R4       VP                  R4       VP                  R4       VP                  R
4       VP                  R4       VP                  R4       VP                  R4       VP                  R
4       VP                  R4       \        V4       F  pVP                  V4       K  	  VP                  R
4       VP                  R4       VP                  RV 24       VP                  R
4       V P                  RR4      P                  RR4      pVP                  RV RV R24       VP                  R4       VP                  R4       VP                  R
4       VP                  R4       VP                  R
4       VP                  R
4       VP                  \        P
                  ! R4      4       VP                  R
4       VP                  R
4       VP                  \        P
                  ! R4      4       VP                  R
4       VP                  R
4       V'       dW   VP                  R4       VP                  R4       VP                  R4       V F  p	VP                  \        V	4      4       K  	  VP                  R
4       VP                  R 4       VP                  R!4       VP                  R
4       R"P                  V4      # )#z)Generate the full CLI script source code. -rx   ry   rz   r{   z#!/usr/bin/env python3z"""CLI for z MCP server.rv   z#Generated by: fastmcp generate-cli z"""zimport jsonz
import syszfrom typing import Annotatedzimport cycloptszimport mcp.typesz from rich.console import Consolezfrom fastmcp import Clientz?# Modify this to change how the CLI connects to the MCP server.zCLIENT_SPEC = zapp = cyclopts.App(name="z", help="CLI for z MCP server")zPcall_tool_app = cyclopts.App(name="call-tool", help="Call a tool on the server")zapp.command(call_tool_app)zconsole = Console()ao          # ---------------------------------------------------------------------------
        # Helpers
        # ---------------------------------------------------------------------------


        def _print_tool_result(result):
            if result.is_error:
                for block in result.content:
                    if isinstance(block, mcp.types.TextContent):
                        console.print(f"[bold red]Error:[/bold red] {block.text}")
                    else:
                        console.print(f"[bold red]Error:[/bold red] {block}")
                sys.exit(1)

            if result.structured_content is not None:
                console.print_json(json.dumps(result.structured_content))
                return

            for block in result.content:
                if isinstance(block, mcp.types.TextContent):
                    console.print(block.text)
                elif isinstance(block, mcp.types.ImageContent):
                    size = len(block.data) * 3 // 4
                    console.print(f"[dim][Image: {block.mimeType}, ~{size} bytes][/dim]")
                elif isinstance(block, mcp.types.AudioContent):
                    size = len(block.data) * 3 // 4
                    console.print(f"[dim][Audio: {block.mimeType}, ~{size} bytes][/dim]")


        async def _call_tool(tool_name: str, arguments: dict) -> None:
            # Filter out None values and empty lists (defaults for optional array params)
            filtered = {
                k: v
                for k, v in arguments.items()
                if v is not None and (not isinstance(v, list) or len(v) > 0)
            }
            async with Client(CLIENT_SPEC) as client:
                result = await client.call_tool(tool_name, filtered, raise_on_error=False)
                _print_tool_result(result)
                if result.is_error:
                    sys.exit(1)u          # ---------------------------------------------------------------------------
        # List / read commands
        # ---------------------------------------------------------------------------


        @app.command
        async def list_tools() -> None:
            """List available tools."""
            async with Client(CLIENT_SPEC) as client:
                tools = await client.list_tools()
                if not tools:
                    console.print("[dim]No tools found.[/dim]")
                    return
                for tool in tools:
                    sig_parts = []
                    props = tool.inputSchema.get("properties", {})
                    required = set(tool.inputSchema.get("required", []))
                    for pname, pschema in props.items():
                        ptype = pschema.get("type", "string")
                        if pname in required:
                            sig_parts.append(f"{pname}: {ptype}")
                        else:
                            sig_parts.append(f"{pname}: {ptype} = ...")
                    sig = f"{tool.name}({', '.join(sig_parts)})"
                    console.print(f"  [cyan]{sig}[/cyan]")
                    if tool.description:
                        console.print(f"    {tool.description}")
                    console.print()


        @app.command
        async def list_resources() -> None:
            """List available resources."""
            async with Client(CLIENT_SPEC) as client:
                resources = await client.list_resources()
                if not resources:
                    console.print("[dim]No resources found.[/dim]")
                    return
                for r in resources:
                    console.print(f"  [cyan]{r.uri}[/cyan]")
                    desc_parts = [r.name or "", r.description or ""]
                    desc = " — ".join(p for p in desc_parts if p)
                    if desc:
                        console.print(f"    {desc}")
                console.print()


        @app.command
        async def read_resource(uri: Annotated[str, cyclopts.Parameter(help="Resource URI")]) -> None:
            """Read a resource by URI."""
            async with Client(CLIENT_SPEC) as client:
                contents = await client.read_resource(uri)
                for block in contents:
                    if isinstance(block, mcp.types.TextResourceContents):
                        console.print(block.text)
                    elif isinstance(block, mcp.types.BlobResourceContents):
                        size = len(block.blob) * 3 // 4
                        console.print(f"[dim][Blob: {block.mimeType}, ~{size} bytes][/dim]")


        @app.command
        async def list_prompts() -> None:
            """List available prompts."""
            async with Client(CLIENT_SPEC) as client:
                prompts = await client.list_prompts()
                if not prompts:
                    console.print("[dim]No prompts found.[/dim]")
                    return
                for p in prompts:
                    args_str = ""
                    if p.arguments:
                        parts = [a.name for a in p.arguments]
                        args_str = f"({', '.join(parts)})"
                    console.print(f"  [cyan]{p.name}{args_str}[/cyan]")
                    if p.description:
                        console.print(f"    {p.description}")
                console.print()


        @app.command
        async def get_prompt(
            name: Annotated[str, cyclopts.Parameter(help="Prompt name")],
            *arguments: str,
        ) -> None:
            """Get a prompt by name. Pass arguments as key=value pairs."""
            parsed: dict[str, str] = {}
            for arg in arguments:
                if "=" not in arg:
                    console.print(f"[bold red]Error:[/bold red] Invalid argument {arg!r} — expected key=value")
                    sys.exit(1)
                key, value = arg.split("=", 1)
                parsed[key] = value

            async with Client(CLIENT_SPEC) as client:
                result = await client.get_prompt(name, parsed or None)
                for msg in result.messages:
                    console.print(f"[bold]{msg.role}:[/bold]")
                    if isinstance(msg.content, mcp.types.TextContent):
                        console.print(f"  {msg.content.text}")
                    elif isinstance(msg.content, mcp.types.ImageContent):
                        size = len(msg.content.data) * 3 // 4
                        console.print(f"  [dim][Image: {msg.content.mimeType}, ~{size} bytes][/dim]")
                    else:
                        console.print(f"  {msg.content}")
                    console.print()zM# ---------------------------------------------------------------------------z.# Tool commands (generated from server schema)zif __name__ == "__main__":z	    app()rG   )r   lowerrZ   sortedtextwrapdedentr   r?   )
r   r   r   r   r   app_namerM   impserver_name_escapedrm   s
   &&&&&     r   generate_cli_scriptr     s    	C%++-55dFCKKCQVW 
 E	LL)*	LL;{m<89	LL	LL6{mDE	LL	LL 
LL	LL	LL/0	LL	LL"#	LL#$	LL34	LL	LL-.m$S %	LL 
LLRS	LL>.!123	LL &--dF;CCCO	LL
#H:->?R>SS`a 
LLZ 
LL-.	LL	LL&'	LL	LL 
LL )# )	$+X 
LL	LL 
LL i' i	(kX 
LL	LL [	
 	EF[	
 DLL.t45  
LL	LL-.	LL	LL99Ur   r1   objectc                0    V ^8  d   QhR\         R\         /# )r   r   r   ra   )r   s   "r   r   r     s     , ,# ,# ,r   c                    \        V 4      p\        P                  ! RRV4      p\        P                  ! RRV4      pVP                  4       P	                  RR4      P                  R4      pV'       d   RV 2# R# )u   Convert a JSON Schema property name to its CLI flag form.

Replicates cyclopts' default_name_transform: camelCase → snake_case,
lowercase, underscores → hyphens, strip leading/trailing hyphens.
z(.)([A-Z][a-z]+)z\1_\2z([a-z0-9])([A-Z])rc   r   z--z--arg)rk   re   rf   r   r   strip)r   rj   s   & r   _param_to_cli_flagr     sj     !+D66%x6D66&$7D::<S)//4DRv;+G+r   c                R    V ^8  d   QhR\         \        \        3,          R\        /# )r   r   r   rD   )r   s   "r   r   r   &  s"      DcN s r   c                   V P                  RR4      p\        V\        4      '       d6   V Uu. uF  p\        P                  W"4      NK  	  ppRP	                  V4      # \        P                  W4      pVR8X  dL   V P                  R/ 4      pVP                  RR4      p\        V\
        4      '       d   V\        9   d   RV R2# V# u upi )	z9Return a human-readable type label for a property schema.r   r   r>   r1   r2   rv   zarray[r<   )r'   r(   r)   _JSON_SCHEMA_TYPE_LABELSr?   r   )r   r+   r$   labelslabelr2   r5   s   &      r   _schema_type_labelr   &  s    //&(3K+t$$>IJk*..q4kJzz&!!$((BE g,IIfb)	i%%)7O*OI;a((L Ks   Cc                d    V ^8  d   QhR\         P                  P                  R\        R\        /# )r   rm   cli_filenamer   rn   )r   s   "r   r   r   9  s)     1 1ciinn 1C 1C 1r   c                
   V P                   pVP                  R/ 4      p\        VP                  R. 4      4      p. pVP                  4        Fz  w  rg\	        V4      pVP                  R4      p	V	R8H  ;'       g    \        V	\        4      ;'       d    RV	9   p
V
'       d   VP                  V4       Kf  VP                  V R24       K|  	  RP                  V4      pRV RV P                   2pV'       d   VRV 2,          p. pVP                  4        F  w  rR	\	        V4       R	2p\        V4      P                  R
R4      pW9   d   RMRpVP                  RR4      p\        V4      w  ppV'       d   V'       d   V R2MRpVP                  RR4      P                  R
R4      pVP                  RV RV RV RV R2	4       K  	  RpV'       d&   RpRV R2RP                  V4      ,           R,           pRV P                   2.pV P                  '       d   VP                  RV P                  .4       VP                  RRVR.4       V'       d#   VP                  RVP                  R4      .4       RP                  V4      # )z.Generate a SKILL.md section for a single tool.rs   rt   r   r   z <value>r   uv run --with fastmcp python z call-tool `|z\|yesnoru   rv   z (JSON string)zJSON stringrG   z| r>   z |zQ| Flag | Type | Required | Description |
|------|------|----------|-------------|z### ```bash```)r   r'   rR   r2   r   r(   r)   rZ   r?   r`   r   r   rB   ru   r   r   )rm   r   r   rs   rt   flag_parts_listpp_schemaflagr+   is_bool
flag_parts
invocationrowsr   r   
type_labelr   ru   rc   r   param_tableheaderrM   s   &&                      r   _tool_skill_sectionr   9  sn   F!'L"!=J6::j"-.H "$O!'')!!$ll6** 
 
{D)FFi;.F 	 ""4(""dV8#45 * /*J0k$))UJ*&&
 D","2"2"4	%i013'4<<S%H
(4e$!oomR8.{;:2=;-~.=  "))$4<<S%Hbc*SSRPQ #5 Ke6("o		$7$>tyyk*+Eb$**+,	LL"iU34b+++D12399Ur   c                    V ^8  d   QhR\         R\         R\        \        P                  P                  ,          R\         /# )r   r   r   r   r   )r   r)   ro   rp   rq   )r   s   "r   r   r   m  s=     + +++ 		+ 		+r   c                  a V P                  RR4      P                  4       P                  RR4      P                  RR4      pV P                  RR4      P                  RR4      pRV R2pRR	V R
2RV R2RRRV  R2R.pV'       d1   RP                  V3R lV 4       4      pVP                  RRVR.4       VP                  RRRRS R2RS R2RS R2RS R2RS R2RR.
4       RP                  V4      # )z4Generate a SKILL.md file for a generated CLI script.r   r   rx   rv   rz   zCLI for the z9 MCP server. Call tools, list resources, and get prompts.z---zname: "z-cli"zdescription: "z# z CLIz

c              3   <   <"   T F  p\        VS4      x  K  	  R # 5ir!   )r   )r#   rm   r   s   & r   r%   )generate_skill_content.<locals>.<genexpr>  s      "
@El33s   z## Tool Commandsz## Utility Commandsr   r   z list-toolsz list-resourcesz read-resource <uri>z list-promptsz" get-prompt <name> [key=value ...]r   rG   )r   r   r?   r   )r   r   r   
skill_namer   ru   rM   tool_bodiess   &f&     r   generate_skill_contentr   m  sM    	C%++-55dB?GGRP  ##D"-55c2>I +deK 	
*U#
Q'

[M
E kk "
@E"
 
 	("k2>?	LL!+L>E+L>I+L>9MN+L>G+L>9[\	
 99Ur   forceFtimeoutauthno_skillc                $   V ^8  d   QhR\         \        \        P                  ! RR7      3,          R\         \        \        P                  ! RR7      3,          R\         \        \        P                  ! RR.R	R
7      3,          R\         \
        R,          \        P                  ! RRR7      3,          R\         \        R,          \        P                  ! RRR7      3,          R\         \        \        P                  ! RRR7      3,          RR/# )r   r   zEServer URL, Python file, MCPConfig JSON, discovered name, or .js file)helpoutputz"Output file path (default: cli.py)r   z-fz--forcez"Overwrite output file if it exists)r`   r   r   Nz	--timeoutzConnection timeout in secondsr   z--authzAAuth method: 'oauth', a bearer token string, or 'none' to disabler   z
--no-skillz8Skip generating a SKILL.md agent skill alongside the CLIr   )r   r   cyclopts	Parameterr   r4   )r   s   "r   r   r     s1    uB uBX	
	uB 5	
	uB 	"5	
	uB* ;-LM	O+uB2 d
T	
	3uB@ K	
	AuBN 
OuBr   c          	       "   \        V4      pVP                  R,          p. pVP                  4       '       d   V'       g   VP                  V4       V'       g0   VP                  4       '       d   V'       g   VP                  V4       V'       dH   RP	                  R V 4       4      p	\
        P                  RV	 R24       \        P                  ! ^4       \        V 4      p
\        V
4      w  r\        V 4      p\        WVR7      p T;_uu_4       GRj  xL
  VP                  4       G Rj  xL
 p\
        P                  R\        V4       R	V  R
24       RRR4      GRj  xL
  \'        TT TTXR7      pTP)                  T4       TP+                  TP-                  4       P.                  ^I,          4       \
        P                  RT R\        T4       R24       T'       gC   \1        TTP2                  TR7      pTP)                  T4       \
        P                  RT R24       \
        P                  RT R24       R#  EL- EL L  + GRj  xL 
 '       g   i     L; i  \        \         \"        \$        3 d:   p\
        P                  RT 24       \        P                  ! ^4        Rp?ELNRp?ii ; i5i)a  Generate a standalone CLI script from an MCP server.

Connects to the server, reads its tools/resources/prompts, and writes
a Python script that can invoke them directly. Also generates a SKILL.md
agent skill file unless --no-skill is passed.

Examples:
    fastmcp generate-cli weather
    fastmcp generate-cli weather my_cli.py
    fastmcp generate-cli http://localhost:8000/mcp
    fastmcp generate-cli server.py output.py -f
    fastmcp generate-cli weather --no-skill
zSKILL.mdrT   c              3   .   "   T F  pR V R2x  K  	  R# 5i)z[cyan][/cyan]Nr   )r#   r   s   & r   r%   'generate_cli_command.<locals>.<genexpr>  s     @x!F1#W-xs   z[bold red]Error:[/bold red] z4 already exist(s). Use [cyan]-f[/cyan] to overwrite.)r   r   Nz[dim]Discovered z tool(s) from z[/dim]z/[bold red]Error:[/bold red] Could not connect: )r   r   r   r   r   u   [green]✓[/green] Wrote [cyan]z[/cyan] with z tool command(s))r   r   r   r   z[dim]Run: python z --help[/dim])r   parentexistsrZ   r?   consoleprintsysexitr	   r^   _derive_server_namer   
list_toolslenRuntimeErrorTimeoutErrorr   OSErrorr   
write_textchmodstatst_moder   r`   )r   r   r   r   r   r   output_path
skill_pathexistingnamesrQ   r   r   r   clientr   excscriptskill_contents   &&$$$$             r   generate_cli_commandr     s=    j v,K##j0J HE$
))++E
#		@x@@*5' 20 1	
 	 #;/H$7$A!N &k2K 84@F	66 ++--EMM"3u:,n[MP 6 !%#F 6"k&&(00589MM
)+ 7E
|+	-
 .#$))

 	m,7
|7KLMM%k]-@AI - 666 ,': GuMNs   >J?J?J?0J?8J?A7J?	I( II( I/I0)II( $I
%I( )CJ?I( I
I( I%	I
I%	I%	 I( $J?%I( (J<.J71J?7J<<J?c                0    V ^8  d   QhR\         R\         /# )r   r   r   ra   )r   s   "r   r   r     s      S S r   c                T   V P                  R4      '       d"   \        V 4      pVP                  ;'       g    R# V P                  R4      '       d   \	        V 4      P
                  # RV 9   d=   V P                  R^4      ^,          pT;'       g    V P                  R^4      ^ ,          # V # )z0Derive a human-friendly name from a server spec.server:)zhttp://zhttps://)z.pyz.jsz.json)r   r   hostnameendswithr   stemrK   )r   parsedr`   s   &  r   r   r     s     566+&**(* 344K %%% k  a(+33{((a033r   c                b    V ^8  d   Qh/ ^ \         9   d   \        \        \        3,          ;R&   # )r   r   )__conditional_annotations__r   r   )r   s   "r   r   r      s)     J JX $sCx. Y Kr   >   r   r   r   r   r   )zcli.py)0r  __doc__rh   re   r   r   pathlibr   typingr   r   urllib.parser   r   	mcp.typesro   rH   r   rich.consoler   fastmcp.cli.clientr   r	   fastmcp.client.transports.baser
   fastmcp.client.transports.stdior   fastmcp.utilities.loggingr   loggerr   r"   r,   r8   rB   rO   r^   rk   r   r   r   r   r   r   r   r   r   r   )r  s   @r   <module>r     s   J  	 
   ! !       A : : 0	N	#
) C(8#L&!Bmjkf hyhy
FWh,  ,&1h+fuB( 	)uB0 	1uB> 	?uBL 	MuB uBpr   