# python-utcp: calling APIs directly from an AI agent without middleware

> The official Python implementation of UTCP splits the core client from per-protocol plugins, so an agent can reach HTTP, CLI, MCP and local text tools through one Pydantic model. Here is how the pieces fit, how to install it, and where the design still leaves gaps.

**universal-tool-calling-protocol/python-utcp** — Official python implementation of UTCP. UTCP is an open standard that lets AI agents call any API directly, without extra middleware.

- Repository: https://github.com/universal-tool-calling-protocol/python-utcp
- Website: https://www.utcp.io/
- Stars: 652 · Forks: 49
- Language: Python
- License: MPL-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/universal-tool-calling-protocol-python-utcp

## The problem python-utcp targets: one agent, many protocols

An agent that can call tools usually ends up with a different integration for each backend. A REST endpoint needs one client, a command-line binary needs a subprocess wrapper, an MCP server needs its own transport, and a folder of files needs a loader. Each integration carries its own description format, so the model sees a different schema per tool and the application carries a different dependency per service.

UTCP is an open standard that, in the project's own description, lets AI agents call any API directly, without extra middleware. The Python package is the reference implementation of that standard. Its audience is Python developers building agent runtimes, not end users: you need to be comfortable with async code, Pydantic models and dependency management. The README frames the design around scalability, extensibility and interoperability, and the repository layout backs that up. The core package holds the data models, the client interface and the plugin interfaces; everything protocol-specific lives in a separate installable package under plugins/communication_protocols/.

That split is the actual claim. UTCP is not trying to be a better HTTP client. It is trying to make the protocol a detail you swap, so the agent-facing surface (tool names, descriptions, arguments) stays constant while the transport underneath changes.

## Core, plugins and call templates: how the pieces connect

The core utcp package defines Pydantic models for Tool, CallTemplate, UtcpManual and Auth, plus the UtcpClient that the application talks to. Plugins register the protocols. The README lists utcp-http for HTTP/REST, SSE, streaming and OpenAPI; utcp-cli for command-line tools; utcp-mcp for the Model Context Protocol; utcp-text for file-based tools; and utcp-websocket for bidirectional communication, all marked Stable. Two more, utcp-socket for TCP/UDP and utcp-gql for GraphQL, are marked In Progress in the same table, so treat them as not ready for production use.

Configuration is where the abstraction becomes concrete. UtcpClient is created with a UtcpClientConfig object, a dict, or a path to a JSON file. Inside that config you supply manual_call_templates: a list describing where tools come from. Each entry names a call_template_type, which selects the plugin, and carries the plugin's own fields. An HTTP entry has a url pointing at a UTCP manual; a CLI entry would describe a command-line source instead. The client resolves the manual, turns the described tools into Tool objects, and exposes them for calling.

Version 1.0.0 renamed this vocabulary. What used to be called a provider is now a call_template, provider_type is now call_template_type, and the http_stream type is now streamable_http. The old providers_file_path option is gone; you pass the list directly. If you are reading older tutorials or examples, that mismatch is the first thing that will break.

## Installing python-utcp and making a first tool call

Installation is two packages: the core library and the plugin for the protocol you need. The README's quick start installs utcp together with utcp-http, which it calls the most common combination, and notes that utcp-cli, utcp-mcp and utcp-text can be added as needed.

```bash
# Install core + HTTP plugin (most common)
pip install utcp utcp-http

# Install additional plugins as needed
pip install utcp-cli utcp-mcp utcp-text
```

With those installed, the README gives this client setup. The config dict contains one manual_call_template of type http, with a name and a url that serves the UTCP manual. The client is created asynchronously with await UtcpClient.create.

```python
from utcp.utcp_client import UtcpClient

# Create client with HTTP API
client = await UtcpClient.create(config={
    "manual_call_templates": [{
        "name": "my_api",
        "call_template_type": "http",
        "url": "https://api.example.com/utcp"
    }]
})

# Call a tool
result = await client.call_tool("my_api.get_data", {"id": "123"})
```

Two details matter here. The tool name is namespaced with the template name you chose, so my_api.get_data refers to get_data from the my_api template. And call_tool is awaited, which means your application needs an event loop; the README's example is async throughout. If you are following a tutorial written before 1.0.0, expect the import path to differ, since the migration guide moves HttpProvider from utcp.client.transport_interfaces.http_transport to utcp_http.http_call_template.

## Working from the repository: editable installs and the plugin tree

The README documents a development path for people who want to modify the library rather than consume it. After cloning the repository and changing into it, the core package installs in editable mode with its dev dependencies, and each plugin installs separately from its own directory.

```bash
# Clone the repository
git clone https://github.com/universal-tool-calling-protocol/python-utcp.git
cd python-utcp

# Install the core package in editable mode with dev dependencies
pip install -e "core[dev]"

# Install a specific protocol plugin in editable mode
pip install -e plugins/communication_protocols/http
```

The layout explains the packaging. Top-level entries are .github/, core/, docs/, plugins/ and scripts/, alongside LICENSE, README.md, CLAUDE.md and .gitignore. Each plugin carries its own README, and the root README links to them individually. That means documentation is distributed: the answer to a question about HTTP streaming lives in plugins/communication_protocols/http/README.md, not in the root file. The root README is a map, not a manual.

Last push to the repository was on 2026-09-06, and the repository is not archived. There are no retrieved releases, so the version history has to be inferred from the README's migration guide rather than from a changelog.

## Where python-utcp is the wrong choice

The plugin split is a cost as well as a benefit. If your agent calls exactly one REST API, you are installing two packages, learning the call_template schema and keeping a plugin version in step with the core, all to reach an endpoint that requests plus a JSON schema could have handled. The abstraction pays off at the second or third protocol, not the first.

Two of the listed plugins, utcp-socket and utcp-gql, are marked In Progress in the README's own table. Anyone whose backend speaks GraphQL or raw TCP should read that as: not yet. GraphQL itself is not exotic, which makes the gap more visible than the socket case.

There is also a documentation boundary worth naming. The README's migration section ends mid-sentence, at "Tool na", so the rule for how tools are named after the 1.0.0 change is not fully stated in the README. If your existing code depends on tool-name formatting, that is a question to resolve against the core README or the source before migrating. And because UTCP is a standard with its own manual format, the tools you expose must be described in that format; an API that already has an OpenAPI document is covered by the HTTP plugin, but an arbitrary internal service is not, and someone has to write the manual.

## UTCP against MCP: different layers, different trade-offs

The comparison the project invites is with the Model Context Protocol, and the README includes an image captioned MCP vs. UTCP. The practical difference is where the translation happens. MCP defines a protocol between an agent host and a server that exposes tools; the server is a process you run, and the agent speaks MCP to it. UTCP defines a manual format for describing tools and a client that can reach them over the protocol the tool already speaks.

That is why python-utcp ships an MCP plugin. Rather than positioning UTCP as a replacement, the plugin lets a UTCP client consume an MCP server as one more call template type alongside HTTP and CLI. If you already have MCP servers, you do not have to abandon them to use this client; if you have a mix of MCP servers and plain REST endpoints, the UTCP client is the layer that flattens them into one tool list.

The trade-off is maturity and ecosystem. MCP has broad tooling and many servers written for it. UTCP's ecosystem is the plugin list in this repository, and two entries there are unfinished. Choosing UTCP means choosing the client that can absorb MCP rather than the protocol with the larger installed base.

## Licence, upgrade cost and what 1.0.0 broke

The repository is licensed under MPL-2.0, a file-level copyleft licence. Modifications to files already covered by the licence stay under it; larger works that combine the library with other code are treated differently. That is a summary of the licence family, not legal advice, and anyone embedding the library in a distributed product should read the LICENSE file at the repository root.

The upgrade cost is documented, which is better than most. The 1.0.0 migration guide lists the breaking changes: new dependency names, the removal of providers_file_path, the provider to call_template rename, the http_stream to streamable_http rename, new import paths, and a new default search strategy called TagAndDescriptionWordMatchStrategy. That last item is the quiet one. If you had a custom search implementation, the guide says the new default requires no changes unless you were implementing your own strategy, which is exactly the case where you do have work to do.

Because there are no retrieved releases, there is no published cadence to plan around. The last push was on 2026-09-06, which is recent, but a single push date says nothing about how often breaking changes land. Pin your core and plugin versions together and read the migration guide before moving either.

## Conclusion

Adopt python-utcp when your agent has to reach several kinds of backend (an HTTP API, a CLI binary, an MCP server, local files) and you want one client interface instead of one adapter per service. Skip it if you only ever call one REST API: the core plus plugin split and the 1.0.0 rename of provider to call_template add configuration work you will not get back. Before committing, verify that the plugin for your protocol is listed as Stable rather than In Progress, and check the migration guide's section on tool naming, which the README truncates mid-sentence.

## FAQ

### What is UTCP?

UTCP is the Universal Tool Calling Protocol, an open standard for defining and interacting with tools across many communication protocols, so AI agents can call APIs without extra middleware. This repository is its official Python implementation, built around Pydantic models and a plugin per protocol.

### What is the alternative to MCP that python-utcp offers?

UTCP differs from MCP in where the translation happens: MCP defines a protocol between an agent and a tool server, while UTCP describes tools in a manual and lets the client reach them over the protocol they already speak. The project does not treat MCP as a rival, since it ships a utcp-mcp plugin that consumes MCP servers as one call template type.

### What are Python protocols in the context of python-utcp?

In this project a protocol is a communication type supported by a plugin, such as HTTP, CLI, MCP, text files or WebSocket. Each plugin registers its own call_template_type, and the core library stays unchanged when a new protocol is added.

## Sources

- [Issues](https://github.com/universal-tool-calling-protocol/python-utcp/issues)
- [License: MPL-2.0](https://github.com/universal-tool-calling-protocol/python-utcp/blob/main/LICENSE)
- [Project website](https://www.utcp.io/)
- [README](https://github.com/universal-tool-calling-protocol/python-utcp/blob/main/README.md)
- [universal-tool-calling-protocol/python-utcp on GitHub](https://github.com/universal-tool-calling-protocol/python-utcp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/universal-tool-calling-protocol-python-utcp
