Skip to main content
Glama
dacebt

Prompt Cleaner MCP Server

by dacebt

normalize-prompt

Standardizes and refines prompts by removing sensitive data, restructuring content, and clarifying formatting for consistent LLM processing.

Instructions

Alias of cleaner. Keywords: normalize, restructure, clarify, tighten, format, preflight. Same input/output schema as 'cleaner'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYesRaw user prompt
modeNoRetouching mode; default 'general'. Use 'code' only for code-related prompts.
temperatureNoSampling temperature (0-2); default 0.2

Implementation Reference

  • src/tools.ts:56-74 (registration)
    Registration of the 'normalize-prompt' tool in the listTools() function, including its description and input schema (identical to 'cleaner').
    {
      name: "normalize-prompt",
      description:
        "Alias of cleaner. Keywords: normalize, restructure, clarify, tighten, format, preflight. Same input/output schema as 'cleaner'.",
      inputSchema: {
        type: "object",
        properties: {
          prompt: { type: "string", description: "Raw user prompt" },
          mode: {
            type: "string",
            enum: ["code", "general"],
            description:
              "Retouching mode; default 'general'. Use 'code' only for code-related prompts.",
          },
          temperature: { type: "number", description: "Sampling temperature (0-2); default 0.2" },
        },
        required: ["prompt"],
      },
    },
  • Dispatch handler in callTool() for 'normalize-prompt' (shared with 'cleaner' and 'sanitize-text'), which validates input using RetouchInput schema, calls retouchPrompt, validates output, logs, and returns JSON.
    case "cleaner":
    case "sanitize-text":
    case "normalize-prompt": {
      const parsed = RetouchInput.parse(args);
      const result = await retouchPrompt(parsed);
      const safe = RetouchOutput.parse(result);
      logger.info("retouch.prompt", {
        elapsed_ms: Date.now() - start,
        input_len: parsed.prompt.length,
        preview: logger.preview(parsed.prompt),
        request_id: parsed.requestId,
      });
      return jsonContent(safe);
    }
  • Core implementation of prompt normalization in retouchPrompt(): loads system prompt from file, calls LLM (chatCompletions) with retry logic for JSON output, extracts/parses JSON, applies redaction, validates with RetouchOutput schema, and logs extensively.
    export async function retouchPrompt(input: RetouchInputT): Promise<RetouchOutputT> {
      const start = Date.now();
      const system = await loadCleanerSystemPrompt();
      const baseTemperature = input.temperature ?? 0;
    
      const userBody = `MODE: ${input.mode || "general"}\nRAW_PROMPT:\n${input.prompt}`;
      const sys = system;
    
      class CleanerNonJsonError extends Error {
        constructor(message = "Cleaner returned non-JSON") {
          super(message);
          this.name = "CleanerNonJsonError";
        }
      }
    
      // Retry loop for content-level non-JSON responses
      const maxAttempts = Math.max(1, 1 + (config.contentMaxRetries ?? 0));
      let lastErr: Error | undefined;
      for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        // Escalate on retries: enforce temperature 0 and stricter system instructions
        const strictSuffix =
          attempt > 1
            ? "\n\nSTRICT OUTPUT MODE: Respond with EXACTLY ONE JSON object and nothing else. No prose. No code fences. No prefix/suffix."
            : "";
        const sysAttempt = sys + strictSuffix;
        const tempAttempt = attempt > 1 ? 0 : baseTemperature;
    
        const response = await chatCompletions(
          {
            model: config.model,
            temperature: tempAttempt,
            max_tokens: 600,
            messages: [
              { role: "system", content: sysAttempt },
              { role: "user", content: userBody },
            ],
          },
          { requestId: input.requestId },
        );
    
        const content = response.choices?.[0]?.message?.content ?? "";
        const initial = redactSecrets(content);
        const redactedText = initial.text;
        try {
          const obj = extractFirstJsonObject(redactedText);
          const parsed = RetouchOutput.safeParse(obj);
          if (!parsed.success) {
            throw new Error("shape-error");
          }
    
          const { value, redactions } = ensureNoSecretsInObject(parsed.data);
          const totalRedactions = initial.count + redactions;
          const result: RetouchOutputT = {
            ...value,
            redactions:
              totalRedactions > 0 ? Array(totalRedactions).fill("[REDACTED]") : value.redactions,
          };
    
          logger.info("retouch.prompt", {
            elapsed_ms: Date.now() - start,
            input_len: input.prompt.length,
            preview: logger.preview(input.prompt),
            request_id: input.requestId,
            attempts: attempt,
            outcome: "ok",
          });
    
          return result;
        } catch (e: any) {
          lastErr = new CleanerNonJsonError("Cleaner returned non-JSON");
          if (attempt < maxAttempts) {
            const base = config.backoffMs ?? 250;
            const jitter = config.backoffJitter ?? 0.2;
            const exp = Math.pow(2, attempt - 1);
            const rand = 1 + (Math.random() * 2 - 1) * jitter; // 1 +/- jitter
            const delay = Math.max(0, Math.floor(base * exp * rand));
            logger.warn("retouch.retry", {
              request_id: input.requestId,
              attempt,
              delay_ms: delay,
              reason: "non-json",
            });
            await new Promise((r) => setTimeout(r, delay));
            continue;
          }
        }
      }
      logger.info("retouch.prompt", {
        elapsed_ms: Date.now() - start,
        input_len: input.prompt.length,
        preview: logger.preview(input.prompt),
        request_id: input.requestId,
        attempts: maxAttempts,
        outcome: "error",
        reason: "non-json",
      });
      throw lastErr ?? new CleanerNonJsonError("Cleaner returned non-JSON");
    }
  • Zod schemas for RetouchInput and RetouchOutput used for validation in the normalize-prompt (cleaner) tool handler.
    export const RetouchInput = z.object({
      prompt: z.string().min(1),
      mode: z.enum(["code", "general"]).optional(),
      temperature: z.number().min(0).max(2).optional(),
      requestId: z.string().uuid().optional(),
    });
    
    export const RetouchOutput = z.object({
      retouched: z.string().min(1),
      notes: z.array(z.string()).optional(),
      openQuestions: z.array(z.string()).optional(),
      risks: z.array(z.string()).optional(),
      redactions: z.array(z.literal("[REDACTED]")).optional(),
    });

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

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/dacebt/prompt-cleaner-mcp'

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