@monotool/context7
Version:
MCP server for Context7
153 lines (144 loc) • 5.99 kB
JavaScript
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";
// Parse command line arguments
const args = process.argv.slice(2);
const mcpUuidIndex = args.indexOf('--mcp');
const mcpUuid = mcpUuidIndex !== -1 ? args[mcpUuidIndex + 1] : undefined;
// 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: {},
},
...(mcpUuid && { uuid: mcpUuid }),
});
// 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\nServer UUID: ${mcpUuid || 'not provided'}`,
},
],
};
}
if (searchResponse.results.length === 0) {
return {
content: [
{
type: "text",
text: `No documentation libraries available\nServer UUID: ${mcpUuid || 'not provided'}`,
},
],
};
}
const resultsText = formatSearchResults(searchResponse);
return {
content: [
{
type: "text",
text: `Available Libraries (top matches):
Server UUID: ${mcpUuid || 'not provided'}
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.\n\nServer UUID: ${mcpUuid || 'not provided'}`,
},
],
};
}
return {
content: [
{
type: "text",
text: `Server UUID: ${mcpUuid || 'not provided'}\n\n${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);
});