bc-webclient-mcp
Version:
Model Context Protocol (MCP) server for Microsoft Dynamics 365 Business Central via WebUI protocol. Enables AI assistants to interact with BC through the web client protocol, supporting Card, List, and Document pages with full line item support and server
114 lines • 4.36 kB
TypeScript
/**
* Base MCP Tool Implementation
*
* Provides common functionality for all MCP tools.
* Handles input validation and error conversion.
*
* Supports both Zod schema validation (recommended) and legacy validation helpers.
*/
import type { IMCPTool } from '../core/interfaces.js';
import type { Result } from '../core/result.js';
import type { BCError } from '../core/errors.js';
import { InputValidationError } from '../core/errors.js';
import type { ZodTypeAny } from 'zod';
import type { AuditLogger } from '../services/audit-logger.js';
/**
* Options for BaseMCPTool constructor.
*/
export interface BaseMCPToolOptions {
/**
* Optional Zod schema for input validation.
* If provided, validateInput will use Zod validation.
* Otherwise, falls back to legacy validation helpers.
*/
inputZod?: ZodTypeAny;
/**
* Optional audit logger for tracking tool executions.
* If provided and requiresConsent is true, all executions will be logged.
*/
auditLogger?: AuditLogger;
}
/**
* Abstract base class for MCP tools.
* Implements common validation and error handling.
*
* Tools can provide a Zod schema for automatic validation with type coercion,
* or use the legacy validation helpers for manual validation.
*/
export declare abstract class BaseMCPTool implements IMCPTool {
abstract readonly name: string;
abstract readonly description: string;
abstract readonly inputSchema: unknown;
/**
* Optional Zod schema for input validation.
* When provided, validateInput uses this instead of legacy validation.
*/
protected readonly inputZod?: ZodTypeAny;
/**
* Optional audit logger for tracking tool executions.
* Used to log all consent-required tool invocations.
*/
protected readonly auditLogger?: AuditLogger;
/**
* Constructor that optionally accepts a Zod schema and audit logger.
*/
constructor(opts?: BaseMCPToolOptions);
/**
* Executes the tool with validated input.
* Subclasses must implement this method.
*/
protected abstract executeInternal(input: unknown): Promise<Result<unknown, BCError>>;
/**
* Validates input against the tool's schema.
* Subclasses can override for custom validation.
*
* If inputZod is provided, uses Zod validation with type coercion.
* Otherwise, uses basic type checking (legacy mode).
*/
protected validateInput(input: unknown): Result<unknown, BCError>;
/**
* Converts Zod validation error to InputValidationError.
*/
private zodErrorToInputValidationError;
/**
* Executes the tool.
* Validates input and calls executeInternal.
*
* CRITICAL FIX: Audit logging happens AFTER execution completes,
* with the actual result status. This prevents contradictory audit
* entries where "success" is logged but the operation fails.
*/
execute(input: unknown): Promise<Result<unknown, BCError>>;
/**
* Get a safe summary of input for audit logging.
* Subclasses can override to customize what gets logged.
*
* Default implementation extracts key fields and truncates complex values.
*/
protected getInputSummary(input: unknown): Record<string, unknown>;
/**
* Helper to check if a property exists on an object.
*/
protected hasProperty<K extends string>(obj: unknown, key: K): obj is Record<K, unknown>;
/**
* Helper to get a required string property.
*/
protected getRequiredString(obj: unknown, key: string): Result<string, InputValidationError>;
/**
* Helper to get an optional string property.
*/
protected getOptionalString(obj: unknown, key: string): Result<string | undefined, InputValidationError>;
/**
* Helper to get a required number property.
*/
protected getRequiredNumber(obj: unknown, key: string): Result<number, InputValidationError>;
/**
* Helper to get an optional number property.
*/
protected getOptionalNumber(obj: unknown, key: string): Result<number | undefined, InputValidationError>;
/**
* Helper to get an optional object property.
*/
protected getOptionalObject(obj: unknown, key: string): Result<Record<string, unknown> | undefined, InputValidationError>;
}
//# sourceMappingURL=base-tool.d.ts.map