zed.mcp
Version:
MCP server for project analysis, AI rules reading, and dependency checking
136 lines (117 loc) • 3.79 kB
text/typescript
import { z } from "zod";
import type {
ToolDefinition,
ToolHandler,
ToolResponse,
} from "../types/index";
import { getLatestVersions } from "../utils/index";
/**
* Input schema for get latest versions tool
*/
const GetLatestVersionsInput = z.object({
packages: z
.array(z.string())
.describe("Array of package names to fetch latest versions for (e.g., ['@opentelemetry/api', '@opentelemetry/sdk-logs'])"),
});
type GetLatestVersionsParams = z.infer<typeof GetLatestVersionsInput>;
/**
* Tool definition for getting latest package versions
*/
export const getLatestVersionsDefinition: ToolDefinition = {
name: "get-latest-versions",
title: "Get Latest Package Versions",
description:
"Fetches the latest versions from npm registry for a list of packages. Returns the package names with their latest versions, useful for determining what versions to install.",
inputSchema: {
packages: GetLatestVersionsInput.shape.packages,
},
};
/**
* Formats the results into a readable string
*/
function formatResults(
results: Map<string, string | null>,
packages: string[],
): string {
let output = "# Latest Package Versions\n\n";
const successCount = Array.from(results.values()).filter((v) => v !== null).length;
const failCount = packages.length - successCount;
output += `Total packages: ${packages.length}\n`;
output += `Successfully fetched: ${successCount}\n`;
if (failCount > 0) {
output += `Failed to fetch: ${failCount}\n`;
}
output += "\n";
output += "## Versions\n\n";
for (const packageName of packages) {
const version = results.get(packageName);
if (version) {
output += `- **${packageName}**: \`${version}\`\n`;
} else {
output += `- **${packageName}**: ❌ Could not fetch version\n`;
}
}
output += "\n## Installation Commands\n\n";
output += "To install these packages:\n\n";
output += "```bash\n";
const validPackages: string[] = [];
for (const packageName of packages) {
const version = results.get(packageName);
if (version) {
validPackages.push(`${packageName}@${version}`);
}
}
if (validPackages.length > 0) {
output += `bun add ${validPackages.join(" ")}\n`;
} else {
output += "# No valid packages to install\n";
}
output += "```\n";
output += "\n## JSON Format\n\n";
output += "For programmatic use:\n\n";
output += "```json\n";
const jsonOutput: Record<string, string | null> = {};
for (const packageName of packages) {
jsonOutput[packageName] = results.get(packageName) || null;
}
output += JSON.stringify(jsonOutput, null, 2);
output += "\n```\n";
return output;
}
/**
* Handler for getting latest package versions
*/
export const getLatestVersionsHandler: ToolHandler<GetLatestVersionsParams> = async ({
packages,
}): Promise<ToolResponse> => {
try {
if (!packages || packages.length === 0) {
return {
content: [
{
type: "text",
text: "Error: No packages provided. Please specify at least one package name.",
},
],
isError: true,
};
}
// Fetch latest versions from npm registry
const latestVersions = await getLatestVersions(packages);
// Format and return
const formattedOutput = formatResults(latestVersions, packages);
return {
content: [{ type: "text", text: formattedOutput }],
};
} catch (error: any) {
return {
content: [
{
type: "text",
text: `An unexpected error occurred while fetching package versions: ${error.message}`,
},
],
isError: true,
};
}
};