TypeScriptTools
Execution Context in Tools
Use the logger, caller identity, and cancellation signal inside a tool
Every tool receives an ExecutionContext as its second argument. It tells the handler who is calling, gives it a logger tied to the request, and signals when the client cancels.
Every tool handler receives an ExecutionContext object providing access to authentication, logging, request lifecycle metadata, and dynamic catalog control.
Context Properties
These are the fields a tool can read. Optional fields are set only when they apply; auth, for example, appears after a guard has identified the caller.
interface ExecutionContext {
/** Structured logger instance */
logger: Logger;
/** Current tool name */
toolName?: string;
/** Unique request identifier for tracing */
requestId: string;
/** Active transport connection or session identifier */
sessionId?: string;
/** Standard AbortSignal triggered if client cancels invocation */
abortSignal?: AbortSignal;
/** Authentication data populated by guards */
auth?: {
subject?: string; // User/client identifier
token?: string; // Raw authentication token
scopes?: string[]; // Permission scopes
[key: string]: unknown;
};
/** Cryptographically verified subject identifier */
verifiedSubject?: string;
/** Request metadata (writable) */
metadata?: Record<string, unknown>;
/** MCP Background Task tracking metadata when taskSupport is active */
task?: {
taskId: string;
status: 'working' | 'completed' | 'failed' | 'cancelled';
totalSteps?: number;
currentStep?: number;
[key: string]: unknown;
};
/** Client responses to prior inputRequired elicitations (SEP-2322) */
inputResponses?: Record<string, unknown>;
/** Opaque round-trip state echoed by client (SEP-2322) */
requestState?: unknown;
/** Dynamic tool visibility helpers */
enableTools?: (toolNames: string[]) => void | Promise<void>;
disableTools?: (toolNames: string[]) => void | Promise<void>;
}Usage Patterns
A typical handler checks who is calling, logs with structured fields, does its work, and emits an event when it's done.
import { ToolDecorator as Tool, UseGuards, ExecutionContext, emitEvent } from '@nitrostack/core';
import { JWTGuard } from './guards/jwt.guard.js';
@Tool({ name: 'process_payment' })
@UseGuards(JWTGuard)
async processPayment(input: PaymentInput, ctx: ExecutionContext) {
// Access authenticated user
const userId = ctx.auth?.subject;
if (!userId) {
throw new Error('Authentication required');
}
// Structured logging with context
ctx.logger.info('Processing payment', {
userId,
amount: input.amount,
requestId: ctx.requestId
});
try {
const result = await this.paymentService.process(input, userId);
// Emit event asynchronously across the event bus
await emitEvent('payment.completed', {
paymentId: result.id,
userId,
amount: input.amount
});
ctx.logger.info('Payment processed successfully', { paymentId: result.id });
return result;
} catch (error: any) {
ctx.logger.error('Payment processing failed', {
error: error.message,
userId,
amount: input.amount
});
throw error;
}
}