o
    ik                     @   s  d dl Z d dlmZmZmZmZmZ d dlmZm	Z	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 d d	lmZ d d
lmZ d dlmZ d dlmZmZmZ d dlmZ d dlm Z  ee!Z"ed Z#ed Z$e%e&ef Z'	dTde(de&de)de&e(B fddZ*de%de&de%e&e&f fd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/g d#Z0ed$eeZ1ed%eeZ2ed&eeZ3ed'e
eZ4ed(eeZ5ed)eeZ6ed*e	eZ7ed+eeZ8d,e%e&ef de(e/ fd-d.Z9G d/d0 d0ee1e3e2e4e5e6e7e8f Z:d1e'dB de'dB fd2d3Z;d1e'dB defd4d5Z<dUd7ed8e=de&fd9d:Z>		dVd;e&d<e%e&ef d=e(e, dB d>e-dB de&f
d?d@Z?	dWdAe%e&ef dBe&dB de%e&ef fdCdDZ@d1e%e&ef de%e&ef fdEdFZAd1e%e&ef ddfdGdHZBd1e%e&ef eB de%e&ef eB fdIdJZCdKe/de%e&ef fdLdMZDd1e%e&ef e(e B de%e&ef e(e B fdNdOZE		dVd<e%e&e.f dPe%e&ef dB dQe&dB de%e&ef dB fdRdSZFdS )X    N)AnyGenericLiteralTypeVarcast)OpenAPI	Operation	ParameterPathItem	ReferenceRequestBodyResponseSchema)r   )r   )r	   )r
   )r   )r   )r   )r   )	BaseModelFieldValidationError)
get_logger)FastMCPBaseModel)GETPOSTPUTDELETEPATCHOPTIONSHEADTRACEpathqueryheadercookieFvaluesparameter_nameis_query_parameterreturnc                 C   s  t dd | D rddd | D S z7g }| D ],}t|tr=g }| D ]\}}|| d|  q%|d| q|t| qd|W S  ty } z4|rVdnd}	t	d	|	 d
| d|  |rp| W  Y d}~S t
ddd}
t| |
}|W  Y d}~S d}~ww )aj  
    Format an array parameter according to OpenAPI specifications.

    Args:
        values: List of values to format
        parameter_name: Name of the parameter (for error messages)
        is_query_parameter: If True, can return list for explode=True behavior

    Returns:
        String (comma-separated) or list (for query params with explode=True)
    c                 s   s&    | ]}t |ttB tB tB V  qd S N)
isinstancestrintfloatbool.0item r.   _/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/fastmcp/utilities/openapi.py	<genexpr>8   s   $ z)format_array_parameter.<locals>.<genexpr>,c                 s   s    | ]}t |V  qd S r%   )r'   )r,   vr.   r.   r/   r0   9   s    :.r   r   zFailed to format complex array z parameter '': N z[]'")alljoinr&   dictitemsappendr'   	Exceptionloggerwarning	maketrans	translate)r!   r"   r#   formatted_partsr-   
item_partskr2   e
param_typetranslation_table	str_valuer.   r.   r/   format_array_parameter)   s0   
rH   param_valuec                 C   s^   t | tstd| dt|   i S i }|  D ]\}}| d| d}t|||< q|S )a  
    Format a dictionary parameter for deepObject style serialization.

    According to OpenAPI 3.0 spec, deepObject style with explode=true serializes
    object properties as separate query parameters with bracket notation.

    For example: `{"id": "123", "type": "user"}` becomes `param[id]=123&param[type]=user`.

    Args:
        param_value: Dictionary value to format
        parameter_name: Name of the parameter

    Returns:
        Dictionary with bracketed parameter names as keys
    zdeepObject style parameter 'z' expected dict, got [])r&   r9   r=   r>   typer:   r'   )rI   r"   resultkeyvaluebracketed_keyr.   r.   r/   format_deep_object_parameter[   s   
