#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { searchLibraries, fetchLibraryDocumentation } from "./lib/api.js"; import { formatSearchResults } from "./lib/utils.js"; import dotenv from "dotenv"; // Load environment variables from .env file if present dotenv.config(); // Get DEFAULT_MINIMUM_TOKENS from environment variable or use default let DEFAULT_MINIMUM_TOKENS = 10000; if (process.env.DEFAULT_MINIMUM_TOKENS) { const parsedValue = parseInt(process.env.DEFAULT_MINIMUM_TOKENS, 10); if (!isNaN(parsedValue) && parsedValue > 0) { DEFAULT_MINIMUM_TOKENS = parsedValue; } else { console.warn( `Warning: Invalid DEFAULT_MINIMUM_TOKENS value provided in environment variable. Using default value of 10000` ); } } // Create server instance const server = new McpServer({ name: "Context7", description: "Retrieves up-to-date documentation and code examples for any library.", version: "1.0.6", capabilities: { resources: {}, tools: {}, }, }); // Register Context7 tools server.tool( "resolve-library-id", `Resolves a package name to a Context7-compatible library ID and returns a list of matching libraries. You MUST call this function before 'get-library-docs' to obtain a valid Context7-compatible library ID. When selecting the best match, consider: - Name similarity to the query - Description relevance - Code Snippet count (documentation coverage) - GitHub Stars (popularity) Return the selected library ID and explain your choice. If there are multiple good matches, mention this but proceed with the most relevant one.`, { libraryName: z .string() .describe("Library name to search for and retrieve a Context7-compatible library ID."), }, async ({ libraryName }) => { const searchResponse = await searchLibraries(libraryName); if (!searchResponse || !searchResponse.results) { return { content: [ { type: "text", text: "Failed to retrieve library documentation data from Context7", }, ], }; } if (searchResponse.results.length === 0) { return { content: [ { type: "text", text: "No documentation libraries available", }, ], }; } const resultsText = formatSearchResults(searchResponse); return { content: [ { type: "text", text: `Available Libraries (top matches): Each result includes: - Library ID: Context7-compatible identifier (format: /org/repo) - Name: Library or package name - Description: Short summary - Code Snippets: Number of available code examples - GitHub Stars: Popularity indicator For best results, select libraries based on name match, popularity (stars), snippet coverage, and relevance to your use case. --- ${resultsText}`, }, ], }; } ); server.tool( "get-library-docs", "Fetches up-to-date documentation for a library. You must call 'resolve-library-id' first to obtain the exact Context7-compatible library ID required to use this tool.", { context7CompatibleLibraryID: z .string() .describe( "Exact Context7-compatible library ID (e.g., 'mongodb/docs', 'vercel/nextjs') retrieved from 'resolve-library-id'." ), topic: z .string() .optional() .describe("Topic to focus documentation on (e.g., 'hooks', 'routing')."), tokens: z .preprocess((val) => (typeof val === "string" ? Number(val) : val), z.number()) .transform((val) => (val < DEFAULT_MINIMUM_TOKENS ? DEFAULT_MINIMUM_TOKENS : val)) .optional() .describe( `Maximum number of tokens of documentation to retrieve (default: ${DEFAULT_MINIMUM_TOKENS}). Higher values provide more context but consume more tokens.` ), }, async ({ context7CompatibleLibraryID, tokens = DEFAULT_MINIMUM_TOKENS, topic = "" }) => { // Extract folders parameter if present in the ID let folders = ""; let libraryId = context7CompatibleLibraryID; if (context7CompatibleLibraryID.includes("?folders=")) { const [id, foldersParam] = context7CompatibleLibraryID.split("?folders="); libraryId = id; folders = foldersParam; } const documentationText = await fetchLibraryDocumentation(libraryId, { tokens, topic, folders, }); if (!documentationText) { return { content: [ { type: "text", text: "Documentation not found or not finalized for this library. This might have happened because you used an invalid Context7-compatible library ID. To get a valid Context7-compatible library ID, use the 'resolve-library-id' with the package name you wish to retrieve documentation for.", }, ], }; } return { content: [ { type: "text", text: documentationText, }, ], }; } ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Context7 Documentation MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });