Repository: jlowin/fastmcp

Issue:
FastMCP tool calling uses wrong $ref schema loadingURI in openapi 3.0 api specs
### Description

I am seeing an issue FastMCP, where it is trying to load $ref schema from a url not from the specs. 

`loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints`


### Example Code

```Python
api_specs = # openapi 3.0 specs
api_client = httpx.AsyncClient(base_url=host_url, headers=headers, verify=False)

def make_custom_route_mapper(allowed_routes_list):
    def custom_route_mapper(route: HTTPRoute, mcp_type: MCPType) -> MCPType | None:
        if len(allowed_routes_list) > 0:
            if any(route.path.startswith(pattern) for pattern in allowed_routes_list):
                return MCPType.TOOL
            return MCPType.EXCLUDE
        else:
            return MCPType.TOOL

    return custom_route_mapper

mcp = FastMCP.from_openapi(
        openapi_spec=api_specs,
        client=api_client,
        name=args.mcp_server_name,
        route_map_fn=make_custom_route_mapper(allowed_routes),
    )

    mcp.run(transport='sse', port=args.mcp_server_port, host="0.0.0.0")
```

### Version Information

```Text
2.8.1
```

### Additional Context

_No response_


Discussion:
I'm not sure I follow, FastMCP doesn't load schemas. You must provide them yourself. Can you provide an example?
@jlowin May be its openapi utilties inside fastmcp which is not loading and reading the $ref schema properly. 
This is what I have in my openapi specs and thats what I supply to fastMcp. 

```
{
    "openapi": "3.0.0",
    "info":
    {
        "description": "APIs for the Market component",
        "version": "v1",
        "title": "Market",
        "termsOfService": "https://example.com/terms",
        "contact":
        {
            "name": ""
        },
        "license":
        {
            "name": "",
            "url": ""
        }
    },
    "tags":
    [
        {
            "name": "products",
            "description": "Offerings to instantiate a resource type in a domain"
        }
    ],
    "paths":
    {
        "/products":
        {
            "post":
            {
                "tags":
                [
                    "products"
                ],
                "summary": "Create a new product",
                "description": "Returns the created product object",
                "operationId": "CreateProduct",
                "requestBody":
                {
                    "content":
                    {
                        "application/json":
                        {
                            "schema":
                            {
                                "$ref": "#/components/schemas/Product"
                            }
                        }
                    },
                    "description": "Specification defining a product",
                    "required": true
                },
                "responses":
                {
                    "201":
                    {
                        "description": "Created",
                        "content":
                        {
                            "*/*":
                            {
                                "schema":
                                {
                                    "$ref": "#/components/schemas/Product"
                                }
                            }
                        }
                    },
                    "400":
                    {
                        "description": "Bad Request"
                    },
                    "401":
                    {
                        "description": "Unauthorized"
                    },
                    "403":
                    {
                        "description": "Forbidden"
                    },
                    "409":
                    {
                        "description": "Conflict"
                    },
                    "500":
                    {
                        "description": "Internal Server Error"
                    },
                    "503":
                    {
                        "description": "Service Unavailable"
                    }
                }
            }
        }
    },
    "components":
    {
        "schemas":
        {
            "Product":
            {
                "type": "object",
                "properties":
                {
                    "title":
                    {
                        "type": "string",
                        "description": "Name or title describing the product"
                    },
                    "description":
                    {
                        "type": "string",
                        "description": "Detailed description of the product"
                    },
                    "constraints":
                    {
                        "$ref": "#/components/schemas/JObject"
                    },
                    "providerData":
                    {
                        "$ref": "#/components/schemas/JObject"
                    }
                },
                "description": "Information describing a product"
            },
            "JObject":
            {
                "type": "object",
                "required":
                [
                    "obj"
                ],
                "properties":
                {
                    "obj":
                    {
                        "type": "array",
                        "items":
                        {
                            "$ref": "#/components/schemas/Tuple2StringJValue"
                        }
                    }
                }
            },
            "Tuple2StringJValue":
            {
                "type": "object",
                "required":
                [
                    "_1",
                    "_2"
                ],
                "properties":
                {
                    "_1":
                    {
                        "type": "string"
                    },
                    "_2":
                    {
                        "$ref": "#/components/schemas/JValue"
                    }
                }
            },
            "JValue":
            {
                "type": "object"
            }
        }
    }
}
```


The logs of fastmcp server - 