rQ   c                   @   sr   e Zd ZU dZeed< eed< dZeed< e	dddZ
eed	< d
Zed
B ed< d
Zed
B ed< d
Zed
B ed< d
S )ParameterInfoz>Represents a single parameter for an HTTP operation in our IR.namelocationFrequired.schema)aliasschema_Ndescriptionexplodestyle)__name__
__module____qualname____doc__r'   __annotations__ParameterLocationrU   r*   r   rX   
JsonSchemarY   rZ   r[   r.   r.   r.   r/   rR   |   s   
 rR   c                   @   sH   e Zd ZU dZdZeed< eedZ	ee
ef ed< dZe
dB ed< dS )RequestBodyInfoz<Represents the request body for an HTTP operation in our IR.FrU   default_factorycontent_schemaNrY   )r\   r]   r^   r_   rU   r*   r`   r   r9   rf   r'   rb   rY   r.   r.   r.   r/   rc      s   
 rc   c                   @   s<   e Zd ZU dZdZedB ed< eedZ	eee
f ed< dS )ResponseInfoz*Represents response information in our IR.NrY   rd   rf   )r\   r]   r^   r_   rY   r'   r`   r   r9   rf   rb   r.   r.   r.   r/   rg      s   
 rg   c                   @   s   e Zd ZU dZeed< eed< dZedB ed< dZedB ed< dZ	edB ed< e
edZee ed	< e
edZee ed
< dZedB ed< e
edZeeef ed< e
edZeeef ed< e
edZeeef ed< dZedB ed< dS )	HTTPRoutez;Intermediate Representation for a single OpenAPI operation.r   methodNoperation_idsummaryrY   rd   tags
parametersrequest_body	responsesschema_definitions
extensionsopenapi_version)r\   r]   r^   r_   r'   r`   
HttpMethodrj   rk   rY   r   listrl   rm   rR   rn   rc   r9   ro   rg   rp   rb   rq   r   rr   r.   r.   r.   r/   rh      s$   
 rh   )rh   rs   rb   rR   ra   rc   rg   _handle_nullable_fields$extract_output_schema_from_responsesrQ   parse_openapi_to_http_routesTOpenAPITSchema
TReference
TParameterTRequestBody	TResponse
TOperation	TPathItemopenapi_dictc              
   C   s   |  dd}zC|dr+t| }td|j  t|tt	t
tttt|	}| W S t| }td|j  t|ttttttt|	}| W S  tyq } ztd|  | }td|  td| |d	}~ww )
z
    Parses an OpenAPI schema dictionary into a list of HTTPRoute objects
    using the openapi-pydantic library.

    Supports both OpenAPI 3.0.x and 3.1.x versions.
    openapir6   3.0z0Successfully parsed OpenAPI 3.0 schema version: z0Successfully parsed OpenAPI 3.1 schema version: z"OpenAPI schema validation failed: zValidation errors: zInvalid OpenAPI schema: N)get
startswith
OpenAPI_30model_validater=   debugr   OpenAPIParserReference_30	Schema_30Parameter_30RequestBody_30Response_30Operation_30PathItem_30parser   r   r   r	   r   r   r   r
   r   errorerrors
ValueError)r   rr   
openapi_30parser
openapi_31rD   error_detailsr.   r.   r/   rw      sT   






rw   c                   @   s  e Zd ZdZdedee dee dee dee	 dee
 dee d	ee d
efddZdedefddZdedefddZdedefddZ		d$dee dB dee dB dee fddZdededB fddZdeeef dB deeef fd d!Zdee fd"d#ZdS )%r   z[Unified parser for OpenAPI schemas with generic type parameters to handle both 3.0 and 3.1.r   reference_cls
schema_clsparameter_clsrequest_body_clsresponse_clsoperation_clspath_item_clsrr   c
           
      C   s:   || _ || _|| _|| _|| _|| _|| _|| _|	| _dS )z?Initialize the parser with the OpenAPI schema and type classes.N)	r   r   r   r   r   r   r   r   rr   )
