fastmcp icon indicating copy to clipboard operation
fastmcp copied to clipboard

Proxied servers have even weird-er lifespans

Open strawgate opened this issue 7 months ago • 6 comments

Description

Now that proxying is available https://github.com/jlowin/fastmcp/pull/309 I've set it up and it looks like every request is getting a new lifespan and thus a new Context.

I would have hoped that the lifespan of the root server and the lifespan of the mounted servers would be the same scope

Example Code


Version Information

2.2.7

Additional Context

No response

strawgate avatar May 03 '25 22:05 strawgate

Coordinating lifespans across unrelated servers may be very difficult, especially if you consider the case of remote proxy servers that we don't even have access to. The only realistic way I could think of is to hold the client connections open for the duration of the main server's lifespan, but that feels like a bad idea in general.

Can you share more about what you're trying to achieve via stateful and linked lifespans? IMO based on everything we've learned, lifespans feel like a relatively poorly developed part of the protocol. It's unclear if they are per-server (they're described as startup/shutdown) per request (since many servers are designed to spin up new instances on request) or per session (e.g. SSE). Since servers aren't capable of graceful shutdowns (e.g. they have no termination conditions), I find that the lifespan exits never seem to be called anyway.

jlowin avatar May 04 '25 01:05 jlowin

We could forcibly open mounted server lifespans in the parent lifespan and then close them with the parent lifespan closes (or better, wait to open them until the first time a client accesses the mounted server) but we'd be back in an as_proxy=False world and I'm a little concerned we'd be ignoring some other aspect of the client handshake.

jlowin avatar May 04 '25 01:05 jlowin

Yeah I think that's the conclusion I've come to as well. I've basically abandoned lifespans for startup and shutdown.

Right now the only use case I have is that I need the LLM to give me a piece of information (the working directory of the MCP client) when it connects so that it doesn't have to keep giving me that information with every request.

strawgate avatar May 04 '25 01:05 strawgate

Totally get it. At the risk of opening another poorly developed can of worms, I wonder if that's the role of "roots" - to supply certain client parameters to the server? But feels like a lot of overhead. I wonder if establishing a more easy way of communicating certain standards via e.g. request headers would help here. like any header (or env var) with X-FASTMCP as the prefix automatically gets placed in some sort of easy to access context? We already have the more cumbersome version of this, for SSE only, with get_http_request(). Could be an avenue to explore. Alternatively some sort of client- or session- caching along the lines of #268

jlowin avatar May 04 '25 02:05 jlowin

I haven't looked but if each client has a unique id or each session has a unique id then I can just use an in memory cache for the state I'm trying to hold

strawgate avatar May 04 '25 12:05 strawgate

There is a client_id and request_id in the Context object but I am not sure of what constitutes a new ID

jlowin avatar May 04 '25 13:05 jlowin