Wire an MCP Server to Your Agent (With Zero Config)
The Model Context Protocol lets any client call your agent as a tool — but only if something hosts, authenticates, and keeps the MCP server in sync with your code. On a2a cloud that server is generated from your agent's skills on every deploy. Here's how it works.
Wire an MCP Server to Your Agent (With Zero Config)
The Model Context Protocol has become the default way to hand tools and context to an agent. The appeal is obvious: write a tool once, expose it over MCP, and any MCP-speaking client — Claude, an IDE, another agent — can call it without a bespoke integration.
The part nobody puts on the slide is that an MCP *server* is a real service. Someone has to host it, authenticate callers, scope what each caller can reach, and — the tedious one — keep the tool schemas in lockstep with the code they wrap. Change a function signature, forget to update the server, and callers break in ways your type checker never sees.
On a2a cloud you don't stand up that server. Every agent's skills are exposed as MCP tools automatically, on every deploy, from the same source of truth as the code. This post is what that actually means and where the edges are.
The manual version, so the savings are concrete
Doing this by hand for one agent looks like:
- Pick or write an MCP server framework and mount it somewhere with a public, TLS-terminated URL.
- For each tool, hand-author an MCP tool definition — name, description, JSON Schema for inputs and outputs.
- Wire auth: decide who may connect, mint and rotate credentials, and enforce scopes so a caller can't invoke tools it shouldn't.
- Marshal every call from MCP into your function and the return value back out.
- Keep 1–4 in sync forever as the agent changes.
Step 5 is where it rots. The schema drifts from the implementation, and the failure is silent until a client sends what the *old* schema promised was valid.
What a2a does instead
Your agent is a class with @skill methods. The signature and docstring of each skill are the tool definition:
from a2a_pack.agent import A2AAgent, skill
from a2a_pack.context import RunContext, NoAuth
class Researcher(A2AAgent[dict, NoAuth]):
name = "researcher"
description = "A research agent"
@skill(description="Answer a research question and return sources")
async def ask(self, ctx: RunContext[NoAuth], question: str) -> dict:
# your logic — LLM calls, tools, a LangGraph graph, whatever
return {"answer": "...", "sources": ["..."]}When you run a2a deploy, the platform reads the skill signatures and generates the MCP tool schema from them: ask becomes an MCP tool, question: str becomes a required string input, the dict return becomes the output shape, and the description becomes the tool description an LLM sees when it decides whether to call it. There is no second file to maintain — the schema *is* the code, so it can't drift.
The generated server is mounted at a stable URL with the rest of the agent's surfaces (the HTTP/OpenAPI API, the agent card at /.well-known/agent-card, SSE streaming). You get all of it from the same three commands that deploy the agent:
a2a init researcher
cd researcher
a2a deployConnecting a client
Once the agent is live, point any MCP client at the gateway. Locally the fastest path is the bundled gateway:
npx -y a2amcpThat exposes your enabled agents as MCP tools to whatever client you've wired it into. For remote/programmatic use there's a hosted connector endpoint (https://api.a2acloud.io/connector-mcp) that speaks MCP over HTTP. Either way the client sees a tool per skill, named and typed from your code.
The two things this quietly gets right
Auth and scope aren't an afterthought. Because the MCP server is provisioned with the agent, it inherits the platform's grant model — a caller reaches the tools it's been granted and nothing across the boundary to another agent. You aren't bolting authentication onto a tool server you wrote at 2am. (The same isolation that keeps each agent's [database private](/blog/give-ai-agents-database-access-without-handing-over-production) applies to its tool surface.)
Every tool call still emits a signed receipt. An MCP tool call is a run like any other, so it produces an Ed25519-signed record of what was invoked, with what inputs, and what came back. When another agent calls yours over MCP, you don't have to trust its account of what happened — you have a cryptographic one. That's the difference between a [signed receipt and a trace log](/blog/signed-receipts-vs-trace-logs-agent-audit-trail): the receipt is verifiable by anyone, after the fact, without trusting the caller or the host.
Where this fits
If you're deploying a framework agent, the MCP server comes along for free — the [LangGraph](/blog/deploy-langgraph-agent-60-seconds), CrewAI, and OpenAI Agents SDK quickstarts all end with a live MCP surface without a line of server code. If you're starting from a bare Python class, [Build Your First A2A Agent](/blog/first-a2a-agent-python-to-url) walks the same path from class to live URL.
The throughline: MCP is a great protocol and a real amount of infrastructure. Generating the server from your skills on every deploy means you write the tool once — as a normal function — and the wire format, the hosting, the auth, and the audit trail are handled for you, and stay handled as the code changes.
Try it
a2a init my-agent
cd my-agent # add a @skill or two
a2a deploy
npx -y a2amcp # your skills are now MCP toolsOne function in, an authenticated, audited MCP tool out.