Skip to content

TypeScript API Reference

Installation

Terminal window
npm install protomcp zod

Imports

import { tool, ToolResult, toolManager, ToolContext, ServerLogger } from 'protomcp';
import { z } from 'zod';

tool(options)

Registers a tool and returns its ToolDef.

Options

FieldTypeRequiredDescription
descriptionstringYesHuman-readable description
argsz.ZodObject<any>YesZod schema for input arguments
handler(args, ctx: ToolContext) => anyYesFunction to call when the tool is invoked
namestringNoExplicit tool name (defaults to handler function name)
outputz.ZodObject<any>NoZod schema for structured output
titlestringNoDisplay name shown in the MCP host UI
destructiveHintbooleanNoHint: the tool has destructive side effects
idempotentHintbooleanNoHint: calling the tool multiple times has the same effect as once
readOnlyHintbooleanNoHint: the tool does not modify state
openWorldHintbooleanNoHint: the tool may access resources outside the current context
taskSupportbooleanNoHint: the tool supports long-running async task semantics
hiddenbooleanNoIf 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 explicitly
tool({
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

FieldTypeDefaultDescription
resultstring""Result string returned to the MCP host
isErrorbooleanfalseSet to true to indicate an error
enableToolsstring[]Tools to enable after this call
disableToolsstring[]Tools to disable after this call
errorCodestringMachine-readable error code
messagestringHuman-readable error message
suggestionstringRecovery suggestion
retryablebooleanfalseWhether retrying might succeed
// Success
new ToolResult({ result: 'done' })
// Error
new ToolResult({
isError: true,
errorCode: 'NOT_FOUND',
message: 'File not found',
suggestion: 'Check the path',
retryable: false,
})
// Enable tools after call
new 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.

ParameterTypeDescription
progressnumberCurrent progress value
totalnumber (optional)Total expected value
messagestring (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>): void

data is serialized to JSON and included in the log envelope. If data is omitted, the message string is used as the payload.

MethodMCP 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:

FieldTypeDescription
enablestring[]Tool names to enable
disablestring[]Tool names to disable
allowstring[]Set allowlist
blockstring[]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;
}