
    $jE                       d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZ ddlZerddlmZ ddlmZ ddlmZ ddlZddlZdd	lmZmZ dd
lmZ ddlmZmZmZmZmZm Z  ddl!m"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-  G d dej.                  Z/ G d dej.                  Z0 G d de-          Zg dZ1ddZ2dS )z2Base classes and interfaces for FastMCP resources.    )annotationsN)Callable)TYPE_CHECKING	AnnotatedAnyClassVaroverload)Docket)	ExecutionFunctionResource)AnnotationsIcon)Resource)AnyUrl
ConfigDictFieldUrlConstraintsfield_validatormodel_validator)SkipJsonSchema)Self)FastMCPDeprecationWarning)	AuthCheck)
TaskConfigTaskMeta)FastMCPComponentc                  Z     e Zd ZU dZded<   dZded<   dZded<   	 	 dd fd
ZddZ xZ	S )ResourceContentaf  Wrapper for resource content with optional MIME type and metadata.

    Accepts any value for content - strings and bytes pass through directly,
    other types (dict, list, BaseModel, etc.) are automatically JSON-serialized.

    Example:
        ```python
        from fastmcp.resources import ResourceContent

        # String content
        ResourceContent("plain text")

        # Binary content
        ResourceContent(b"binary data", mime_type="application/octet-stream")

        # Auto-serialized to JSON
        ResourceContent({"key": "value"})
        ResourceContent(["a", "b", "c"])
        ```
    zstr | bytescontentN
str | None	mime_typedict[str, Any] | Nonemetar   c                "   t          |t                    r|}|pd}nMt          |t                    r|}|pd}n1t          j        |t                                                    }|pd}t                                          |||           dS )u  Create ResourceContent with automatic serialization.

        Args:
            content: The content value. str and bytes pass through directly.
                     Other types (dict, list, BaseModel) are JSON-serialized.
            mime_type: Optional MIME type. Defaults based on content type:
                       str → "text/plain", bytes → "application/octet-stream",
                       other → "application/json"
            meta: Optional metadata dictionary.
        
text/plainapplication/octet-stream)fallbackapplication/json)r    r"   r$   N)
isinstancestrbytespydantic_coreto_jsondecodesuper__init__)selfr    r"   r$   normalized_content	__class__s        ^/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/fastmcp/resources/base.pyr1   zResourceContent.__init__A   s      gs## 		8.5!1\II'' 	8!(!?%?II "/!6w!M!M!M!T!T!V!V!7%7I!3ytTTTTT    uriAnyUrl | strreturn?mcp.types.TextResourceContents | mcp.types.BlobResourceContentsc                   t          | j        t                    rXt          j                            t          |t                    rt          |          n|| j        | j        pd| j                  S t          j        	                    t          |t                    rt          |          n|t          j        | j                                                  | j        pd| j                  S )zConvert to MCP resource contents type.

        Args:
            uri: The URI of the resource (required by MCP types)

        Returns:
            TextResourceContents for str content, BlobResourceContents for bytes
        r&   )r7   textmimeType_metar'   )r7   blobr=   r>   )r*   r    r+   mcptypesTextResourceContentsr   r"   r$   BlobResourceContentsbase64	b64encoder/   )r2   r7   s     r5   to_mcp_resource_contentsz(ResourceContent.to_mcp_resource_contents^   s     dlC(( 	911#-c3#7#7@F3KKKS\7<i	 2    911#-c3#7#7@F3KKKS%dl33::<<E+Ei	 2   r6   )NN)r    r   r"   r!   r$   r#   )r7   r8   r9   r:   )
__name__
__module____qualname____doc____annotations__r"   r$   r1   rF   __classcell__r4   s   @r5   r   r   '   s          *  I    "&D&&&&
 !%&*	U U U U U U U:       r6   r   c                  b     e Zd ZU dZded<   dZded<   	 dd fdZedd
            ZddZ	 xZ
S )ResourceResulta  Canonical result type for resource reads.

    Provides explicit control over resource responses: multiple content items,
    per-item MIME types, and metadata at both the item and result level.

    Accepts:
        - str: Wrapped as single ResourceContent (text/plain)
        - bytes: Wrapped as single ResourceContent (application/octet-stream)
        - list[ResourceContent]: Used directly for multiple items or custom MIME types

    Example:
        ```python
        from fastmcp import FastMCP
        from fastmcp.resources import ResourceResult, ResourceContent

        mcp = FastMCP()

        # Simple string content
        @mcp.resource("data://simple")
        def get_simple() -> ResourceResult:
            return ResourceResult("hello world")

        # Multiple items with custom MIME types
        @mcp.resource("data://items")
        def get_items() -> ResourceResult:
            return ResourceResult(
                contents=[
                    ResourceContent({"key": "value"}),  # auto-serialized to JSON
                    ResourceContent(b"binary data"),
                ],
                meta={"count": 2}
            )
        ```
    list[ResourceContent]contentsNr#   r$   #str | bytes | list[ResourceContent]c                x    |                      |          }t                                          ||           dS )zCreate ResourceResult.

        Args:
            contents: String, bytes, or list of ResourceContent objects.
            meta: Optional metadata about the resource result.
        )rQ   r$   N)_normalize_contentsr0   r1   )r2   rQ   r$   