```
[06/23/25 23:44:58] ERROR    Error calling tool 'CreateProduct': HTTP error 400: Bad Request - {'statusCode': 400, 'failureInfo': {'reason': 'Invalid constraints schema:\n[ {\n  "level" : tool_manager.py:140
                             "error",\n  "schema" : {\n    "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n    "pointer" :                                                   
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$"\n  },\n  "instance" : {\n    "pointer" : "/obj"\n  },\n  "domain" : "validation",\n  "keyword" : "oneOf",\n                         
                             "message" : "instance failed to match exactly one schema (matched 0 out of 6)",\n  "matched" : 0,\n  "nrSchemas" : 6,\n  "reports" : {\n                                          
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/0" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : ""\n      },\n      "instance" : {\n        "pointer" : "/obj"\n                           
                             },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed:                        
                             [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1" : [ {\n                          
                             "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" :                             
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n                     
                             "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n                     
                             "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2" : [ {\n      "level" : "error",\n      "schema" : {\n                              
                             "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2"\n                     
                             },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type                       
                             (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ]\n  }\n} ]', 'detail': ''}}                    
                             ╭──────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────╮                    
                             │ /Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/server/openapi.py:449 in run                                                │                    
                             │                                                                                                                                                            │                    
                             │    446 │   │   │   )                                                                                                                                       │                    
                             │    447 │   │   │                                                                                                                                           │                    
                             │    448 │   │   │   # Raise for 4xx/5xx responses                                                                                                           │                    
                             │ ❱  449 │   │   │   response.raise_for_status()                                                                                                             │                    
                             │    450 │   │   │                                                                                                                                           │                    
                             │    451 │   │   │   # Try to parse as JSON first                                                                                                            │                    
                             │    452 │   │   │   try:                                                                                                                                    │                    
                             │                                                                                                                                                            │                    
                             │ /Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/httpx/_models.py:829 in raise_for_status                                            │                    
                             │                                                                                                                                                            │                    
                             │    826 │   │   }                                                                                                                                           │                    
                             │    827 │   │   error_type = error_types.get(status_class, "Invalid status code")                                                                           │                    
                             │    828 │   │   message = message.format(self, error_type=error_type)                                                                                       │                    
                             │ ❱  829 │   │   raise HTTPStatusError(message, request=request, response=self)                                                                              │                    
                             │    830 │                                                                                                                                                   │                    
                             │    831 │   def json(self, **kwargs: typing.Any) -> typing.Any:                                                                                             │                    
                             │    832 │   │   return jsonlib.loads(self.content, **kwargs)                                                                                                │                    
                             ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                    
                             HTTPStatusError: Client error '400 Bad Request' for url 'https://10.186.34.3/bpocore/market/api/v1/products'                                                                      
                             For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400                                                                                          
                                                                                                                                                                                                               
                             During handling of the above exception, another exception occurred:                                                                                                               
                                                                                                                                                                                                               
                             ╭──────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────╮                    
                             │ /Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/tools/tool_manager.py:131 in call_tool                                      │                    
                             │                                                                                                                                                            │                    
                             │   128 │   │   │   raise NotFoundError(f"Unknown tool: {key}")                                                                                              │                    
                             │   129 │   │                                                                                                                                                │                    
                             │   130 │   │   try:                                                                                                                                         │                    
                             │ ❱ 131 │   │   │   return await tool.run(arguments)                                                                                                         │                    
                             │   132 │   │                                                                                                                                                │                    
                             │   133 │   │   # raise ToolErrors as-is                                                                                                                     │                    
                             │   134 │   │   except ToolError as e:                                                                                                                       │                    
                             │                                                                                                                                                            │                    
                             │ /Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/server/openapi.py:471 in run                                                │                    
                             │                                                                                                                                                            │                    
                             │    468 │   │   │   │   if e.response.text:                                                                                                                 │                    
                             │    469 │   │   │   │   │   error_message += f" - {e.response.text}"                                                                                        │                    
                             │    470 │   │   │                                                                                                                                           │                    
                             │ ❱  471 │   │   │   raise ValueError(error_message)                                                                                                         │                    
                             │    472 │   │                                                                                                                                               │                    
                             │    473 │   │   except httpx.RequestError as e:                                                                                                             │                    
                             │    474 │   │   │   # Handle request errors (connection, timeout, etc.)                                                                                     │                    
                             ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                    
                             ValueError: HTTP error 400: Bad Request - {'statusCode': 400, 'failureInfo': {'reason': 'Invalid constraints schema:\n[ {\n  "level" : "error",\n  "schema" :                     
                             {\n    "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n    "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$"\n  },\n                    
                             "instance" : {\n    "pointer" : "/obj"\n  },\n  "domain" : "validation",\n  "keyword" : "oneOf",\n  "message" : "instance failed to match exactly one schema                      
                             (matched 0 out of 6)",\n  "matched" : 0,\n  "nrSchemas" : 6,\n  "reports" : {\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/0" : [ {\n      "level"                     
                             : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : ""\n      },\n                      
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n                                            
                             "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" :                                                 
                             "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5"\n      },\n                          
                             "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does                     
                             not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ]\n  }\n} ]', 'detail': ''}}                    
ERROR:FastMCP.fastmcp.tools.tool_manager:Error calling tool 'CreateProduct': HTTP error 400: Bad Request - {'statusCode': 400, 'failureInfo': {'reason': 'Invalid constraints schema:\n[ {\n  "level" : "error",\n  "schema" : {\n    "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n    "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$"\n  },\n  "instance" : {\n    "pointer" : "/obj"\n  },\n  "domain" : "validation",\n  "keyword" : "oneOf",\n  "message" : "instance failed to match exactly one schema (matched 0 out of 6)",\n  "matched" : 0,\n  "nrSchemas" : 6,\n  "reports" : {\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/0" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : ""\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ]\n  }\n} ]', 'detail': ''}}
Traceback (most recent call last):
  File "/Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/server/openapi.py", line 449, in run
    response.raise_for_status()
  File "/Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/httpx/_models.py", line 829, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://10.186.34.3/bpocore/market/api/v1/products'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/tools/tool_manager.py", line 131, in call_tool
    return await tool.run(arguments)
  File "/Users/dvishwak/Downloads/vedf/mcp-server/lib/python3.10/site-packages/fastmcp/server/openapi.py", line 471, in run
    raise ValueError(error_message)
ValueError: HTTP error 400: Bad Request - {'statusCode': 400, 'failureInfo': {'reason': 'Invalid constraints schema:\n[ {\n  "level" : "error",\n  "schema" : {\n    "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n    "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$"\n  },\n  "instance" : {\n    "pointer" : "/obj"\n  },\n  "domain" : "validation",\n  "keyword" : "oneOf",\n  "message" : "instance failed to match exactly one schema (matched 0 out of 6)",\n  "matched" : 0,\n  "nrSchemas" : 6,\n  "reports" : {\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/0" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : ""\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/1"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/2"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/3"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/4"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ],\n    "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5" : [ {\n      "level" : "error",\n      "schema" : {\n        "loadingURI" : "http://cyaninc.com/json-schemas/market-v1/product-constraints#",\n        "pointer" : "/patternProperties/^[a-zA-Z][-_a-zA-Z0-9]*$/oneOf/5"\n      },\n      "instance" : {\n        "pointer" : "/obj"\n      },\n      "domain" : "validation",\n      "keyword" : "type",\n      "message" : "instance type (null) does not match any allowed primitive type (allowed: [\\"object\\"])",\n      "found" : "null",\n      "expected" : [ "object" ]\n    } ]\n  }\n} ]', 'detail': ''}}
```
@jlowin also to mention that my openapi 3.0 api specs loads fine in swagger editor, so not able to find why fastmcp tool calling is failing due to schema validation.