selfr   r   r   r   r   r   r   r   rr   r.   r.   r/   __init__  s   
zOpenAPIParser.__init__param_inr$   c                 C   s"   |dv r|S t d| d dS )z@Convert string parameter location to our ParameterLocation type.r   zUnknown parameter location: z, defaulting to 'query'r   )r=   r>   )r   r   r.   r.   r/   _convert_to_parameter_location$  s   z,OpenAPIParser._convert_to_parameter_locationr-   c                 C   s  t || jr|j}z|dstd| |dd}| j}|D ]s}| r5t |t	r5|t
| }nRt |trq||jjv rGt||d}n@|jrU||jv rU|j| }n2|dkrbt|drb|j}n%t||rnt||d}nd}nt |tr|||}ntd| d| d|du rtd	| d
| dq#t || jr| |W S |W S  tttttfy } ztd| d| |d}~ww |S )z.Resolves a reference to its target definition.#//External or non-local reference not supported: /N
componentszCannot traverse part 'z' in reference ''zReference part 'z' not found in path 'zFailed to resolve reference 'r5   )r&   r   refr   r   stripsplitr   isdigitrt   r(   r   	__class__model_fieldsgetattrmodel_extrahasattrr   r9   r   _resolve_refAttributeErrorKeyError
IndexError	TypeError)r   r-   ref_strpartstargetpartrD   r.   r.   r/   r   +  sP   



zOpenAPIParser._resolve_ref
schema_objc              
   C   s   z.|  |}t|| jr|jdddd}nt|tr|}ntdt| d i }t|W S  t	yS } zdt
|v r= tjd| dd	 i W  Y d
}~S d
}~w typ } ztjd| dd	 i W  Y d
}~S d
}~ww )z1Resolves a schema and returns it as a dictionary.jsonT)modeby_aliasexclude_nonez%Expected Schema after resolving, got z. Returning empty dict.-External or non-local reference not supportedz"Failed to extract schema as dict: Fexc_infoN)r   r&   r   
model_dumpr9   r=   r>   rL   _replace_ref_with_defsr   r'   r   r<   )r   r   resolved_schemarM   rD   r.   r.   r/   _extract_schema_as_dict_  s0   


z%OpenAPIParser._extract_schema_as_dictNoperation_paramspath_item_paramsc                 C   s  g }i }|pg |p
g  }|D ]}z|  |}t|| js)tdt| d W q|j}ddlm}	 t||	r:|j	n|}
| 
|
}|j}|j|
f}||v rOW qd||< i }|rw| |}|  |}t|| jsvt|drv|jdurv|j|d< n>t|dr|jrtt|j d}|rt|d	r|jr|j}| |}|  |}t|| jst|dr|jdur|j|d< t|d
d}t|dd}t|j||j||j||d}|| W q ty } zt|dt|dd}tjd| d| dd W Y d}~qd}~ww |S )z<Extract and resolve parameters from operation and path item.z(Expected Parameter after resolving, got . Skipping.r   )EnumTdefaultNcontentmedia_type_schemarZ   r[   )rS   rT   rU   rV   rY   rZ   r[   rS   r   unknownzFailed to extract parameter 'r5   Fr   )r   r&   r   r=   r>   rL   r   enumr   rO   r   param_schemarS   r   r   r   r   r   nextiterr!   r   r   rR   rU   rY   r;   r<   r   )r   r   r   extracted_paramsseen_params
all_paramsparam_or_ref	parameterr   r   param_in_strparam_locationparam_schema_obj	param_keyparam_schema_dictr   first_media_typemedia_schemaresolved_media_schemarZ   r[   
param_inforD   
param_namer.   r.   r/   _extract_parameters|  s   












	z!OpenAPIParser._extract_parametersrequest_body_or_refc           	      C   s  |sdS z|  |}t|| jstdt| d W dS t|j|jd}t	|dr|j
