ask_chatgpt
Send a prompt to ChatGPT and receive a response. Choose between regular models with adjustable temperature or reasoning models with configurable effort and verbosity.
Instructions
Ask ChatGPT a question and get a response. Supports both regular models (with temperature) and reasoning models (with effort/verbosity).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | The prompt to send to ChatGPT | |
| model | No | The model to use (default: from OPENAI_DEFAULT_MODEL env var or gpt-5). Unless specified by the user, you should not set this model parameter. Supported models: gpt-5, gpt-5-mini, gpt-5-nano, o3, o3-pro, o4-mini, gpt-4.1, gpt-4.1-mini | gpt-5 |
| system | No | System prompt to set context and behavior for the AI | |
| temperature | No | Temperature for response generation (0-2). Not available for reasoning models (gpt-5, o1, o3, etc.) | |
| effort | No | Reasoning effort level: minimal, low, medium, high (default: from REASONING_EFFORT env var). For reasoning models only. | |
| verbosity | No | Output verbosity level: low, medium, high (default: from VERBOSITY env var). For reasoning models only. | |
| searchContextSize | No | Search context size: low, medium, high (default: from SEARCH_CONTEXT_SIZE env var). For reasoning models only. | |
| maxTokens | No | Maximum number of output tokens | |
| maxRetries | No | Maximum number of API retry attempts (default: from OPENAI_MAX_RETRIES env var or 3) | |
| timeoutMs | No | Request timeout in milliseconds. Auto-adjusts based on effort level: high=300s, medium=120s, low/minimal=60s. Can be overridden with OPENAI_API_TIMEOUT env var. | |
| useStreaming | No | Force streaming mode to prevent timeouts during long reasoning tasks. Defaults to auto (true for medium/high effort reasoning models). |
Implementation Reference
- src/index.ts:107-245 (handler)Main handler for the 'ask_chatgpt' tool call. Extracts parameters, determines timeout/streaming based on effort level, and calls either chatStream() for streaming or chat() for non-streaming via ChatGPTClient.
server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name !== 'ask_chatgpt') { throw new Error(`Unknown tool: ${request.params.name}`); } const { prompt, model = process.env.OPENAI_DEFAULT_MODEL || 'gpt-5', system, temperature = 0.7, effort = (process.env.REASONING_EFFORT as | 'minimal' | 'low' | 'medium' | 'high') || undefined, verbosity = (process.env.VERBOSITY as 'low' | 'medium' | 'high') || undefined, searchContextSize = (process.env.SEARCH_CONTEXT_SIZE as | 'low' | 'medium' | 'high') || undefined, maxTokens, maxRetries = parseInt(process.env.OPENAI_MAX_RETRIES || '3'), timeoutMs: userTimeoutMs, useStreaming, } = request.params.arguments as { prompt: string; model?: string; system?: string; temperature?: number; effort?: 'minimal' | 'low' | 'medium' | 'high'; verbosity?: 'low' | 'medium' | 'high'; searchContextSize?: 'low' | 'medium' | 'high'; maxTokens?: number; maxRetries?: number; timeoutMs?: number; useStreaming?: boolean; }; // Dynamic timeout based on effort level for reasoning models let timeoutMs = userTimeoutMs; if (timeoutMs === undefined) { if (effort === 'high') { // 5 minutes for high effort reasoning timeoutMs = parseInt(process.env.OPENAI_API_TIMEOUT || '300000'); } else if (effort === 'medium') { // 2 minutes for medium effort reasoning timeoutMs = parseInt(process.env.OPENAI_API_TIMEOUT || '120000'); } else { // Default 1 minute for low/minimal effort or regular models timeoutMs = parseInt(process.env.OPENAI_API_TIMEOUT || '60000'); } } // Use streaming for reasoning models with medium/high effort to prevent timeouts // Can be overridden by useStreaming parameter const shouldUseStreaming = useStreaming !== undefined ? useStreaming : effort === 'medium' || effort === 'high'; const chatRequest: ChatRequest = { prompt, model: model as SupportedModel, system, temperature, effort, verbosity, searchContextSize, maxTokens, maxRetries, timeoutMs, stream: shouldUseStreaming, // Use streaming for long-running reasoning tasks }; try { if (shouldUseStreaming) { // Use streaming to prevent timeout, but accumulate response for MCP console.error('Starting streaming request for reasoning model...'); let accumulatedContent = ''; let chunkCount = 0; for await (const chunk of client.chatStream(chatRequest)) { if (!chunk.done && chunk.content) { accumulatedContent += chunk.content; chunkCount++; // Show progress to prevent timeout perception if (chunkCount % 10 === 0) { console.error( `Received ${chunkCount} chunks, accumulated ${accumulatedContent.length} characters...` ); } } if (chunk.done) { console.error( `Streaming completed. Total chunks: ${chunkCount}, content length: ${accumulatedContent.length}` ); break; } } return { content: [ { type: 'text', text: accumulatedContent, }, ], }; } else { // Use regular non-streaming mode const response = await client.chat(chatRequest); return { content: [ { type: 'text', text: response.content, }, ], }; } } catch (error: any) { console.error('OpenAI API error:', error); // Provide helpful timeout message for reasoning models if (error.message?.includes('timeout') && effort === 'high') { throw new Error( `Request timed out after ${timeoutMs}ms. Reasoning models with high effort can take several minutes. ` + `Consider increasing OPENAI_API_TIMEOUT environment variable or setting a higher timeoutMs value. ` + `Current timeout: ${timeoutMs}ms` ); } throw new Error(`Failed to call ChatGPT: ${error.message}`); } }); - src/index.ts:28-102 (schema)Tool registration with inputSchema for 'ask_chatgpt'. Defines all parameters: prompt (required), model, system, temperature, effort, verbosity, searchContextSize, maxTokens, maxRetries, timeoutMs, useStreaming.
tools: [ { name: 'ask_chatgpt', description: 'Ask ChatGPT a question and get a response. Supports both regular models (with temperature) and reasoning models (with effort/verbosity).', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'The prompt to send to ChatGPT', }, model: { type: 'string', // 注意書きが無いとClaude Codeは古いモデルを使おうとする。アホ。 description: `The model to use (default: from OPENAI_DEFAULT_MODEL env var or gpt-5). Unless specified by the user, you should not set this model parameter. Supported models: ${ALL_SUPPORTED_MODELS.join(', ')}`, enum: [...ALL_SUPPORTED_MODELS], default: process.env.OPENAI_DEFAULT_MODEL || 'gpt-5', }, system: { type: 'string', description: 'System prompt to set context and behavior for the AI', }, temperature: { type: 'number', description: 'Temperature for response generation (0-2). Not available for reasoning models (gpt-5, o1, o3, etc.)', default: 0.7, }, effort: { type: 'string', description: 'Reasoning effort level: minimal, low, medium, high (default: from REASONING_EFFORT env var). For reasoning models only.', enum: ['minimal', 'low', 'medium', 'high'], default: process.env.REASONING_EFFORT || undefined, }, verbosity: { type: 'string', description: 'Output verbosity level: low, medium, high (default: from VERBOSITY env var). For reasoning models only.', enum: ['low', 'medium', 'high'], default: process.env.VERBOSITY || undefined, }, searchContextSize: { type: 'string', description: 'Search context size: low, medium, high (default: from SEARCH_CONTEXT_SIZE env var). For reasoning models only.', enum: ['low', 'medium', 'high'], default: process.env.SEARCH_CONTEXT_SIZE || undefined, }, maxTokens: { type: 'number', description: 'Maximum number of output tokens', }, maxRetries: { type: 'number', description: 'Maximum number of API retry attempts (default: from OPENAI_MAX_RETRIES env var or 3)', default: parseInt(process.env.OPENAI_MAX_RETRIES || '3'), }, timeoutMs: { type: 'number', description: 'Request timeout in milliseconds. Auto-adjusts based on effort level: high=300s, medium=120s, low/minimal=60s. Can be overridden with OPENAI_API_TIMEOUT env var.', }, useStreaming: { type: 'boolean', description: 'Force streaming mode to prevent timeouts during long reasoning tasks. Defaults to auto (true for medium/high effort reasoning models).', }, }, required: ['prompt'], }, }, - src/index.ts:26-105 (registration)Registers the 'ask_chatgpt' tool via ListToolsRequestSchema handler on the MCP server, returning the tool definition with name and inputSchema.
server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'ask_chatgpt', description: 'Ask ChatGPT a question and get a response. Supports both regular models (with temperature) and reasoning models (with effort/verbosity).', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'The prompt to send to ChatGPT', }, model: { type: 'string', // 注意書きが無いとClaude Codeは古いモデルを使おうとする。アホ。 description: `The model to use (default: from OPENAI_DEFAULT_MODEL env var or gpt-5). Unless specified by the user, you should not set this model parameter. Supported models: ${ALL_SUPPORTED_MODELS.join(', ')}`, enum: [...ALL_SUPPORTED_MODELS], default: process.env.OPENAI_DEFAULT_MODEL || 'gpt-5', }, system: { type: 'string', description: 'System prompt to set context and behavior for the AI', }, temperature: { type: 'number', description: 'Temperature for response generation (0-2). Not available for reasoning models (gpt-5, o1, o3, etc.)', default: 0.7, }, effort: { type: 'string', description: 'Reasoning effort level: minimal, low, medium, high (default: from REASONING_EFFORT env var). For reasoning models only.', enum: ['minimal', 'low', 'medium', 'high'], default: process.env.REASONING_EFFORT || undefined, }, verbosity: { type: 'string', description: 'Output verbosity level: low, medium, high (default: from VERBOSITY env var). For reasoning models only.', enum: ['low', 'medium', 'high'], default: process.env.VERBOSITY || undefined, }, searchContextSize: { type: 'string', description: 'Search context size: low, medium, high (default: from SEARCH_CONTEXT_SIZE env var). For reasoning models only.', enum: ['low', 'medium', 'high'], default: process.env.SEARCH_CONTEXT_SIZE || undefined, }, maxTokens: { type: 'number', description: 'Maximum number of output tokens', }, maxRetries: { type: 'number', description: 'Maximum number of API retry attempts (default: from OPENAI_MAX_RETRIES env var or 3)', default: parseInt(process.env.OPENAI_MAX_RETRIES || '3'), }, timeoutMs: { type: 'number', description: 'Request timeout in milliseconds. Auto-adjusts based on effort level: high=300s, medium=120s, low/minimal=60s. Can be overridden with OPENAI_API_TIMEOUT env var.', }, useStreaming: { type: 'boolean', description: 'Force streaming mode to prevent timeouts during long reasoning tasks. Defaults to auto (true for medium/high effort reasoning models).', }, }, required: ['prompt'], }, }, ], }; }); - src/core/chatgpt-client.ts:36-175 (helper)ChatGPTClient class providing chat() and chatStream() methods that call the OpenAI API. chatStream() yields StreamChunks for progressive output; chat() returns a ChatResponse. Both use callResponsesAPI/streamResponsesAPI private methods which include web_search tool integration.
export class ChatGPTClient { private openai: OpenAI; constructor(apiKey?: string) { this.openai = new OpenAI({ apiKey: apiKey || process.env.OPENAI_API_KEY, }); } private createOpenAIClient(request: ChatRequest): OpenAI { const options: ClientOptions = { apiKey: this.openai.apiKey, }; if (request.maxRetries !== undefined) { options.maxRetries = request.maxRetries; } if (request.timeoutMs !== undefined) { options.timeout = request.timeoutMs; } return new OpenAI(options); } private validateRequest(request: ChatRequest): void { if (!this.openai.apiKey) { throw new Error('OPENAI_API_KEY environment variable is not set'); } if (!isSupportedModel(request.model)) { throw new Error( `Unsupported model "${request.model}". Supported models are: ${ALL_SUPPORTED_MODELS.join(', ')}` ); } } async chat(request: ChatRequest): Promise<ChatResponse> { this.validateRequest(request); const client = this.createOpenAIClient(request); try { return await this.callResponsesAPI(request, client, false); } catch (error: any) { throw new Error(`Failed to call ChatGPT: ${error.message}`); } } async *chatStream(request: ChatRequest): AsyncGenerator<StreamChunk> { this.validateRequest(request); const client = this.createOpenAIClient(request); try { yield* this.streamResponsesAPI(request, client); } catch (error: any) { throw new Error(`Failed to call ChatGPT: ${error.message}`); } } private async callResponsesAPI( request: ChatRequest, client: OpenAI, stream: boolean ): Promise<ChatResponse> { const requestBody: any = { 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 as any).output_text || ''; return { content: responseContent, model: request.model, usage: (completion as any).usage, }; } private async *streamResponsesAPI( request: ChatRequest, client: OpenAI ): AsyncGenerator<StreamChunk> { const requestBody: any = { 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 as any) { if (event.type === 'response.output_text.delta') { yield { content: event.delta, done: false, }; } } yield { content: '', done: true, }; } } - src/utils/models.ts:1-40 (helper)Model constants and type definitions. Defines REASONING_MODELS, REGULAR_MODELS, ALL_SUPPORTED_MODELS, and helper functions isSupportedModel/isReasoningModel. Also exports ChatParams and ReasoningParams interfaces.
export const REASONING_MODELS = [ 'gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'o3', 'o3-pro', 'o4-mini', ] as const; export const REGULAR_MODELS = ['gpt-4.1', 'gpt-4.1-mini'] as const; export const ALL_SUPPORTED_MODELS = [ ...REASONING_MODELS, ...REGULAR_MODELS, ] as const; export type SupportedModel = (typeof ALL_SUPPORTED_MODELS)[number]; export function isReasoningModel(model: string): boolean { return REASONING_MODELS.includes(model as any); } export function isSupportedModel(model: string): model is SupportedModel { return ALL_SUPPORTED_MODELS.includes(model as any); } export interface ReasoningParams { effort?: 'minimal' | 'low' | 'medium' | 'high'; verbosity?: 'low' | 'medium' | 'high'; } export interface ChatParams { model: string; prompt: string; temperature?: number; stream?: boolean; maxTokens?: number; reasoning?: ReasoningParams; }