TypeScript API Reference
Installation
npm install protomcp zodImports
import { tool, ToolResult, toolManager, ToolContext, ServerLogger } from 'protomcp';import { z } from 'zod';tool(options)
Registers a tool and returns its ToolDef.
Options
| Field | Type | Required | Description |
|---|---|---|---|
description | string | Yes | Human-readable description |
args | z.ZodObject<any> | Yes | Zod schema for input arguments |
handler | (args, ctx: ToolContext) => any | Yes | Function to call when the tool is invoked |
name | string | No | Explicit tool name (defaults to handler function name) |
output | z.ZodObject<any> | No | Zod schema for structured output |
title | string | No | Display name shown in the MCP host UI |
destructiveHint | boolean | No | Hint: the tool has destructive side effects |
idempotentHint | boolean | No | Hint: calling the tool multiple times has the same effect as once |
readOnlyHint | boolean | No | Hint: the tool does not modify state |
openWorldHint | boolean | No | Hint: the tool may access resources outside the current context |
taskSupport | boolean | No | Hint: the tool supports long-running async task semantics |
hidden | boolean | No | If true, the tool is registered but hidden from the initial tool list |
Name inference
The tool name is derived from the handler function name. Arrow functions assigned to the handler property get the name "handler", which is ignored. To use a specific name, use a named function or pass name explicitly.
import { tool, ToolResult } from 'protomcp';import { z } from 'zod';
// Name inferred from function name: "multiply"tool({ description: 'Multiply two numbers', args: z.object({ a: z.number(), b: z.number() }), handler: function multiply({ a, b }) { return new ToolResult({ result: String(a * b) }); },});
// Name set explicitlytool({ name: 'my_tool', description: 'A tool', args: z.object({ input: z.string() }), handler({ input }) { return new ToolResult({ result: input }); },});Return value
Returns a ToolDef<T> object (also added to the global registry).
ToolResult
class ToolResult { result: string; // default: "" isError: boolean; // default: false enableTools?: string[]; disableTools?: string[]; errorCode?: string; message?: string; suggestion?: string; retryable: boolean; // default: false
constructor(options?: ToolResultOptions);}ToolResultOptions
| Field | Type | Default | Description |
|---|---|---|---|
result | string | "" | Result string returned to the MCP host |
isError | boolean | false | Set to true to indicate an error |
enableTools | string[] | — | Tools to enable after this call |
disableTools | string[] | — | Tools to disable after this call |
errorCode | string | — | Machine-readable error code |
message | string | — | Human-readable error message |
suggestion | string | — | Recovery suggestion |
retryable | boolean | false | Whether retrying might succeed |
// Successnew ToolResult({ result: 'done' })
// Errornew ToolResult({ isError: true, errorCode: 'NOT_FOUND', message: 'File not found', suggestion: 'Check the path', retryable: false,})
// Enable tools after callnew ToolResult({ result: 'Authenticated', enableTools: ['write_file', 'delete_file'],})ToolContext
Injected by protomcp as the second argument to tool handlers. Provides progress reporting and cancellation detection.
import { ToolContext } from 'protomcp';Constructor
new ToolContext(progressToken: string, sendFn: (msg: any) => void)Not constructed directly — protomcp creates and injects it.
Methods
reportProgress(progress, total?, message?)
Send a progress notification to the MCP host.
| Parameter | Type | Description |
|---|---|---|
progress | number | Current progress value |
total | number (optional) | Total expected value |
message | string (optional) | Human-readable status message |
No-op if the host did not supply a progressToken for this call.
ctx.reportProgress(50, 100, 'Halfway done');isCancelled() -> boolean
Returns true if the MCP host has sent a cancellation for this call.
if (ctx.isCancelled()) { return new ToolResult({ isError: true, message: 'Cancelled' });}ServerLogger
Sends structured log messages to the MCP host over the protomcp protocol.
import { ServerLogger } from 'protomcp';Constructor
new ServerLogger(sendFn: (msg: any) => void, name?: string)Not constructed directly — protomcp creates and injects it. The optional name field identifies the logger source in log messages.
Methods
All log methods accept a message string and an optional data object:
method(msg: string, data?: Record<string, unknown>): voiddata is serialized to JSON and included in the log envelope. If data is omitted, the message string is used as the payload.
| Method | MCP log level |
|---|---|
debug(msg, data?) | debug |
info(msg, data?) | info |
notice(msg, data?) | notice |
warning(msg, data?) | warning |
error(msg, data?) | error |
critical(msg, data?) | critical |
alert(msg, data?) | alert |
emergency(msg, data?) | emergency |
logger.info('Starting job', { jobId: 'abc123' });logger.error('Job failed', { error: 'timeout' });toolManager
Singleton instance for programmatic tool list control. All methods are async and return Promise<string[]> — the updated list of active tool names.
import { toolManager } from 'protomcp';toolManager.enable(toolNames)
const active: string[] = await toolManager.enable(['write_file', 'delete_file']);toolManager.disable(toolNames)
const active: string[] = await toolManager.disable(['write_file', 'delete_file']);toolManager.setAllowed(toolNames)
Switch to allowlist mode. Only the specified tools are active.
const active: string[] = await toolManager.setAllowed(['read_file', 'search']);toolManager.setBlocked(toolNames)
Switch to blocklist mode. All tools except the specified ones are active.
const active: string[] = await toolManager.setBlocked(['delete_database']);toolManager.getActiveTools()
const active: string[] = await toolManager.getActiveTools();toolManager.batch(options)
const active: string[] = await toolManager.batch({ enable: ['write_file'], disable: ['read_only_mode'], allow: [], block: [],});BatchOptions:
| Field | Type | Description |
|---|---|---|
enable | string[] | Tool names to enable |
disable | string[] | Tool names to disable |
allow | string[] | Set allowlist |
block | string[] | Set blocklist |
All fields are optional.
Internal API (for testing)
getRegisteredTools()
Returns a shallow copy of the current tool registry.
import { getRegisteredTools } from 'protomcp';
const tools = getRegisteredTools(); // ToolDef[]clearRegistry()
Clears the tool registry. Use in test beforeEach to avoid cross-test contamination.
import { clearRegistry } from 'protomcp';
beforeEach(() => clearRegistry());ToolDef<T>
interface ToolDef<T extends z.ZodType = z.ZodType> { name: string; description: string; inputSchemaJson: string; // JSON string outputSchemaJson: string; // JSON string, empty if no output schema title: string; destructiveHint: boolean; idempotentHint: boolean; readOnlyHint: boolean; openWorldHint: boolean; taskSupport: boolean; hidden?: boolean; handler: (args: z.infer<T>, ctx: ToolContext) => any;}