r|j
 D ]\\}}|rt	|dr|jrz| |j}||j|< W q3 tyr } zdt|v r] td| d	|  W Y d}~q3d}~w ty } ztd| d	|  W Y d}~q3d}~ww q3|W S  ty } z!dt|v r t|d
d}tjd| d	| dd W Y d}~dS d}~w ty } zt|d
d}tjd| d	| dd W Y d}~dS d}~ww )z-Extract and resolve request body information.Nz*Expected RequestBody after resolving, got z. Returning None.)rU   rY   r   r   r   )Failed to extract schema for media type 'r5   r   r   z Failed to extract request body 'Fr   )r   r&   r   r=   r>   rL   rc   rU   rY   r   r   r:   r   r   rf   r   r'   r   r<   r   )	r   r   rn   request_body_infomedia_type_strmedia_type_objschema_dictrD   ref_namer.   r.   r/   _extract_request_body  sz   
z#OpenAPIParser._extract_request_bodyoperation_responsesc                 C   s   i }|s|S |  D ]\}}z| |}t|| js*td| dt| d W q
t|jd}t	|dr|j
r|j
  D ]b\}}|rt	|dr|jrz| |j}	|	|j|< W q= ty }
 zdt|
v rg td| d	| d
|
  W Y d}
~
q=d}
~
w ty }
 ztd| d	| d
|
  W Y d}
~
q=d}
~
ww q=||t|< W q
 ty }
 z#dt|
v r t|dd}tjd| d| d|
 dd W Y d}
~
q
d}
~
w ty }
 zt|dd}tjd| d| d|
 dd W Y d}
~
q
d}
~
ww |S )z)Extract and resolve response information.z2Expected Response after resolving for status code z, got r   )rY   r   r   r   r   z' in response : Nr   r   z+Failed to extract response for status code z from reference 'r5   Fr   )r:   r   r&   r   r=   r>   rL   rg   rY   r   r   r   r   rf   r   r'   r   r<   r   )r   r   extracted_responsesstatus_coderesp_or_refresponse	resp_infor   r   r   rD   r   r.   r.   r/   _extract_responses!  s   
z OpenAPIParser._extract_responsesc                 C   s  g }t | jdr| jjstd g S i }t | jdrn| jjrn| jj}t |drn|jrn|j D ]=\}}zt|| j	rH| 
|}| |||< n| |||< W q0 tym } ztd| d|  W Y d}~q0d}~ww | jj D ]\}}	t|	| jstd| d	t|	 d
 qtt |	dr|	jnd}
g d}|D ]}t|	|d}|ryt|| jry| }ze| t|dd|
}| t|dd}| t|dd}i }t |dr|jrdd |j D }t||t|ddt|ddt|ddt|dg pg |||||| jd}|| td| d|  W q tyM } z'dt|v r* t|dd}tjd| d| d| d| dd W Y d}~qd}~w tyx } zt|dd}tjd| d| d| d| dd W Y d}~qd}~ww qqttd t| d! |S )"z*Parse the OpenAPI schema into HTTP routes.pathsz$OpenAPI schema has no paths defined.r   schemasz%Failed to extract schema definition 'r5   Nz%Skipping invalid path item for path 'z	' (type: )rm   )r   putpostdeleteoptionsheadpatchtracerequestBodyro   r   c                 S   s    i | ]\}}| d r||qS )zx-)r   r,   rC   r2   r.   r.   r/   
<dictcomp>  s    z'OpenAPIParser.parse.<locals>.<dictcomp>operationIdrk   rY   rl   )r   ri   rj   rk   rY   rl   rm   rn   ro   rp   rq   rr   zSuccessfully extracted route:  r   r   zFailed to process operation z (ID: z): Tr   zFinished parsing. Extracted z HTTP routes.)r   r   r   r=   r>   r   r   r:   r&   r   r   r   r<   r   rL   rm   r   r   upperr   r   r   r   rh   rr   r;   r   r   r'   r   len)r   routesrp   r   rS   rV   r   rD   path_strpath_item_objpath_level_paramshttp_methodsmethod_lower	operationmethod_upperrm   r   ro   rq   routeop_errorop_idr.   r.   r/   r   k  s   