normalizedr4   s       r5   r1   zResourceResult.__init__   s;     --h77
*488888r6   r9   c           
     |   t          | t                    rt          |           gS t          | t                    rt          |           gS t          | t                    rWt          |           D ]E\  }}t          |t                    s+t          d| dt          |          j         d|d          F| S t          | t          t          z  t          z  t          z  t          z  t          z            s| $t          t          j        |           d          gS t          dt          |           j                   )	z)Normalize input to list[ResourceContent].z	contents[z] must be ResourceContent, got z. Use ResourceContent(z) to wrap the value.Nr)   )r"   z;contents must be str, bytes, or list[ResourceContent], got )r*   r+   r   r,   list	enumerate	TypeErrortyperG   dicttupleintfloatbooljsondumps)rQ   iitems      r5   rT   z"ResourceResult._normalize_contents   sa   
 h$$ 	/#H--..h&& 	/#H--..h%% 	$X..  4!$88 #LA L Ld4jjFY L L/3L L L  
 O xu!4s!:U!BT!IJJ	Y#DJx$8$8DVWWWXXc$x..Jacc
 
 	
r6   r7   r8   mcp.types.ReadResourceResultc                v    fd| j         D             }t          j                            || j                  S )zConvert to MCP ReadResourceResult.

        Args:
            uri: The URI of the resource (required by MCP types)

        Returns:
            MCP ReadResourceResult with converted contents
        c                :    g | ]}|                               S  )rF   ).0rc   r7   s     r5   
<listcomp>z0ResourceResult.to_mcp_result.<locals>.<listcomp>   s'    UUUt55c::UUUr6   )rQ   r>   )rQ   r@   rA   ReadResourceResultr$   )r2   r7   mcp_contentss    ` r5   to_mcp_resultzResourceResult.to_mcp_result   sH     VUUUt}UUUy++!) , 
 
 	
r6   N)rQ   rR   r$   r#   )rQ   rR   r9   rP   )r7   r8   r9   rd   )rG   rH   rI   rJ   rK   r$   r1   staticmethodrT   rl   rL   rM   s   @r5   rO   rO   y   s         ! !F $###"&D&&&&
 '+9 9 9 9 9 9 9 
 
 
 \
6
 
 
 
 
 
 
 
