#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { WebSearchTool } from "./tools/webSearch.js";
import { loadConfig, validateConfig } from "./utils/config.js";
import { formatError } from "./utils/errors.js";
import {
ModelTypeSchema,
UserLocationSchema,
} from "./schemas.js";
import { SEARCH_MODELS, DEFAULT_MODEL } from "./constants.js";
const SERVER_NAME = "openai-websearch-mcp";
const SERVER_VERSION = "1.0.0";
async function main() {
try {
const config = loadConfig();
validateConfig(config);
const webSearchTool = new WebSearchTool(
config.openaiApiKey,
config.defaultModel
);
const server = new McpServer(
{
name: SERVER_NAME,
version: SERVER_VERSION,
},
{
capabilities: {
tools: {},
},
}
);
server.registerTool(
"openai_web_search",
{
description:
"Intelligent web search with reasoning model support. Use this tool to search for current information, facts, news, or any topic that requires up-to-date knowledge from the web.",
inputSchema: {
input: z.string().describe("The search query or question to search for"),
model: ModelTypeSchema
.optional()
.describe(
`AI model to use. Available models: ${SEARCH_MODELS.join(", ")}. Default: ${DEFAULT_MODEL}.`
),
user_location: UserLocationSchema
.optional()
.describe("Optional location information for localized search results. Must include type='approximate' along with country, city, and/or region."),
},
},
async (args) => {
try {
const result = await webSearchTool.execute(args as any);
const content: any[] = [
{
type: "text",
text: result.text,
},
];
if (result.sources && result.sources.length > 0) {
const sourcesText = "\n\nSources:\n" + result.sources
.map((s, i) => `${i + 1}. ${s.title}\n ${s.url}`)
.join("\n");
content.push({
type: "text",
text: sourcesText,
});
}
return {
content,
};
} catch (error) {
const errorMessage = formatError(error);
console.error(`Error executing web search: ${errorMessage}`);
return {
content: [
{
type: "text",
text: `Error: ${errorMessage}`,
},
],
isError: true,
};
}
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
console.error(`Default model: ${config.defaultModel}`);
} catch (error) {
console.error("Fatal error during server initialization:");
console.error(formatError(error));
process.exit(1);
}
}
main().catch((error) => {
console.error("Unhandled error in main:");
console.error(formatError(error));
process.exit(1);
});