@zOpenAPIParser.parseNN)r\   r]   r^   r_   rx   rL   rz   ry   r{   r|   r}   r~   r   r'   r   ra   r   r   r   rb   r   rt   rR   r   rc   r   r9   rg   r   rh   r   r.   r.   r.   r/   r      sP    	

4


cB

Jr   rV   c                 C   s   | rt | ts	| S |  }g d}|D ]}||v r|| qd|v r9dd |d  D |d< |d s9|d d|v rNt|d |d< |d sN|d d|v rlt |d trct|d |d< dS |d du rn	 dS dS dS )	zW
    Clean up a schema dictionary for display by removing internal/complex fields.
    )allOfanyOfoneOfnotnullablediscriminatorreadOnly	writeOnly
deprecatedxmlexternalDocs
propertiesc                 S      i | ]	\}}|t |qS r.   )clean_schema_for_displayr   r.   r.   r/   r   	  s    z,clean_schema_for_display.<locals>.<dictcomp>r:   additionalPropertiesTN)r&   r9   copypopr:   r  )rV   cleanedfields_to_removefieldr.   r.   r/   r    s6   




r  c                 C   s  | rt | ts	dS d| v r| d S d| v r&t | d tr&| d r&| d d S d| v r;t | d tr;| d r;| d d S d| v rC| d S | d}|dkri }| d	i }t |trt| d
g }t| dd }|D ]}||v r{t|| ||< qm|D ]}||vr||v rt|| ||< q~|r|S ddiS |dkr| d}t |trt|}	|	dur|	gS g S dgS |dkr| d}
|
dkrdS |
dkrdS |
dkrdS |
dkrdS |
dkrdS dS |dkrdS |d krd!S |d"krd#S |d$krdS d%S )&zy
    Generate a simple example value from a JSON schema dictionary.
    Very basic implementation focusing on types.
    r   r   r   r   examplesexamplerL   objectr  rU   N   rN   rO   arrayr:   example_itemstringformatz	date-timez2024-01-01T12:00:00Zdatez
2024-01-01emailzuser@example.comuuidz$123e4567-e89b-12d3-a456-426614174000bytezZXhhbXBsZQ==integer   numberg      ?booleanTnullunknown_type)r&   r9   rt   r   setkeysgenerate_example_from_schema)rV   schema_typerM   r  required_propsprops_to_include	prop_namereq_propitems_schemaitem_exampleformat_typer.   r.   r/   r7  !  s   





