o
    )j-                     @   s   d Z ddlmZmZmZ ddlZddlmZ ddlm	Z	m
Z
 ddlmZ e ZdZG dd	 d	eZG d
d deZG dd deZG dd deZdS )z
MCP (Model Context Protocol) API interface for ModelScope Hub.

This module provides a simple interface to interact with
ModelScope MCP plaza (https://www.modelscope.cn/mcp).
    )AnyDictOptionalN)HubApi)RequestErrorraise_for_http_status)
get_loggerz/openapi/v1/mcp/serversc                   @      e Zd ZdZdS )MCPApiErrorz"Base exception for MCP API errors.N__name__
__module____qualname____doc__ r   r   W/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/modelscope/hub/mcp_api.pyr
          r
   c                   @   r	   )MCPApiRequestErrorz,Exception raised when MCP API request fails.Nr   r   r   r   r   r      r   r   c                   @   r	   )MCPApiResponseErrorz2Exception raised when MCP API response is invalid.Nr   r   r   r   r   r   !   r   r   c                       s   e Zd ZdZ		ddee dee ddf fddZededefd	d
Z				ddee dee	ee
f  dee dee de	ee
f f
ddZ	ddede	ee
f fddZ	ddedee de	ee
f fddZ  ZS )MCPApiaU  
    MCP (Model Context Protocol) API interface class.

    This class provides interfaces to interact with ModelScope MCP servers,
    such as to list, deploy and manage MCP servers.

    Note: MCPApi inherits login() from HubApi for authentication.
    Different methods have different token requirements - see individual method docs.
    Nendpointtokenreturnc                    s    t  j||d | jt | _dS )z
        Initialize MCP API.

        Args:
            endpoint: The modelscope server address. Defaults to None (uses default endpoint).
            token: Optional access token for Bearer authentication.
        )r   r   N)super__init__r   MCP_API_PATHmcp_base_url)selfr   r   	__class__r   r   r   1   s   
zMCPApi.__init__	server_idc                 C   s   d| v r|  ddd S | S )z#Extract server name from server ID./   )split)r    r   r   r   _get_server_name_from_id?   s   zMCPApi._get_server_name_from_id    filtertotal_countsearchc              
   C   s   |du s|dk s|dkrt d|pi d||d}z| j|dd}| jj| j||d}t| W n tjjyL } zt	
d	| td
| |d}~ww z| |}	W n tyh } ztd| |d}~ww |	dg }
dd |
D }|	dd|dS )a  
        List available MCP servers, if (optional) token is presented, this would return private MCP servers as well.

        Args:
            token: Optional access token for authentication
            filter: Optional filters to apply to the search
                - 'category': str, server category, e.g. 'communication'
                - 'tag': str, server tag, e.g. 'social-media'
                - 'is_hosted': bool, server is hosted
                When all three are passed in, the intersection is taken.
            total_count: Number of servers to return, max 100, default 20
            search: Optional search query string,e.g. Chinese service name, English service name, author/owner username
            You can combine `filter` and `search` to retrieve desired MCP servers.

        Returns:
            Dict containing:
                - total_count: Total number of servers
                - servers: List of server dictionaries with name, id, description

        Raises:
            MCPApiRequestError: If API request fails (network, server errors)
            MCPApiResponseError: If response format is invalid or JSON parsing fails

        Authentication:
            Optional, only required if you wish to retrieve private MCP servers.
            You may leverage the token parameter for one-time authentication, or use api.login()

        Returns:
            {
                'total_count': 20,
                'servers': [
                    {'name': 'ServerA', 'id': '@demo/ServerA', 'description': 'This is a demo server for xxx.'},
                    {'name': 'ServerB', 'id': '@demo/ServerB', 'description': 'This is another demo server.'},
                    ...
                ]
            }
        Nr"   d   z%total_count must be between 1 and 100)r'   Zpage_numberZ	page_sizer)   Fr   Ztoken_required)urlheadersjsonzFailed to get MCP servers: %szFailed to get MCP servers: z(Invalid response from MCP servers list: mcp_server_listc                 S   s0   g | ]}| d d| dd| dddqS )namer&   iddescription)r0   r1   r2   )get).0itemr   r   r   
<listcomp>   s    