This is the payload I am providing (same works without any problem hitting the api directly)-

```
{
  "resourceTypeId": "resourceTypes.Monitor",
  "title": "My Monitor",
  "description": "An event bus monitor resource.",
  "active": true,
  "domainId": "built-in",
  "providerProductId": "prov_prod_2",
  "constraints": {},
  "providerData": {}
}
```
Ok, I'm still not totally sure of the source of the error but we've opened #954 to address some validation issues with external schemas



Patch:
diff --git a/src/fastmcp/utilities/openapi.py b/src/fastmcp/utilities/openapi.py
index 0cae85cb2..746fb4b60 100644
--- a/src/fastmcp/utilities/openapi.py
+++ b/src/fastmcp/utilities/openapi.py
@@ -274,6 +274,12 @@ def _extract_schema_as_dict(self, schema_obj: Any) -> JsonSchema:
                 result = {}
 
             return _replace_ref_with_defs(result)
+        except ValueError as e:
+            # Re-raise ValueError for external reference errors and other validation issues
+            if "External or non-local reference not supported" in str(e):
+                raise
+            logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
+            return {}
         except Exception as e:
             logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
             return {}
@@ -400,12 +406,30 @@ def _extract_request_body(self, request_body_or_ref: Any) -> RequestBodyInfo | N
                             request_body_info.content_schema[media_type_str] = (
                                 schema_dict
                             )
+                        except ValueError as e:
+                            # Re-raise ValueError for external reference errors
+                            if "External or non-local reference not supported" in str(
+                                e
+                            ):
+                                raise
+                            logger.error(
+                                f"Failed to extract schema for media type '{media_type_str}': {e}"
+                            )
                         except Exception as e:
                             logger.error(
                                 f"Failed to extract schema for media type '{media_type_str}': {e}"
                             )
 
             return request_body_info