r7     dataindentc                 C   s<   zt j| |d}d| dW S  ty   d|  d Y S w )z8Formats Python data as a JSON string block for markdown.rB  z```json
z
```z!```
Could not serialize to JSON: )r   dumpsr   )rA  rB  json_strr.   r.   r/   format_json_for_descriptiont  s   rF  base_descriptionro   rm   rn   c              
      s  | g}|redd |D }|r5d}| | |D ]}|jrdnd}d|j d| d|jp,d	 }	| |	 qd
d |D }
|
red}| | |
D ]}|jrNdnd}d|j d| d|jp\d	 }	| |	 qG|r|jrd}| | |jrvdnd}| d|j |  |jrd|jv rdntt|jd}|r|j|i }t|t	rd|v r| d |d 
 D ]+\}}t|t	rd|v r||dg v }|rdnd}| d| d| d|d   q rd}d}h d}t fdd|D d} 
 }t|D ]\}}|s| | d}||krdnd}| d| d| d|jp"d	  |jrd|jv r2dntt|jd}|r|j|}| d| d t|t	r|ddkrd|v r|d }t|t	rd|v r| d  |d 
 D ]\}}t|t	rd|v r| d!| d"|d   qyn.d|v r| d# |d 
 D ]\}}t|t	rd|v r| d!| d"|d   q|rt|}|d$kr|dur| d% | t|d&d' qd|S )(aX  
    Formats the base description string with response, parameter, and request body information.

    Args:
        base_description (str): The initial description to be formatted.
        responses (dict[str, Any]): A dictionary of response information, keyed by status code.
        parameters (list[ParameterInfo] | None, optional): A list of parameter information,
            including path and query parameters. Each parameter includes details such as name,
            location, whether it is required, and a description.
        request_body (RequestBodyInfo | None, optional): Information about the request body,
            including its description, whether it is required, and its content schema.

    Returns:
        str: The formatted description string with additional details about responses, parameters,
        and the request body.
    c                 S      g | ]	}|j d kr|qS )r   rT   r,   pr.   r.   r/   
<listcomp>      z5format_description_with_responses.<locals>.<listcomp>z

**Path Parameters:**z (Required)r6   z
- **z**r   zNo description.c                 S   rH  )r   rI  rJ  r.   r.   r/   rL    rM  z

**Query Parameters:**z

**Request Body:**
application/jsonNr  z

**Request Properties:**rY   rU   z

**Responses:**F>   200201202204c                 3   s    | ]	}| v r|V  qd S r%   r.   )r,   sro   r.   r/   r0     s    z4format_description_with_responses.<locals>.<genexpr>Tz
 (Success)z  - Content-Type: ``rL   r'  r:   z"
  - **Response Item Properties:**z	
    - **z**: z
  - **Response Properties:**r4  z
  - **Example:**r@  rC  )r;   rU   rS   rY   rf   r   r   r   r&   r9   r:   sortedr7  rF  r8   )rG  ro   rm   rn   
desc_partspath_paramsparam_sectionparamrequired_marker
param_descquery_paramsreq_body_section
media_typerV   r;  prop_schemarU   req_markresponse_sectionadded_response_sectionsuccess_codessuccess_statusresponses_to_processr   r   status_markerr=  r$  r.   rU  r/   !format_description_with_responses}  s   
















ri  inforY   c           
      C   s  |   }|d }r2t|tr1|dr$|dd }d| |d< n9|ds1td| dn+|d	 }rPd|v rDt||d	< nd
d | D |d	< n|d }r]t||d< dD ]}t	||g D ]\}}	t|	|| |< qiq_| d|r|ds||d< |S )a  
    Replace openapi $ref with jsonschema $defs

    Examples:
    - {"type": "object", "properties": {"$ref": "#/components/schemas/..."}}
    - {"$ref": "#/components/schemas/..."}
    - {"items": {"$ref": "#/components/schemas/..."}}
    - {"anyOf": [{"$ref": "#/components/schemas/..."}]}
    - {"allOf": [{"$ref": "#/components/schemas/..."}]}
    - {"oneOf": [{"$ref": "#/components/schemas/..."}]}

    Args:
        info: dict[str, Any]
        description: str | None

    Returns:
        dict[str, Any]
    $ref#/components/schemas/r   #/$defs/r   r   z. FastMCP only supports local schema references starting with '#/'. Please include all schema definitions within the OpenAPI document.r  c                 S   r  r.   )r   )r,   r;  ra  r.   r.   r/   r   >  s    z*_replace_ref_with_defs.<locals>.<dictcomp>r:   )r  r  r  rY   )
r  r   r&   r'   r   r   r   r   r:   	enumerate)
rj  rY   rV   ref_pathschema_namer  item_schemasectionir-   r.   r.   r/   r     s4   



r   c                 C   s   d| v sd| v sd| v r| S t | dtrd| d v r| S d| v rj| d }t |trjd|i}i }t }|dkr=h d}n|dkrEh d	}|  D ]\}}|dkrRqI||v r[|||< qI|||< qI|ddig|d< |S | S )
z
    Make an optional parameter schema nullable to allow None values.

    For optional parameters, we need to allow null values in addition to the
    specified type to handle cases where None is passed for optional parameters.
    r  r  r  rL   r3  r'  >	   r:   containsmaxItemsminItemsmaxContainsminContainsprefixItemsuniqueItemsunevaluatedItemsr%  >   rU   r  maxPropertiesminPropertiespropertyNamespatternPropertiesr  unevaluatedProperties)r&   r   rt   r'   r5  r:   )rV   original_typenested_non_nullable_schemanullable_schematype_specific_propertiesrN   rO   r.   r.   r/   !_make_optional_parameter_nullableL  s0   



r  c                 C   s   d| v r,| d }t |tr|dg| d< dS t |tr(d|vr*g |d| d< dS dS dS d| v r?g | dddi| d< dS d| v r[tdd | d D sY| d ddi dS dS d| v rnd| diddig| d< dS dS )	zdAdd 'null' to the schema's type field or handle oneOf/anyOf/allOf constructs if not already present.rL   r3  r  r  c                 s   s    | ]
}| d dkV  qdS )rL   r3  N)r   r+   r.   r.   r/   r0     s    z$_add_null_to_type.<locals>.<genexpr>r  N)r&   r'   rt   r  anyr;   )rV   current_typer.   r.   r/   _add_null_to_type  s$   

r  c                 C   s  t | ts| S d| v }|o | d o d| v p d| v p d| v p d| v }d}d| v r=| d  D ]}t |tr<d|v r<d} nq-|sC|sC| S |  }|rT|d |rTt| |rd|v r|d  D ](\}}t |trd|v r|d}|rd|v sd|v sd|v sd|v rt| q`|S )	zConvert OpenAPI nullable fields to JSON Schema format: {"type": "string",
    "nullable": true} -> {"type": ["string", "null"]}r  rL   r  r  r  Fr  T)r&   r9   r!   r  r  r  r:   )rV   has_root_nullable_fieldhas_root_nullable_truehas_property_nullable_fieldra  rM   
