search_opportunities
Find Australian Government ICT procurement opportunities across multiple marketplaces using keyword searches and filters to identify relevant contracts.
Instructions
Search for procurement opportunities on BuyICT with optional filters
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keyword | No | Search term to filter opportunities | |
| marketplace | No | Filter by marketplace code (e.g., PCS, SMP, CMP, LH, TMP, DC, HMP) | |
| page_size | No | Number of results per page (default: 15) | |
| page | No | Page number (default: 1) |
Implementation Reference
- src/servicenow-client.ts:119-155 (handler)The core handler function for the search_opportunities tool, which fetches the opportunities page from ServiceNow and extracts the relevant widget data containing opportunities.async searchOpportunities( params: OpportunitySearchParams ): Promise<OpportunitySearchResult> { // TODO: Implement actual API call once we discover the correct endpoint // For now, this is a placeholder that returns the structure console.warn( 'searchOpportunities is not fully implemented yet. ' + 'Need to discover the correct API endpoint for fetching opportunity data.' ); // Try fetching the page to get widget data const pageData = await this.fetchOpportunitiesPage(); // Extract widget data const opportunitiesWidget = this.findWidget(pageData, 'Opportunities V2'); if (opportunitiesWidget?.data) { const widgetData = opportunitiesWidget.data; return { items: widgetData.pageItems || [], total_count: widgetData.totalItems || 0, page: params.page || 1, page_size: params.page_size || 15, total_pages: Math.ceil((widgetData.totalItems || 0) / (params.page_size || 15)) }; } return { items: [], total_count: 0, page: 1, page_size: 15, total_pages: 0 }; }
- src/index.ts:56-82 (schema)Input schema defining the parameters for the search_opportunities tool: keyword, marketplace, page_size, and page.inputSchema: { type: 'object', properties: { keyword: { type: 'string', description: 'Search term to filter opportunities' }, marketplace: { type: 'string', description: 'Filter by marketplace code (e.g., PCS, SMP, CMP, LH, TMP, DC, HMP)', enum: config.marketplaces.map(m => m.code) }, page_size: { type: 'number', description: 'Number of results per page (default: 15)', minimum: 1, maximum: 100, default: 15 }, page: { type: 'number', description: 'Page number (default: 1)', minimum: 1, default: 1 } } }
- src/index.ts:53-83 (registration)Tool object registration in the TOOLS array used for listing available tools via ListToolsRequest.{ name: 'search_opportunities', description: 'Search for procurement opportunities on BuyICT with optional filters', inputSchema: { type: 'object', properties: { keyword: { type: 'string', description: 'Search term to filter opportunities' }, marketplace: { type: 'string', description: 'Filter by marketplace code (e.g., PCS, SMP, CMP, LH, TMP, DC, HMP)', enum: config.marketplaces.map(m => m.code) }, page_size: { type: 'number', description: 'Number of results per page (default: 15)', minimum: 1, maximum: 100, default: 15 }, page: { type: 'number', description: 'Page number (default: 1)', minimum: 1, default: 1 } } } },
- src/index.ts:138-150 (registration)Dispatch logic in the CallToolRequest handler that routes search_opportunities calls to the ServiceNowClient handler.case 'search_opportunities': { const params = args as OpportunitySearchParams; const result = await snClient.searchOpportunities(params); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; }
- src/servicenow-client.ts:186-199 (helper)Helper utility function used within searchOpportunities to locate the 'Opportunities V2' widget in the ServiceNow page response.private findWidget(pageData: ServiceNowPageResponse, widgetName: string) { for (const container of pageData.result.containers || []) { for (const row of container.rows || []) { for (const column of row.columns || []) { for (const widgetInstance of column.widgets || []) { if (widgetInstance.widget.name === widgetName) { return widgetInstance.widget; } } } } } return null; }