Skip to main content
Glama
types.ts9.26 kB
import { z } from "zod"; // ============================================ // Configuration // ============================================ export interface TuskDriftConfig { /** Base URL for the Tusk Drift API (e.g., https://api.usetusk.ai) */ apiBaseUrl: string; /** API key or JWT token for authentication */ apiToken: string; /** Optional default observable service ID (can be overridden per request) */ observableServiceId?: string; } // ============================================ // Shared Filter Schemas // ============================================ export const stringFilterSchema = z.object({ eq: z.string().optional(), neq: z.string().optional(), in: z.array(z.string()).optional(), contains: z.string().optional(), startsWith: z.string().optional(), endsWith: z.string().optional(), }); export const numberFilterSchema = z.object({ eq: z.number().optional(), neq: z.number().optional(), gt: z.number().optional(), gte: z.number().optional(), lt: z.number().optional(), lte: z.number().optional(), }); export const booleanFilterSchema = z.object({ eq: z.boolean(), }); // ============================================ // JSONB Filter Schema // ============================================ export const jsonbFilterSchema = z.object({ column: z.enum(["inputValue", "outputValue", "metadata", "status"]), jsonPath: z.string().regex(/^\$/, "JSONPath must start with $"), eq: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(), neq: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(), gt: z.number().optional(), gte: z.number().optional(), lt: z.number().optional(), lte: z.number().optional(), contains: z.string().optional(), startsWith: z.string().optional(), endsWith: z.string().optional(), isNull: z.boolean().optional(), in: z.array(z.union([z.string(), z.number()])).optional(), castAs: z.enum(["text", "int", "float", "boolean"]).optional(), decodeBase64: z.boolean().optional(), thenPath: z.string().regex(/^\$/, "JSONPath must start with $").optional(), }); export type JsonbFilter = z.infer<typeof jsonbFilterSchema>; // ============================================ // Span Where Clause // ============================================ export const spanWhereClauseSchema: z.ZodType<SpanWhereClause> = z.lazy(() => z .object({ // Field filters name: stringFilterSchema.optional(), packageName: stringFilterSchema.optional(), instrumentationName: stringFilterSchema.optional(), environment: stringFilterSchema.optional(), traceId: stringFilterSchema.optional(), spanId: stringFilterSchema.optional(), duration: numberFilterSchema.optional(), isRootSpan: booleanFilterSchema.optional(), // Logical operators AND: z.array(spanWhereClauseSchema).optional(), OR: z.array(spanWhereClauseSchema).optional(), }) .partial() ); export interface SpanWhereClause { name?: z.infer<typeof stringFilterSchema>; packageName?: z.infer<typeof stringFilterSchema>; instrumentationName?: z.infer<typeof stringFilterSchema>; environment?: z.infer<typeof stringFilterSchema>; traceId?: z.infer<typeof stringFilterSchema>; spanId?: z.infer<typeof stringFilterSchema>; duration?: z.infer<typeof numberFilterSchema>; isRootSpan?: z.infer<typeof booleanFilterSchema>; AND?: SpanWhereClause[]; OR?: SpanWhereClause[]; } // ============================================ // API Response Types // ============================================ export interface SpanRecording { id: string; spanId: string; traceId: string; parentSpanId?: string; name: string; kind: number; status: { code: number; message?: string }; timestamp: string; duration: number; isRootSpan: boolean; packageName: string; instrumentationName: string; submoduleName?: string; environment?: string; inputValue?: unknown; outputValue?: unknown; inputSchema?: unknown; outputSchema?: unknown; metadata?: unknown; } export interface TraceSpan extends SpanRecording { children?: TraceSpan[]; } export interface SchemaResult { inputSchema?: unknown; outputSchema?: unknown; exampleSpanRecording?: Partial<SpanRecording>; commonJsonbFields: { inputValue: string[]; outputValue: string[]; }; description?: string; } export interface DistinctValue { value: unknown; count: number; } export interface AggregationRow { groupValues: Record<string, unknown>; timeBucket?: string; count: number; errorCount?: number; errorRate?: number; avgDuration?: number; minDuration?: number; maxDuration?: number; p50Duration?: number; p95Duration?: number; p99Duration?: number; } // ============================================ // Tool Input Schemas // ============================================ export const querySpansInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), where: spanWhereClauseSchema.optional().describe("Filter conditions for spans"), jsonbFilters: z.array(jsonbFilterSchema).optional().describe("JSONB path filters for inputValue/outputValue"), orderBy: z .array( z.object({ field: z.enum(["timestamp", "duration", "name"]), direction: z.enum(["ASC", "DESC"]), }) ) .optional() .describe("Ordering"), limit: z.number().min(1).max(100).default(20).describe("Max results to return"), offset: z.number().min(0).default(0).describe("Pagination offset"), includeInputOutput: z.boolean().default(false).describe("Include full inputValue/outputValue (verbose)"), maxPayloadLength: z.number().min(0).default(500).describe("Truncate payload strings to this length"), }); export const getSchemaInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), packageName: z.string().optional().describe("Package name (e.g., 'http', 'pg', 'fetch')"), instrumentationName: z.string().optional().describe("Instrumentation name"), name: z.string().optional().describe("Span name to filter by"), showExample: z.boolean().default(true).describe("Include an example span"), maxPayloadLength: z.number().min(0).default(500).describe("Truncate example payload strings"), }); export const listDistinctValuesInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), field: z.string().describe("Field to get distinct values for (e.g., 'name', 'packageName', 'outputValue.statusCode')"), where: spanWhereClauseSchema.optional().describe("Filter conditions"), jsonbFilters: z.array(jsonbFilterSchema).optional().describe("JSONB path filters"), limit: z.number().min(1).max(100).default(50).describe("Max distinct values to return"), }); export const aggregateSpansInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), where: spanWhereClauseSchema.optional().describe("Filter conditions"), groupBy: z .array(z.enum(["name", "packageName", "instrumentationName", "environment", "statusCode"])) .optional() .describe("Fields to group by"), metrics: z .array( z.enum([ "count", "errorCount", "errorRate", "avgDuration", "minDuration", "maxDuration", "p50Duration", "p95Duration", "p99Duration", ]) ) .min(1) .describe("Metrics to calculate"), timeBucket: z.enum(["hour", "day", "week"]).optional().describe("Time bucket for time-series data"), orderBy: z .object({ metric: z.string(), direction: z.enum(["ASC", "DESC"]), }) .optional() .describe("Order by metric"), limit: z.number().min(1).max(100).default(20).describe("Max results"), }); export const getTraceInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), traceId: z.string().describe("Trace ID to fetch"), includePayloads: z.boolean().default(false).describe("Include inputValue/outputValue"), maxPayloadLength: z.number().min(0).default(500).describe("Truncate payload strings"), }); export const getSpansByIdsInputSchema = z.object({ observableServiceId: z.string().optional().describe("Service ID to query (required if multiple services available)"), ids: z.array(z.string()).min(1).max(20).describe("Span recording IDs to fetch"), includePayloads: z.boolean().default(true).describe("Include inputValue/outputValue"), maxPayloadLength: z.number().min(0).default(500).describe("Truncate payload strings"), }); // Type exports export type QuerySpansInput = z.infer<typeof querySpansInputSchema>; export type GetSchemaInput = z.infer<typeof getSchemaInputSchema>; export type ListDistinctValuesInput = z.infer<typeof listDistinctValuesInputSchema>; export type AggregateSpansInput = z.infer<typeof aggregateSpansInputSchema>; export type GetTraceInput = z.infer<typeof getTraceInputSchema>; export type GetSpansByIdsInput = z.infer<typeof getSpansByIdsInputSchema>;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Use-Tusk/drift-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server