Skip to main content
Glama

session_save_image

Save image files to a project's visual memory for UI states, diagrams, or bug screenshots. Images are indexed and available in future sessions.

Instructions

Save a local image file into the project's permanent visual memory. Use this to remember UI states, diagrams, architecture graphs, or bug screenshots. The image is copied into Prism's media vault and indexed in the handoff metadata. On the next session_load_context, the agent will see a lightweight index of available images.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectYesProject identifier — must match an existing project.
file_pathYesAbsolute or relative path to the image file (png, jpg, jpeg, webp, gif, svg).
descriptionYesWhat does this image show? Used for indexing and context display.

Implementation Reference

  • The handler for `session_save_image` that validates inputs, saves the image to the media vault, and updates handoff metadata.
    export async function sessionSaveImageHandler(args: unknown) {
      if (!isSessionSaveImageArgs(args)) {
        return {
          content: [{ type: "text", text: "Invalid arguments. Requires: project, file_path, description." }],
          isError: true,
        };
      }
    
      const { project, file_path, description } = args;
    
      // Resolve path (supports relative paths)
      const resolvedPath = nodePath.resolve(file_path);
      if (!fs.existsSync(resolvedPath)) {
        return {
          content: [{ type: "text", text: `Error: File not found at "${resolvedPath}".` }],
          isError: true,
        };
      }
    
      // Validate extension
      const ext = nodePath.extname(resolvedPath).toLowerCase() || ".png";
      const SUPPORTED_EXTS = [".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg"];
      if (!SUPPORTED_EXTS.includes(ext)) {
        return {
          content: [{
            type: "text",
            text: `Error: Unsupported image format "${ext}". Supported: ${SUPPORTED_EXTS.join(", ")}.`,
          }],
          isError: true,
        };
      }
    
      // Setup media vault directory
      const mediaDir = nodePath.join(os.homedir(), ".prism-mcp", "media", project);
      if (!fs.existsSync(mediaDir)) {
        fs.mkdirSync(mediaDir, { recursive: true });
      }
    
      // Copy to vault with short UUID
      const imageId = randomUUID().slice(0, 8);
      const vaultFilename = `${imageId}${ext}`;
      const vaultPath = nodePath.join(mediaDir, vaultFilename);
      fs.copyFileSync(resolvedPath, vaultPath);
    
      // Update handoff metadata
      const storage = await getStorage();
      const context = await storage.loadContext(project, "quick", PRISM_USER_ID);
    
      if (!context) {
        return {
          content: [{
            type: "text",
            text: `Error: No active context for project "${project}". Save a handoff first.`,
          }],
          isError: true,
        };
      }
    
      const contextObj = context as any;
      const meta = contextObj.metadata || {};
      meta.visual_memory = meta.visual_memory || [];
      meta.visual_memory.push({
        id: imageId,
        description,
        filename: vaultFilename,
        original_path: resolvedPath,
        timestamp: new Date().toISOString(),
      });
    
      // Save back (triggers history snapshot + telepathy)
      const handoffUpdate = {
        project,
        user_id: PRISM_USER_ID,
        metadata: meta,
        last_summary: contextObj.last_summary ?? null,
        pending_todo: contextObj.pending_todo ?? null,
        active_decisions: contextObj.active_decisions ?? null,
        keywords: contextObj.keywords ?? null,
        key_context: contextObj.key_context ?? null,
        active_branch: contextObj.active_branch ?? null,
      };
    
      const currentVersion = contextObj.version;
      await storage.saveHandoff(handoffUpdate, currentVersion);
    
      const fileSize = fs.statSync(vaultPath).size;
      const sizeKB = (fileSize / 1024).toFixed(1);
      console.error(`[Visual Memory] Saved image [${imageId}] for "${project}" (${sizeKB}KB, ${ext})`);
    
      return {
        content: [{
          type: "text",
          text: `✅ Image saved to visual memory.\n\n` +
            `• ID: \`${imageId}\`\n` +
            `• Description: ${description}\n` +
            `• Format: ${ext} (${sizeKB}KB)\n` +
            `• Vault: ${vaultPath}\n\n` +
            `Use \`session_view_image("${project}", "${imageId}")\` to retrieve it later.`,
        }],
        isError: false,
      };
    }
  • Definition of the `session_save_image` tool schema and argument validation function.
    export const SESSION_SAVE_IMAGE_TOOL: Tool = {
      name: "session_save_image",
      description:
        "Save a local image file into the project's permanent visual memory. " +
        "Use this to remember UI states, diagrams, architecture graphs, or bug screenshots. " +
        "The image is copied into Prism's media vault and indexed in the handoff metadata. " +
        "On the next session_load_context, the agent will see a lightweight index of available images.",
      inputSchema: {
        type: "object",
        properties: {
          project: {
            type: "string",
            description: "Project identifier — must match an existing project.",
          },
          file_path: {
            type: "string",
            description: "Absolute or relative path to the image file (png, jpg, jpeg, webp, gif, svg).",
          },
          description: {
            type: "string",
            description: "What does this image show? Used for indexing and context display.",
          },
        },
        required: ["project", "file_path", "description"],
      },
    };
    
    export const SESSION_VIEW_IMAGE_TOOL: Tool = {
      name: "session_view_image",
      description:
        "Retrieve an image from visual memory using its ID. " +
        "Returns the image as Base64 inline content for the LLM to analyze. " +
        "Use session_load_context first to see available image IDs.",
      inputSchema: {
        type: "object",
        properties: {
          project: {
            type: "string",
            description: "Project identifier.",
          },
          image_id: {
            type: "string",
            description: "The short image ID (e.g., '8f2a1b3c') from the visual memory index.",
          },
        },
        required: ["project", "image_id"],
      },
    };
    
    // ─── v2.0: Visual Memory Type Guards ─────────────────────────
    
    export function isSessionSaveImageArgs(

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/dcostenco/BCBA'

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