websets_manager
Manage content websets: create, search, enhance with AI, and set notifications for web content collections using Exa's platform.
Instructions
Manage content websets, searches, and data enhancements using Exa's platform. This single tool handles creating websets of web content, searching within them, enhancing data with AI, and setting up notifications. Much simpler than using separate tools for each operation.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | What you want to do | |
| resourceId | No | ID of the webset, search, or enhancement to work with | |
| webset | No | ||
| search | No | ||
| enhancement | No | ||
| notification | No | ||
| update | No | ||
| query | No |
Implementation Reference
- src/tools/websetsManager.ts:148-269 (handler)The main tool registration object for 'websets_manager'. Contains the handler function that routes to sub-operations (create_webset, list_websets, search_webset, enhance_content, etc.) based on the 'operation' field.
toolRegistry["websets_manager"] = { name: "websets_manager", description: "Manage content websets, searches, and data enhancements using Exa's platform. This single tool handles creating websets of web content, searching within them, enhancing data with AI, and setting up notifications. Much simpler than using separate tools for each operation.", schema: WebsetsManagerSchema.shape, category: ToolCategory.WEBSETS, service: ServiceType.WEBSETS, handler: async (args) => { const { operation, resourceId, webset, search, enhancement, notification, update, query: params } = args; const requestId = `websets_manager-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`; const logger = createRequestLogger(requestId, 'websets_manager'); logger.start(`${operation} operation`); try { // Get API key from environment (no more repetition in parameters!) const apiKey = process.env.EXA_API_KEY; if (!apiKey) { throw new Error("EXA_API_KEY environment variable is required"); } const services = createServices(apiKey); // Route to appropriate operation handler switch (operation) { case "create_webset": return await handleCreateWebset(services, webset, logger); case "list_websets": return await handleListWebsets(services, params, logger); case "get_webset_status": return await handleGetWebsetStatus(services, resourceId, logger); case "update_webset": return await handleUpdateWebset(services, resourceId, update, logger); case "delete_webset": return await handleDeleteWebset(services, resourceId, logger); case "cancel_webset": return await handleCancelWebset(services, resourceId, logger); case "search_webset": return await handleSearchWebset(services, resourceId, search, logger); case "get_search_results": return await handleGetSearchResults(services, resourceId, logger); case "cancel_search": return await handleCancelSearch(services, resourceId, logger); case "enhance_content": return await handleEnhanceContent(services, resourceId, enhancement, logger); case "get_enhancement_results": return await handleGetEnhancementResults(services, resourceId, logger); case "delete_enhancement": return await handleDeleteEnhancement(services, resourceId, logger); case "cancel_enhancement": return await handleCancelEnhancement(services, resourceId, logger); case "setup_notifications": return await handleSetupNotifications(services, notification, logger); case "list_notifications": return await handleListNotifications(services, params, logger); case "get_notification_details": return await handleGetNotificationDetails(services, resourceId, logger); case "remove_notifications": return await handleRemoveNotifications(services, resourceId, logger); case "list_activities": return await handleListActivities(services, params, logger); case "get_activity_details": return await handleGetActivityDetails(services, resourceId, logger); case "list_content_items": return await handleListContentItems(services, resourceId, params, logger); default: throw new Error(`Unknown operation: ${operation}`); } } catch (error) { logger.error(error); let errorMessage: string; if (error instanceof Error) { errorMessage = error.message; } else if (typeof error === 'object' && error !== null) { // Try to extract meaningful information from the error object errorMessage = JSON.stringify(error, null, 2); } else if (error === undefined) { errorMessage = 'An unknown error occurred'; } else { errorMessage = String(error); } logger.log(`Operation failed: ${errorMessage}`); return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, operation, error: errorMessage, help: getOperationHelp(operation) }, null, 2) }], isError: true }; } }, enabled: true }; - src/tools/websetsManager.ts:22-145 (schema)Input validation schemas for the tool. Includes BaseOperationSchema (defining all 19 operations), WebsetParamsSchema, SearchParamsSchema, EnhancementParamsSchema, NotificationParamsSchema, UpdateParamsSchema, QueryParamsSchema, and the combined WebsetsManagerSchema.
const BaseOperationSchema = z.object({ operation: z.enum([ // Content Webset Operations "create_webset", "list_websets", "get_webset_status", "update_webset", "delete_webset", "cancel_webset", // Content Search Operations "search_webset", "get_search_results", "cancel_search", // Data Enhancement Operations "enhance_content", "get_enhancement_results", "delete_enhancement", "cancel_enhancement", // Notification Operations "setup_notifications", "list_notifications", "get_notification_details", "remove_notifications", // Activity Monitoring "list_activities", "get_activity_details", // Content Management "list_content_items" ]).describe("What you want to do"), // Target resource ID (when working with existing resources) resourceId: z.string().optional().describe("ID of the webset, search, or enhancement to work with") }); // Content Webset Parameters const WebsetParamsSchema = z.object({ searchQuery: z.string().describe("What you want to find (required for new websets)"), description: z.string().optional().describe("Human-readable description of this webset"), advanced: z.object({ resultCount: z.number().min(1).max(1000).default(10).describe("How many items to find"), focusArea: z.enum(["company"]).optional().describe("What type of entities to focus on"), criteria: z.array(z.object({ description: z.string().describe("Specific requirement or filter") })).optional().describe("Additional requirements for filtering results"), externalReference: z.string().optional().describe("Your own reference ID for tracking"), tags: z.record(z.string().max(1000)).optional().describe("Custom labels for organization") }).optional().describe("Advanced webset settings") }).optional(); // Search Parameters const SearchParamsSchema = z.object({ query: z.string().describe("What to search for within the webset"), maxResults: z.number().min(1).max(100).default(10).describe("Maximum number of results to return"), advanced: z.object({ focusArea: z.object({ type: z.literal("company").describe("Currently supports companies only") }).optional().describe("What type of entities to focus search on"), requirements: z.array(z.object({ description: z.string().describe("Specific requirement for search results") })).optional().describe("Additional search requirements"), tags: z.record(z.string().max(1000)).optional().describe("Custom labels for this search"), waitForResults: z.boolean().optional().describe("Automatically poll until search completes (max 1 minute)") }).optional().describe("Advanced search settings") }).optional(); // Enhancement Parameters const EnhancementParamsSchema = z.object({ task: z.string().describe("What kind of additional data you want to extract or analyze"), advanced: z.object({ outputFormat: z.enum(["text", "date", "number", "options", "email", "phone"]).default("text").describe("Expected format of the results"), waitForResults: z.boolean().optional().describe("Automatically poll until enhancement completes (max 2 minutes)"), choices: z.array(z.object({ label: z.string().describe("Possible answer option") })).optional().describe("Predefined answer choices (only for 'options' format)"), tags: z.record(z.string().max(1000)).optional().describe("Custom labels for this enhancement") }).optional().describe("Advanced enhancement settings") }).optional(); // Notification Parameters const NotificationParamsSchema = z.object({ webhookUrl: z.string().url().describe("URL where notifications should be sent"), events: z.array(z.enum([ "webset.created", "webset.deleted", "webset.paused", "webset.idle", "webset.search.created", "webset.search.completed", "webset.search.updated", "webset.search.canceled", "webset.export.created", "webset.export.completed", "webset.item.created", "webset.item.enriched" ])).describe("Which events you want to be notified about"), advanced: z.object({ tags: z.record(z.string().max(1000)).optional().describe("Custom labels for this notification setup") }).optional().describe("Advanced notification settings") }).optional(); // Update Parameters const UpdateParamsSchema = z.object({ description: z.string().optional().describe("New description for the webset"), tags: z.record(z.string().max(1000)).optional().describe("Updated custom labels") }).optional(); // Query Parameters (for listing operations) const QueryParamsSchema = z.object({ limit: z.number().min(1).max(100).default(25).describe("Maximum number of items to return"), offset: z.number().min(0).default(0).describe("Number of items to skip"), status: z.enum(["pending", "processing", "completed", "failed", "cancelled"]).optional().describe("Filter by status") }).optional(); // Combined schema const WebsetsManagerSchema = BaseOperationSchema.extend({ // Operation-specific parameters webset: WebsetParamsSchema, search: SearchParamsSchema, enhancement: EnhancementParamsSchema, notification: NotificationParamsSchema, update: UpdateParamsSchema, query: QueryParamsSchema }); - src/index.ts:124-143 (registration)Tools are registered with the MCP server in registerTools(). The websets_manager tool is pulled from toolRegistry and registered via this.server.tool(name, description, schema, handler).
private registerTools(): void { // Create our simplified tool registry with three tools const simplifiedRegistry = { web_search_exa: toolRegistry["web_search_exa"], websets_manager: toolRegistry["websets_manager"], websets_guide: websetsGuideTool, knowledge_graph: toolRegistry["knowledge_graph"], }; // Register our tools Object.values(simplifiedRegistry).forEach(tool => { if (tool) { this.server.tool( tool.name, tool.description, tool.schema, tool.handler ); } }); - src/index.ts:18-19 (registration)Importing './tools/websetsManager.js' at module level triggers the tool's self-registration into toolRegistry via the side-effect import pattern.
import "./tools/websetsManager.js"; import "./tools/knowledgeGraph.js"; - src/tools/websetsManager.ts:515-536 (helper)Helper function getOperationHelp() that provides user-friendly guidance for operations when errors occur.
function getOperationHelp(operation: string): string[] { const helpMap: Record<string, string[]> = { "create_webset": [ "Provide a searchQuery describing what content you want to collect", "Optionally specify resultCount in advanced settings", "Webset creation takes 10-15 minutes to complete" ], "search_webset": [ "Provide resourceId of the webset to search within", "Provide query describing what to find in the webset" ], "enhance_content": [ "Provide resourceId of the webset to enhance", "Provide task describing what additional data you want to extract" ] }; return helpMap[operation] || [ "Check the operation name and required parameters", "Ensure resourceId is provided when working with existing resources" ]; }