
    i?                    8   d Z ddlmZ ddlmZmZmZ ddlmZm	Z	m
Z
mZ ddlZddlmZ ddlmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZ ddlmZmZmZ erddl m!Z!  ee"      Z# e
de	      Z$ e
d      Z%	 	 	 	 	 	 ddZ&	 	 	 	 	 	 	 	 ddZ' G d d      Z(y)zGMCP protocol handler setup and wire-format handlers for FastMCP Server.    )annotations)	AwaitableCallableSequence)TYPE_CHECKINGAnyTypeVarcastN)McpError)ContentBlock)AnyUrl)DisabledErrorNotFoundError)TaskMeta)
get_logger)paginate_sequence)VersionSpecparse_version_keyversion_sort_key)FastMCPC)bound	PaginateTc                   i }| D ])  }|j                   ||      g       j                  |       + g }|j                         D ]  }t        t        t        |t                    }t        d |D              rwt        |D cg c]  }|j                  |j                   c}t        d      }|j                  xs i }|j                  di |di |j                  di       d|iii      }|j                  |        |S c c}w )	a  Deduplicate components by key, keeping highest version.

    Groups components by key, selects the highest version from each group,
    and injects available versions into meta if any component is versioned.

    Args:
        components: Sequence of components to deduplicate.
        key_fn: Function to extract the grouping key from a component.

    Returns:
        Deduplicated list with versions injected into meta.
    )keyc              3  8   K   | ]  }|j                   d u  y wN)version).0cs     t/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/server/mixins/mcp_operations.py	<genexpr>z(_dedupe_with_versions.<locals>.<genexpr>3   s     7hqyy$hs   T)r   reversemetafastmcpversions)update)
setdefaultappendvaluesr
   r   maxr   anysortedr   r   r$   
model_copyget)	
componentskey_fnby_keyr    resultr&   highestall_versionsr$   s	            r!   _dedupe_with_versionsr6      s     "$F&)R(//2  FMMO!S/?@A7h77!$,FHq		0EHF%L
 <<%2D(( ! $"hhy"5$&$ ) 
G 	g) $* M# Gs    D
D
c           	         |t        |       dfS 	 t        | ||      S # t        $ r9}t        t        j
                  j                  dt        |                  |d}~ww xY w)zApply pagination to items, raising McpError for invalid cursors.

    If page_size is None, returns all items without pagination.
    Nicodemessage)listr   
ValueErrorr   mcptypes	ErrorDatastr)itemscursor	page_sizees       r!   _apply_paginationrE   I   se     E{D  P 	:: Psyy**A*GHaOPs    	A 4AA c                      e Zd ZdZddZ	 	 	 	 	 	 ddZ	 	 	 	 ddZ	 	 	 	 ddZ	 	 	 	 ddZ	 	 	 	 ddZ		 	 	 	 	 	 ddZ
	 	 	 	 dd	Z	 	 	 	 	 	 dd
Zy)MCPOperationsMixina  Mixin providing MCP protocol handler setup and wire-format handlers.

    Note: Methods registered with SDK decorators (e.g., _list_tools_mcp, _call_tool_mcp)
    cannot use `self: FastMCP` type hints because the SDK's `get_type_hints()` fails
    to resolve FastMCP at runtime (it's only available under TYPE_CHECKING). When
    type hints fail to resolve, the SDK falls back to calling handlers with no arguments.
    These methods use untyped `self` to avoid this issue.
    c                    | j                   j                         | j                          | j                   j                         | j                          | j                   j                         | j                         | j                  | j                        | j                   j                  t        j                  j                  <    | j                   j                  | j                        | j                          | j                   j!                         | j"                          | j                   j%                         | j&                         | j)                          y)aR  Set up core MCP protocol handlers.

        List handlers use SDK decorators that pass the request object to our handler
        (needed for pagination cursor). The SDK also populates caches like _tool_cache.

        Exception: list_resource_templates SDK decorator doesn't pass the request,
        so we register that handler directly.

        The call_tool decorator is from the SDK (supports CreateTaskResult + validate_input).
        The read_resource and get_prompt decorators are from LowLevelServer to add
        CreateTaskResult support until the SDK provides it natively.
        )validate_inputN)_mcp_server