_prop_namenullable_valuer.   r.   r/   ru     sN   


ru   r  c                    sj  i }g }t  t  t  t  d}i }| jD ]}||j |j q| jrB| jjrBtt| jj}t	| jj| 
 | jj}|di }t  }| D ]}	||	 qIt | }
||
@ }| jD ]\}|j|v r|j d|j }|jrv|| t	|j
 |j}|dd}d|j  d}|r| d| |d< n||d< |||< q^|jr||j t	|j
 |j}|||j< q^| jr| jjr| D ]\}}|||< q| jjr||d	g  d
||d}| jr| j
 |d< |ddu r|d d|v r3t   fdd | D ]\}}|dkr | qr.fdd|d  D |d< |S |d |S )z
    Combines parameter and request body schemas into a single schema.
    Handles parameter name collisions by adding location suffixes.

    Args:
        route: HTTPRoute object

    Returns:
        Combined schema dictionary
    r   r  __rY   r6   (z parameter)r   rU   r%  )rL   r  rU   $defsr  Fc                       t | tr0d| v r#t | d tr#| d }|dr#|dd  |  D ]} | q'd S t | tr>| D ]} | q7d S d S Nrk  rn  r   rm  r&   r9   r'   r   addr   r!   rt   rO   r   r2   r-   find_refs_in_value	used_refsr.   r/   r  I     




z,_combine_schemas.<locals>.find_refs_in_valuec                       i | ]\}}| v r||qS r.   r.   r,   rS   
def_schemar  r.   r/   r   \  
    z$_combine_schemas.<locals>.<dictcomp>)r5  rm   rT   r  rS   rn   rf   r   r   r   r  rY   r   r!   updater6  rU   r;   rX   
