Migrating from Google ADK
This guide walks through migrating an existing raw Google ADK agent onto SwarmD using theswarmd-google-adk package. By the end your
agent’s main.py contains only domain logic — the tool functions, the
description, and the instruction — and swarmd-google-adk owns every
platform concern.
If you have not read Google ADK on SwarmD yet, do that
first. It explains what each of create_runtime, create_llm_agent,
and serve actually does. This guide focuses on the migration
journey — what to delete, what to replace, and how to roll it out —
rather than re-explaining the helpers.
Each step shows the before (raw Google ADK) and the after
(SwarmD) side by side. Read top to bottom the first time, then use it
as a checklist.
What you are migrating away from
A typical standalone Google ADK agent — one file owning everything: the tool function, the LLM config, hardcodedRemoteA2aAgent URLs for any
sub-agents, the FastAPI app, and uvicorn startup.
main.py
- Sub-agent URLs are baked into source — adding, removing, or moving a sub-agent requires a code change and redeploy.
- No identity between agents. Every outbound A2A call is unauthenticated unless you write your own header-injection layer.
- No central audit, policy, or HITL — the relay isn’t in the path.
- Long-running sub-agents block the LLM.
RemoteA2aAgentreturns whatever it got; if the downstream returnsworking, the parent has no way to wait for the terminal state. - MCP tools aren’t there at all.
get_weather)
and the agent’s identity (name, description, instruction) exactly as
they are while replacing every other line with one of three SDK
helpers.
What you are migrating to
main.py
Migration steps
Step 1 — Register the agent
In the dashboard (or viaPOST /registry/v1/agents), register weather_agent. Capture the
three secrets shown once in the response: agentId, clientSecret,
and webhookSecret. Store them with your deployment configuration.
After this step: the platform knows your agent exists. You have
the OAuth2 credentials it will use for outbound calls.
Step 2 — Install the SDK
google-adk pin — swarmd-google-adk
declares a compatible range, not an exact version.
After this step: from swarmd_google_adk import create_runtime, create_llm_agent, serve resolves.
Step 3 — Add platform credentials to .env
Append to your existing .env:
.env
create_runtime() will
attach the agent to SwarmD. With them unset, the agent still runs
locally in “standalone mode” — useful for local dev without a SwarmD
account.
Step 4 — Replace bootstrap with create_runtime()
runtime and pass it into the next two helpers.
Step 5 — Delete the hardcoded RemoteA2aAgent blocks
Step 6 — Replace LlmAgent(...) with create_llm_agent(runtime, ...)
model= (the SDK picks
LiteLlm with the right config — gateway-routed if
SWARMD_LLM_GATEWAY_ID is set, direct OpenAI otherwise), no
sub_agents= (discovered from subscriptions), and no MCP toolset
construction (also discovered).
For exactly what create_llm_agent does internally, see
the helper reference.
After this step: the returned LlmAgent is a regular ADK agent
with sub_agents and tools already populated from your
subscriptions. You can still set LlmAgent callbacks or structured
output on it before passing to serve().
Step 7 — Replace to_a2a(...) + uvicorn.run(...) with serve(agent, runtime)
serve mounts (A2A protocol, agent card, /admin,
correlation middleware, task store, refresh-in-place), see
the helper reference.
After this step: the agent process exposes the same A2A protocol
ADK gave you, plus the /admin surface SwarmD uses to push refresh
events.
Step 8 — Subscribe to downstream agents and MCP servers
Configuration only — no code change. In the dashboard subscribeweather_agent to the sub-agents and MCP servers it needs (the same
ones you used to hardcode in Step 5). The dashboard’s
POST /registry/v1/agents/{id}/subscriptions endpoint works too.
After this step: the platform fires a SUBSCRIPTION_CHANGED
webhook. Your running agent verifies the HMAC, calls
fetch_remote_agents and fetch_mcp_tools again, and the new
sub-agent or MCP tool appears in the LLM’s catalogue without a
restart.
Step 9 — Verify and roll out
In order, before flipping production traffic:- Boot the agent locally with
SWARMD_*vars set. Look for the banner with the agent name, thenFound N subscribed agentsandLoaded N MCP toolset(s)in the logs. Check credentials and base URL if either is missing. curl /.well-known/agent-card.json— the response should include the sub-agent and MCP-tool names you subscribed to.- Send a message that exercises a sub-agent via
POST /(JSON-RPCmessage/send). Confirm the LLM picks the right sub-agent, that the call shows up in the audit log under a single correlation ID, and that the response makes its way back. - Send a message that exercises an MCP tool. Confirm the same.
- Rotate a subscription in the dashboard. Watch
/admin/webhookfire andLoaded N+/-1 MCP toolset(s)reappear in logs. No restart. - Roll out. The migration is purely additive on the agent process — the same binary runs unconfigured (standalone) or configured (SwarmD-attached) depending on env, so you can canary it.
Summary
What changed.main.pyshrinks to domain logic. No more bootstrap, no more hardcoded URLs, no more manualto_a2a.- Outbound calls go through the relay. You get audit, policy, HITL, and rate limits for free.
- Sub-agents and MCP tools are discovered from subscriptions.
- LLM calls can optionally go through a SwarmD LLM gateway.
/admin/webhookkeeps the agent’s catalogue in sync without restarts.
- Your tool function signatures.
- Your
LlmAgent’s name, description, and instruction. - The A2A protocol your agent speaks — both sides are still A2A 0.3.0.
- Local-only behaviour: with
SWARMD_*unset the agent runs as a standalone ADK agent against direct OpenAI.
time_agent
in the repo — a complete agent in ~30 lines of main.py.
For the LangChain equivalent of this guide, see
Migrating from LangChain.