MCP in action

Every method is also a tool for AI agents. Any framework that speaks MCP gets all of amoorion this way: Claude, CrewAI, Google’s ADK, LangChain, nanobot and others. Tools that only read are marked, so clients may let them run and ask before the rest.

from amoorion import Amoorion

# The same methods as tools for agents; started as `amoorion mcp`.
server = Amoorion().mcp()

# What an agent sees on connecting.
tools = await server.list_tools()

# Read-only ones an agent may use freely; the others deserve a confirmation.
for tool in tools[:6]:
    print(f"{tool.name:10} read-only={tool.annotations.read_only_hint}")
accounts   read-only=True
compose    read-only=False
delete     read-only=False
inbox      read-only=True
notify     read-only=False
plugins    read-only=True

What an agent sees for one tool:

# A tool's parameters, generated from the method's `Params`.
next(tool for tool in tools if tool.name == "search").input_schema[
    "properties"
].keys()
dict_keys(['text', 'platform', 'limit'])

A client’s configuration:

{"mcpServers": {"amoorion": {"command": "uv", "args": ["run", "amoorion", "mcp"]}}}

Publishing reaches real accounts, so keep the asking on for tools that change things.

Tools and resources of your own

Amoorion’s server is the official MCPServer, named and versioned, so tools and resources are added the way the MCP documentation shows. Its own tools come from the methods; these are next to them.

server = Amoorion().use("dryrun").mcp()

print(server.name)


@server.tool()
def add(
    a: int,
    b: int,
) -> int:
    """Add two numbers."""

    return a + b


@server.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""

    return f"Hello, {name}!"
amoorion

A client, as a member of the simulated party would be

Client takes the server itself, in memory, or a URL such as http://localhost:8000/mcp.

from mcp import Client

async with Client(server) as client:
    # A tool of ours.
    answer = await client.call_tool(
        "add",
        {
            "a": 1,
            "b": 2,
        },
    )

    print(answer.structured_content)

    # A resource of ours.
    print((await client.read_resource("greeting://party")).contents[0].text)

    # What every amoorion server has by itself.
    print(
        (await client.read_resource("amoorion://methods"))
        .contents[0]
        .text[:80],
        "…",
    )

    # And the methods, as tools.
    done = await client.call_tool(
        "publish",
        {
            "text": "hello from a member",
            "to": ["dryrun"],
        },
    )

    print(done.is_error)

    print(
        (await client.read_resource("amoorion://inbox/5"))
        .contents[0]
        .text[:80],
        "…",
    )
{'result': 3}
Hello, party!
[{"name": "accounts", "description": "Which platforms have their secrets in the  …
False
[] …