capitalizer:   extendrp   r  )r  r  rU   param_names_by_location
body_propsr[  content_typebody_schemaall_non_body_paramslocation_paramsbody_param_namescolliding_paramssuffixed_namer   original_desclocation_descr;  ra  rM   rN   rO   r.   r  r/   _combine_schemas  s   












r  c                 C   s   t | trJd| v }d}|  D ]}t |ttB rd} nq|s#|s#| S |  }|r0|d|d< |rH| D ]\}}t |ttB rGt|||< q6|S t | trVdd | D S | S )zPRecursively replace 'oneOf' with 'anyOf' in schema to handle overlapping unions.r  FTr  c                 S   s   g | ]}t |qS r.   )_adjust_union_typesr+   r.   r.   r/   rL    s    z'_adjust_union_types.<locals>.<listcomp>)r&   r9   r!   rt   r  r  r:   r  )rV   
has_one_ofneeds_recursive_processingr2   rM   rC   r.   r.   r/   r  g  s,   

r  rp   rr   c                    s`  | sdS g d}d}|D ]}|| v r| | } nq|du r/|   D ]\}}|dr.|} nq!|du s6|js8dS g d}d}|D ]}	|	|jv rN|j|	 } nq@|du rj|jrjtt|j}
|j|
 }td|
  |rqt|tssdS |	 }d|v r|r|d }|dr|
dd	 }||v r|| 	 }|r|d
rt|}|ddkrdd|idgdd}|}|rd|	 vri }|  D ]\}}|r|d
rt|||< q|||< q||d< |ddu r|d d|v r#t  fdd |  D ]\}}|dkr
 | qrfdd|d   D |d< n|d ttttf t|}|S )a  
    Extract output schema from OpenAPI responses for use as MCP tool output schema.

    This function finds the first successful response (200, 201, 202, 204) with a
    JSON-compatible content type and extracts its schema. If the schema is not an
    object type, it wraps it to comply with MCP requirements.

    Args:
        responses: Dictionary of ResponseInfo objects keyed by status code
        schema_definitions: Optional schema definitions to include in the output schema
        openapi_version: OpenAPI version string, used to optimize nullable field handling

    Returns:
        dict: MCP-compliant output schema with potential wrapping, or None if no suitable schema found
    N)rP  rQ  rR  rS  2)rO  zapplication/vnd.api+jsonzapplication/hal+jsonzapplication/ld+jsonz	text/jsonz/Using non-JSON content type for output schema: rk  rl  r   rm  r   rL   r%  rM   T)rL   r  rU   zx-fastmcp-wrap-resultr  r  Fc                    r  r  r  r  r  r.   r/   r    r  z@extract_output_schema_from_responses.<locals>.find_refs_in_valuec                    r  r.   r.   r  r  r.   r/   r     r  z8extract_output_schema_from_responses.<locals>.<dictcomp>)r:   r   rf   r   r   r=   r   r&   r9   r  r   ru   r   r  r5  r   r'   r   r  )ro   rp   rr   re  response_infor   r   json_compatible_typesrV   r  first_content_typeoutput_schemarp  rq  wrapped_schemaprocessed_defsdef_namer  rN   rO   r.   r  r/   rv     s   











rv   )F)r@  r  r%   )Gr   typingr   r   r   r   r   openapi_pydanticr   r   r	   r
   r   r   r   r   openapi_pydantic.v3.v3_0r   r   r   r   r   r   r   r   pydanticr   r   r   fastmcp.utilities.loggingr   fastmcp.utilities.typesr   r\   r=   rs   ra   r9   r'   rb   rt   r*   rH   rQ   rR   rc   rg   rh   __all__rx   ry   rz   r{   r|   r}   r~   r   rw   r   r  r7  r(   rF  ri  r   r  r  ru   r  r  rv   r.   r.   r.   r/   <module>   s    (
2

!

6   i<S

 


"3F*8 
&
