> For the complete documentation index, see [llms.txt](/llms.txt).
> A full single-fetch corpus is available at [llms-full.txt](/llms-full.txt).
---
title: Serve your project over MCP
description: Expose your AGNT5 functions, workflows, and agents as an MCP server, deploy it, and connect it to Claude so every tool call runs as a durable run you can inspect in Studio.
last_verified: 2026-10-20
---

This guide takes a working AGNT5 project and publishes part of it as a Model Context Protocol (MCP) server. When you finish, Claude can call your code as tools, and each call appears in Studio as a run with its input, output, duration, and the user who made it.

It uses Python. For connecting your agents to other people's MCP servers, and for the full `MCPServer` API, see [Model Context Protocol](/docs/build/mcp.md).

**You need:**

- A project with at least one function, workflow, or agent, and the AGNT5 CLI signed in (`agnt5 whoami` shows your account).
- A Claude account that can add a custom connector.

## 1. Choose what to publish

A hosted MCP server publishes three kinds of component. Each becomes one tool:

| Component | What the client gets |
|---|---|
| Function | A tool that answers right away. |
| Workflow | A tool that runs your durable steps and returns the workflow's result. |
| Agent | A tool that takes a message (`input`) and an optional `session_id` to continue a conversation. |

For a workflow that takes minutes, add it with `mode="background"`. The call then hands back a `run_handle` at once, and the client follows the run with the built-in `get_run` tool, which reports the current step, progress, and finally the result:

```python
support.add_workflow("audit_orders", audit_orders, mode="background")
```

A `@tool` is not published to a hosted server; it is served only over stdio (see [Model Context Protocol](/docs/build/mcp.md#serve-locally-over-stdio)). To publish one, wrap its logic in a function and publish the function.

Publish the smallest surface a client needs. A workflow that does the whole job gives you one run per request. Separate functions give a client more control, but it then chooses which to call and in what order (see [See the calls](#6-see-the-calls)).

## 2. Define the server

Create a module that defines the server and adds the components. This example publishes a function and a workflow:

```python title="src/my_project/server.py"
from agnt5 import MCPServer

from my_project.functions import lookup_order
from my_project.workflows import refund_order

support = MCPServer(
    "support",
    title="Order support",
    instructions=(
        "Tools for customer orders. Use lookup_order to read an order and "
        "refund_order to refund one in full."
    ),
)

support.add_function("lookup_order", lookup_order, annotations={"readOnlyHint": True})
support.add_workflow(
    "refund_order",
    refund_order,
    annotations={"destructiveHint": True, "idempotentHint": False},
)
```

The first argument is the server name. It becomes part of the server's URL, so use lowercase letters, digits, `-`, and `_`. The `instructions` string is shown to the client, so write it for the model that will choose between your tools. Annotations are MCP tool hints for the client: `readOnlyHint` marks a tool that only reads, `destructiveHint` one that changes data, and `idempotentHint` whether repeating a call has no further effect.

## 3. Register the server with your worker

A worker publishes a server only when the module that defines it is imported. Import it in your worker's entry point, and register every component the server publishes:

```python title="app.py"
import asyncio

from agnt5 import Worker

from my_project.functions import lookup_order, issue_refund
from my_project.server import support  # noqa: F401  (importing this publishes the server)
from my_project.workflows import refund_order


async def main() -> None:
    worker = Worker(
        service_name="support",
        functions=[lookup_order, issue_refund],
        workflows=[refund_order],
    )
    await worker.run()


if __name__ == "__main__":
    asyncio.run(main())
```

Name the server in `agnt5.yaml` so the CLI can check that a deploy published it:

```yaml title="agnt5.yaml"
mcp:
  servers:
    - name: support
```

## 4. Try it locally

Start the dev worker from the project directory:

```bash
agnt5 dev
```

The output ends with a dev URL for the server. Only you can sign in to a dev URL. To call the tools from Claude Code, write its config and sign in:

```bash
agnt5 mcp connect support --dev --client claude-code
```

This writes `.mcp.json` in the current directory. Start `claude` from that directory, run `/mcp`, choose `support`, and sign in with AGNT5. Then ask Claude to use one of your tools.

`agnt5 mcp connect` also writes config for `cursor`, `vscode`, and `codex`. Add `--print` to see the config without writing it.

## 5. Deploy and connect Claude

If your agents call a model provider, set its key as a secret first, so the deployed worker can read it:

```bash
agnt5 secrets set --name OPENAI_API_KEY --type api_key
```

Deploy to production:

```bash
agnt5 deploy --env production
```

The output lists the MCP servers the deployment published. You can list them again later:

```bash
agnt5 mcp list --env production
```

A deployed server is served at:

```text
https://api.agnt5.com/mcp/{project-ref}/production/support
```

`{project-ref}` is your project's ref (a string like `c8d647bf8bb94e6b8ee3e`), not its name. Copy the full URL from the deploy output or from `agnt5 mcp list`.



[Video](/videos/docs/mcp-claude-connect-light.mp4): In Claude's settings, open Connectors, select Add, then Add custom connector. Name the connector order-support and paste the server URL, keep the detected sign-in options, and select Add. After signing in with AGNT5, the connector appears in the list. In a chat, asking to look up order o-1001 calls lookup_order and shows the order, and the call appears as a completed run in Studio.

_Add the deployed server as a custom connector, sign in with AGNT5, and call a tool from a chat._



Add the URL to Claude as a custom connector, following the steps in [Use AGNT5 in Claude](/docs/integrations/claude-connector.md#connect) with your server URL in place of the AGNT5 connector URL. Sign in with AGNT5 when Claude asks; the connector uses OAuth, so don't paste an API key into Claude.

Ask Claude to use one of your tools, for example "Look up order o-1001". Claude calls the tool and answers from its result.

To check a deployed server from the CLI, run:

```bash
agnt5 mcp check support --env production
```

The check confirms that AGNT5 serves the server and its tools, and that client sign-in is set up.

## 6. See the calls

Open the project in Studio. Every tool call is a run with the component name, status, duration, the user who made the call, and a trace ID. Open a run to see its input and output.

What a run contains depends on what the tool is:

- **A function tool** is one run.
- **A workflow tool** is one run, and its steps are part of it.
- **An agent, or a workflow that runs an agent,** is one run with one trace. The agent's iterations, model calls, and tool calls are all events in that run.

When a client has several fine-grained tools, it plans the sequence itself. A request that makes four tool calls produces four separate runs, each with its own trace. To get one run for a whole request, publish a workflow that does the work, and let the client call that.

## Next steps

- [Model Context Protocol](/docs/build/mcp.md): the full `MCPServer` and `MCPClient` reference, including serving over stdio.
- [Workflows](/docs/build/workflows.md): put multi-step work behind one durable run.
- [Deploying](/docs/run/deploying.md): environments, secrets, and promotion.
- [Use AGNT5 in Claude](/docs/integrations/claude-connector.md): connect Claude to AGNT5 itself to inspect your runs and deployments.
