Skip to main content
Glama

Apply Adjustment

photopea_apply_adjustment

Apply destructive adjustments like brightness, hue/saturation, levels, or curves to the active layer. Modify pixel data directly; use undo to revert. Requires prior layer selection.

Instructions

Apply a destructive image adjustment to the active layer's pixel data. Use select_layer to target a specific layer first. Modifies pixels directly — use undo to revert if needed.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
typeYesAdjustment type: 'brightness' for brightness/contrast, 'hue_sat' for hue/saturation/lightness, 'levels' for input levels, 'curves' for tone curves
settingsNoKey-value settings for the adjustment. For brightness: { brightness: -100..100, contrast: -100..100 }. For hue_sat: { hue: -180..180, saturation: -100..100, lightness: -100..100 }. For levels: { inputBlack: 0..255, inputWhite: 0..255 }

Implementation Reference

  • The core handler function that builds the Photopea JavaScript script for applying adjustments. Supports brightness/contrast, hue/saturation/lightness, levels, and curves adjustments based on params type and settings.
    export function buildApplyAdjustment(params: ApplyAdjustmentParams): string {
      const { type, settings = {} } = params;
      const lines: string[] = [];
      const layer = `app.activeDocument.activeLayer`;
    
      switch (type) {
        case "brightness": {
          const brightness = (settings.brightness as number) ?? 0;
          const contrast = (settings.contrast as number) ?? 0;
          lines.push(`${layer}.adjustBrightnessContrast(${brightness}, ${contrast});`);
          break;
        }
        case "hue_sat": {
          const hue = (settings.hue as number) ?? 0;
          const saturation = (settings.saturation as number) ?? 0;
          const lightness = (settings.lightness as number) ?? 0;
          lines.push(`${layer}.adjustColorBalance(${hue}, ${saturation}, ${lightness});`);
          break;
        }
        case "levels": {
          const inputMin = (settings.inputMin as number) ?? 0;
          const inputMax = (settings.inputMax as number) ?? 255;
          const gamma = (settings.gamma as number) ?? 1;
          const outputMin = (settings.outputMin as number) ?? 0;
          const outputMax = (settings.outputMax as number) ?? 255;
          lines.push(
            `${layer}.adjustLevels(${inputMin}, ${inputMax}, ${gamma}, ${outputMin}, ${outputMax});`
          );
          break;
        }
        case "curves": {
          const curvePoints = typeof settings.points === "string" && /^[\[\]0-9,.\s-]+$/.test(settings.points)
            ? settings.points
            : "[[0,0],[255,255]]";
          lines.push(`${layer}.adjustCurves(${curvePoints});`);
          break;
        }
        default:
          lines.push(`// Unknown adjustment type: ${type}`);
      }
    
      lines.push(`app.echoToOE('ok');`);
      return lines.join("\n");
    }
  • Registration of the 'photopea_apply_adjustment' MCP tool with its input schema (type enum + optional settings record), annotations, and the async handler that calls buildApplyAdjustment and executes via bridge.
    // 20. photopea_apply_adjustment
    server.registerTool("photopea_apply_adjustment", {
      title: "Apply Adjustment",
      description: "Apply a destructive image adjustment to the active layer's pixel data. Use select_layer to target a specific layer first. Modifies pixels directly — use undo to revert if needed.",
      inputSchema: {
        type: z.enum(["brightness", "hue_sat", "levels", "curves"]).describe("Adjustment type: 'brightness' for brightness/contrast, 'hue_sat' for hue/saturation/lightness, 'levels' for input levels, 'curves' for tone curves"),
        settings: z.record(z.union([z.number(), z.string(), z.boolean()])).optional().describe("Key-value settings for the adjustment. For brightness: { brightness: -100..100, contrast: -100..100 }. For hue_sat: { hue: -180..180, saturation: -100..100, lightness: -100..100 }. For levels: { inputBlack: 0..255, inputWhite: 0..255 }"),
      },
      annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
    }, async (params) => {
      const script = buildApplyAdjustment(params);
      bridge.sendActivity({ type: "activity", id: "", tool: "apply_adjustment", summary: `Apply ${params.type} adjustment` });
      const result = await bridge.executeScript(script);
      if (!result.success) return { isError: true, content: [{ type: "text" as const, text: result.error || "Failed to apply adjustment" }] };
      return { content: [{ type: "text" as const, text: `Adjustment applied: ${params.type}` }] };
    });
  • TypeScript interface defining the ApplyAdjustmentParams: type (string) and optional settings record for adjustment parameters.
    export interface ApplyAdjustmentParams {
      type: string;
      settings?: Record<string, number | string | boolean>;
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description explicitly states the adjustment is 'destructive', but the annotations have destructiveHint: false, directly contradicting the description. This contradiction undermines transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the core purpose, and every sentence adds value. No unnecessary words or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and two parameters, the description adequately explains the destructive behavior and undo capability. It could mention adjustment types, but the schema covers those.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description does not discuss parameters, but the input schema covers 100% of parameter descriptions. Thus, the description adds no additional meaning beyond the schema, meeting the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it applies a destructive image adjustment to the active layer's pixel data, which is specific and distinguishes it from sibling tools like apply_filter or add_layer. The verb 'apply adjustment' matches the title and schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises to use select_layer first to target a specific layer and mentions using undo to revert, providing clear context for when to use this tool. However, it does not explicitly state when not to use it or mention alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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/attalla1/photopea-mcp-server'

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