@upstash/context7-mcp 2.2.1 → 2.2.3

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.
Files changed (2) hide show
  1. package/dist/index.js +54 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -160,6 +160,9 @@ IMPORTANT: Do not call this tool more than 3 times per question. If you cannot f
160
160
  },
161
161
  annotations: {
162
162
  readOnlyHint: true,
163
+ destructiveHint: false,
164
+ openWorldHint: true,
165
+ idempotentHint: true,
163
166
  },
164
167
  }, async ({ query, libraryName }) => {
165
168
  const searchResponse = await searchLibraries(query, libraryName, getClientContext());
@@ -194,7 +197,7 @@ server.registerTool("query-docs", {
194
197
 
195
198
  You must call 'Resolve Context7 Library ID' tool 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.
196
199
 
197
- Workflow: call first without researchMode. If that doesn't answer the question, retry with researchMode: true. Do not call each tool more than 3 times per question`,
200
+ Workflow: call first without researchMode. If that doesn't answer the question, retry with researchMode: true. Do not call each tool more than 3 times per question.`,
198
201
  inputSchema: {
199
202
  libraryId: z
200
203
  .string()
@@ -205,21 +208,54 @@ Workflow: call first without researchMode. If that doesn't answer the question,
205
208
  researchMode: z
206
209
  .boolean()
207
210
  .optional()
208
- .describe(`Retry the query with deep research: spins up sandboxed agents that read the actual source repos and runs a live web search, then synthesizes a fresh answer. Set true on retry if you weren't satisfied with the first answer and want a more thorough one. Requires an API key you can get one free at https://context7.com.`),
211
+ .describe(`Retry the query with deep research: spins up sandboxed agents that read the actual source repos and runs a live web search, then synthesizes a fresh answer. Set true on retry if you weren't satisfied with the first answer and want a more thorough one. Requires an API key. You can get one free at https://context7.com.`),
209
212
  },
210
213
  annotations: {
211
214
  readOnlyHint: true,
215
+ destructiveHint: false,
216
+ openWorldHint: true,
217
+ idempotentHint: true,
212
218
  },
213
- }, async ({ query, libraryId, researchMode }) => {
214
- const response = await fetchLibraryContext({ query, libraryId, researchMode }, getClientContext());
215
- return {
216
- content: [
217
- {
218
- type: "text",
219
- text: response.data,
220
- },
221
- ],
222
- };
219
+ }, async ({ query, libraryId, researchMode }, { sendNotification, _meta }) => {
220
+ // Emit periodic progress notifications while the upstream call is in flight.
221
+ // MCP clients that opt into resetTimeoutOnProgress (e.g. opencode) reset their
222
+ // request timer on each notification, which keeps long-running tools (notably
223
+ // researchMode) alive past the SDK's default 60s wall-clock timeout. Clients
224
+ // that don't pass a progressToken simply never see these, so behavior is unchanged.
225
+ const progressToken = _meta?.progressToken;
226
+ let progressInterval;
227
+ if (researchMode && progressToken !== undefined) {
228
+ let progress = 0;
229
+ progressInterval = setInterval(() => {
230
+ progress += 1;
231
+ sendNotification({
232
+ method: "notifications/progress",
233
+ params: {
234
+ progressToken,
235
+ progress,
236
+ message: "Researching documentation...",
237
+ },
238
+ }).catch(() => {
239
+ // Notifications are best-effort; swallow transport errors so the tool
240
+ // call itself isn't aborted by a notification write failure.
241
+ });
242
+ }, 20_000);
243
+ }
244
+ try {
245
+ const response = await fetchLibraryContext({ query, libraryId, researchMode }, getClientContext());
246
+ return {
247
+ content: [
248
+ {
249
+ type: "text",
250
+ text: response.data,
251
+ },
252
+ ],
253
+ };
254
+ }
255
+ finally {
256
+ if (progressInterval)
257
+ clearInterval(progressInterval);
258
+ }
223
259
  });
224
260
  async function main() {
225
261
  const transportType = TRANSPORT_TYPE;
@@ -307,9 +343,14 @@ async function main() {
307
343
  clientInfo: extractClientInfoFromUserAgent(req.headers["user-agent"]),
308
344
  transport: "http",
309
345
  };
346
+ // Use SSE responses for tool calls (enableJsonResponse: false). The SDK then
347
+ // flushes response headers immediately after parsing the request rather than
348
+ // buffering until the tool returns. This is required for long-running tools
349
+ // (e.g. researchMode) because some MCP HTTP clients cap the underlying fetch
350
+ // at 60s waiting for headers, even though the per-tool timeout is much higher.
310
351
  const transport = new StreamableHTTPServerTransport({
311
352
  sessionIdGenerator: undefined,
312
- enableJsonResponse: true,
353
+ enableJsonResponse: false,
313
354
  });
314
355
  res.on("close", () => {
315
356
  transport.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upstash/context7-mcp",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "mcpName": "io.github.upstash/context7",
5
5
  "description": "MCP server for Context7",
6
6
  "repository": {