feat: create MCP server and tools to see available packages and retrieve specific package context

This commit is contained in:
Abdusshh 2025-03-31 15:19:29 +03:00
parent 92f3fad73e
commit 22d6e5ef59
2 changed files with 202 additions and 0 deletions

166
src/index.ts Normal file
View File

@ -0,0 +1,166 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { Project } from "./lib/types.js";
const CONTEXT7_BASE_URL = "https://context7.com";
// Create server instance
const server = new McpServer({
name: "context7",
version: "1.0.0",
capabilities: {
resources: {},
tools: {},
},
});
// Helper function for making Context7 API requests
async function makeContext7Request<T>(url: string): Promise<T | null> {
try {
const response = await fetch(url);
if (!response.ok) {
return null;
}
return await response.json();
} catch (error) {
console.error("Error making Context7 API request:", error);
return null;
}
}
// Helper function for formatting projects
function formatProject(project: Project): string {
return `Title: ${project.settings.title}\n Package name to fetch context: ${project.settings.project}\n`;
}
// Register context7 tools
server.tool(
"see-available-packages",
"See the list of packages that are finalized and available to fetch their context",
async () => {
const packagesUrl = `${CONTEXT7_BASE_URL}/api/projects`;
const packagesData = await makeContext7Request<Project[]>(packagesUrl);
if (!packagesData) {
return {
content: [
{
type: "text",
text: "Failed to retrieve packages data",
},
],
};
}
const projects = packagesData || [];
if (projects.length === 0) {
return {
content: [
{
type: "text",
text: "No packages available",
},
],
};
}
const formattedProjects = projects.map(formatProject);
const projectsText = `${formattedProjects.length} available packages:\n\n${formattedProjects.join("\n")}`;
return {
content: [
{
type: "text",
text: projectsText,
},
],
};
}
);
server.tool(
"get-package-context",
"Get a specific package's context based on it's documentation",
{
packageName: z.string().describe("Name of the package to retrieve context for"),
tokens: z.number().min(5000).optional().describe("Number of tokens to retrieve context for"),
topic: z.string().optional().describe("Topic of search to rerank context for"),
},
async ({ packageName, tokens = 5000, topic = "" }) => {
try {
let contextURL = `${CONTEXT7_BASE_URL}/${packageName}/llm.txt`;
const params = [];
if (tokens) {
params.push(`tokens=${tokens}`);
}
if (topic) {
params.push(`topic=${encodeURIComponent(topic)}`);
}
if (params.length > 0) {
contextURL += `?${params.join("&")}`;
}
const response = await fetch(contextURL);
if (!response.ok) {
if (response.status === 404) {
return {
content: [
{
type: "text",
text: "Project not found or not finalized.",
},
],
};
}
throw new Error(`HTTP error! status: ${response.status}`);
}
const text = await response.text();
if (!text || text === "No content available" || text === "No context data available") {
return {
content: [
{
type: "text",
text: "No context data available",
},
],
};
}
return {
content: [
{
type: "text",
text: text,
},
],
};
} catch (error) {
console.error("Error fetching package context:", error);
return {
content: [
{
type: "text",
text: `Failed to retrieve context for project: ${packageName}`,
},
],
};
}
}
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Context7 MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});

36
src/lib/types.ts Normal file
View File

@ -0,0 +1,36 @@
export interface ProjectSettings {
title: string;
project: string;
folders: string[];
docsRepoUrl: string;
}
export interface Version {
lastUpdate: string;
state: "initial" | "parsed" | "finalized" | "invalid_docs" | "error" | "stop" | "delete";
parseDuration: number;
totalTokens: number;
totalSnippets: number;
averageTokens: number;
}
export interface Project {
settings: ProjectSettings;
version: Version;
}
export interface CodeListElement {
language: string;
code: string;
}
export interface CodeSnippet {
codeTitle: string;
codeDescription: string;
codeLanguage: string;
codeTokens: number;
codeId: string;
pageTitle: string;
codeList: CodeListElement[];
relavance: number;
}