Summary
When MetaMCP refreshes a backend server's tool list (tool-list cache/hash check), it opens a new connection to the backend and logs Created background idle session for server [<name>] <uuid>. This happens repeatedly over the gateway's uptime, but the previously created idle session is never closed. For backends that hold per-session state (e.g. a browser context, as with the official Playwright MCP server), this leaks one browser session per refresh cycle until the backend runs out of resources and dies.
Environment
- MetaMCP image:
ghcr.io/metatool-ai/metamcp:latest, image created 2025-12-11 (sha256:6d5e0cba...)
- Backend affected:
mcr.microsoft.com/playwright/mcp (official Playwright MCP server, Streamable HTTP transport), image created 2026-05-07
- Backend registered as an aggregated tool source behind a MetaMCP vServer (namespace), reached via
/metamcp/<vserver>/mcp
- Deployment: both as separate Docker containers on the same Docker network
What we observed
docker logs metamcp repeatedly shows, for the same backend UUID, over many hours:
[DEBUG-TOOLS] 🔧 Server: playwright
Creating new connection for server playwright (<backend-uuid>) with namespace: <namespace-uuid>
Connecting to server playwright (<backend-uuid>) with max attempts: 1
[DEBUG-TOOLS] ⏱️ Fetched 23 tools from playwright in ~50ms
[DEBUG-TOOLS] 🔍 Hash check for playwright: UNCHANGED
Created background idle session for server [playwright] <backend-uuid>
Counting Created background idle session for server [playwright] lines since the container's last start (~7.7 days uptime at time of writing) gave 149 occurrences — with no corresponding "session closed"/"session removed" log line anywhere in the same window. The events aren't on a fixed timer (gaps range from ~30s to 100+ minutes), so they appear to be triggered by client reconnects / tool-list refresh checks rather than a single cron.
A separate log line dumping the gateway's tracked session-id array (printed while handling an unrelated request) showed several dozen UUIDs still tracked as live sessions.
Impact
The backend container (Playwright MCP) eventually accumulated enough concurrent idle sessions/browser contexts that it stopped responding and exited (clean exit code 0, not OOM-killed at the container level — but the accumulation is the clear precursor). We had to manually restart the backend to restore service. Since the "hash check: UNCHANGED" path means the tool list didn't even change, no new persistent session should have been necessary at all — this looks like it should have been a stateless check.
Suspected root cause
The periodic/lazy tool-list refresh path for aggregated backends appears to always create a brand-new connection + "background idle session" rather than:
- reusing an existing idle/cached session for the tool-list check, or
- explicitly tearing down the session after the hash-check completes (since nothing further is done with it), or
- deduplicating by backend so only one idle session per backend/namespace is ever kept alive.
Suggested fix
For the tool-list refresh/hash-check path specifically, either avoid opening a full backend session at all (if the transport allows a lighter-weight tools/list without a persistent session), or ensure any session opened purely for this check is closed immediately afterward instead of being kept as a long-lived "background idle session".
How to reproduce
- Register any Streamable-HTTP MCP backend that holds per-session server-side state (Playwright MCP is a good example since state cost is visible/expensive).
- Leave MetaMCP running for a while with periodic client activity that triggers tool-list refreshes against that backend (or trigger it manually/repeatedly).
- Watch
docker logs <metamcp> for repeated Created background idle session for server [...] lines with different backend-connection UUIDs (or the same UUID reused as the "logical" identity but a new underlying session/socket each time) accumulating without any matching close.
- Watch the backend's own resource usage (process count / memory) grow correspondingly.
Happy to share more log excerpts if useful.
Summary
When MetaMCP refreshes a backend server's tool list (tool-list cache/hash check), it opens a new connection to the backend and logs
Created background idle session for server [<name>] <uuid>. This happens repeatedly over the gateway's uptime, but the previously created idle session is never closed. For backends that hold per-session state (e.g. a browser context, as with the official Playwright MCP server), this leaks one browser session per refresh cycle until the backend runs out of resources and dies.Environment
ghcr.io/metatool-ai/metamcp:latest, image created 2025-12-11 (sha256:6d5e0cba...)mcr.microsoft.com/playwright/mcp(official Playwright MCP server, Streamable HTTP transport), image created 2026-05-07/metamcp/<vserver>/mcpWhat we observed
docker logs metamcprepeatedly shows, for the same backend UUID, over many hours:Counting
Created background idle session for server [playwright]lines since the container's last start (~7.7 days uptime at time of writing) gave 149 occurrences — with no corresponding "session closed"/"session removed" log line anywhere in the same window. The events aren't on a fixed timer (gaps range from ~30s to 100+ minutes), so they appear to be triggered by client reconnects / tool-list refresh checks rather than a single cron.A separate log line dumping the gateway's tracked session-id array (printed while handling an unrelated request) showed several dozen UUIDs still tracked as live sessions.
Impact
The backend container (Playwright MCP) eventually accumulated enough concurrent idle sessions/browser contexts that it stopped responding and exited (clean exit code 0, not OOM-killed at the container level — but the accumulation is the clear precursor). We had to manually restart the backend to restore service. Since the "hash check: UNCHANGED" path means the tool list didn't even change, no new persistent session should have been necessary at all — this looks like it should have been a stateless check.
Suspected root cause
The periodic/lazy tool-list refresh path for aggregated backends appears to always create a brand-new connection + "background idle session" rather than:
Suggested fix
For the tool-list refresh/hash-check path specifically, either avoid opening a full backend session at all (if the transport allows a lighter-weight
tools/listwithout a persistent session), or ensure any session opened purely for this check is closed immediately afterward instead of being kept as a long-lived "background idle session".How to reproduce
docker logs <metamcp>for repeatedCreated background idle session for server [...]lines with different backend-connection UUIDs (or the same UUID reused as the "logical" identity but a new underlying session/socket each time) accumulating without any matching close.Happy to share more log excerpts if useful.