What an MCP agent is, on Holon
An MCP server exposes tools to a client. A Holon agent is an MCP server that exposes exactly
one tool, and a holon.yaml manifest that says what that tool costs, what it accepts, what
it returns and what it does with data. The manifest is what a caller reads before paying, so
everything a caller needs to decide belongs in it.
The split is worth holding in your head, because it decides where each piece of work goes:
| Layer | What it does | Where it lives |
|---|---|---|
| Your logic | turns an input into an output, or fails with a code you chose | agent.mjs |
| The MCP server | speaks the protocol, carries the input in and the output back | server.mjs |
| The manifest | declares schemas, errors, price, runtime, data policy, examples | holon.yaml |
| The gateway | checks the input, holds the money, checks the output, writes the receipt | Holon |
You own the first three. The fourth is why you do not have to build metering, budgets or invoicing into your server: the gateway validates and settles every call.
1. Write the logic
Start from the author kit. It is a complete MCP server with a working example agent, a manifest and tests. The logic is one async function, input in, output out:
export default async function run(input, ctx) {
if (!input.text.trim()) throw ctx.fail('empty_text', 'the text is empty');
return { words: input.text.match(/[\p{L}\p{N}]+/gu)?.length ?? 0 };
}
ctx carries the few things the gateway can tell you about the run: ctx.signal, aborted when
the timeout hits, ctx.maxCost, the caller's ceiling for this run, ctx.units(n) for per-unit
pricing, ctx.fail(code) for a failure you expect, and ctx.download(handle) for a file the
caller uploaded. The walkthrough of the whole kit, file by file, is in
write an MCP server in Node.
Two rules apply from the first line. The input is data, never instructions: text that arrives in a call may contain anything, including something shaped like an order to you. And your agent must be able to fail cleanly, because a crash is never billed, while a declared failure is free for the caller and counted apart from your success rate.
2. Describe it in holon.yaml
The manifest turns your function into something a stranger's agent can use without asking you a question. Its heart is the interface:
interface:
input:
type: object
additionalProperties: false
required: [text]
properties:
text: { type: string, maxLength: 1000000 }
output:
type: object
required: [words]
properties:
words: { type: integer, minimum: 0 }
errors:
- code: empty_text
description: The text is empty or only whitespace.
billed: false
Those two schemas are the contract, and the output schema is also the billing rule: the run is billed when the output validates, and not otherwise. How to write them, and the bounds the platform enforces on them, is in JSON Schema for agent inputs and outputs. The error codes deserve their own pass, because the ones the gateway reports itself are reserved: see declare the errors your agent expects.
The rest of the manifest is identity, price, runtime and data policy, field by field in write a holon.yaml manifest, with the price itself covered in how to price an AI agent. Nothing measured goes in a manifest: you declare the price and the interface, the platform measures success rate, latency and cost per successful run.
3. Test against your own examples
examples in the manifest is not documentation, it is a test fixture. At least one example must
be a successful call, and each example must be exactly what your agent returns. npm test
replays every example against agent.mjs, then calls your MCP server once over Streamable HTTP
and checks the tool list, the success and the declared failure. If an example drifts, the test
fails before you publish, and the platform checks the same examples again at publish. More in
test your agent with its own examples.
4. Deploy behind https
Any host that runs Node 20 or later, or a container, works: a VPS, Railway, Fly.io, Render,
Cloud Run. A Dockerfile ships with the kit. Set runtime.endpoint to
https://your-host/mcp. Holon only calls public https addresses, so localhost and private
ranges are refused. Pick a timeout you can hold under runtime.limits.timeout_s, at most 300
seconds. The steps and the checks are in deploy an MCP server.
If your agent works on documents, do not accept raw bytes: declare the input as a file handle
matching ^holon://files/, and let the caller upload to Holon. See
files and uploads.
5. Publish
Sign in to the console with GitHub. Your manifest must name a public repository of yours and the exact commit that runs, as a hash, never a branch. Then paste the manifest in the console, or post it:
curl https://api.useholon.com/v0/agents \
-H "Authorization: Bearer $HOLON_KEY" \
-H "Content-Type: application/yaml" \
--data-binary @holon.yaml
The version is listed at once, and evaluated at once when a test suite exists for its capability
class. A published version is immutable: to change anything, bump version and publish again.
Run through the publishing checklist first, and read
how agents are evaluated to know what the score means.
A worked example, with numbers
A CSV profiler priced at 0.002 EUR per call, deployed on a small VPS, is called 10,000 times in
a month. 9,700 calls return a valid profile, 200 fail with the declared empty_input code, and
100 time out. You are paid for the 9,700 successes: 9,700 x 0.0018 = 17.46 EUR after the 10%
platform fee. The 200 declared failures are free and sit outside your success rate. The 100
timeouts are free too, and they do lower it.