+        except ValueError as e:
+            # Re-raise ValueError for external reference errors
+            if "External or non-local reference not supported" in str(e):
+                raise
+            ref_name = getattr(request_body_or_ref, "ref", "unknown")
+            logger.error(
+                f"Failed to extract request body '{ref_name}': {e}", exc_info=False
+            )
+            return None
         except Exception as e:
             ref_name = getattr(request_body_or_ref, "ref", "unknown")
             logger.error(
@@ -449,6 +473,17 @@ def _extract_responses(
                                     media_type_obj.media_type_schema
                                 )
                                 resp_info.content_schema[media_type_str] = schema_dict
+                            except ValueError as e:
+                                # Re-raise ValueError for external reference errors
+                                if (
+                                    "External or non-local reference not supported"
+                                    in str(e)
+                                ):
+                                    raise
+                                logger.error(
+                                    f"Failed to extract schema for media type '{media_type_str}' "
+                                    f"in response {status_code}: {e}"
+                                )
                             except Exception as e:
                                 logger.error(
                                     f"Failed to extract schema for media type '{media_type_str}' "
@@ -456,6 +491,16 @@ def _extract_responses(
                                 )
 
                 extracted_responses[str(status_code)] = resp_info
+            except ValueError as e:
+                # Re-raise ValueError for external reference errors
+                if "External or non-local reference not supported" in str(e):
+                    raise
+                ref_name = getattr(resp_or_ref, "ref", "unknown")
+                logger.error(
+                    f"Failed to extract response for status code {status_code} "
+                    f"from reference '{ref_name}': {e}",
+                    exc_info=False,
+                )
             except Exception as e:
                 ref_name = getattr(resp_or_ref, "ref", "unknown")
                 logger.error(
@@ -556,6 +601,17 @@ def parse(self) -> list[HTTPRoute]:
                         logger.info(
                             f"Successfully extracted route: {method_upper} {path_str}"
                         )
+                    except ValueError as op_error:
+                        # Re-raise ValueError for external reference errors
+                        if "External or non-local reference not supported" in str(
+                            op_error
+                        ):
+                            raise
+                        op_id = getattr(operation, "operationId", "unknown")
+                        logger.error(
+                            f"Failed to process operation {method_upper} {path_str} (ID: {op_id}): {op_error}",
+                            exc_info=True,
+                        )
                     except Exception as op_error:
                         op_id = getattr(operation, "operationId", "unknown")
                         logger.error(
@@ -901,6 +957,12 @@ def _replace_ref_with_defs(
         if ref_path.startswith("#/components/schemas/"):
             schema_name = ref_path.split("/")[-1]
             schema["$ref"] = f"#/$defs/{schema_name}"
+        elif not ref_path.startswith("#/"):
+            raise ValueError(
+                f"External or non-local reference not supported: {ref_path}. "
+                f"FastMCP only supports local schema references starting with '#/'. "
+                f"Please include all schema definitions within the OpenAPI document."
+            )
     elif properties := schema.get("properties"):
         if "$ref" in properties:
             schema["properties"] = _replace_ref_with_defs(properties)


Test patch:
diff --git a/tests/utilities/openapi/test_openapi_advanced.py b/tests/utilities/openapi/test_openapi_advanced.py
index 979ca9b28..58a03143d 100644
--- a/tests/utilities/openapi/test_openapi_advanced.py
+++ b/tests/utilities/openapi/test_openapi_advanced.py
@@ -614,3 +614,52 @@ def test_http_trace_method_path(parsed_http_methods_routes):
 
     assert trace_route is not None
     assert trace_route.path == "/resource"
+
+
+@pytest.fixture
+def schema_with_external_reference() -> dict[str, Any]:
+    """Fixture that returns a schema with external schema references like in issue #926."""
+    return {
+        "openapi": "3.0.0",
+        "info": {"title": "External Reference API", "version": "1.0.0"},
+        "paths": {
+            "/products": {
+                "post": {
+                    "summary": "Create a product",
+                    "operationId": "createProduct",
+                    "requestBody": {
+                        "required": True,
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "type": "object",
+                                    "properties": {
+                                        "obj": {
+                                            "$ref": "http://cyaninc.com/json-schemas/market-v1/product-constraints"
+                                        }
+                                    },
+                                }
+                            }
+                        },
+                    },
+                    "responses": {"201": {"description": "Product created"}},
+                }
+            }
+        },
+    }
+
+
+# --- Tests for external schema reference handling --- #
+
+
+def test_external_reference_raises_clear_error(schema_with_external_reference):
+    """Test that external schema references raise a clear, helpful error message."""
+    with pytest.raises(ValueError) as exc_info:
+        parse_openapi_to_http_routes(schema_with_external_reference)
+
+    error_message = str(exc_info.value)
+    assert "External or non-local reference not supported" in error_message
+    assert (
+        "http://cyaninc.com/json-schemas/market-v1/product-constraints" in error_message
+    )
+    assert "FastMCP only supports local schema references" in error_message