list_tools_list_tools_mcplist_resources_list_resources_mcplist_prompts_list_prompts_mcp_wrap_list_handler_list_resource_templates_mcprequest_handlersr=   r>   ListResourceTemplatesRequest	call_toolstrict_input_validation_call_tool_mcpread_resource_read_resource_mcp
get_prompt_get_prompt_mcp_setup_task_protocol_handlers)selfs    r!   _setup_handlersz"MCPOperationsMixin._setup_handlersd   s    	&##%d&:&:;)'')$*B*BC'%%'(>(>?
 ##D$E$EF 	))#))*P*PQ 	P""$2N2N"O	
 	)&&()@)@A%##%d&:&:; 	**,    c                    dfd}|S )z@Wrap a list handler to pass the request and return ServerResult.c                n   K    |        d {   }t         j                  j                  |      S 7 #wr   )r=   r>   ServerResult)requestr3   handlers     r!   wrapperz6MCPOperationsMixin._wrap_list_handler.<locals>.wrapper   s.     "7++F99))&11 ,s   53$5)rc   r   returnzmcp.types.ServerResult )r]   rd   re   s    ` r!   rQ   z%MCPOperationsMixin._wrap_list_handler   s    
	2 r_   c                  K   t        d|       }t        j                  d|j                   d       t	        t        |j                          d{         d       }|D cg c]  }|j                  |j                          }}|"|j                  r|j                  j                  nd}t        |||j                        \  }}t        j                  j                  ||      S 7 c c}w w)z
        List all available tools, in the format expected by the low-level MCP
        server. Supports pagination when list_page_size is configured.
        r   [z] Handler called: list_toolsNc                    | j                   S r   namets    r!   <lambda>z4MCPOperationsMixin._list_tools_mcp.<locals>.<lambda>   s    QRQWQWr_   rk   )tools
nextCursor)r
   loggerdebugrl   r6   r;   rK   to_mcp_toolparamsrB   rE   _list_page_sizer=   r>   ListToolsResult)	r]   rc   serverrp   tool	sdk_toolsrB   pagenext_cursors	            r!   rL   z"MCPOperationsMixin._list_tools_mcp   s      i&q%ABC%d1B1B1D+D&EGWXBGH%$T%%499%5%	H &-%8W^^GNN!!QU 	 .iAWAWXkyy((t(LL ,EHs%   AC/C(C/"#C*A$C/*C/c                  K   t        d|       }t        j                  d|j                   d       t	        t        |j                          d{         d       }|D cg c]'  }|j                  t        |j                              ) }}|j                  r|j                  j                  nd}t        |||j                        \  }}t        j                  j!                  ||      S 7 c c}w w)z
        List all available resources, in the format expected by the low-level MCP
        server. Supports pagination when list_page_size is configured.
        r   ri   z ] Handler called: list_resourcesNc                ,    t        | j                        S r   )r@   uri)rs    r!   ro   z8MCPOperationsMixin._list_resources_mcp.<locals>.<lambda>   s    3quu:r_   )r   )	resourcesrq   )r
   rr   rs   rl   r6   r;   rM   to_mcp_resourcer@   r   ru   rB   rE   rv   r=   r>   ListResourcesResult)	r]   rc   rx   r   resourcesdk_resourcesrB   r{   r|   s	            r!   rN   z&MCPOperationsMixin._list_resources_mcp   s      i&q%EFG)v,,../1E
	 MV
LUH$$X\\):$;I 	 
 +2..&&d-66#9#9
k yy,,t,TT /
s%   AC6C/C6",C1A"C61C6c                  K   t        d|       }t        j                  d|j                   d       t	        t        |j                          d{         d       }|D cg c]  }|j                  |j                          }}|j                  r|j                  j                  nd}t        |||j                        \  }}t        j                  j                  ||      S 7 c c}w w)z
        List all available resource templates, in the format expected by the low-level MCP
        server. Supports pagination when list_page_size is configured.
        r   ri   z)] Handler called: list_resource_templatesNc                    | j                   S r   )uri_templaterm   s    r!   ro   zAMCPOperationsMixin._list_resource_templates_mcp.<locals>.<lambda>   s    ANNr_   )uriTemplate)resourceTemplatesrq   )r
   rr   rs   rl   r6   r;   list_resource_templatesto_mcp_templater   ru   rB   rE   rv   r=   r>   ListResourceTemplatesResult)	r]   rc   rx   	templatestemplatesdk_templatesrB   r{   r|   s	            r!   rR   z/MCPOperationsMixin._list_resource_templates_mcp   s      i&q%NOP)v55778:R
	
 &
% $$1F1F$G% 	 
 +2..&&d-66#9#9
k yy44"{ 5 
 	
 8
