Tools
Use
tool(name)to start defining a tool.Add a description and annotations for metadata and hints.
Specify the input type (must have a Circe
Codecand TapirSchema), or use.inputJson(schema)for a raw JSON Schema.Provide the server logic:
handle— synchronous logic from input toToolResult.handleWithHeaders— synchronous logic that also receives the request headers.serverLogic— effectful logic, with the request headers.
A tool that pushes to the client while running (progress, logging) instead uses
streamingServerLogic— see server capabilities.Assemble tools into an
McpServerand call.endpoint(path)to create a Tapir endpoint.
import chimp.server.*
import io.circe.Codec
import sttp.tapir.*
case class AddInput(a: Int, b: Int) derives Codec, Schema
val adder = tool("adder")
.description("Adds two numbers")
.withAnnotations(ToolAnnotations(idempotentHint = Some(true)))
.input[AddInput]
.handle(in => ToolResult.text(s"The result is ${in.a + in.b}"))
val endpoint = McpServer(tools = List(adder)).endpoint(List("mcp"))
A ToolResult can carry text, images, audio, embedded resources and structured output — see its constructors (text, image, audio, embedded, structured).