/**
* Example tool implementations
*
* These demonstrate the patterns for building MCP tools.
* Remove or replace with your own tools.
*/
import { z } from 'zod';
import { ToolRegistry } from './registry.js';
import { createLogger } from '../shared/logger.js';
import { cacheGet, cacheSet, cacheStats, makeCacheKey } from '../db/index.js';
import { getConfig } from '../config/index.js';
import type { ToolResult } from '../types/index.js';
const logger = createLogger('tools/examples');
/**
* Echo tool input schema
*/
const EchoInputSchema = z.object({
message: z.string().min(1).describe('The message to echo back'),
uppercase: z.boolean().optional().describe('Convert to uppercase'),
});
type EchoInput = z.infer<typeof EchoInputSchema>;
/**
* Echo tool - demonstrates basic tool pattern
*/
async function echoHandler(input: EchoInput): Promise<ToolResult<{ echoed: string }>> {
logger.debug('Echo called', { message: input.message });
const echoed = input.uppercase === true ? input.message.toUpperCase() : input.message;
return {
success: true,
data: { echoed },
};
}
/**
* Add numbers tool input schema
*/
const AddNumbersInputSchema = z.object({
a: z.number().describe('First number'),
b: z.number().describe('Second number'),
});
type AddNumbersInput = z.infer<typeof AddNumbersInputSchema>;
/**
* Add numbers tool - demonstrates number handling
*/
async function addNumbersHandler(input: AddNumbersInput): Promise<ToolResult<{ result: number }>> {
logger.debug('Add called', { a: input.a, b: input.b });
return {
success: true,
data: { result: input.a + input.b },
};
}
/**
* Cached fetch tool input schema
*/
const CachedDataInputSchema = z.object({
key: z.string().min(1).describe('Key to fetch or store'),
value: z.string().optional().describe('Value to store (if setting)'),
ttlSeconds: z.number().positive().optional().describe('Cache TTL in seconds'),
});
type CachedDataInput = z.infer<typeof CachedDataInputSchema>;
/**
* Cached data tool - demonstrates caching pattern
*/
async function cachedDataHandler(
input: CachedDataInput
): Promise<ToolResult<{ key: string; value: string | null; cached: boolean }>> {
const cacheKey = makeCacheKey('example', input.key);
if (input.value !== undefined) {
// Store value
cacheSet(cacheKey, input.value, input.ttlSeconds);
logger.debug('Stored value', { key: input.key });
return {
success: true,
data: { key: input.key, value: input.value, cached: false },
};
} else {
// Fetch value
const cached = cacheGet<string>(cacheKey);
logger.debug('Fetched value', { key: input.key, found: cached !== null });
return {
success: true,
data: { key: input.key, value: cached, cached: cached !== null },
};
}
}
/**
* Status tool - demonstrates server health pattern
*/
async function statusHandler(): Promise<
ToolResult<{
server: { name: string; version: string };
cache: { entries: number; expired: number; hits: number };
timestamp: string;
}>
> {
const config = getConfig();
const cache = cacheStats();
return {
success: true,
data: {
server: {
name: config.serverName,
version: config.serverVersion,
},
cache: {
entries: cache.totalEntries,
expired: cache.expiredEntries,
hits: cache.totalHits,
},
timestamp: new Date().toISOString(),
},
};
}
/**
* Register all example tools
*/
export function registerExampleTools(registry: ToolRegistry): void {
registry.register(
'echo',
'Echo a message back, optionally in uppercase',
EchoInputSchema,
echoHandler
);
registry.register(
'add',
'Add two numbers together',
AddNumbersInputSchema,
addNumbersHandler
);
registry.register(
'cache',
'Get or set a cached value. Provide only key to get, provide key and value to set.',
CachedDataInputSchema,
cachedDataHandler
);
registry.register(
'status',
'Get server status and cache statistics',
z.object({}),
statusHandler
);
logger.info('Registered example tools', { count: 4 });
}