mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-23 05:54:19 +02:00
Replace FastMCP.as_proxy() with create_proxy() function (#2829)
This commit is contained in:
parent
d8351993f7
commit
3163e61ee4
16 changed files with 341 additions and 124 deletions
|
|
@ -46,13 +46,13 @@ server2 = FastMCP("Server2", providers=[provider])
|
|||
|
||||
### ProxyProvider
|
||||
|
||||
`ProxyProvider` (`src/fastmcp/server/providers/proxy.py`) proxies components from remote MCP servers via a client factory. Used by `FastMCP.as_proxy()` and `FastMCP.mount()` for remote server integration.
|
||||
`ProxyProvider` (`src/fastmcp/server/providers/proxy.py`) proxies components from remote MCP servers via a client factory. Used by `create_proxy()` and `FastMCP.mount()` for remote server integration.
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Create proxy to remote server
|
||||
server = FastMCP.as_proxy("http://remote-server/mcp")
|
||||
server = create_proxy("http://remote-server/mcp")
|
||||
```
|
||||
|
||||
### OpenAPIProvider
|
||||
|
|
|
|||
|
|
@ -263,11 +263,11 @@ Users on Claude Pro, Max, Team, and Enterprise plans have first-class remote ser
|
|||
Create a proxy server that connects to a remote HTTP server:
|
||||
|
||||
```python proxy_server.py
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Create a proxy to a remote server
|
||||
proxy = FastMCP.as_proxy(
|
||||
"https://example.com/mcp/sse",
|
||||
proxy = create_proxy(
|
||||
"https://example.com/mcp/sse",
|
||||
name="Remote Server Proxy"
|
||||
)
|
||||
|
||||
|
|
@ -280,8 +280,9 @@ if __name__ == "__main__":
|
|||
For authenticated remote servers, create an authenticated client following the guidance in the [client auth documentation](/clients/auth/bearer) and pass it to the proxy:
|
||||
|
||||
```python auth_proxy_server.py {7}
|
||||
from fastmcp import FastMCP, Client
|
||||
from fastmcp import Client
|
||||
from fastmcp.client.auth import BearerAuth
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Create authenticated client
|
||||
client = Client(
|
||||
|
|
@ -290,7 +291,7 @@ client = Client(
|
|||
)
|
||||
|
||||
# Create proxy using the authenticated client
|
||||
proxy = FastMCP.as_proxy(client, name="Authenticated Proxy")
|
||||
proxy = create_proxy(client, name="Authenticated Proxy")
|
||||
|
||||
if __name__ == "__main__":
|
||||
proxy.run()
|
||||
|
|
|
|||
|
|
@ -47,6 +47,77 @@ main.mount(weather_server)
|
|||
# Now main has access to get_forecast and data://cities
|
||||
```
|
||||
|
||||
## Mounting External Servers
|
||||
|
||||
Mount remote HTTP servers or subprocess-based MCP servers using `create_proxy()`:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
mcp = FastMCP("Orchestrator")
|
||||
|
||||
# Mount a remote HTTP server (URLs work directly)
|
||||
mcp.mount(create_proxy("http://api.example.com/mcp"), namespace="api")
|
||||
|
||||
# Mount local Python scripts (file paths work directly)
|
||||
mcp.mount(create_proxy("./my_server.py"), namespace="local")
|
||||
```
|
||||
|
||||
### Mounting npm/uvx Packages
|
||||
|
||||
For npm packages or Python tools, use the config dict format:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
mcp = FastMCP("Orchestrator")
|
||||
|
||||
# Mount npm package via config
|
||||
github_config = {
|
||||
"mcpServers": {
|
||||
"default": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-github"]
|
||||
}
|
||||
}
|
||||
}
|
||||
mcp.mount(create_proxy(github_config), namespace="github")
|
||||
|
||||
# Mount Python tool via config
|
||||
sqlite_config = {
|
||||
"mcpServers": {
|
||||
"default": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-sqlite", "--db", "data.db"]
|
||||
}
|
||||
}
|
||||
}
|
||||
mcp.mount(create_proxy(sqlite_config), namespace="db")
|
||||
```
|
||||
|
||||
Or use explicit transport classes:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
from fastmcp.client.transports import NpxStdioTransport, UvxStdioTransport
|
||||
|
||||
mcp = FastMCP("Orchestrator")
|
||||
|
||||
mcp.mount(
|
||||
create_proxy(NpxStdioTransport(package="@modelcontextprotocol/server-github")),
|
||||
namespace="github"
|
||||
)
|
||||
mcp.mount(
|
||||
create_proxy(UvxStdioTransport(tool_name="mcp-server-sqlite", tool_args=["--db", "data.db"])),
|
||||
namespace="db"
|
||||
)
|
||||
```
|
||||
|
||||
For advanced configuration, see [Proxying](/servers/providers/proxy).
|
||||
|
||||
## Namespacing
|
||||
|
||||
<VersionBadge version="3.0.0" />
|
||||
|
|
@ -145,18 +216,16 @@ main.mount(subserver, namespace="api")
|
|||
|
||||
### Proxy Mounting
|
||||
|
||||
The parent server treats the mounted server as a separate entity:
|
||||
<Warning>
|
||||
The `as_proxy` parameter is deprecated. Mounted servers now always have their lifespan and middleware invoked. To create a proxy server explicitly, use `create_proxy()` from `fastmcp.server`.
|
||||
</Warning>
|
||||
|
||||
```python
|
||||
main.mount(subserver, namespace="api", as_proxy=True)
|
||||
```
|
||||
Previously, the parent server could treat the mounted server as a separate entity with its own lifecycle. This behavior is now the default for all mounted servers:
|
||||
|
||||
- Full client lifecycle events on mounted server
|
||||
- Mounted server's lifespan is executed
|
||||
- Communication via in-memory Client transport
|
||||
|
||||
FastMCP automatically uses proxy mounting when the mounted server has a custom lifespan. Override with `as_proxy=True` or `as_proxy=False`.
|
||||
|
||||
## Tag Filtering
|
||||
|
||||
<VersionBadge version="3.0.0" />
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ FastMCP includes providers for common patterns:
|
|||
|----------|--------------|----------------|
|
||||
| `LocalProvider` | Stores components you define in code | `@mcp.tool`, `mcp.add_tool()` |
|
||||
| `FastMCPProvider` | Wraps another FastMCP server | `mcp.mount(server)` |
|
||||
| `ProxyProvider` | Connects to remote MCP servers | `FastMCP.as_proxy(client)` |
|
||||
| `ProxyProvider` | Connects to remote MCP servers | `create_proxy(client)` |
|
||||
| `TransformingProvider` | Adds prefixes to avoid name collisions | `mcp.mount(server, namespace="api")` |
|
||||
|
||||
Most users only interact with `LocalProvider` (through decorators) and occasionally mount or proxy other servers. The provider abstraction stays invisible until you need it.
|
||||
|
|
|
|||
|
|
@ -36,17 +36,13 @@ sequenceDiagram
|
|||
|
||||
<VersionBadge version="2.10.3" />
|
||||
|
||||
Create a proxy using `FastMCP.as_proxy()`:
|
||||
Create a proxy using `create_proxy()`:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.proxy import ProxyClient
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Create a proxy to a remote server
|
||||
proxy = FastMCP.as_proxy(
|
||||
ProxyClient("http://example.com/mcp"),
|
||||
name="MyProxy"
|
||||
)
|
||||
# create_proxy() accepts URLs, file paths, and transports directly
|
||||
proxy = create_proxy("http://example.com/mcp", name="MyProxy")
|
||||
|
||||
if __name__ == "__main__":
|
||||
proxy.run()
|
||||
|
|
@ -57,19 +53,19 @@ This gives you:
|
|||
- Automatic forwarding of MCP features (sampling, elicitation, etc.)
|
||||
- Session isolation to prevent context mixing
|
||||
|
||||
<Tip>
|
||||
To mount a proxy inside another FastMCP server, see [Mounting External Servers](/servers/providers/mounting#mounting-external-servers).
|
||||
</Tip>
|
||||
|
||||
## Transport Bridging
|
||||
|
||||
A common use case is bridging transports - making a remote server available locally:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.proxy import ProxyClient
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Bridge remote HTTP to local stdio
|
||||
remote_proxy = FastMCP.as_proxy(
|
||||
ProxyClient("http://example.com/mcp/sse"),
|
||||
name="Remote-to-Local"
|
||||
)
|
||||
remote_proxy = create_proxy("http://example.com/mcp/sse", name="Remote-to-Local")
|
||||
|
||||
# Run locally via stdio for Claude Desktop
|
||||
if __name__ == "__main__":
|
||||
|
|
@ -79,11 +75,10 @@ if __name__ == "__main__":
|
|||
Or expose a local server via HTTP:
|
||||
|
||||
```python
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Bridge local server to HTTP
|
||||
local_proxy = FastMCP.as_proxy(
|
||||
ProxyClient("local_server.py"),
|
||||
name="Local-to-HTTP"
|
||||
)
|
||||
local_proxy = create_proxy("local_server.py", name="Local-to-HTTP")
|
||||
|
||||
if __name__ == "__main__":
|
||||
local_proxy.run(transport="http", host="0.0.0.0", port=8080)
|
||||
|
|
@ -93,13 +88,13 @@ if __name__ == "__main__":
|
|||
|
||||
<VersionBadge version="2.10.3" />
|
||||
|
||||
ProxyClient provides session isolation - each request gets its own isolated backend session:
|
||||
`create_proxy()` provides session isolation - each request gets its own isolated backend session:
|
||||
|
||||
```python
|
||||
from fastmcp.server.proxy import ProxyClient
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# Each request creates a fresh backend session (recommended)
|
||||
proxy = FastMCP.as_proxy(ProxyClient("backend_server.py"))
|
||||
proxy = create_proxy("backend_server.py")
|
||||
|
||||
# Multiple clients can use this proxy simultaneously:
|
||||
# - Client A calls a tool → gets isolated session
|
||||
|
|
@ -113,10 +108,11 @@ If you pass an already-connected client, the proxy reuses that session:
|
|||
|
||||
```python
|
||||
from fastmcp import Client
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
async with Client("backend_server.py") as connected_client:
|
||||
# This proxy reuses the connected session
|
||||
proxy = FastMCP.as_proxy(connected_client)
|
||||
proxy = create_proxy(connected_client)
|
||||
|
||||
# ⚠️ Warning: All requests share the same session
|
||||
```
|
||||
|
|
@ -129,7 +125,7 @@ Shared sessions may cause context mixing in concurrent scenarios. Use only in si
|
|||
|
||||
<VersionBadge version="2.10.3" />
|
||||
|
||||
ProxyClient automatically forwards MCP protocol features:
|
||||
Proxies automatically forward MCP protocol features:
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
|
|
@ -140,11 +136,10 @@ ProxyClient automatically forwards MCP protocol features:
|
|||
| Progress | Progress notifications |
|
||||
|
||||
```python
|
||||
from fastmcp.server.proxy import ProxyClient
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
# All features forwarded automatically
|
||||
backend = ProxyClient("advanced_backend.py")
|
||||
proxy = FastMCP.as_proxy(backend)
|
||||
proxy = create_proxy("advanced_backend.py")
|
||||
|
||||
# When the backend:
|
||||
# - Requests LLM sampling → forwarded to your client
|
||||
|
|
@ -157,6 +152,8 @@ proxy = FastMCP.as_proxy(backend)
|
|||
Selectively disable forwarding:
|
||||
|
||||
```python
|
||||
from fastmcp.server.providers.proxy import ProxyClient
|
||||
|
||||
backend = ProxyClient(
|
||||
"backend_server.py",
|
||||
sampling_handler=None, # Disable LLM sampling
|
||||
|
|
@ -171,7 +168,7 @@ backend = ProxyClient(
|
|||
Create proxies from configuration dictionaries:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
config = {
|
||||
"mcpServers": {
|
||||
|
|
@ -182,7 +179,7 @@ config = {
|
|||
}
|
||||
}
|
||||
|
||||
proxy = FastMCP.as_proxy(config, name="Config-Based Proxy")
|
||||
proxy = create_proxy(config, name="Config-Based Proxy")
|
||||
```
|
||||
|
||||
### Multi-Server Proxies
|
||||
|
|
@ -190,6 +187,8 @@ proxy = FastMCP.as_proxy(config, name="Config-Based Proxy")
|
|||
Combine multiple servers with automatic namespacing:
|
||||
|
||||
```python
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
config = {
|
||||
"mcpServers": {
|
||||
"weather": {
|
||||
|
|
@ -206,7 +205,7 @@ config = {
|
|||
# Creates unified proxy with prefixed components:
|
||||
# - weather_get_forecast
|
||||
# - calendar_add_event
|
||||
composite = FastMCP.as_proxy(config, name="Composite")
|
||||
composite = create_proxy(config, name="Composite")
|
||||
```
|
||||
|
||||
## Component Prefixing
|
||||
|
|
@ -229,7 +228,10 @@ Components from a proxy server are "mirrored" - they reflect the remote server's
|
|||
To modify a proxied component (like disabling it), create a local copy:
|
||||
|
||||
```python
|
||||
proxy = FastMCP.as_proxy("backend_server.py")
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
proxy = create_proxy("backend_server.py")
|
||||
|
||||
# Get mirrored tool
|
||||
mirrored_tool = await proxy.get_tool("useful_tool")
|
||||
|
|
@ -258,12 +260,14 @@ When mounting proxy servers, this latency affects all operations on the parent s
|
|||
|
||||
For low-latency requirements, consider using [`import_server()`](/servers/providers/mounting#static-importing) to copy tools at startup.
|
||||
|
||||
## Advanced: FastMCPProxy Class
|
||||
## Advanced Usage
|
||||
|
||||
### FastMCPProxy Class
|
||||
|
||||
For explicit session control, use `FastMCPProxy` directly:
|
||||
|
||||
```python
|
||||
from fastmcp.server.proxy import FastMCPProxy, ProxyClient
|
||||
from fastmcp.server.providers.proxy import FastMCPProxy, ProxyClient
|
||||
|
||||
# Custom session factory
|
||||
def create_client():
|
||||
|
|
@ -273,3 +277,25 @@ proxy = FastMCPProxy(client_factory=create_client)
|
|||
```
|
||||
|
||||
This gives you full control over session creation and reuse strategies.
|
||||
|
||||
### Adding Proxied Components to Existing Server
|
||||
|
||||
Mount a proxy to add remote components to an existing server:
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
server = FastMCP("My Server")
|
||||
|
||||
# Add local tools
|
||||
@server.tool
|
||||
def local_tool() -> str:
|
||||
return "Local result"
|
||||
|
||||
# Mount proxied tools from remote server
|
||||
remote = create_proxy("http://remote-server/mcp")
|
||||
server.mount(remote)
|
||||
|
||||
# Now server has both local and proxied tools
|
||||
```
|
||||
|
|
|
|||
|
|
@ -288,17 +288,18 @@ main.mount(sub, namespace="sub")
|
|||
|
||||
<VersionBadge version="2.0.0" />
|
||||
|
||||
FastMCP can act as a proxy for any MCP server (local or remote) using `FastMCP.as_proxy`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa.
|
||||
FastMCP can act as a proxy for any MCP server (local or remote) using `create_proxy`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa.
|
||||
|
||||
Proxies automatically handle concurrent operations safely by creating fresh sessions for each request when using disconnected clients.
|
||||
|
||||
See the [Remote Proxies](/servers/providers/proxy) guide for details and advanced usage.
|
||||
|
||||
```python
|
||||
from fastmcp import FastMCP, Client
|
||||
from fastmcp import Client
|
||||
from fastmcp.server import create_proxy
|
||||
|
||||
backend = Client("http://example.com/mcp/sse")
|
||||
proxy = FastMCP.as_proxy(backend, name="ProxyServer")
|
||||
proxy = create_proxy(backend, name="ProxyServer")
|
||||
# Now use the proxy like any FastMCP server
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue