MCP Server Custom Tools
The MCP Server Handler supports custom tools that allow you to create sophisticated MCP (Model Context Protocol) tools using code rather than simple 1:1 OpenAPI route mappings. This provides the flexibility to build complex workflows that can invoke multiple API routes, implement custom business logic, and provide rich responses to AI systems.
Custom tools give you full programmatic control over tool behavior within the MCP Server Handler. This is more flexible than automatic OpenAPI route transformation, allowing complex multi-step workflows and custom logic.
Key Features
- Programmatic Control: Define tools using TypeScript with full access to Zuplo's runtime
- Complex Workflows: Chain multiple API calls, implement business logic, and handle complex data transformations
- Type Safety: Built-in Zod schema validation for inputs and outputs
- Runtime Integration: Access to
context.invokeRoute()
, logging, and other Zuplo runtime features
Quick Start
1. Create Your Custom Tools Module
Create a module that defines your custom MCP tools:
Code
2. Configure the MCP Server Handler
Add the custom tools to your MCP Server Handler in routes.oas.json:
Code
3. Deploy and Test
Deploy your project and test your MCP server:
Code
SDK Reference
McpCustomToolsSDK
The main SDK class providing helper methods for creating tools and responses.
Methods
defineTool(config)
Define a tool with a configuration object.
Response Helpers:
textResponse(text: string)
- Create a text responsejsonResponse(data: any)
- Create a JSON response with structured contenterrorResponse(message: string)
- Create an error responseimageResponse(data: string, mimeType: string)
- Create an image responseresourceResponse(uri: string, mimeType?: string)
- Create a resource responsegetInvokeHeaders()
- Access original MCP request headers
Handler Configuration
The customTools
option in the MCP Server Handler expects:
- Default Export: Your module must export an array of
McpToolDefinition
as the default export - Tool Names: Must be unique across all tools (server won't build if names clash)
- Array Format: Tools must be exported as an array, not individual exports
Advanced Usage
Output Schema Validation
Starting with 2025-06-18
, MCP clients may support validating the output of
tool calls from servers based on a provided outputSchema
:
Code
Error Handling
For more ergonomic and AI friendly error handling, utilize the errorResponse
helper. This wraps the JSON RPC 2.0 for raising errors.
For example, the following tool will raise an error if the caller selects
shouldFail
:
Code
Multi-Step Workflow Tool
Using the ZuploContext invokeRoute
, you can create powerful aggregate
workflows that call multiple routes on your gateway. This works by re-invoking
routes on your gateway without having to go back out to HTTP.
context.invokeRoute
will utilize the full inbound and outbound policy
pipeline. This means that policies you set on your MCP server route will be
invoked alongside policies that are associated with any calls made through
invokeRoute
.
Code
Request Headers
You can access the original MCP request headers using the SDK and the
getInvokeHeaders
method. This is especially useful if a tool uses
context.invokeRoute
and headers need to be passed through to your downstream
request.
For example, this tool gets the original headers via getInvokeHeaders
and
returns the provided as an argument in headerName
.
Code
Testing Custom Tools
Using MCP Inspector
The MCP Inspector is ideal for testing custom tools:
Code
- Set Transport Type to "Streamable HTTP"
- Set URL to your MCP endpoint (e.g.,
https://your-gateway.zuplo.dev/mcp
) - Connect and test your tools interactively
Using cURL
Test individual tools directly:
Code
Best Practices
Input Validation
Use a well structured and defined Zod schema with the schema
param. This is
used by the server to validate MCP client inputs (i.e., JSON generated by an
LLM). Providing descriptive schemas ensures an MCP Client's LLM always has the
appropriate context on exactly what arguments to provide to tools and can
dramatically reduce invalid tool usage. This validation is done automatically.
The args
passed to your handler assume the type of the object inferred by
schema
.
Code
Tool Design
- Clear Names: Use descriptive, action-oriented names (
get_user_profile
,create_order
) - Detailed Descriptions: Help AI systems understand what your tool does
- Error Handling: Provide meaningful error messages
- Avoid Name Clashes: Ensure tool names are unique (server won't build otherwise)
Troubleshooting
Common Issues
Tool not appearing in tools/list
:
- Check tool name for duplicates (server won't build with name clashes)
- Verify tool is included in the default export array
- Check that the module exports an array as default export
- Check for validation errors in handler configuration or relevant logs
Server won't build:
- Check for tool name conflicts across all tools
- Verify the module has a proper default export of type
McpToolDefinition[]
- Check TypeScript compilation errors in your tools module
Schema validation errors:
- Ensure Zod schemas are properly defined and aligned with expected tool handler usage
- Check that handler arguments match schema types
- Verify output matches
outputSchema
if defined
Handler execution failures:
- Apply logs using
context.log.error()
,context.log.warn()
,context.log.info()
, etc. - Verify API routes being invoked through
invokeRoute
exist and are accessible - Test individual API calls outside the MCP context
Debugging Tips
- Enable Debug Logging: Use
context.log.debug()
liberally and turn on debug mode in your MCP server - Test Components Separately: Test API routes and business logic independently
- Use MCP Inspector: Interactive testing is invaluable for development
Learn More
- MCP Server Handler - For simple route-to-tool mapping
- Model Context Protocol Overview - Understanding MCP concepts
- MCP Specification - Official protocol documentation