%   AC-C&C-"#C(A"C-(C-c                  K   t        d|       }t        j                  d|j                   d       t	        t        |j                          d{         d       }|D cg c]  }|j                  |j                          }}|j                  r|j                  j                  nd}t        |||j                        \  }}t        j                  j                  ||      S 7 c c}w w)z
        List all available prompts, in the format expected by the low-level MCP
        server. Supports pagination when list_page_size is configured.
        r   ri   z] Handler called: list_promptsNc                    | j                   S r   rk   )ps    r!   ro   z6MCPOperationsMixin._list_prompts_mcp.<locals>.<lambda>   s    r_   rk   )promptsrq   )r
   rr   rs   rl   r6   r;   rO   to_mcp_promptru   rB   rE   rv   r=   r>   ListPromptsResult)	r]   rc   rx   r   promptsdk_promptsrB   r{   r|   s	            r!   rP   z$MCPOperationsMixin._list_prompts_mcp   s      i&q%CDE'v**,,-/?
 MTTG&v+++=GT*1..&&d-!7!7
k yy**4K*PP -Tr   c                R  K   t        d|       }t        j                  d|j                   d||       	 d}d}	 |j                  j
                  }|j                  r=|j                  j                  d      }|j                  di       j                  d      }|j                  j                  rC|j                  j                  }|j                  d      }	t        |	j                  d	      
      }|rt        |      nd}
|j!                  |||
|       d{   }t#        |t$        j&                  j(                        r|S |j+                         S # t        t        f$ r Y tw xY w7 O# t,        $ r}t/        d|      |d}~wt.        $ r}t/        d|      |d}~ww xY ww)a  
        Handle MCP 'callTool' requests.

        Extracts task metadata from MCP request context and passes it explicitly
        to call_tool(). The tool's _run() method handles the backgrounding decision,
        ensuring middleware runs before Docket.

        Args:
            key: The name of the tool to call
            arguments: Arguments to pass to the tool

        Returns:
            Tool result or CreateTaskResult for background execution
        r   ri   z&] Handler called: call_tool %s with %sNTexclude_noner%   r   ttlr   eqr   	task_metazUnknown tool: )r
   rr   rs   rl   rJ   request_contextr$   
model_dumpr/   experimentalis_tasktask_metadatar   AttributeErrorLookupErrorr   rU   
isinstancer=   r>   CreateTaskResultto_mcp_resultr   r   )r]   r   	argumentsrx   version_strr   ctx	meta_dictmcp_task_metatask_meta_dictr   r3   rD   s                r!   rW   z!MCPOperationsMixin._call_tool_mcp   s    , i&}BCS)	
	A '+K)-I((8888 # 3 3 3 FI"+--	2">"B"B9"MK##++$'$4$4$B$BM%2%=%=4%=%PN (^-?-?-F GI 6Ak[1dG!++Y9 ,  F &#))"<"<='')) #K0   	A. 89q@ 	A. 89q@	Asp   2F'E, B8E 2(E, E*)E, F'E, F'E'$E, &E''E, ,	F$5FF$FF$$F'c           
       K   t        d|       }t        j                  d|j                   d|       	 d}d}	 |j                  j
                  }|j                  rB|j                  j                  d      }|j                  d      xs i }|j                  d      }|j                  j                  rC|j                  j                  }|j                  d      }	t        |	j                  d	      
      }|rt        |      nd}
|j!                  t#        |      |
|       d{   }t%        |t&        j(                  j*                        r|S |j-                  |      S # t        t        f$ r Y }w xY w7 P# t.        $ r<}t1        t&        j(                  j3                  ddt#        |                  |d}~wt4        $ r3}t1        t&        j(                  j3                  dd|             |d}~ww xY ww)a  Handle MCP 'readResource' requests.

        Extracts task metadata from MCP request context and passes it explicitly
        to read_resource(). The resource's _read() method handles the backgrounding
        decision, ensuring middleware runs before Docket.

        Args:
            uri: The resource URI

        Returns:
            ReadResourceResult or CreateTaskResult for background execution
        r   ri   z"] Handler called: read_resource %sNTr   r%   r   r   r   r   r   izResource not found: r8   )r
   rr   rs   rl   rJ   r   r$   r   r/   r   r   r   r   r   r   r   rX   r@   r   r=   r>   r   r   r   r   r?   r   )r]   r   rx   r   r   r   r   fastmcp_metar   r   r   r3   rD   s                r!   rY   z%MCPOperationsMixin._read_resource_mcp%  s     i&q%GH#N$	&*K)-I((8888 # 3 3 3 FI#,==#;#ArL"."2"29"=K##++$'$4$4$B$BM%2%=%=4%=%PN (^-?-?-F GI 6Ak[1dG!//C'Y 0  F &#))"<"<='',, #K0   			##+?C|)L $  	
  			##;OPQs9S#T	sp   1G;E9 B=E" 60E9 &E7')E9 G;E9 !G;"E41E9 3E44E9 9	G87F99G8.G33G88G;c                .  K   t        d|       }t        j                  d|j                   d||       	 d}d}	 |j                  j
                  }|j                  r=|j                  j                  d      }|j                  di       j                  d      }|j                  j                  rC|j                  j                  }|j                  d      }	t        |	j                  d	      
      }|rt        |      nd}