z+MCPApi.list_mcp_servers.<locals>.<listcomp>r(   r   r(   servers)
ValueError_build_bearer_headerssessionputr   r   requests
exceptionsRequestExceptionloggererrorr   _parse_openapi_responser   r   r3   )r   r   r'   r(   r)   bodyr-   redatar/   mcp_config_listr   r   r   list_mcp_serversF   sJ   +
zMCPApi.list_mcp_serversc              
   C   sr  | j  d}z| j|dd}| jj||d}t| W n tjjy9 } zt	d|  t
d| |d}~ww td|j  z| |}W n ty^ } ztd| |d}~ww |d	g }g }|D ]F}	i }
|	d
d|
d
< |	dd|
d< |	dd|
d< g |
d< |	dg D ]}|
d |dpddd |ddd q||
 qi|dd|dS )aQ  
        Get list of operational MCP servers that have been triggered hosting service by the user.

        Returns:
            Dict containing:
                - total_counts: Total number of operational servers
                - servers: List of server info with name, id, description

        Raises:
            MCPApiRequestError: If authentication fails or API request fails
            MCPApiResponseError: If response format is invalid or JSON parsing fails

        Returns:
            {
                'total_count': 10,
                'servers': [
                    {
                        'name': 'ServerA',
                        "id": "@Group1/ServerA",
                        'description': 'This is a demo server for xxx.'
                        'mcp_servers': [
                            {
                                'type': 'sse',
                                'url': 'https://mcp.api-inference.modelscope.net/{uuid}/sse'
                            },
                            {
                                'type': 'streamable_http',
                                'url': 'https://mcp.api-inference.modelscope.net/{uuid}/streamable_http'
                            },
                            ...
                        ]
                    },
                    ...
                ]
            }
        z/operationalTr+   )r-   z'Failed to get operational MCP servers: NzResponse status code: z/Invalid response from operational MCP servers: r/   r0   r&   r1   r2   Zmcp_serversoperational_urlsr,   r!   typer,   r(   r   r7   )r   r:   r;   r3   r   r=   r>   r?   r@   rA   r   debugstatus_coderB   r   r   appendr#   )r   r   r,   r-   rD   rE   rF   r/   rG   r5   
mcp_configoperational_urlr   r   r   list_operational_mcp_servers   sX   &


z#MCPApi.list_operational_mcp_serversc              
   C   sl  |st d| j d| }z| j|dd}| jj||ddid}t| W n$ tjjyJ } zt	
d| d	|  td| d	| |d
}~ww z| |}W n tyi } ztd| d	| |d
}~ww |dd|dd|ddd}|dd}t|}	|dg }
g }|	r|
r|
D ]}|dpddd |ddd}|| q||d< |S )aU  
        Get detailed information for a specific MCP Server,
        a valid token shall be provided if the MCP server is private.

        Args:
            server_id: MCP server ID (e.g., "@amap/amap-maps")
            token: Optional access token for authentication

        Returns:
            Dict containing:
                - name: Server name
                - description: Server description
                - id: Server ID
                - service_config: Connection configuration with type and url

        Raises:
            ValueError: If server_id is empty or None
            MCPApiRequestError: If API request fails or server not found
            MCPApiResponseError: If response format is invalid or JSON parsing fails

        Returns:
            {
                'name': 'ServerA',
                'description': 'This is a demo server for xxx.',
                'id': '@demo/serverA',
                'servers': [
                    {
                        'type': 'sse',
                        'url': 'https://mcp.api-inference.modelscope.net/{uuid}/sse'
                    },
                    {
                        'type': 'streamable_http',
                        'url': 'https://mcp.api-inference.modelscope.net/{uuid}/streamable_http'
                    }
                    ...
                ]
            }
        zserver_id cannot be emptyr!   Fr+   Zget_operational_urlT)r-   paramszFailed to get MCP server z: Nz!Invalid response from MCP server r0   r&   r2   r1   )r0   r2   r1   rI   r,   rJ   rK   r8   )r9   r   r:   r;   r3   r   r=   r>   r?   r@   rA   r   rB   r   r   r   r$   r#   rO   )r   r    r   r,   r-   rD   rE   rF   resultZserver_namerI   rG   rQ   rP   r   r   r   get_mcp_server   s\   )





zMCPApi.get_mcp_server)NN)NNr%   r&   )N)r   r   r   r   r   strr   staticmethodr$   r   r   intrH   rR   rU   __classcell__r   r   r   r   r   &   sT    

R

Q
r   )r   typingr   r   r   r=   Zmodelscope.hub.apir   Zmodelscope.hub.errorsr   r   Zmodelscope.utils.loggerr   r@   r   	Exceptionr
   r   r   r   r   r   r   r   <module>   s   