Skip to main content

agent-surface

CI PyPI License: MIT

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.

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.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agent-surface 0.2.2
File Size Uploaded
agent_surface-0.2.2.tar.gz 204.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agent-surface 0.2.2
File Interpreter ABI Platform
agent_surface-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 263.8 kB

Release files / agent_surface-0.2.2.tar.gz

Download URL agent_surface-0.2.2.tar.gz
Size 204.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f48085ae76fe2676f52fc7dbafa022dc992f006a5a909b1f52397b0a15b6430f
BLAKE2b-256 checksum
How to use checksums
0a3443d193f414cd4890c29a835f6fddeabd75fabceac7a715243d1a73250f7d
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 4, 2026.

Transparency log

Release files / agent_surface-0.2.2-py3-none-any.whl

Download URL agent_surface-0.2.2-py3-none-any.whl
Size 58.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c8394df7b77581fd7416f4a0b5d1007b7ba5fc5e3378b6bc11b38e191f14546b
BLAKE2b-256 checksum
How to use checksums
f6280cb67eb9f214072a62044d752576c18a03212cae9676fd975a5e727d817c
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 4, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.3

2 release files

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page