|j!                  |||
|       d{   }t#        |t$        j&                  j(                        r|S |j+                         S # t        t        f$ r Y tw xY w7 O# t,        $ r}t/        d|      |d}~wt.        $ r  w xY ww)a  Handle MCP 'getPrompt' requests.

        Extracts task metadata from MCP request context and passes it explicitly
        to render_prompt(). The prompt's _render() method handles the backgrounding
        decision, ensuring middleware runs before Docket.

        Args:
            name: The prompt name
            arguments: Prompt arguments

        Returns:
            GetPromptResult or CreateTaskResult for background execution
        r   ri   z'] Handler called: get_prompt %s with %sNTr   r%   r   r   r   r   r   zUnknown prompt: )r
   rr   rs   rl   rJ   r   r$   r   r/   r   r   r   r   r   r   r   render_promptr   r=   r>   r   to_mcp_prompt_resultr   r   )r]   rl   r   rx   r   r   r   r   r   r   r   r3   rD   s                r!   r[   z"MCPOperationsMixin._get_prompt_mcp]  s      i&}CDdI	
	 '+K)-I((8888 # 3 3 3 FI"+--	2">"B"B9"MK##++$'$4$4$B$BM%2%=%=4%=%PN (^-?-?-F GI 6Ak[1dG!//iI 0  F &#))"<"<=..00 #K0   	D"24( ;<!C 		sd   2FE, B8E 2(E, E*)E, FE, FE'$E, &E''E, ,	F5FFFN)r]   r   rf   None)r]   r   rd   zCallable[..., Awaitable[Any]]rf   z0Callable[..., Awaitable[mcp.types.ServerResult]])rc   zmcp.types.ListToolsRequestrf   zmcp.types.ListToolsResult)rc   zmcp.types.ListResourcesRequestrf   zmcp.types.ListResourcesResult)rc   z&mcp.types.ListResourceTemplatesRequestrf   z%mcp.types.ListResourceTemplatesResult)rc   zmcp.types.ListPromptsRequestrf   zmcp.types.ListPromptsResult)r   r@   r   zdict[str, Any]rf   zvlist[ContentBlock] | tuple[list[ContentBlock], dict[str, Any]] | mcp.types.CallToolResult | mcp.types.CreateTaskResult)r   zAnyUrl | strrf   z9mcp.types.ReadResourceResult | mcp.types.CreateTaskResult)rl   r@   r   zdict[str, Any] | Nonerf   z6mcp.types.GetPromptResult | mcp.types.CreateTaskResult)__name__
__module____qualname____doc__r^   rQ   rL   rN   rR   rP   rW   rY   r[   rg   r_   r!   rG   rG   Z   s    -@		 =		9	M1M	"M,U5U	&U.
=
	.
2Q3Q	$Q(:A:A#1:A	%:Ax66	B6p33$93	?3r_   rG   )r0   zSequence[C]r1   zCallable[[C], str]rf   zlist[C])rA   zSequence[PaginateT]rB   z
str | NonerC   z
int | Nonerf   z"tuple[list[PaginateT], str | None]))r   
__future__r   collections.abcr   r   r   typingr   r   r	   r
   	mcp.typesr=   mcp.shared.exceptionsr   r   pydanticr   fastmcp.exceptionsr   r   fastmcp.server.tasks.configr   fastmcp.utilities.loggingr   fastmcp.utilities.paginationr   fastmcp.utilities.versionsr   r   r   fastmcp.server.serverr   r   rr   r   r   r6   rE   rG   rg   r_   r!   <module>r      s    M " 9 9 4 4  * "  ; 0 0 : W W-	H	CsK 	*** *ZPPP P (	P"v vr_   