@@ -201,11 +201,12 @@ Each tool is implemented in TypeScript and follows a standardized pattern that s
201201
202202``` typescript
203203import { z } from ' zod' ;
204- import { createTypedTool } from ' ../../../utils/typed-tool-factory.js' ;
204+ import { createTypedTool , getHandlerContext } from ' ../../../utils/typed-tool-factory.js' ;
205205import type { CommandExecutor } from ' ../../../utils/execution/index.js' ;
206206import { getDefaultCommandExecutor } from ' ../../../utils/execution/index.js' ;
207207import { log } from ' ../../../utils/logging/index.js' ;
208- import { createTextResponse , createErrorResponse } from ' ../../../utils/responses/index.js' ;
208+ import { withErrorHandling } from ' ../../../utils/tool-error-handling.js' ;
209+ import { header , statusLine } from ' ../../../utils/tool-event-builders.js' ;
209210
210211// 1. Define the Zod schema for parameters
211212const someToolSchema = z .object ({
@@ -216,41 +217,46 @@ const someToolSchema = z.object({
216217// 2. Infer the parameter type from the schema
217218type SomeToolParams = z .infer <typeof someToolSchema >;
218219
219- // 3. Implement the core logic in a separate, testable function
220- // This function receives strongly-typed parameters and an injected executor .
220+ // 3. Implement the core logic as an event-emitting function.
221+ // Handlers emit structured events via ctx.emit() instead of returning ToolResponse .
221222export async function someToolLogic(
222223 params : SomeToolParams ,
223224 executor : CommandExecutor ,
224- ): Promise <ToolResponse > {
225- log (' info' , ` Executing some_tool with param: ${params .requiredParam } ` );
226-
227- try {
228- const result = await executor ([' some' , ' command' ], ' Some Tool Operation' );
229-
230- if (! result .success ) {
231- return createErrorResponse (' Operation failed' , result .error );
232- }
233-
234- return createTextResponse (` ✅ Success: ${result .output } ` );
235- } catch (error ) {
236- const errorMessage = error instanceof Error ? error .message : String (error );
237- return createErrorResponse (' Tool execution failed' , errorMessage );
238- }
225+ ): Promise <void > {
226+ const headerEvent = header (' Some Tool' , [
227+ { label: ' Param' , value: params .requiredParam },
228+ ]);
229+ const ctx = getHandlerContext ();
230+
231+ return withErrorHandling (
232+ ctx ,
233+ async () => {
234+ const result = await executor ([' some' , ' command' ], ' Some Tool Operation' );
235+
236+ if (! result .success ) {
237+ ctx .emit (headerEvent );
238+ ctx .emit (statusLine (' error' , ` Operation failed: ${result .error } ` ));
239+ return ;
240+ }
241+
242+ ctx .emit (headerEvent );
243+ ctx .emit (statusLine (' success' , ` Success: ${result .output } ` ));
244+ },
245+ {
246+ header: headerEvent ,
247+ errorMessage : ({ message }) => ` Tool execution failed: ${message } ` ,
248+ },
249+ );
239250}
240251
241- // 4. Export the tool definition for auto-discovery
242- export default {
243- name: ' some_tool' ,
244- description: ' Tool description for AI agents. Example: some_tool({ requiredParam: "value" })' ,
245- schema: someToolSchema .shape , // Expose shape for MCP SDK
246-
247- // 5. Create the handler using the type-safe factory
248- handler: createTypedTool (
249- someToolSchema ,
250- someToolLogic ,
251- getDefaultCommandExecutor ,
252- ),
253- };
252+ // 4. Export schema shape and handler for manifest-driven auto-discovery
253+ export const schema = someToolSchema .shape ;
254+
255+ export const handler = createTypedTool (
256+ someToolSchema ,
257+ someToolLogic ,
258+ getDefaultCommandExecutor ,
259+ );
254260```
255261
256262This pattern ensures that:
0 commit comments