Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/good-geese-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@upstash/context7-mcp": patch
---

Remove masked API key display from unauthorized error responses
3 changes: 1 addition & 2 deletions packages/mcp/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { SearchResponse } from "./types.js";
import { generateHeaders } from "./encryption.js";
import { ProxyAgent, setGlobalDispatcher } from "undici";
import { DocumentationMode, DOCUMENTATION_MODES } from "./types.js";
import { maskApiKey } from "./utils.js";

const CONTEXT7_API_BASE_URL = "https://context7.com/api";
const DEFAULT_TYPE = "txt";
Expand Down Expand Up @@ -52,7 +51,7 @@ function createErrorMessage(errorCode: number, apiKey?: string): string {
if (!apiKey) {
return "Unauthorized. Please provide an API key.";
}
return `Unauthorized. Please check your API key. The API key you provided (possibly incorrect) is: ${maskApiKey(apiKey)}. API keys should start with 'ctx7sk'`;
return `Unauthorized. Please check your API key. API keys should start with 'ctx7sk'`;
default:
return `Failed to fetch documentation. Please try again later. Error code: ${errorCode}`;
}
Expand Down
19 changes: 0 additions & 19 deletions packages/mcp/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,3 @@ export function formatSearchResults(searchResponse: SearchResponse): string {
const formattedResults = searchResponse.results.map(formatSearchResult);
return formattedResults.join("\n----------\n");
}

/**
* Masks an API key by showing only the first 10 characters and last 4 characters.
* This prevents full API keys from being exposed in logs while maintaining some
* identifiability for debugging.
*
* @param apiKey The API key to mask
* @returns Masked API key string (e.g., "ctx7sk-abc...xyz1") or "[NO-API-KEY]" if no key provided
*/
export function maskApiKey(apiKey: string): string {
if (apiKey.length <= 14) {
// If the key is too short to mask meaningfully, just show first part
return apiKey.substring(0, 7) + "...";
}

const firstPart = apiKey.substring(0, 10);
const lastPart = apiKey.substring(apiKey.length - 4);
return `${firstPart}...${lastPart}`;
}