@upstash/context7-mcp 1.0.29 → 1.0.31-canary-20251124145014
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -46
- package/dist/index.js +17 -10
- package/dist/lib/api.js +64 -52
- package/dist/lib/encryption.js +5 -2
- package/dist/lib/types.js +7 -1
- package/dist/lib/utils.js +17 -0
- package/package.json +54 -1
package/README.md
CHANGED
|
@@ -280,6 +280,72 @@ Or you can directly edit MCP servers configuration:
|
|
|
280
280
|
|
|
281
281
|
</details>
|
|
282
282
|
|
|
283
|
+
<details>
|
|
284
|
+
<summary><b>Install in Zed</b></summary>
|
|
285
|
+
|
|
286
|
+
It can be installed via [Zed Extensions](https://zed.dev/extensions?query=Context7) or you can add this to your Zed `settings.json`. See [Zed Context Server docs](https://zed.dev/docs/assistant/context-servers) for more info.
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"context_servers": {
|
|
291
|
+
"Context7": {
|
|
292
|
+
"source": "custom",
|
|
293
|
+
"command": "npx",
|
|
294
|
+
"args": ["-y", "@upstash/context7-mcp", "--api-key", "YOUR_API_KEY"]
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
</details>
|
|
301
|
+
|
|
302
|
+
<details>
|
|
303
|
+
<summary><b>Install in Augment Code</b></summary>
|
|
304
|
+
|
|
305
|
+
To configure Context7 MCP in Augment Code, you can use either the graphical interface or manual configuration.
|
|
306
|
+
|
|
307
|
+
### **A. Using the Augment Code UI**
|
|
308
|
+
|
|
309
|
+
1. Click the hamburger menu.
|
|
310
|
+
2. Select **Settings**.
|
|
311
|
+
3. Navigate to the **Tools** section.
|
|
312
|
+
4. Click the **+ Add MCP** button.
|
|
313
|
+
5. Enter the following command:
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
npx -y @upstash/context7-mcp@latest
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
6. Name the MCP: **Context7**.
|
|
320
|
+
7. Click the **Add** button.
|
|
321
|
+
|
|
322
|
+
Once the MCP server is added, you can start using Context7's up-to-date code documentation features directly within Augment Code.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### **B. Manual Configuration**
|
|
327
|
+
|
|
328
|
+
1. Press Cmd/Ctrl Shift P or go to the hamburger menu in the Augment panel
|
|
329
|
+
2. Select Edit Settings
|
|
330
|
+
3. Under Advanced, click Edit in settings.json
|
|
331
|
+
4. Add the server configuration to the `mcpServers` array in the `augment.advanced` object
|
|
332
|
+
|
|
333
|
+
```json
|
|
334
|
+
"augment.advanced": {
|
|
335
|
+
"mcpServers": [
|
|
336
|
+
{
|
|
337
|
+
"name": "context7",
|
|
338
|
+
"command": "npx",
|
|
339
|
+
"args": ["-y", "@upstash/context7-mcp", "--api-key", "YOUR_API_KEY"]
|
|
340
|
+
}
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Once the MCP server is added, restart your editor. If you receive any errors, check the syntax to make sure closing brackets or commas are not missing.
|
|
346
|
+
|
|
347
|
+
</details>
|
|
348
|
+
|
|
283
349
|
<details>
|
|
284
350
|
<summary><b>Install in Kilo Code</b></summary>
|
|
285
351
|
|
|
@@ -307,6 +373,7 @@ If a server is defined in both places, the **project-level configuration overrid
|
|
|
307
373
|
`https://mcp.context7.com/mcp`
|
|
308
374
|
|
|
309
375
|
**Headers → Add Header**
|
|
376
|
+
|
|
310
377
|
- **Key:** `Authorization`
|
|
311
378
|
- **Value:** `Bearer YOUR_API_KEY`
|
|
312
379
|
|
|
@@ -351,69 +418,38 @@ Kilo Code will automatically detect and load the configuration.
|
|
|
351
418
|
</details>
|
|
352
419
|
|
|
353
420
|
<details>
|
|
354
|
-
<summary><b>Install in
|
|
421
|
+
<summary><b>Install in Google Antigravity</b></summary>
|
|
355
422
|
|
|
356
|
-
|
|
423
|
+
Add this to your Antigravity MCP config file. See [Antigravity MCP docs](https://antigravity.google/docs/mcp) for more info.
|
|
424
|
+
|
|
425
|
+
#### Google Antigravity Remote Server Connection
|
|
357
426
|
|
|
358
427
|
```json
|
|
359
428
|
{
|
|
360
|
-
"
|
|
361
|
-
"
|
|
362
|
-
"
|
|
363
|
-
"
|
|
364
|
-
|
|
429
|
+
"mcpServers": {
|
|
430
|
+
"context7": {
|
|
431
|
+
"serverUrl": "https://mcp.context7.com/mcp",
|
|
432
|
+
"headers": {
|
|
433
|
+
"CONTEXT7_API_KEY": "YOUR_API_KEY"
|
|
434
|
+
}
|
|
365
435
|
}
|
|
366
436
|
}
|
|
367
437
|
}
|
|
368
438
|
```
|
|
369
439
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
<details>
|
|
373
|
-
<summary><b>Install in Augment Code</b></summary>
|
|
374
|
-
|
|
375
|
-
To configure Context7 MCP in Augment Code, you can use either the graphical interface or manual configuration.
|
|
376
|
-
|
|
377
|
-
### **A. Using the Augment Code UI**
|
|
378
|
-
|
|
379
|
-
1. Click the hamburger menu.
|
|
380
|
-
2. Select **Settings**.
|
|
381
|
-
3. Navigate to the **Tools** section.
|
|
382
|
-
4. Click the **+ Add MCP** button.
|
|
383
|
-
5. Enter the following command:
|
|
384
|
-
|
|
385
|
-
```
|
|
386
|
-
npx -y @upstash/context7-mcp@latest
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
6. Name the MCP: **Context7**.
|
|
390
|
-
7. Click the **Add** button.
|
|
391
|
-
|
|
392
|
-
Once the MCP server is added, you can start using Context7's up-to-date code documentation features directly within Augment Code.
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
### **B. Manual Configuration**
|
|
397
|
-
|
|
398
|
-
1. Press Cmd/Ctrl Shift P or go to the hamburger menu in the Augment panel
|
|
399
|
-
2. Select Edit Settings
|
|
400
|
-
3. Under Advanced, click Edit in settings.json
|
|
401
|
-
4. Add the server configuration to the `mcpServers` array in the `augment.advanced` object
|
|
440
|
+
#### Google Antigravity Local Server Connection
|
|
402
441
|
|
|
403
442
|
```json
|
|
404
|
-
|
|
405
|
-
"mcpServers":
|
|
406
|
-
{
|
|
407
|
-
"name": "context7",
|
|
443
|
+
{
|
|
444
|
+
"mcpServers": {
|
|
445
|
+
"context7": {
|
|
408
446
|
"command": "npx",
|
|
409
447
|
"args": ["-y", "@upstash/context7-mcp", "--api-key", "YOUR_API_KEY"]
|
|
410
448
|
}
|
|
411
|
-
|
|
449
|
+
}
|
|
412
450
|
}
|
|
413
451
|
```
|
|
414
452
|
|
|
415
|
-
Once the MCP server is added, restart your editor. If you receive any errors, check the syntax to make sure closing brackets or commas are not missing.
|
|
416
|
-
|
|
417
453
|
</details>
|
|
418
454
|
|
|
419
455
|
<details>
|
|
@@ -1253,6 +1289,24 @@ Once configured, Context7 tools will be available in your droid sessions. Type `
|
|
|
1253
1289
|
|
|
1254
1290
|
</details>
|
|
1255
1291
|
|
|
1292
|
+
<details>
|
|
1293
|
+
<summary><b>Install in Emdash</b></summary>
|
|
1294
|
+
|
|
1295
|
+
[Emdash](https://github.com/generalaction/emdash) is an orchestration layer for running multiple coding agents in parallel. Provider-agnostic, worktree-isolated, and local-first. Emdash supports Context7 MCP to enable Context7 for your agents.
|
|
1296
|
+
|
|
1297
|
+
**What Emdash provides:**
|
|
1298
|
+
|
|
1299
|
+
- Global toggle: Settings → MCP → "Enable Context7 MCP"
|
|
1300
|
+
- Per-workspace enable: The Context7 button in the ProviderBar (off by default). First click enables it for that workspace. Clicking again disables it.
|
|
1301
|
+
- ProviderBar: The Context7 button shows status, a short explanation, and a link to docs
|
|
1302
|
+
|
|
1303
|
+
**What you still need to do:**
|
|
1304
|
+
Configure your coding agent (Codex, Claude Code, Cursor, etc.) to connect to Context7 MCP. Emdash does not modify your agent's config. See the respective MCP configuration sections above for your agent (e.g., OpenAI Codex, Claude Code, Cursor).
|
|
1305
|
+
|
|
1306
|
+
See the [Emdash repository](https://github.com/generalaction/emdash) for more information.
|
|
1307
|
+
|
|
1308
|
+
</details>
|
|
1309
|
+
|
|
1256
1310
|
## 🔨 Available Tools
|
|
1257
1311
|
|
|
1258
1312
|
Context7 MCP provides the following tools that LLMs can use:
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { searchLibraries, fetchLibraryDocumentation } from "./lib/api.js";
|
|
6
6
|
import { formatSearchResults } from "./lib/utils.js";
|
|
7
|
+
import { DOCUMENTATION_MODES } from "./lib/types.js";
|
|
7
8
|
import express from "express";
|
|
8
9
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
9
10
|
import { Command } from "commander";
|
|
@@ -69,7 +70,7 @@ function getClientIp(req) {
|
|
|
69
70
|
}
|
|
70
71
|
const server = new McpServer({
|
|
71
72
|
name: "Context7",
|
|
72
|
-
version: "1.0.
|
|
73
|
+
version: "1.0.13",
|
|
73
74
|
}, {
|
|
74
75
|
instructions: "Use this server to retrieve up-to-date documentation and code examples for any library.",
|
|
75
76
|
});
|
|
@@ -116,7 +117,7 @@ For ambiguous queries, request clarification before proceeding with a best-guess
|
|
|
116
117
|
};
|
|
117
118
|
}
|
|
118
119
|
const resultsText = formatSearchResults(searchResponse);
|
|
119
|
-
const responseText = `Available Libraries
|
|
120
|
+
const responseText = `Available Libraries:
|
|
120
121
|
|
|
121
122
|
Each result includes:
|
|
122
123
|
- Library ID: Context7-compatible identifier (format: /org/project)
|
|
@@ -143,11 +144,16 @@ ${resultsText}`;
|
|
|
143
144
|
});
|
|
144
145
|
server.registerTool("get-library-docs", {
|
|
145
146
|
title: "Get Library Docs",
|
|
146
|
-
description: "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, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query.",
|
|
147
|
+
description: "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, UNLESS the user explicitly provides a library ID in the format '/org/project' or '/org/project/version' in their query. Use mode='code' (default) for API references and code examples, or mode='info' for conceptual guides, narrative information, and architectural questions.",
|
|
147
148
|
inputSchema: {
|
|
148
149
|
context7CompatibleLibraryID: z
|
|
149
150
|
.string()
|
|
150
151
|
.describe("Exact Context7-compatible library ID (e.g., '/mongodb/docs', '/vercel/next.js', '/supabase/supabase', '/vercel/next.js/v14.3.0-canary.87') retrieved from 'resolve-library-id' or directly from user query in the format '/org/project' or '/org/project/version'."),
|
|
152
|
+
mode: z
|
|
153
|
+
.enum(["code", "info"])
|
|
154
|
+
.optional()
|
|
155
|
+
.default("code")
|
|
156
|
+
.describe("Documentation mode: 'code' for API references and code examples (default), 'info' for conceptual guides, narrative information, and architectural questions."),
|
|
151
157
|
topic: z
|
|
152
158
|
.string()
|
|
153
159
|
.optional()
|
|
@@ -160,10 +166,10 @@ server.registerTool("get-library-docs", {
|
|
|
160
166
|
.optional()
|
|
161
167
|
.describe("Page number for pagination (start: 1, default: 1). If the context is not sufficient, try page=2, page=3, page=4, etc. with the same topic."),
|
|
162
168
|
},
|
|
163
|
-
}, async ({ context7CompatibleLibraryID, page = 1, topic }) => {
|
|
169
|
+
}, async ({ context7CompatibleLibraryID, mode = DOCUMENTATION_MODES.CODE, page = 1, topic }) => {
|
|
164
170
|
const ctx = requestContext.getStore();
|
|
165
171
|
const apiKey = ctx?.apiKey || globalApiKey;
|
|
166
|
-
const fetchDocsResponse = await fetchLibraryDocumentation(context7CompatibleLibraryID, {
|
|
172
|
+
const fetchDocsResponse = await fetchLibraryDocumentation(context7CompatibleLibraryID, mode, {
|
|
167
173
|
page,
|
|
168
174
|
limit: DEFAULT_RESULTS_LIMIT,
|
|
169
175
|
topic,
|
|
@@ -268,11 +274,8 @@ async function main() {
|
|
|
268
274
|
});
|
|
269
275
|
});
|
|
270
276
|
const startServer = (port, maxAttempts = 10) => {
|
|
271
|
-
const httpServer = app.listen(port
|
|
272
|
-
|
|
273
|
-
console.error(`Context7 Documentation MCP Server running on HTTP at http://localhost:${actualPort}/mcp`);
|
|
274
|
-
});
|
|
275
|
-
httpServer.on("error", (err) => {
|
|
277
|
+
const httpServer = app.listen(port);
|
|
278
|
+
httpServer.once("error", (err) => {
|
|
276
279
|
if (err.code === "EADDRINUSE" && port < initialPort + maxAttempts) {
|
|
277
280
|
console.warn(`Port ${port} is in use, trying port ${port + 1}...`);
|
|
278
281
|
startServer(port + 1, maxAttempts);
|
|
@@ -282,6 +285,10 @@ async function main() {
|
|
|
282
285
|
process.exit(1);
|
|
283
286
|
}
|
|
284
287
|
});
|
|
288
|
+
httpServer.once("listening", () => {
|
|
289
|
+
actualPort = port;
|
|
290
|
+
console.error(`Context7 Documentation MCP Server running on HTTP at http://localhost:${actualPort}/mcp`);
|
|
291
|
+
});
|
|
285
292
|
};
|
|
286
293
|
startServer(initialPort);
|
|
287
294
|
}
|
package/dist/lib/api.js
CHANGED
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
import { generateHeaders } from "./encryption.js";
|
|
2
2
|
import { ProxyAgent, setGlobalDispatcher } from "undici";
|
|
3
|
+
import { DOCUMENTATION_MODES } from "./types.js";
|
|
4
|
+
import { maskApiKey } from "./utils.js";
|
|
3
5
|
const CONTEXT7_API_BASE_URL = "https://context7.com/api";
|
|
4
6
|
const DEFAULT_TYPE = "txt";
|
|
7
|
+
/**
|
|
8
|
+
* Parses a Context7-compatible library ID into its components
|
|
9
|
+
* @param libraryId The library ID (e.g., "/vercel/next.js" or "/vercel/next.js/v14.3.0")
|
|
10
|
+
* @returns Object with username, library, and optional tag
|
|
11
|
+
*/
|
|
12
|
+
function parseLibraryId(libraryId) {
|
|
13
|
+
// Remove leading slash if present
|
|
14
|
+
const cleaned = libraryId.startsWith("/") ? libraryId.slice(1) : libraryId;
|
|
15
|
+
const parts = cleaned.split("/");
|
|
16
|
+
if (parts.length < 2) {
|
|
17
|
+
throw new Error(`Invalid library ID format: ${libraryId}. Expected format: /username/library or /username/library/tag`);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
username: parts[0],
|
|
21
|
+
library: parts[1],
|
|
22
|
+
tag: parts[2], // undefined if not present
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generates appropriate error messages based on HTTP status codes
|
|
27
|
+
* @param errorCode The HTTP error status code
|
|
28
|
+
* @param apiKey Optional API key (used for rate limit message)
|
|
29
|
+
* @returns Error message string
|
|
30
|
+
*/
|
|
31
|
+
function createErrorMessage(errorCode, apiKey) {
|
|
32
|
+
switch (errorCode) {
|
|
33
|
+
case 429:
|
|
34
|
+
return apiKey
|
|
35
|
+
? "Rate limited due to too many requests. Please try again later."
|
|
36
|
+
: "Rate limited due to too many requests. You can create a free API key at https://context7.com/dashboard for higher rate limits.";
|
|
37
|
+
case 404:
|
|
38
|
+
return "The library you are trying to access does not exist. Please try with a different library ID.";
|
|
39
|
+
case 401:
|
|
40
|
+
if (!apiKey) {
|
|
41
|
+
return "Unauthorized. Please provide an API key.";
|
|
42
|
+
}
|
|
43
|
+
return `Unauthorized. Please check your API key. The API key you provided (possibly incorrect) is: ${maskApiKey(apiKey)}. API keys should start with 'ctx7sk'`;
|
|
44
|
+
default:
|
|
45
|
+
return `Failed to fetch documentation. Please try again later. Error code: ${errorCode}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
5
48
|
// Pick up proxy configuration in a variety of common env var names.
|
|
6
49
|
const PROXY_URL = process.env.HTTPS_PROXY ??
|
|
7
50
|
process.env.https_proxy ??
|
|
@@ -30,40 +73,21 @@ if (PROXY_URL && !PROXY_URL.startsWith("$") && /^(http|https):\/\//i.test(PROXY_
|
|
|
30
73
|
*/
|
|
31
74
|
export async function searchLibraries(query, clientIp, apiKey) {
|
|
32
75
|
try {
|
|
33
|
-
const url = new URL(`${CONTEXT7_API_BASE_URL}/
|
|
76
|
+
const url = new URL(`${CONTEXT7_API_BASE_URL}/v2/search`);
|
|
34
77
|
url.searchParams.set("query", query);
|
|
35
78
|
const headers = generateHeaders(clientIp, apiKey);
|
|
36
79
|
const response = await fetch(url, { headers });
|
|
37
80
|
if (!response.ok) {
|
|
38
81
|
const errorCode = response.status;
|
|
39
|
-
|
|
40
|
-
const errorMessage = apiKey
|
|
41
|
-
? "Rate limited due to too many requests. Please try again later."
|
|
42
|
-
: "Rate limited due to too many requests. You can create a free API key at https://context7.com/dashboard for higher rate limits.";
|
|
43
|
-
console.error(errorMessage);
|
|
44
|
-
return {
|
|
45
|
-
results: [],
|
|
46
|
-
error: errorMessage,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
if (errorCode === 401) {
|
|
50
|
-
const errorMessage = "Unauthorized. Please check your API key. The API key you provided (possibly incorrect) is: " +
|
|
51
|
-
apiKey +
|
|
52
|
-
". API keys should start with 'ctx7sk'";
|
|
53
|
-
console.error(errorMessage);
|
|
54
|
-
return {
|
|
55
|
-
results: [],
|
|
56
|
-
error: errorMessage,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const errorMessage = `Failed to search libraries. Please try again later. Error code: ${errorCode}`;
|
|
82
|
+
const errorMessage = createErrorMessage(errorCode, apiKey);
|
|
60
83
|
console.error(errorMessage);
|
|
61
84
|
return {
|
|
62
85
|
results: [],
|
|
63
86
|
error: errorMessage,
|
|
64
87
|
};
|
|
65
88
|
}
|
|
66
|
-
|
|
89
|
+
const searchData = await response.json();
|
|
90
|
+
return searchData;
|
|
67
91
|
}
|
|
68
92
|
catch (error) {
|
|
69
93
|
const errorMessage = `Error searching libraries: ${error}`;
|
|
@@ -74,54 +98,42 @@ export async function searchLibraries(query, clientIp, apiKey) {
|
|
|
74
98
|
/**
|
|
75
99
|
* Fetches documentation context for a specific library
|
|
76
100
|
* @param libraryId The library ID to fetch documentation for
|
|
77
|
-
* @param
|
|
101
|
+
* @param docMode Documentation mode (CODE for API references and code examples, INFO for conceptual guides)
|
|
102
|
+
* @param options Optional request parameters (page, limit, topic)
|
|
78
103
|
* @param clientIp Optional client IP address to include in headers
|
|
79
104
|
* @param apiKey Optional API key for authentication
|
|
80
105
|
* @returns The documentation text or null if the request fails
|
|
81
106
|
*/
|
|
82
|
-
export async function fetchLibraryDocumentation(libraryId, options = {}, clientIp, apiKey) {
|
|
107
|
+
export async function fetchLibraryDocumentation(libraryId, docMode, options = {}, clientIp, apiKey) {
|
|
83
108
|
try {
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
const { username, library, tag } = parseLibraryId(libraryId);
|
|
110
|
+
// Build URL path
|
|
111
|
+
let urlPath = `${CONTEXT7_API_BASE_URL}/v2/docs/${docMode}/${username}/${library}`;
|
|
112
|
+
if (tag) {
|
|
113
|
+
urlPath += `/${tag}`;
|
|
86
114
|
}
|
|
87
|
-
const url = new URL(
|
|
115
|
+
const url = new URL(urlPath);
|
|
116
|
+
url.searchParams.set("type", DEFAULT_TYPE);
|
|
117
|
+
if (options.topic)
|
|
118
|
+
url.searchParams.set("topic", options.topic);
|
|
88
119
|
if (options.page)
|
|
89
120
|
url.searchParams.set("page", options.page.toString());
|
|
90
121
|
if (options.limit)
|
|
91
122
|
url.searchParams.set("limit", options.limit.toString());
|
|
92
|
-
if (options.topic)
|
|
93
|
-
url.searchParams.set("topic", options.topic);
|
|
94
|
-
url.searchParams.set("type", DEFAULT_TYPE);
|
|
95
123
|
const headers = generateHeaders(clientIp, apiKey, { "X-Context7-Source": "mcp-server" });
|
|
96
124
|
const response = await fetch(url, { headers });
|
|
97
125
|
if (!response.ok) {
|
|
98
126
|
const errorCode = response.status;
|
|
99
|
-
|
|
100
|
-
const errorMessage = apiKey
|
|
101
|
-
? "Rate limited due to too many requests. Please try again later."
|
|
102
|
-
: "Rate limited due to too many requests. You can create a free API key at https://context7.com/dashboard for higher rate limits.";
|
|
103
|
-
console.error(errorMessage);
|
|
104
|
-
return errorMessage;
|
|
105
|
-
}
|
|
106
|
-
if (errorCode === 404) {
|
|
107
|
-
const errorMessage = "The library you are trying to access does not exist. Please try with a different library ID.";
|
|
108
|
-
console.error(errorMessage);
|
|
109
|
-
return errorMessage;
|
|
110
|
-
}
|
|
111
|
-
if (errorCode === 401) {
|
|
112
|
-
const errorMessage = "Unauthorized. Please check your API key. The API key you provided (possibly incorrect) is: " +
|
|
113
|
-
apiKey +
|
|
114
|
-
". API keys should start with 'ctx7sk'";
|
|
115
|
-
console.error(errorMessage);
|
|
116
|
-
return errorMessage;
|
|
117
|
-
}
|
|
118
|
-
const errorMessage = `Failed to fetch documentation. Please try again later. Error code: ${errorCode}`;
|
|
127
|
+
const errorMessage = createErrorMessage(errorCode, apiKey);
|
|
119
128
|
console.error(errorMessage);
|
|
120
129
|
return errorMessage;
|
|
121
130
|
}
|
|
122
131
|
const text = await response.text();
|
|
123
132
|
if (!text || text === "No content available" || text === "No context data available") {
|
|
124
|
-
|
|
133
|
+
const suggestion = docMode === DOCUMENTATION_MODES.CODE
|
|
134
|
+
? " Try mode='info' for guides and tutorials."
|
|
135
|
+
: " Try mode='code' for API references and code examples.";
|
|
136
|
+
return `No ${docMode} documentation available for this library.${suggestion}`;
|
|
125
137
|
}
|
|
126
138
|
return text;
|
|
127
139
|
}
|
package/dist/lib/encryption.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { createCipheriv, randomBytes } from "crypto";
|
|
2
|
-
const
|
|
3
|
-
|
|
2
|
+
const DEFAULT_ENCRYPTION_KEY = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
|
|
3
|
+
const ENCRYPTION_KEY = process.env.CLIENT_IP_ENCRYPTION_KEY || DEFAULT_ENCRYPTION_KEY;
|
|
4
4
|
const ALGORITHM = "aes-256-cbc";
|
|
5
|
+
if (ENCRYPTION_KEY === DEFAULT_ENCRYPTION_KEY) {
|
|
6
|
+
console.warn("WARNING: Using default CLIENT_IP_ENCRYPTION_KEY.");
|
|
7
|
+
}
|
|
5
8
|
function validateEncryptionKey(key) {
|
|
6
9
|
// Must be exactly 64 hex characters (32 bytes)
|
|
7
10
|
return /^[0-9a-fA-F]{64}$/.test(key);
|
package/dist/lib/types.js
CHANGED
package/dist/lib/utils.js
CHANGED
|
@@ -58,3 +58,20 @@ export function formatSearchResults(searchResponse) {
|
|
|
58
58
|
const formattedResults = searchResponse.results.map(formatSearchResult);
|
|
59
59
|
return formattedResults.join("\n----------\n");
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Masks an API key by showing only the first 10 characters and last 4 characters.
|
|
63
|
+
* This prevents full API keys from being exposed in logs while maintaining some
|
|
64
|
+
* identifiability for debugging.
|
|
65
|
+
*
|
|
66
|
+
* @param apiKey The API key to mask
|
|
67
|
+
* @returns Masked API key string (e.g., "ctx7sk-abc...xyz1") or "[NO-API-KEY]" if no key provided
|
|
68
|
+
*/
|
|
69
|
+
export function maskApiKey(apiKey) {
|
|
70
|
+
if (apiKey.length <= 14) {
|
|
71
|
+
// If the key is too short to mask meaningfully, just show first part
|
|
72
|
+
return apiKey.substring(0, 7) + "...";
|
|
73
|
+
}
|
|
74
|
+
const firstPart = apiKey.substring(0, 10);
|
|
75
|
+
const lastPart = apiKey.substring(apiKey.length - 4);
|
|
76
|
+
return `${firstPart}...${lastPart}`;
|
|
77
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1,54 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "@upstash/context7-mcp",
|
|
3
|
+
"version": "1.0.31-canary-20251124145014",
|
|
4
|
+
"mcpName": "io.github.upstash/context7",
|
|
5
|
+
"description": "MCP server for Context7",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/upstash/context7.git",
|
|
9
|
+
"directory": "packages/mcp"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"modelcontextprotocol",
|
|
13
|
+
"mcp",
|
|
14
|
+
"context7",
|
|
15
|
+
"vibe-coding",
|
|
16
|
+
"developer tools",
|
|
17
|
+
"documentation",
|
|
18
|
+
"context"
|
|
19
|
+
],
|
|
20
|
+
"author": "abdush",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"bin": {
|
|
24
|
+
"context7-mcp": "dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/upstash/context7/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/upstash/context7#readme",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.17.5",
|
|
37
|
+
"@types/express": "^5.0.4",
|
|
38
|
+
"commander": "^14.0.0",
|
|
39
|
+
"express": "^5.1.0",
|
|
40
|
+
"undici": "^6.6.3",
|
|
41
|
+
"zod": "^3.24.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.13.14",
|
|
45
|
+
"typescript": "^5.8.2"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc && chmod 755 dist/index.js",
|
|
49
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
50
|
+
"dev": "tsc --watch",
|
|
51
|
+
"start": "node dist/index.js --transport http",
|
|
52
|
+
"pack-mcpb": "pnpm install && pnpm run build && rm -rf node_modules && pnpm install --prod && mv mcpb/.mcpbignore .mcpbignore && mv mcpb/manifest.json manifest.json && mv public/icon.png icon.png && mcpb validate manifest.json && mcpb pack . mcpb/context7.mcpb && mv manifest.json mcpb/manifest.json && mv .mcpbignore mcpb/.mcpbignore && mv icon.png public/icon.png && bun install"
|
|
53
|
+
}
|
|
54
|
+
}
|