One capability, many hosts
The directory API is a handful of Endpoints bound once. JVM, Node, and Native run that bind.
HTTP, OpenAPI, MCP Streamable HTTP, and stdio are hosts of that bind. JVM, Node, and Native run the same Server.install. They are not three implementations. CLI is the same OpArgs shape, not shipped yet.
getShow
Endpoint + In => ZIO[R, E, Out]. Written once.
Same OpArgs. Not shipped. The AST is already this shape.
GET /shows/1 HTTP/1.1
HTTP/1.1 200 OK
content-type: application/json
{"id":1,"name":"Evening bill"}Hosts are interpreters. Do not grow a second tool DSL.
Write the capability once
getUser is an Endpoint. .mcp promotes it as a tool. Api.bind is the function agents and
HTTP both run.
HTTP
api.routes is Routes. A GET is an ordinary Request. Humans hit this from a browser or
Swagger. Systems hit it from Client. The same Server.install runs that Routes on JVM,
Node, and Native. Do not grow a second Scala.js Api.
MCP Streamable HTTP
Mcp.from(api) speaks JSON-RPC on POST /mcp. Native is 2026-07-28 (server/discover).
The same endpoint answers 2025-11-25 initialize so older hosts can list and call.
tools/list is the promoted set. tools/call with get_show runs the same function as
GET /shows/1.
stdio
mcp.stdio() is the same engine on a pipe: one JSON-RPC line in, one line out. Native lines
carry _meta; a 2025 host may send initialize first. Local agent runtimes spawn
sbt "example/run -- --mcp-stdio" (or a published main) and speak that framing.
Toggle the host
The same get-user operation as HTTP, OpenAPI, tools/call, and a stdio line. Payloads match the
examples above.
GET /shows/1 HTTP/1.1
HTTP/1.1 200 OK
content-type: application/json
{"id":1,"name":"Evening bill"}HTTP, OpenAPI, MCP, and stdio are hosts. They are not copies.