Skip to main content
Scripts extend tool behavior beyond what configuration can express. A handler script replaces database execution entirely. Transform scripts modify inputs before execution and results after. All three are TypeScript, bundled at compile time, and executed inside an embedded sandboxed runtime with no external dependencies.

Script hooks

There are three hooks, each corresponding to a stage in the execution pipeline:
HookDefault exportPurpose
Handlerexport default (...)Replaces DB execution entirely
Input transformexport default (...)Pre-process arguments before execution
Output transformexport default (...)Post-process results before returning

Selecting exported functions

For all script references, you can target a non-default export with #:
handler: "./weather-handler.ts#weather"
mappers:
  input: "./input.ts#normalize"
  output: "./output.ts#shape"
Without #exportName, Hyperterse calls the script’s export default function.
The function name itself is optional and ignored by the runtime.

Handler

A handler replaces adapter-based execution. When handler is configured, no use or statement is needed. The return value becomes the tool’s result payload.
export default function handler(payload: {
  inputs: Record<string, any>
  tool: string
}) {
  const { inputs } = payload
  return {
    location: inputs.city || 'unknown',
    temperature_c: 22.5,
    conditions: 'partly cloudy',
  }
}

Input transform

An input transform pre-processes arguments before they reach the executor or handler. Use it for validation, normalization, or rejection. The returned object replaces the original inputs for all subsequent pipeline stages. Throwing an error aborts execution.
export default function inputTransform(payload: {
  inputs: Record<string, any>
  tool: string
}) {
  if (
    typeof payload.inputs.user_id !== 'number' ||
    payload.inputs.user_id <= 0
  ) {
    throw new Error('user_id must be a positive integer')
  }
  return { ...payload.inputs, user_id: Math.floor(payload.inputs.user_id) }
}

Output transform

An output transform post-processes results before they are returned. Use it for field mapping, formatting, or redaction.
export default function outputTransform(payload: { results: any[]; tool: string }) {
  return payload.results.map((row) => ({
    id: row.id,
    name: row.name,
    created_at_iso: new Date(row.created_at).toISOString(),
  }))
}

Runtime APIs

Scripts execute in a sandboxed runtime with two injected globals:
  • fetch(url, options?) — HTTP client for outbound requests. Returns { status, ok, text(), json() }.
  • consolelog, error, warn, info, debug — all wired to the framework’s structured logger with the tool name as context.
Scripts cannot access the host filesystem, spawn processes, or open network sockets. setTimeout and setInterval are not available — use async/await instead.

Convention discovery

When script paths are omitted in tool config, Hyperterse auto-discovers script files from the tool directory. Convention names include:
  • handler.ts
  • input.ts (or *input*validator*.ts)
  • output.ts (or *data*mapper*.ts)

npm packages

If your scripts import external packages, add a package.json at the project root. The build process packages dependencies with your scripts, so deployment does not require node_modules/.
import dayjs from 'dayjs'
import { v4 as uuidv4 } from 'uuid'

Error handling

Errors thrown from scripts propagate as MCP error responses. The error message is included in the response; stack traces are logged at debug level but not exposed to callers.

Further reading

See Execution pipeline for how scripts fit into the request lifecycle, and Tool configuration reference for handler and mappers configuration.