agent-surface
Typed Python operations that become HATEOAS CLI and MCP surfaces—so people and agents can discover and take the next valid action without guessing commands, routes, or object encodings.
Define an operation once with Pydantic; project it as a YAML-first Click CLI and native MCP tools
with bounded, concrete next_actions.
Get up and running in 5 seconds
Install the general-purpose agent-friendly-cli-design for building HATEOAS CLI tools, generally, and the agent-surface-authoring for building with this agent-surface project, specifically:
curl -fsSL https://raw.githubusercontent.com/allenday/agent-surface/main/src/agent_surface/skills/install.sh | sh
Then tell your agent to load the agent-surface-authoring to get started building a HATEOAS CLI or MCP tool.
Followup: Read the skill files directly.
In 30 more seconds
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 it and run the command:
pip install 'agent-surface[mcp]'
python hello.py people greet --name Ada
The same typed operation is now callable from Python, exposed through Click, and available as the
exact MCP tool people.greet.
Use it from MCP
For a local client, use stdio: the client starts hello.py --mcp and exchanges MCP messages
over its standard input and output.
Add this to ~/.codex/config.toml, replacing both absolute paths with yours. 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 for serving MCP remotely from a web application; it is not needed for this local setup. See the MCP contract when you need that deployment.
Why HATEOAS matters here
HATEOAS—Hypermedia as the Engine of Application State—means a response advertises the concrete transitions valid from its current state. A caller follows them; it does not reconstruct a command tree from memory.
For example, in the bookstore tutorial tutorial, a call like:
./examples/bookstore books search --query dune --limit 2
produces output like:
result:
items: [{ref: {value: book_dune}, title: Dune}]
next_actions:
items:
- rel: inspect
command: [./examples/bookstore, books, inspect, --book, book_dune]
operation: books.inspect
bound: {book: book_dune}
total: 1
returned: 1
truncated: false
For Click, follow command. For MCP, call operation with bound. The complete executable
search → inspect → reserve → cancel → delete trajectory is in the
bookstore tutorial.
Choose your path
- Evaluate the idea. Read HATEOAS and bounded discovery, then run the bookstore example.
- Adopt it in an application. Start with the Python API and the existing-application guide, then add references and actions when your domain needs them.
- Connect an agent. Follow the bookstore MCP integration, MCP contract, and CLI contract.
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
For contribution and release details, see CONTRIBUTING.md and the release guide.
License
MIT
Metadata
Release files for agent-surface 0.1.3
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.3.tar.gz | 169.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_surface-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 212.9 kB
Release files / agent_surface-0.1.3.tar.gz
| Download URL | agent_surface-0.1.3.tar.gz |
|---|---|
| Size | 169.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0e757f4f0f9dbc19468d991a48e6529ac6c1c0d4bd5b78defde6e67a1b2960bc
|
|
BLAKE2b-256 checksum How to use checksums |
2d23446d628ea82ef15d120e4593dc931a54eadc73b289895888035943c97233
|
| 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 Aug 21, 2026.
Transparency logRelease files / agent_surface-0.1.3-py3-none-any.whl
| Download URL | agent_surface-0.1.3-py3-none-any.whl |
|---|---|
| Size | 43.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dfa4f7c19699bc21982fa640578b4d808a9ef9b44640793ade28b2f29d05fcd3
|
|
BLAKE2b-256 checksum How to use checksums |
4187e6082dd43657f2969d2639e50772ce21557d9e7f6d881be1f78aeddd52ed
|
| 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 Aug 21, 2026.
Transparency log