mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-22 13:34:17 +02:00
fix: substitute server variable defaults when building base URL from OpenAPI spec (#3770)
* fix: resolve OpenAPI 3.x server variables in _create_default_client When an OpenAPI spec defines server variables (e.g. `https://{region}.api.example.com/v1`), the default values are now substituted before constructing the httpx client base URL. Previously, the URL was used as-is, causing all requests to fail for specs that use server variable templating. Fixes #1681 * fix: use str.replace instead of format_map for server variable substitution format_map applies Python string formatting rules, so variable names like {api.version} would be treated as attribute access and raise errors. Literal token replacement handles all valid OpenAPI variable names safely.
This commit is contained in:
parent
eac646e744
commit
99eaeb8af4
2 changed files with 55 additions and 0 deletions
|
|
@ -175,6 +175,9 @@ class OpenAPIProvider(Provider):
|
|||
"entry to the spec or provide an httpx.AsyncClient explicitly."
|
||||
)
|
||||
base_url = servers[0]["url"]
|
||||
variables = servers[0].get("variables", {})
|
||||
for name, var in variables.items():
|
||||
base_url = base_url.replace(f"{{{name}}}", var.get("default", ""))
|
||||
return httpx.AsyncClient(base_url=base_url, timeout=DEFAULT_TIMEOUT)
|
||||
|
||||
@asynccontextmanager
|
||||
|
|
|
|||
|
|
@ -9,6 +9,58 @@ from fastmcp.server.providers.openapi import OpenAPIProvider
|
|||
from fastmcp.server.providers.openapi.provider import DEFAULT_TIMEOUT
|
||||
|
||||
|
||||
class TestOpenAPIProviderServerVariables:
|
||||
"""Test that OpenAPIProvider resolves OpenAPI 3.x server variables."""
|
||||
|
||||
def test_server_variables_substituted_with_defaults(self):
|
||||
spec = {
|
||||
"openapi": "3.0.0",
|
||||
"info": {"title": "Test API", "version": "1.0.0"},
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://{region}.api.example.com/v1",
|
||||
"variables": {
|
||||
"region": {
|
||||
"default": "us",
|
||||
"enum": ["us", "eu", "apac"],
|
||||
}
|
||||
},
|
||||
}
|
||||
],
|
||||
"paths": {},
|
||||
}
|
||||
client = OpenAPIProvider._create_default_client(spec)
|
||||
assert str(client.base_url) == "https://us.api.example.com/v1/"
|
||||
|
||||
def test_multiple_server_variables_substituted(self):
|
||||
spec = {
|
||||
"openapi": "3.0.0",
|
||||
"info": {"title": "Test API", "version": "1.0.0"},
|
||||
"servers": [
|
||||
{
|
||||
"url": "{scheme}://{host}/v1",
|
||||
"variables": {
|
||||
"scheme": {"default": "https"},
|
||||
"host": {"default": "api.example.com"},
|
||||
},
|
||||
}
|
||||
],
|
||||
"paths": {},
|
||||
}
|
||||
client = OpenAPIProvider._create_default_client(spec)
|
||||
assert str(client.base_url) == "https://api.example.com/v1/"
|
||||
|
||||
def test_static_server_url_unaffected(self):
|
||||
spec = {
|
||||
"openapi": "3.0.0",
|
||||
"info": {"title": "Test API", "version": "1.0.0"},
|
||||
"servers": [{"url": "https://api.example.com"}],
|
||||
"paths": {},
|
||||
}
|
||||
client = OpenAPIProvider._create_default_client(spec)
|
||||
assert str(client.base_url) == "https://api.example.com"
|
||||
|
||||
|
||||
class TestOpenAPIProviderBasicFunctionality:
|
||||
"""Test basic OpenAPIProvider functionality."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue