agent-surface
Typed Python operations that become HATEOAS CLI and MCP surfaces. A response tells a person or agent the next valid thing to do, so callers follow concrete actions instead of guessing commands, routes, or object encodings.
Define an operation once with Pydantic. agent-surface projects it as a YAML-first Click CLI and
native MCP tools with bounded, concrete next_actions.
See a HATEOAS trajectory
From a checkout of this repository, run the bookstore example:
uv sync --frozen --all-extras --dev
./examples/bookstore books search --query dune --limit 2
The relevant fields from its YAML envelope show the first page and its concrete next actions:
result:
query: dune
items:
- ref: {value: book_dune}
title: Dune
author: Frank Herbert
- ref: {value: book_dune_messiah}
title: Dune Messiah
author: Frank Herbert
total: 3
returned: 2
truncated: true
next_cursor: book_dune_messiah
next_actions:
items:
- rel: inspect
description: Inspect the first returned book
command: [./examples/bookstore, books, inspect, --book, book_dune]
operation: books.inspect
bound: {book: book_dune}
slots: {}
- rel: next-page
description: Continue this search
command: [./examples/bookstore, books, search, --query, dune, --cursor, book_dune_messiah, --limit, '2']
operation: books.search
bound: {query: dune, cursor: book_dune_messiah, limit: 2}
slots: {}
total: 2
returned: 2
truncated: false
Follow the advertised CLI command verbatim:
./examples/bookstore books inspect --book book_dune
For MCP, call operation: books.inspect with bound: {book: book_dune} instead. The complete
search → inspect → reserve → cancel → delete trajectory is executable in the
bookstore tutorial.
Use the library now
Save this as hello.py:
import asyncio
import sys
from pydantic import BaseModel
from agent_surface import App
from agent_surface.adapters.click import build_click_group
from agent_surface.adapters.mcp import MCPAdapter
class GreetRequest(BaseModel):
name: str
class Greeting(BaseModel):
message: str
app = App("hello")
@app.operation("people.greet", summary="Greet one person", read_only=True)
def greet(request: GreetRequest) -> Greeting:
return Greeting(message=f"Hello, {request.name}!")
cli = build_click_group(app)
mcp = MCPAdapter(app)
if __name__ == "__main__":
if sys.argv[1:] == ["--mcp"]:
asyncio.run(mcp.run_stdio())
else:
cli()
Install the package into your existing Python environment and run the CLI:
pip install 'agent-surface[mcp]'
python hello.py people greet --name Ada
The same typed operation is callable from Python, exposed through Click, and available as the exact
MCP tool people.greet.
Connect it to MCP
For a local client, use stdio: the client starts hello.py --mcp and exchanges MCP messages
over standard input and output. Add this to ~/.codex/config.toml, replacing both absolute paths.
python must be the interpreter where you installed agent-surface:
[mcp_servers.hello]
command = "/absolute/path/to/.venv/bin/python"
args = ["/absolute/path/to/hello.py", "--mcp"]
Restart Codex, then use /mcp to inspect hello. For Claude Code, save the equivalent
project-local .mcp.json next to hello.py:
{
"mcpServers": {
"hello": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["/absolute/path/to/hello.py", "--mcp"]
}
}
}
Streamable HTTP is only for serving MCP remotely from a web application. See the MCP contract when you need that deployment.
Author a new surface
Install the optional authoring skills for an agent that will build a HATEOAS CLI or MCP tool:
curl -fsSL https://raw.githubusercontent.com/allenday/agent-surface/main/src/agent_surface/skills/install.sh | sh
The agent-surface-authoring skill first checks how the current project manages Python before it
uses the library; it does not choose a virtual environment or install packages globally. You can
also read the skills directly:
Go deeper when needed
Start with the documentation map if you are unsure which path fits.
- Evaluate the approach. Read HATEOAS and bounded discovery, then run the bookstore example.
- Adopt it in an application. Start with the Python API and existing-application guide, then add references and actions.
- Connect an agent. Follow the bookstore MCP integration, MCP contract, and CLI contract.
- Contribute or release. Read CONTRIBUTING.md and the release guide.
Principles
- one typed operation registry; sibling Python, Click, and MCP adapters
- YAML-first structured output with compact flow style for small values
- bounded HATEOAS
next_actions, stable references, and explicit confirmation for writes - predictable discovery and repair-oriented errors
License
MIT
Metadata
Release files for agent-surface 0.1.12
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_surface-0.1.12.tar.gz | 195.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_surface-0.1.12-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 249.8 kB
Release files / agent_surface-0.1.12.tar.gz
| Download URL | agent_surface-0.1.12.tar.gz |
|---|---|
| Size | 195.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a02432d6eabf817dd660e106992a44ab9afbf60b3e37c2ec9498dc25f6c6e18f
|
|
BLAKE2b-256 checksum How to use checksums |
7122368e5780371d9c6cc16113d68b8ad2cf875cdbda07176a955183a2549144
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / agent_surface-0.1.12-py3-none-any.whl
| Download URL | agent_surface-0.1.12-py3-none-any.whl |
|---|---|
| Size | 54.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
714960ea5daaa2469987c50692376cf4e845797cb826100bc00f54d73c863d3b
|
|
BLAKE2b-256 checksum How to use checksums |
39583d50c2c46065effda279e54eefe1450e8c87fba8a8248c674bc774a534a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency log