Files
2026-06-28 20:18:07 -04:00

7.0 KiB

Handoff: update_category_image Feature Request Analysis

1. Observation

From inspecting the codebase, the following files and lines were analyzed:

  • Prisma Schema (apps/backend/prisma/schema.prisma lines 33-42):
    model Category {
      id           Int                   @id @default(autoincrement())
      name         String                @unique
      imageUrl     String?
      products     Product[]
      attributes   AttributeDefinition[]
      translations CategoryTranslation[]
      createdAt    DateTime              @default(now())
      updatedAt    DateTime              @updatedAt
    }
    
    Observation: The database schema model Category already contains a nullable imageUrl field.
  • Shared Types (packages/types/index.ts lines 9-17):
    export interface Category {
      id: number
      name: TranslatableString
      imageUrl?: string | null
      _count?: { products: number }
      translations?: { langCode: string; name: string }[]
      createdAt?: string
      updatedAt?: string
    }
    
    Observation: The shared TypeScript types for Category already declare imageUrl as optional/nullable (imageUrl?: string | null).
  • Backend Category Routes (apps/backend/src/routes/categories.ts lines 190-218): The existing PUT route performs full/partial category updates:
    .put("/:id", async ({ params, body, status }) => {
      const id = parseInt(params.id);
      if (isNaN(id)) return status(400, { message: "Invalid category ID" });
    
      try {
        const category = await prisma.category.update({
          where: { id },
          data: {
            name: body.name,
            imageUrl: body.imageUrl,
          },
        });
        return category;
      ...
    }, {
      body: t.Object({
        name: t.Optional(t.String()),
        imageUrl: t.Optional(t.Union([t.String(), t.Null()])),
      })
    })
    
  • MCP Server Schema and Handler (apps/mcp-server/index.ts lines 121-132, 862-870): Exposed categories tools like update_category_translation define and route requests via a custom axios api instance:
    // Tool definition
    {
      name: "update_category_translation",
      description: "Add or update translations for a specific category. Do NOT use this tool for products.",
      inputSchema: {
        type: "object",
        properties: {
          id: { type: "number", description: "Category ID" },
          lang: { type: "string", description: "Language code (th, en, ja, zh, vi, ko)" },
          name: { type: "string", description: "Translated category name" }
        },
        required: ["id", "lang", "name"]
      }
    }
    
    // Tool handler
    case "update_category_translation": {
      const { id, lang, name } = params as any;
      const res = await api.patch(`/categories/${id}/translations`, {
        name: { [lang]: name }
      });
      return {
        content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }]
      };
    }
    

2. Logic Chain

  1. Since the Category model in the database (prisma/schema.prisma) and the Category type interface in packages/types/index.ts already support the imageUrl field, no modifications to database structures, Prisma migrations, or the types package are needed.
  2. In apps/backend/src/routes/categories.ts, we need to implement PATCH /categories/:id/image. It should accept a body with imageUrl: t.Union([t.String(), t.Null()]) to update/clear the category image.
  3. In apps/mcp-server/index.ts, we need to define the update_category_image tool schema under ListToolsRequestSchema and map its invocation under CallToolRequestSchema's switch-case block, forwarding the payload to the new backend PATCH endpoint.

3. Caveats

  • In-place backend compilation: The backend TypeScript config includes "declaration": true without "outDir", meaning transpiled files (.js, .d.ts, and .js.map) are produced directly inside the src/ directory. If these transpiled files are checked into the repository, they should be regenerated after modifying .ts files by running npm run build or similar.
  • JSON Schema type support: The MCP tool definition schema uses type: ["string", "null"] for imageUrl to explicitly support clearing images. If an MCP client doesn't support array types, passing an empty string "" is also a valid fallback.

4. Conclusion

To implement the update_category_image feature:

  1. Implement the following route in apps/backend/src/routes/categories.ts (e.g. before the .post("/") route):

    .patch("/:id/image", async ({ params, body, status }) => {
      const id = parseInt(params.id);
      if (isNaN(id)) return status(400, { message: "Invalid category ID" });
    
      try {
        const category = await prisma.category.update({
          where: { id },
          data: {
            imageUrl: body.imageUrl,
          },
        });
        return category;
      } catch (err: any) {
        if (err.code === "P2025") {
          return status(404, { message: "Category not found" });
        }
        console.error("Update category image error:", err);
        return status(500, { message: "Failed to update category image" });
      }
    }, {
      body: t.Object({
        imageUrl: t.Union([t.String(), t.Null()]),
      })
    })
    
  2. Register the tool in apps/mcp-server/index.ts under ListToolsRequestSchema tools list:

          {
            name: "update_category_image",
            description: "Update the image URL for a specific category.",
            inputSchema: {
              type: "object",
              properties: {
                id: { type: "number", description: "Category ID" },
                imageUrl: { type: ["string", "null"], description: "New image URL, or null/empty string to remove the image" }
              },
              required: ["id", "imageUrl"]
            }
          },
    
  3. Implement the handler in apps/mcp-server/index.ts under CallToolRequestSchema's switch (request.params.name) block:

          case "update_category_image": {
            const { id, imageUrl } = params as any;
            const res = await api.patch(`/categories/${id}/image`, {
              imageUrl: imageUrl || null
            });
            return {
              content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }]
            };
          }
    

5. Verification Method

  • Endpoint Verification: Start the backend server (bun run dev in apps/backend). Call the new endpoint using curl:
    curl -X PATCH http://localhost:3051/api/categories/1/image \
      -H "Content-Type: application/json" \
      -d '{"imageUrl": "https://example.com/test-image.png"}'
    
    Verify that the response returns the updated category object with imageUrl matching the provided URL.
  • MCP Tool Verification: Start the MCP server and run the tool update_category_image via an MCP client:
    {
      "name": "update_category_image",
      "arguments": {
        "id": 1,
        "imageUrl": "https://example.com/test-image.png"
      }
    }
    
    Verify that the tool succeeds and returns the JSON representation of the updated category.