agent.close() and await agent.aclose() shut down every resource the agent owns — LLM clients, memory, MCP tools, runtime MCPs, and per-agent circuit breakers — in one call.
Quick Start
1
Simple
Pass an MCP at construction time;
close() shuts down its subprocess and stream.2
Async
Use the async context manager or call
aclose() explicitly — it prefers each tool’s aclose().How It Works
Closing an agent walks each owned resource and shuts it down best-effort.close() / aclose() set _closed = True and become no-ops on subsequent calls, so calling them twice is safe. Check agent.is_closed to confirm.Before PR #5083 the async path (
aclose()) skipped LLM-client teardown entirely, so a per-request clone in the HTTP invoke API leaked its client pool even when the caller (correctly) awaited aclose(). If you build long-running services that rely on await agent.aclose(), upgrade to that release.Best Practices
Prefer a team-level context manager
Prefer a team-level context manager
Wrap a multi-agent run in
with PraisonAIAgents(...) as workflow: — the team-level context manager fans out to each agent’s close(). See Resource Lifecycle.Use try/finally for a single agent
Use try/finally for a single agent
For a lone agent, wrap the run in
try/finally and call agent.close() (or await agent.aclose()), so cleanup runs even when the run raises.Don't rely on del alone
Don't rely on del alone
Garbage-collection cleanup is best-effort — the async client cannot be awaited from a finalizer. Call
close() / aclose() explicitly for deterministic teardown.Cleanup never masks your error
Cleanup never masks your error
Each step is guarded individually; failures are logged as warnings and never raise, so a bad shutdown never hides the original exception.
Long-running invoke servers close clones for you
Long-running invoke servers close clones for you
The HTTP invoke API (
POST /api/v1/agents/{id}/invoke) and invoke_agent_standalone() both wrap the invocation in try/finally and close the per-request clone after every request. You do not need to add extra cleanup around individual invokes; the wrapper handles per-request clones. See n8n API → Per-request cleanup.Long-running servers: approval grants are reclaimed
Long-running servers: approval grants are reclaimed
If you create one
Agent(...) per request or session and never call close(), the process-global approval registry no longer grows without bound — __del__ also releases the agent’s scope when it is garbage-collected. close() / aclose() remain the recommended deterministic path, since finalizer timing is not guaranteed. Only the closing agent’s own grants are dropped; every other live agent keeps its approvals. See Permissions → Approval-scope cleanup.Related
Runtime MCP
Attach and detach MCP servers at runtime
MCP Lifecycle
Per-MCP context manager and manual shutdown
Resource Lifecycle
Team-level cleanup with PraisonAIAgents
Tool Circuit Breaker
How per-agent breakers work and auto-prune
Permissions
Approval scopes and the cleanup that close() performs
n8n API
Per-request clone cleanup in the HTTP invoke endpoint
Agent Invoke Registry
Templates vs. per-request clones and their teardown

