@nekobato/chatgpt-websearch-mcp
Version:
A local MCP stdio server that provides access to the OpenAI (ChatGPT) API with web search capabilities for Claude Code and other MCP clients.
120 lines (119 loc) • 4.02 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatGPTClient = void 0;
const openai_1 = __importDefault(require("openai"));
const models_js_1 = require("../utils/models.js");
class ChatGPTClient {
openai;
constructor(apiKey) {
this.openai = new openai_1.default({
apiKey: apiKey || process.env.OPENAI_API_KEY,
});
}
createOpenAIClient(request) {
const options = {
apiKey: this.openai.apiKey,
};
if (request.maxRetries !== undefined) {
options.maxRetries = request.maxRetries;
}
if (request.timeoutMs !== undefined) {
options.timeout = request.timeoutMs;
}
return new openai_1.default(options);
}
validateRequest(request) {
if (!this.openai.apiKey) {
throw new Error('OPENAI_API_KEY environment variable is not set');
}
if (!(0, models_js_1.isSupportedModel)(request.model)) {
throw new Error(`Unsupported model "${request.model}". Supported models are: ${models_js_1.ALL_SUPPORTED_MODELS.join(', ')}`);
}
}
async chat(request) {
this.validateRequest(request);
const client = this.createOpenAIClient(request);
try {
return await this.callResponsesAPI(request, client, false);
}
catch (error) {
throw new Error(`Failed to call ChatGPT: ${error.message}`);
}
}
async *chatStream(request) {
this.validateRequest(request);
const client = this.createOpenAIClient(request);
try {
yield* this.streamResponsesAPI(request, client);
}
catch (error) {
throw new Error(`Failed to call ChatGPT: ${error.message}`);
}
}
async callResponsesAPI(request, client, stream) {
const requestBody = {
model: request.model,
input: request.prompt,
stream,
tools: [
{
type: 'web_search',
search_context_size: request.searchContextSize ||
process.env.SEARCH_CONTEXT_SIZE ||
'medium',
},
],
tool_choice: 'auto',
parallel_tool_calls: true,
};
if (request.effort) {
requestBody.reasoning = { effort: request.effort };
}
if (request.verbosity) {
requestBody.text = { verbosity: request.verbosity };
}
if (request.maxTokens) {
requestBody.max_output_tokens = request.maxTokens;
}
const completion = await client.responses.create(requestBody);
const responseContent = completion.output_text || '';
return {
content: responseContent,
model: request.model,
usage: completion.usage,
};
}
async *streamResponsesAPI(request, client) {
const requestBody = {
model: request.model,
input: request.prompt,
stream: true,
};
if (request.effort) {
requestBody.reasoning = { effort: request.effort };
}
if (request.verbosity) {
requestBody.text = { verbosity: request.verbosity };
}
if (request.maxTokens) {
requestBody.max_output_tokens = request.maxTokens;
}
const completion = await client.responses.create(requestBody);
for await (const event of completion) {
if (event.type === 'response.output_text.delta') {
yield {
content: event.delta,
done: false,
};
}
}
yield {
content: '',
done: true,
};
}
}
exports.ChatGPTClient = ChatGPTClient;