Skip to main content

Basic Tool

import { z } from "zod"
import { tool, serve } from "@reminix/runtime"

const getWeather = tool("get-weather", {
  description: "Get current weather for a city",
  inputSchema: z.object({
    location: z.string().describe("City name"),
    units: z.enum(["celsius", "fahrenheit"]).describe("Temperature units").optional(),
  }),
  handler: async ({ location, units }) => {
    return { temperature: 72, condition: "sunny", location }
  },
})

serve({ tools: [getWeather] })
When deployed, your tools are automatically served via MCP and discoverable by any MCP-compatible client.

tool() Options

description
string
required
Tool description. Shown in MCP discovery and used by AI models to understand when to call the tool.
inputSchema
ZodType | JSONSchema
required
Zod schema (recommended) or JSON Schema defining the tool’s input parameters. Zod schemas provide typed handlers and automatic runtime validation.
outputSchema
ZodType | JSONSchema
Zod schema or JSON Schema defining the tool’s output. Optional but recommended for documentation.
tags
string[]
Tags for filtering and organizing tools.
metadata
Record<string, unknown>
Additional metadata attached to the tool.
handler
function
required
The tool’s handler function. Receives (args, context?) and returns the tool’s output. When using Zod, args is fully typed.

Input Schema

Define input parameters with Zod. Required fields, types, descriptions, and defaults are all supported.
import { z } from "zod"

const searchDocs = tool("search-docs", {
  description: "Search the document index",
  inputSchema: z.object({
    query: z.string().describe("Search query"),
    maxResults: z.number().default(10).describe("Max results to return"),
    filters: z.object({
      category: z.string().optional(),
      dateRange: z.string().optional(),
    }).optional().describe("Optional filters"),
  }),
  handler: async ({ query, maxResults, filters }) => {
    return [{ title: "Result 1", score: 0.95 }]
  },
})

Output Schema

Optional but recommended. Defines the shape of the tool’s return value for documentation and validation.
import { z } from "zod"

const getWeather = tool("get-weather", {
  description: "Get weather",
  inputSchema: z.object({
    location: z.string(),
  }),
  outputSchema: z.object({
    temperature: z.number(),
    condition: z.string(),
  }),
  handler: async ({ location }) => {
    return { temperature: 72, condition: "sunny" }
  },
})

Context Parameter

Tools can receive execution context as the second argument, providing access to the caller’s identity and metadata.
import { z } from "zod"

const myTool = tool("my-tool", {
  description: "Tool with context",
  inputSchema: z.object({
    query: z.string(),
  }),
  handler: async ({ query }, context?) => {
    const identity = context?.identity
    return { result: query, user: identity }
  },
})

Serving Tools with Agents

Tools and agents can be served together from the same server. Agents get REST endpoints while tools are served via MCP.
import { z } from "zod"
import { agent, tool, serve } from "@reminix/runtime"

const bot = agent("bot", {
  type: "chat",
  handler: async (input) => "Hello!",
})

const search = tool("search", {
  description: "Search for information",
  inputSchema: z.object({ query: z.string() }),
  handler: async ({ query }) => [{ result: query }],
})

serve({ agents: [bot], tools: [search] })

MCP compatibility

When deployed, your tools are automatically served via the Model Context Protocol (MCP). Any MCP-compatible client — including Claude Desktop, custom MCP clients, and other Reminix agents — can discover and call your tools.
MCP is an open standard for connecting AI models to tools and data sources. Your Reminix tools work with any client that speaks MCP.

Next steps

Tools (concept)

How tools become MCP servers and how clients discover them.

Connecting MCP clients

Add your tools to Claude Desktop, Cursor, and Windsurf.

Creating Agents

Define agents that call your tools internally.

Deploying

Ship your tools to production.