Skip to main content
Glama

Sentry MCP

Official
by getsentry
slug-validation.ts2.88 kB
/** * Slug validation utilities to prevent path traversal and injection attacks. * * Provides reusable validation functions for use with Zod's superRefine() * to add security validation for URL parameters. */ import { z } from "zod"; /** * Maximum reasonable length for a slug. */ const MAX_SLUG_LENGTH = 100; /** * Maximum reasonable length for a numeric ID. */ const MAX_ID_LENGTH = 20; /** * Helper to check if a string is a numeric ID. */ export function isNumericId(value: string): boolean { return /^\d+$/.test(value); } /** * Valid slug pattern: alphanumeric, hyphens, underscores, and dots. * Must start with alphanumeric character. */ const VALID_SLUG_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/; /** * Validates a slug to prevent path traversal and injection attacks. * Designed to be used with Zod's superRefine() method. * * @example * ```typescript * const OrganizationSlug = z.string() * .toLowerCase() * .trim() * .superRefine(validateSlug) * .describe("Organization slug"); * * const TeamSlug = z.string() * .toLowerCase() * .trim() * .superRefine(validateSlug) * .describe("Team slug"); * ``` */ export function validateSlug(val: string, ctx: z.RefinementCtx): void { // Check for empty string if (val.length === 0) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Slug cannot be empty", }); return; } // Check length if (val.length > MAX_SLUG_LENGTH) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Slug exceeds maximum length of ${MAX_SLUG_LENGTH} characters`, }); return; } // Validate pattern - this implicitly blocks all dangerous characters and patterns if (!VALID_SLUG_PATTERN.test(val)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Slug must contain only alphanumeric characters, hyphens, underscores, and dots, and must start with an alphanumeric character", }); } } /** * Validates a parameter that can be either a slug or numeric ID. * Designed to be used with Zod's superRefine() method. * * @example * ```typescript * const ProjectSlugOrId = z.string() * .toLowerCase() * .trim() * .superRefine(validateSlugOrId) * .describe("Project slug or numeric ID"); * * const IssueSlugOrId = z.string() * .trim() * .superRefine(validateSlugOrId) * .describe("Issue slug or numeric ID"); * ``` */ export function validateSlugOrId(val: string, ctx: z.RefinementCtx): void { // Check if it's a numeric ID if (isNumericId(val)) { if (val.length > MAX_ID_LENGTH) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Numeric ID exceeds maximum length of ${MAX_ID_LENGTH} characters`, }); } // Numeric IDs don't need slug validation return; } // Otherwise validate as a slug validateSlug(val, ctx); }

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/getsentry/sentry-mcp'

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