Skip to main content
Glama

part.compare

Compare UI components side by side to analyze styles, layout, interaction, and accessibility aspects for design evaluation and improvement.

Instructions

2-5個のUIコンポーネントパーツをスタイル・レイアウト・インタラクション・アクセシビリティの観点で並列比較します。 / Compare 2-5 UI component parts side by side on styles, layout, interaction, and accessibility aspects.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
part_idsYes比較対象パーツID(2-5個) / 2-5 part IDs to compare
compare_aspectsNo比較観点(デフォルト: styles, layout) / Aspects to compare (default: styles, layout)

Implementation Reference

  • Main handler for the part.compare tool, implementing the comparison logic for UI component parts.
    export async function partCompareHandler(input: unknown): Promise<PartCompareOutput> {
      if (isDevelopment()) {
        logger.info("[MCP Tool] part.compare called", {
          partCount: Array.isArray((input as Record<string, unknown>)?.part_ids)
            ? ((input as Record<string, unknown>).part_ids as unknown[]).length
            : 0,
        });
      }
    
      // 入力バリデーション / Input validation
      let validated: PartCompareInput;
      try {
        validated = partCompareInputSchema.parse(input);
      } catch (error) {
        if (error instanceof ZodError) {
          const errorMessage = error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
    
          logger.warn("[MCP Tool] part.compare validation error", {
            errors: error.errors,
          });
    
          return {
            success: false,
            error: {
              code: PART_COMPARE_ERROR_CODES.VALIDATION_ERROR,
              message: `Validation error: ${errorMessage}`,
            },
          };
        }
        throw error;
      }
    
      try {
        // DB からパーツを取得(リレーション含む)
        // Fetch parts from DB (with relations)
        const dbParts = await prisma.componentPart.findMany({
          where: { id: { in: validated.part_ids } },
          include: {
            webPage: { select: { url: true } },
            sectionPattern: { select: { sectionType: true } },
          },
        });
    
        // 見つからなかったパーツを検出 / Detect missing parts
        const foundIds = new Set(dbParts.map((p) => p.id));
        const missingIds = validated.part_ids.filter((id) => !foundIds.has(id));
    
        if (missingIds.length > 0) {
          logger.warn("[MCP Tool] part.compare parts not found", {
            missingCount: missingIds.length,
            missingIds: missingIds.map((id) => truncateId(id)),
          });
    
          return {
            success: false,
            error: {
              code: PART_COMPARE_ERROR_CODES.PARTS_NOT_FOUND,
              message: `${missingIds.length} part(s) not found`,
            },
          };
        }
    
        // パーツ情報を構築 / Build part info
        const partsInfo: ComparedPartInfo[] = dbParts.map((p) => ({
          id: p.id,
          partType: p.partType,
          webPageUrl: p.webPage.url,
          sectionType: p.sectionPattern.sectionType,
        }));
    
        // 比較ロジック用の中間表現
        // Intermediate representation for comparison logic
        const partsForComparison = dbParts.map((p) => ({
          id: p.id,
          computedStyles: (p.computedStyles ?? {}) as Record<string, unknown>,
          boundingBox: (p.boundingBox ?? {}) as Record<string, unknown>,
          interactionInfo: (p.interactionInfo ?? {}) as Record<string, unknown>,
          attributes: (p.attributes ?? {}) as Record<string, unknown>,
        }));
    
        // 比較観点ごとに結果を構築 / Build comparisons per aspect
        const comparisons: Record<string, ComparisonDetail> = {};
    
        for (const aspect of validated.compare_aspects) {
          switch (aspect) {
            case "styles":
              comparisons.styles = buildStylesComparison(partsForComparison);
              break;
            case "layout":
              comparisons.layout = buildLayoutComparison(partsForComparison);
              break;
            case "interaction":
              comparisons.interaction = buildInteractionComparison(partsForComparison);
              break;
            case "accessibility":
              comparisons.accessibility = buildAccessibilityComparison(partsForComparison);
              break;
          }
        }
    
        if (isDevelopment()) {
          logger.info("[MCP Tool] part.compare completed", {
            partCount: partsInfo.length,
            aspects: validated.compare_aspects,
          });
        }
    
        return {
          success: true,
          data: {
            parts: partsInfo,
            comparisons,
          },
        };
      } catch (error) {
        const errorInstance = error instanceof Error ? error : new Error(String(error));
    
        // 全環境でログ出力(isDevelopmentガードなし)
        // Log in all environments (no isDevelopment guard)
        logger.warn("[MCP Tool] part.compare error", {
          code: PART_COMPARE_ERROR_CODES.INTERNAL_ERROR,
          error: errorInstance.message,
        });
    
        return {
          success: false,
          error: {
            code: PART_COMPARE_ERROR_CODES.INTERNAL_ERROR,
            message: sanitizeErrorMessage(error),
          },
        };
      }
    }
  • MCP tool definition for part.compare, including input schema and metadata.
    export const partCompareToolDefinition = {
      name: "part.compare" as const,
      description:
        "2-5個のUIコンポーネントパーツをスタイル・レイアウト・インタラクション・" +
        "アクセシビリティの観点で並列比較します。" +
        " / Compare 2-5 UI component parts side by side on styles, layout, " +
        "interaction, and accessibility aspects.",
      annotations: {
        title: "Part Compare",
        readOnlyHint: true,
        idempotentHint: true,
        openWorldHint: false,
      },
      inputSchema: {
        type: "object" as const,
        properties: {
          part_ids: {
            type: "array",
            items: { type: "string", format: "uuid" },
            minItems: 2,
            maxItems: 5,
            description: "比較対象パーツID(2-5個) / 2-5 part IDs to compare",
          },
          compare_aspects: {
            type: "array",
            items: {
              type: "string",
              enum: ["styles", "layout", "interaction", "accessibility"],
            },
            default: ["styles", "layout"],
            description:
              "比較観点(デフォルト: styles, layout) / Aspects to compare (default: styles, layout)",
          },
        },
        required: ["part_ids"],
      },
    };

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/TKMD/reftrix-mcp'

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