Skip to main content

Migrating from Google ADK

This guide walks through migrating an existing raw Google ADK agent onto SwarmD using the swarmd-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, hardcoded RemoteA2aAgent URLs for any sub-agents, the FastAPI app, and uvicorn startup.
main.py
Pain points that compound the moment this leaves your laptop:
  • 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. RemoteA2aAgent returns whatever it got; if the downstream returns working, the parent has no way to wait for the terminal state.
  • MCP tools aren’t there at all.
The goal of the migration is to keep the tool function (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
That’s the whole file. For what each helper does under the hood, see Google ADK on SwarmD.

Migration steps

Step 1 — Register the agent

In the dashboard (or via POST /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

You can keep your existing 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
After this step: with these vars set, 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()

After this step: the runtime owns auth, token caching, registry calls, MCP discovery, and correlation-ID propagation. You hold one reference to runtime and pass it into the next two helpers.

Step 5 — Delete the hardcoded RemoteA2aAgent blocks

If a downstream URL was used anywhere else (a helper script, a test, a deployment manifest), audit and remove those too. The next step shows what replaces them. After this step: there is nothing in your source tree that knows the URL of another agent. The registry is the source of truth.

Step 6 — Replace LlmAgent(...) with create_llm_agent(runtime, ...)

Notice what disappears from the call: no 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)

For exactly what 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 subscribe weather_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:
  1. Boot the agent locally with SWARMD_* vars set. Look for the banner with the agent name, then Found N subscribed agents and Loaded N MCP toolset(s) in the logs. Check credentials and base URL if either is missing.
  2. curl /.well-known/agent-card.json — the response should include the sub-agent and MCP-tool names you subscribed to.
  3. Send a message that exercises a sub-agent via POST / (JSON-RPC message/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.
  4. Send a message that exercises an MCP tool. Confirm the same.
  5. Rotate a subscription in the dashboard. Watch /admin/webhook fire and Loaded N+/-1 MCP toolset(s) reappear in logs. No restart.
  6. 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.py shrinks to domain logic. No more bootstrap, no more hardcoded URLs, no more manual to_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/webhook keeps the agent’s catalogue in sync without restarts.
What didn’t.
  • 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.
For a reference implementation of the end state, see 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.