r6   rO   c                      e Zd ZU dZdZded<    ed          Z edd	          Z	d
ed<    edd	          Z
ded<    edd	          Zded<   dZded<   dZded<   edddddddddddddSd-            Z edd./          edTd0                        Z ed1/          dUd3            ZdVd5ZdWd9ZedXdYd<            ZedZd?            Z	 dXd[dBZd\dEZd]dFZed]dG            Zd^dJZdddKd_dPZd` fdRZ xZS )ar   zBase class for all resources.resourcezClassVar[str]
KEY_PREFIXT)validate_default.zURI of the resource)defaultdescriptionz6Annotated[AnyUrl, UrlConstraints(host_required=False)]r7    zName of the resourcer+   namer&   z!MIME type of the resource contentr"   NzfAnnotated[Annotations | None, Field(description="Optional annotations about the resource's behavior")]r   zAnnotated[SkipJsonSchema[AuthCheck | list[AuthCheck] | None], Field(description='Authorization checks for this resource', exclude=True)]auth)rv   versiontitlert   iconsr"   tagsr   r$   taskrw   fnCallable[..., Any]str | AnyUrlr!   rx   str | int | Nonery   rt   rz   list[Icon] | Noner{   set[str] | NoneAnnotations | Noner$   r#   r|   bool | TaskConfig | None"AuthCheck | list[AuthCheck] | Noner9   r   c               H    ddl m}  |j        |||||||||	|
|||          S )Nr   r   )r}   r7   rv   rx   ry   rt   rz   r"   r{   r   r$   r|   rw   )#fastmcp.resources.function_resourcer   from_function)clsr}   r7   rv   rx   ry   rt   rz   r"   r{   r   r$   r|   rw   r   s                  r5   r   zResource.from_function   sf    $	
 	
 	
 	
 	
 	
 .-##
 
 
 	
r6   before)modec                    |r|S dS )z&Set default MIME type if not provided.r&   rg   )r   r"   s     r5   set_default_mime_typezResource.set_default_mime_type  s      	|r6   afterr   c                v    | j         rn0| j        rt          | j                  | _         nt          d          | S )z*Set default name from URI if not provided.z#Either name or uri must be provided)rv   r7   r+   
ValueErrorr2   s    r5   set_default_namezResource.set_default_name   sB     9 	DX 	DDHDIIBCCCr6   str | bytes | ResourceResultc                $   K   t          d          )a
  Read the resource content.

        Subclasses implement this to return resource data. Supported return types:
            - str: Text content
            - bytes: Binary content
            - ResourceResult: Full control over contents and result-level meta
        z Subclasses must implement read())NotImplementedErrorr   s    r5   readzResource.read+  s       ""DEEEr6   	raw_valuer   rO   c                8   t          |t                    r|S t          |t          t          f          r*t          t	          || j        | j                  g          S t          |t          t          z  t          z  t          z  t          z  t          z            s|pt          |t                    r|rt          |d         t                    s>t          t	          t          j        |          | j        pd| j                  g          S t          |          S )a$  Convert a raw result to ResourceResult.

        This is used in two contexts:
        1. In _read() to convert user function return values to ResourceResult
        2. In tasks_result_handler() to convert Docket task results to ResourceResult

        Handles ResourceResult passthrough and converts raw values using
        ResourceResult's normalization.  When the raw value is a plain
        string or bytes, the resource's own ``mime_type`` is forwarded so
        that ``ui://`` resources (and others with non-default MIME types)
        don't fall back to ``text/plain``.

        The resource's component-level ``meta`` (e.g. ``ui`` metadata for
        MCP Apps CSP/permissions) is propagated to each content item so
        that hosts can read it from the ``resources/read`` response.
        )r"   r$   Nr   r)   )r*   rO   r+   r,   r   r"   r$   r[   rW   r\   r]   r^   r_   r`   ra   )r2   r   s     r5   convert_resultzResource.convert_result7  s   " i00 	
 i#u.. 	! dn49UUUV   y$+"5";e"Cd"JKK	 y$'' !  ! 9Q<99	 ! "#
