Generate tagged errors for MCP server domains (API, Quota, Timeout, Config)
Generates tagged errors specific to an MCP server domain, following Effect-TS error patterns.
Error class definitions in src/types.ts:
claude @mcp-errors "Create Stripe errors: StripeApiError, StripeRateLimitError, TimeoutError, ConfigError"
// src/types.ts (errors section)
import { Data } from "effect";
// Platform-specific API error
export class $PLATFORM_ApiError extends Data.TaggedError("$PLATFORM_ApiError")<{
readonly message: string;
readonly status?: number;
readonly code?: string;
readonly cause?: unknown;
}> {}
// Quota/rate limit error
export class $PLATFORM_QuotaError extends Data.TaggedError("$PLATFORM_QuotaError")<{
readonly message: string;
readonly retryAfter?: number;
readonly quotaType?: string;
}> {}
// Rate limit error (alternative naming)
export class $PLATFORM_RateLimitError extends Data.TaggedError("$PLATFORM_RateLimitError")<{
readonly message: string;
readonly retryAfter?: number;
readonly limit?: number;
}> {}
// Timeout error
export class TimeoutError extends Data.TaggedError("TimeoutError")<{
readonly message: string;
readonly operation: string;
readonly duration?: number;
}> {}
// Configuration error
export class ConfigError extends Data.TaggedError("ConfigError")<{
readonly message: string;
readonly field?: string;
readonly expectedType?: string;
}> {}
// Generic domain error
export class $PLATFORM_McpError extends Data.TaggedError("$PLATFORM_McpError")<{
readonly message: string;
readonly cause?: unknown;
readonly context?: Record<string, unknown>;
}> {}
$PLATFORM - Platform/domain name (e.g., "Stripe", "GA4", "Meta", "GitHub")For general API failures from third-party services:
export class StripeApiError extends Data.TaggedError("StripeApiError")<{
readonly message: string;
readonly status?: number; // HTTP status code
readonly code?: string; // Platform-specific error code
readonly cause?: unknown; // Original error object
}> {}
For quota exceeded or rate limiting:
export class GA4QuotaError extends Data.TaggedError("GA4QuotaError")<{
readonly message: string;
readonly retryAfter?: number; // Seconds until retry allowed
readonly quotaType?: string; // Type of quota exceeded
}> {}
export class MetaRateLimitError extends Data.TaggedError("MetaRateLimitError")<{
readonly message: string;
readonly retryAfter?: number; // Seconds until retry allowed
readonly limit?: number; // Rate limit threshold
}> {}
For operation timeouts (generic, not platform-specific):
export class TimeoutError extends Data.TaggedError("TimeoutError")<{
readonly message: string;
readonly operation: string; // Operation that timed out
readonly duration?: number; // Timeout duration in seconds
}> {}
For missing or invalid configuration (generic):
export class ConfigError extends Data.TaggedError("ConfigError")<{
readonly message: string;
readonly field?: string; // Config field name
readonly expectedType?: string; // Expected type/format
}> {}
For platform-specific issues:
export class ShopifyWebhookError extends Data.TaggedError("ShopifyWebhookError")<{
readonly message: string;
readonly webhookId?: string;
readonly cause?: unknown;
}> {}
export class GitHubPermissionError extends Data.TaggedError("GitHubPermissionError")<{
readonly message: string;
readonly scope?: string; // Required scope
readonly repository?: string; // Repository name
}> {}
Input:
Create Stripe errors: StripeApiError, StripeRateLimitError, StripeWebhookError, TimeoutError, ConfigError
Output:
// src/types.ts
import { Data } from "effect";
export class StripeApiError extends Data.TaggedError("StripeApiError")<{
readonly message: string;
readonly status?: number;
readonly code?: string;
readonly cause?: unknown;
}> {}
export class StripeRateLimitError extends Data.TaggedError("StripeRateLimitError")<{
readonly message: string;
readonly retryAfter?: number;
readonly limit?: number;
}> {}
export class StripeWebhookError extends Data.TaggedError("StripeWebhookError")<{
readonly message: string;
readonly eventId?: string;
readonly cause?: unknown;
}> {}
export class TimeoutError extends Data.TaggedError("TimeoutError")<{
readonly message: string;
readonly operation: string;
readonly duration?: number;
}> {}
export class ConfigError extends Data.TaggedError("ConfigError")<{
readonly message: string;
readonly field?: string;
readonly expectedType?: string;
}> {}
Input:
Create GA4 errors: GA4ApiError, GA4QuotaError, TimeoutError, ConfigError
Output:
// src/types.ts
import { Data } from "effect";
export class GA4ApiError extends Data.TaggedError("GA4ApiError")<{
readonly message: string;
readonly status?: number;
readonly code?: string;
readonly cause?: unknown;
}> {}
export class GA4QuotaError extends Data.TaggedError("GA4QuotaError")<{
readonly message: string;
readonly retryAfter?: number;
readonly quotaType?: string;
}> {}
export class TimeoutError extends Data.TaggedError("TimeoutError")<{
readonly message: string;
readonly operation: string;
readonly duration?: number;
}> {}
export class ConfigError extends Data.TaggedError("ConfigError")<{
readonly message: string;
readonly field?: string;
readonly expectedType?: string;
}> {}
import { Effect } from "effect";
import { GA4ApiError, GA4QuotaError, TimeoutError } from "../types.js";
// Error mapping
Effect.tryPromise({
try: () => client.runReport(request),
catch: (error) => {
if (isQuotaError(error)) {
return new GA4QuotaError({
message: "Quota exceeded",
quotaType: "daily",
});
}
return new GA4ApiError({ cause: error });
},
}).pipe(
Effect.timeoutFail({
duration: "60 seconds",
onTimeout: () => new TimeoutError({
operation: "runReport",
duration: 60,
}),
})
);
import { Effect } from "effect";
import { GA4ApiError, TimeoutError } from "../types.js";
const toolEffect = (input: Input) =>
Effect.gen(function* () {
// ... tool logic
}).pipe(
Effect.catchTag("GA4ApiError", (error) =>
Effect.succeed({
content: [{ type: "text" as const, text: `GA4 API error: ${error.message}` }],
isError: true as const,
})
),
Effect.catchTag("TimeoutError", (error) =>
Effect.succeed({
content: [{ type: "text" as const, text: `Timeout: ${error.operation} took too long` }],
isError: true as const,
})
)
);
ApiError, QuotaError, RateLimitErrorTimeoutError, ConfigError (no prefix)readonly message: string?)cause?: unknown for wrapping third-party errors.claude/rules/effect-typescript.md for error handling patterns.claude/rules/mcp-server.md for MCP-specific error usage@effect-errors for basic Effect error patterns@mcp-service for using errors in services@mcp-tool for catching errors in tools