Google's Agent Development Kit (ADK) is a code-first framework: you write a Python module, declare an Agent, give it tools, and run it. That is great when one developer owns one agent. It gets harder when a team needs dozens of agents, changes their instructions every week, and wants to know who ran what, on which model, for how many tokens.
apowerb is an open source (Apache-2.0) platform we built for that second case. Agents are stored as database records, created from a web UI or a REST API, and apowerb builds the ADK objects for you. This post walks through creating an ADK agent with an MCP server attached, using nothing but HTTP calls, and shows what came back on a real run.
From a record to an ADK agent
Each agent is a row: a name, an instruction, a model string, a list of tools, optional sub-agents and MCP servers. A function called to_agent() turns that row into an ADK object:
-
llmagents become anLlmAgent;sequential,parallelandloopagents become aSequentialAgent,ParallelAgentorLoopAgent, with their sub-agents built recursively. - The model string is wrapped in ADK's
LiteLlmmodel, so any LiteLLM provider works. Gemini models take thegemini/prefix. - Each entry in
mcp_serversbecomes an ADKMcpToolset.
When an agent changes, apowerb regenerates its ADK module and the ADK FastAPI app mounted inside apowerb picks it up. Runs go through the standard ADK runner, so sessions, events and traces are plain ADK.
1. Get a token
import requests
BASE_URL = "http://localhost:8000"
EMAIL = "you@example.com"
response = requests.post(
f"{BASE_URL}/api/auth/token",
data={"username": EMAIL, "password": "YOUR_PASSWORD"},
)
response.raise_for_status()
HEADERS = {"Authorization": f"Bearer {response.json()['access_token']}"}
2. Create an agent with an MCP server
For the test I used DeepWiki's public MCP server, which needs no account and answers questions about GitHub repositories.
agent = requests.post(
f"{BASE_URL}/api/agents",
headers=HEADERS,
json={
"agent_name": "docs_assistant",
"agent_description": "Answers questions with the tools of an MCP server",
"agent_instruction": "You are a helpful assistant. Use the MCP tools when they fit the request.",
"agent_model": "gemini/gemini-flash-latest",
"agent_model_params": {"model_api_key": "YOUR_GEMINI_API_KEY"},
"agent_type": "llm",
"agent_tools": [],
"mcp_servers": [
{"name": "my_mcp_server", "transport": "http", "url": "https://mcp.deepwiki.com/mcp"}
],
},
)
agent.raise_for_status()
Remote servers use the http transport by default. The stdio transport launches a local command, so it is off unless the operator sets MCP_STDIO_ENABLED=1, and only administrators can use it.
3. Run it
result = requests.post(
f"{BASE_URL}/api/adk/run",
headers=HEADERS,
json={
"agent_name": "docs_assistant",
"user_id": EMAIL,
"session_id": "session_001",
"new_message": {
"role": "user",
"parts": [{"text": "Use your tools: what is the GitHub repository google/adk-python about?"}],
},
},
)
events = result.json()
The response is the list of ADK events for the turn. On the real run, the events contained a functionCall to the MCP tool ask_wiki_question, followed by the model's answer:
The google/adk-python repository contains the Agent Development Kit (ADK), an open-source, code-first Python framework designed for building, evaluating, and deploying sophisticated AI agents.
Asked "Which tools do you have access to?", the same agent listed the three DeepWiki tools (ask_wiki_question, read_wiki_structure, read_wiki_contents) next to apowerb's own built-in tools.
The same body posted to /api/adk/run_sse streams the events as server-sent events. The full conversation and its execution trace are then available at /api/adk/sessions/{agent}/{user}/{session} and .../trace.
What the platform adds around ADK
ADK stays in charge of the agent loop. apowerb adds what a team needs around it:
- a web UI and REST API to create and edit agents without redeploying code;
- built-in tools for RAG, Text-to-SQL, BI charts, Google Workspace and Microsoft 365;
- scheduled runs and runs triggered by email;
- per-user token quotas and a per-session audit trail;
- self-hosting with Docker Compose or a Helm chart.
Try it
- Code: https://github.com/apowerb/apowerb
- Docs and quickstart: https://docs.apowerb.com/quickstart
pip install apowerb
Feedback and issues are welcome on GitHub.
Top comments (3)
Great walkthrough, David! Creating an agent with an MCP toolset and running it with nothing but HTTP calls is exactly the demo people need 🤩.
One improvement that would make it even more useful for real deployments: an example with an authenticated MCP server. DeepWiki is public, but most teams will plug in internal servers that need a token. The mcp_servers config already accepts headers, so a short snippet with an Authorization header, and a word on where that token is stored, would answer the first question readers will have. Same for the model key: the shared default key in .env keeps it out of the request body.
Two ideas for a follow-up: what the agent sees when the MCP server is slow or down (plus a raise_for_status() on the /run call), and the toolbox-db type, which connects agents to databases through MCP Toolbox. That one deserves its own post.
Thanks Anis, good points.
Authenticated MCP server. Yes,
headersis passed as-is to the MCP client (HTTP and SSE transports):Read
MCP_TOKENfrom your environment or secret manager on the client side, never hard-code it. On where apowerb keeps it: it is stored with the agent's MCP config, and I'd rather cover storage and rotation properly in a follow-up than hand-wave it here.Model key. Right: with
"agent_model": "thaink2/default", the agent uses the server'sDEFAULT_LLM_MODEL/DEFAULT_LLM_API_KEY, so there is no key in the request body and none stored on the agent.raise_for_status()on/run: fair, I'll add it. A slow or unavailable MCP server and thetoolbox-dbtype are noted for the next post.Looking forward to the follow-up on token storage and rotation. That’s the first thing a security team will ask about, and showing how to rotate an MCP token across every agent that uses it would make a great post.