9--"&."F4F!Y     i(((r6   	task_metaNonec                
   K   d S rm   rg   r2   r   s     r5   _readzResource._readm  s      EHSr6   r   mcp.types.CreateTaskResultc                
   K   d S rm   rg   r   s     r5   r   zResource._readp  s      NQcr6   TaskMeta | None+ResourceResult | mcp.types.CreateTaskResultc                   K   ddl m}  || dd|           d{V }|r|S |                                  d{V }|                     |          S )a  Server entry point that handles task routing.

        This allows ANY Resource subclass to support background execution by setting
        task_config.mode to "supported" or "required". The server calls this
        method instead of read() directly.

        Args:
            task_meta: If provided, execute as a background task and return
                CreateTaskResult. If None (default), execute synchronously and
                return ResourceResult.

        Returns:
            ResourceResult when task_meta is None.
            CreateTaskResult when task_meta is provided.

        Subclasses can override this to customize task routing behavior.
        For example, FastMCPProviderResource overrides to delegate to child
        middleware without submitting to Docket.
        r   )check_background_taskrp   N)	component	task_type	argumentsr   )fastmcp.server.tasks.routingr   r   r   )r2   r   r   task_resultresults        r5   r   zResource._reads  s      , 	GFFFFF11jDI
 
 
 
 
 
 
 
 
  	 yy{{""""""""6***r6   	overridesSDKResourcec                   t          |                    d| j                  |                    d| j                  |                    d| j                  |                    d| j                  |                    d| j                  |                    d| j                  |                    d| j                  |                    d| 	                                          	          S )
z'Convert the resource to an SDKResource.rv   r7   rt   r=   ry   rz   r   r>   )rv   r7   rt   r=   ry   rz   r   r>   )
r   getrv   r7   rt   r"   ry   rz   r   get_meta)r2   r   s     r5   to_mcp_resourcezResource.to_mcp_resource  s     vty11eTX..!mT5EFF]]:t~>>--44--44!mT5EFF-- 
 
 
 	
r6   c           
     `    | j         j         d| j        d| j        d| j        d| j         d
S )Nz(uri=z, name=z, description=z, tags=))r4   rG   r7   rv   rt   r{   r   s    r5   __repr__zResource.__repr__  sj    .)  F  F  F  F49  F  F^b^n  F  Fy}  zC  F  F  F  	Fr6   c                l    |                      t          | j                            }| d| j        pd S )z1The globally unique lookup key for this resource.@ru   )make_keyr+   r7   rx   )r2   base_keys     r5   keyzResource.key  s8     ==TX//11T\/R111r6   docketr
   c                    | j                                         sdS |                    | j        | j        g           dS )z<Register this resource with docket for background execution.N)names)task_configsupports_tasksregisterr   r   )r2   r   s     r5   register_with_docketzResource.register_with_docket  s@    ..00 	F	$(44444r6   )fn_keytask_keyr   r   kwargsr   c               ^   K   |p| j         }|r||d<     |j        |fi |             d{V S )aC  Schedule this resource for background execution via docket.

        Args:
            docket: The Docket instance
            fn_key: Function lookup key in Docket registry (defaults to self.key)
            task_key: Redis storage key for the result
            **kwargs: Additional kwargs passed to docket.add()
        r   N)r   add)r2   r   r   r   r   
lookup_keys         r5   add_to_docketzResource.add_to_docket  sY        'tx
 	%$F5M5ZVZ
55f55777777777r6   dict[str, Any]c                P    t                                                      dddz  S )Nrp   LocalProvider)zfastmcp.component.typezfastmcp.provider.type)r0   get_span_attributes)r2   r4   s    r5   r   zResource.get_span_attributes  s0    ww**,,&0%40
 0
 
 	
r6   )r}   r~   r7   r   rv   r!   rx   r   ry   r!   rt   r!   rz   r   r"   r!   r{   r   r   r   r$   r#   r|   r   rw   r   r9   r   )r"   r!   r9   r+   )r9   r   )r9   r   )r   r   r9   rO   rm   )r   r   r9   rO   )r   r   r9   r   )r   r   r9   r   )r   r   r9   r   )r9   r+   )r   r
   r9   r   )
r   r
   r   r!   r   r!   r   r   r9   r   )r9   r   ) rG   rH   rI   rJ   rq   rK   r   model_configr   r7   rv   r"   r   rw   classmethodr   r   r   r   r   r   r   r	   r   r   r   propertyr   r   r   r   rL   rM   s   @r5   r   r      s        '' *J****:t444LBG%!6C C CC     b.DEEEDEEEEU7  I     	      	 	    
   $( "&#' $ $*.&*)-37#
 #
 #
 #
 #
 [#
J _[x000   [ 10 _'"""   #"
F 
F 
F 
F4) 4) 4) 4)l HHHH XHQQQ XQ ,0 +  +  +  +  +D
 
 
 
&F F F F 2 2 2 X2
5 5 5 5 "#8 8 8 8 8 8*
 
 
 
 
 
 
 
 
 
r6   r   )r   r   rO   rv   r+   r9   r   c                    ddd}| |v rKddl }ddl}|j        j        r!|                    d|  dt
          d	           dd
lm} t          ||           S t          dt          d|           )z2Deprecated re-exports for backwards compatibility.r   rp   )r   rp   r   Nz
Importing zh from fastmcp.resources.resource is deprecated. Import from fastmcp.resources.function_resource instead.   )
stacklevel)function_resourcezmodule z has no attribute )warningsfastmcpsettingsdeprecation_warningswarnr   fastmcp.resourcesr   getattrAttributeErrorrG   )rv   deprecated_exportsr   r   r   s        r5   __getattr__r     s     / 
 !!!0 	MMLT L L L)	     	877777($///
I8IIII
J
JJr6   )rv   r+   r9   r   )3rJ   
__future__r   rD   r`   collections.abcr   typingr   r   r   r   r	   	mcp.typesr@   r   r
   docket.executionr   r   r   pydanticr-   r   r   r   r   r   r   r   r   r   r   pydantic.json_schemar   typing_extensionsr   fastmcp.exceptionsr   !fastmcp.server.auth.authorizationr   fastmcp.server.tasks.configr   r   fastmcp.utilities.componentsr   	BaseModelr   rO   __all__r   rg   r6   r5   <module>r      s   8 8 " " " " " "   $ $ $ $ $ $ D D D D D D D D D D D D D D     E******DDDDDD      ' ' ' ' ' ' ' ' - - - - - -                0 / / / / / " " " " " " 8 8 8 8 8 8 7 7 7 7 7 7 < < < < < < < < 9 9 9 9 9 9O O O O Oh( O O Od^
 ^
 ^
 ^
 ^
X' ^
 ^
 ^
Bv
 v
 v
 v
 v
 v
 v
 v
r  K K K K K Kr6   