Skip to main content
Glama

compare_packages

Compare two npm packages side-by-side to analyze differences in features, dependencies, and statistics for informed package selection decisions.

Instructions

Compare two packages side-by-side

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
packageName1Yes
packageName2Yes

Implementation Reference

  • The handler function for the 'compare_packages' tool. It fetches full package information and last-month download stats for two packages from the npm registry, extracts latest versions, constructs a comparison output with details like version, description, downloads, maintainers, and keywords, formats a textual comparison, and returns both structured data and formatted text, handling errors appropriately.
    async ({ packageName1, packageName2 }) => {
      try {
        const [pkg1Full, pkg2Full, pkg1Stats, pkg2Stats] = await Promise.all([
          fetchFullPackageInfo(packageName1),
          fetchFullPackageInfo(packageName2),
          fetch(
            `https://api.npmjs.org/downloads/point/last-month/${encodeURIComponent(
              packageName1
            )}`
          ).then((r) => r.json()),
          fetch(
            `https://api.npmjs.org/downloads/point/last-month/${encodeURIComponent(
              packageName2
            )}`
          ).then((r) => r.json()),
        ]);
    
        const pkg1Latest = pkg1Full.versions[pkg1Full["dist-tags"].latest];
        const pkg2Latest = pkg2Full.versions[pkg2Full["dist-tags"].latest];
    
        const output = {
          packages: [
            {
              name: pkg1Latest.name,
              version: pkg1Latest.version,
              description: pkg1Latest.description,
              downloads: pkg1Stats.downloads || 0,
              maintainers: pkg1Latest.maintainers?.map((m: any) => m.name) || [],
              keywords: pkg1Latest.keywords,
            },
            {
              name: pkg2Latest.name,
              version: pkg2Latest.version,
              description: pkg2Latest.description,
              downloads: pkg2Stats.downloads || 0,
              maintainers: pkg2Latest.maintainers?.map((m: any) => m.name) || [],
              keywords: pkg2Latest.keywords,
            },
          ],
        };
    
        const formattedText = `Package Comparison:\n\n${pkg1Latest.name} vs ${
          pkg2Latest.name
        }\n\n${pkg1Latest.name}:\n  Version: ${
          pkg1Latest.version
        }\n  Description: ${
          pkg1Latest.description || "N/A"
        }\n  Downloads (last month): ${(
          pkg1Stats.downloads || 0
        ).toLocaleString()}\n  Maintainers: ${
          output.packages[0].maintainers.join(", ") || "N/A"
        }\n  Keywords: ${pkg1Latest.keywords?.join(", ") || "None"}\n\n${
          pkg2Latest.name
        }:\n  Version: ${pkg2Latest.version}\n  Description: ${
          pkg2Latest.description || "N/A"
        }\n  Downloads (last month): ${(
          pkg2Stats.downloads || 0
        ).toLocaleString()}\n  Maintainers: ${
          output.packages[1].maintainers.join(", ") || "N/A"
        }\n  Keywords: ${pkg2Latest.keywords?.join(", ") || "None"}`;
    
        return {
          content: [
            {
              type: "text",
              text: formattedText,
            },
          ],
          structuredContent: output,
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `Error comparing packages: ${
                error instanceof Error ? error.message : "Unknown error"
              }`,
            },
          ],
          isError: true,
        };
      }
    }
  • Input and output schemas defining the parameters (packageName1, packageName2 as strings) and the structured output (array of package objects with name, version, description, downloads, maintainers, keywords).
    {
      title: "Compare Packages",
      description: "Compare two packages side-by-side",
      inputSchema: {
        packageName1: z.string(),
        packageName2: z.string(),
      },
      outputSchema: {
        packages: z.array(
          z.object({
            name: z.string(),
            version: z.string(),
            description: z.string().optional(),
            downloads: z.number(),
            maintainers: z.array(z.string()),
            keywords: z.array(z.string()).optional(),
          })
        ),
      },
    },
  • src/index.ts:727-833 (registration)
    Registration of the 'compare_packages' tool using server.registerTool, including the tool name, schema, and handler function.
    server.registerTool(
      "compare_packages",
      {
        title: "Compare Packages",
        description: "Compare two packages side-by-side",
        inputSchema: {
          packageName1: z.string(),
          packageName2: z.string(),
        },
        outputSchema: {
          packages: z.array(
            z.object({
              name: z.string(),
              version: z.string(),
              description: z.string().optional(),
              downloads: z.number(),
              maintainers: z.array(z.string()),
              keywords: z.array(z.string()).optional(),
            })
          ),
        },
      },
      async ({ packageName1, packageName2 }) => {
        try {
          const [pkg1Full, pkg2Full, pkg1Stats, pkg2Stats] = await Promise.all([
            fetchFullPackageInfo(packageName1),
            fetchFullPackageInfo(packageName2),
            fetch(
              `https://api.npmjs.org/downloads/point/last-month/${encodeURIComponent(
                packageName1
              )}`
            ).then((r) => r.json()),
            fetch(
              `https://api.npmjs.org/downloads/point/last-month/${encodeURIComponent(
                packageName2
              )}`
            ).then((r) => r.json()),
          ]);
    
          const pkg1Latest = pkg1Full.versions[pkg1Full["dist-tags"].latest];
          const pkg2Latest = pkg2Full.versions[pkg2Full["dist-tags"].latest];
    
          const output = {
            packages: [
              {
                name: pkg1Latest.name,
                version: pkg1Latest.version,
                description: pkg1Latest.description,
                downloads: pkg1Stats.downloads || 0,
                maintainers: pkg1Latest.maintainers?.map((m: any) => m.name) || [],
                keywords: pkg1Latest.keywords,
              },
              {
                name: pkg2Latest.name,
                version: pkg2Latest.version,
                description: pkg2Latest.description,
                downloads: pkg2Stats.downloads || 0,
                maintainers: pkg2Latest.maintainers?.map((m: any) => m.name) || [],
                keywords: pkg2Latest.keywords,
              },
            ],
          };
    
          const formattedText = `Package Comparison:\n\n${pkg1Latest.name} vs ${
            pkg2Latest.name
          }\n\n${pkg1Latest.name}:\n  Version: ${
            pkg1Latest.version
          }\n  Description: ${
            pkg1Latest.description || "N/A"
          }\n  Downloads (last month): ${(
            pkg1Stats.downloads || 0
          ).toLocaleString()}\n  Maintainers: ${
            output.packages[0].maintainers.join(", ") || "N/A"
          }\n  Keywords: ${pkg1Latest.keywords?.join(", ") || "None"}\n\n${
            pkg2Latest.name
          }:\n  Version: ${pkg2Latest.version}\n  Description: ${
            pkg2Latest.description || "N/A"
          }\n  Downloads (last month): ${(
            pkg2Stats.downloads || 0
          ).toLocaleString()}\n  Maintainers: ${
            output.packages[1].maintainers.join(", ") || "N/A"
          }\n  Keywords: ${pkg2Latest.keywords?.join(", ") || "None"}`;
    
          return {
            content: [
              {
                type: "text",
                text: formattedText,
              },
            ],
            structuredContent: output,
          };
        } catch (error) {
          return {
            content: [
              {
                type: "text",
                text: `Error comparing packages: ${
                  error instanceof Error ? error.message : "Unknown error"
                }`,
              },
            ],
            isError: true,
          };
        }
      }
    );

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/JuanSebastianGB/npm-context-agent-mcp'

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