The AST
The compiler is small on purpose.
| Value | Role |
|---|---|
Schema / SchemaDoc | Domain shape every host can read |
Endpoint / EndpointDoc | One operation, still unbound |
BoundOp | Endpoint + In => ZIO[R, E, Out] |
Api | Named collection of bound ops |
OpArgs | Flatten path, query, JSON body into one argument object |
Interpreters fold that AST:
| Interpreter | Output |
|---|---|
api.routes | HTTP |
api.openApi | OpenAPI 3.1 + Swagger UI |
Mcp.from(api) | MCP tools (promoted) + optional catalog |
| CLI (later) | argv / subcommands via OpArgs |
EndpointDoc · click a field
GET/shows/{id}.mcpReadOnly
read by
HTTP, OpenAPI, derived tool name
OpArgs is why MCP (and CLI) can share HTTP
OpArgs.promotable is the tool rule: JSON in, JSON out, and no response header. An endpoint may
use any BodyCodec. Path params and query strings flatten into the same JSON object a tool call
(or a future CLI) already knows how to pass. A request header does not: it stays on the HTTP
request. A response header is part of that HTTP output, so an endpoint that declares one stays off
the tool list even when its body is JSON. HTML, text, form, bytes, and event streams stay on HTTP
too. Do not smash them into tools.
OpArgs.promotable(BoxOffice.getShow.doc)trueOpArgs.inputSchema(BoxOffice.getShow.doc).map(_.jsonSchema.toString).exists(_.contains("id"))true{
val tagged = Endpoint.get("item").out[String].outHeader[EntityTag]
(OpArgs.promotable(tagged.doc), tagged.doc.successHeader)
}(false,Some(ETag))Click through EndpointDoc
Each field names its readers. Click one. That is the AST, not a metaphor.