get_opportunity
Retrieve complete details for a specific government opportunity from your last enriched search, including strategic fit memo, political context, description, agency, and application URL.
Instructions
Get full details for a specific opportunity from the last enriched search. Returns the strategic fit memo, political context memo, full description, application URL, agency, keywords, and status. FREE - no extra credit cost. You must run search_enriched first.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes | The result number from the enriched search (1-10) |
Implementation Reference
- src/index.ts:223-224 (registration)Registration of the 'get_opportunity' tool via McpServer.registerTool, defining its name, description, and input schema.
server.registerTool( 'get_opportunity', - src/index.ts:228-234 (schema)Input schema for get_opportunity: requires a single 'number' parameter (1-10) validated with Zod.
inputSchema: { number: z .number() .min(1) .max(10) .describe('The result number from the enriched search (1-10)'), }, - src/index.ts:236-297 (handler)Handler function for get_opportunity: retrieves a cached opportunity by index (1-based) from the last enriched search result. Validates cache exists, checks bounds, then formats and returns the full opportunity details including strategic fit memo, political context, description, application URL, and keywords.
async ({ number }) => { if (cachedMatches.length === 0) { return { content: [{ type: 'text' as const, text: 'No search results available. Run **search_enriched** first to get matches, then use this tool to view details.', }], isError: true, } } const index = number - 1 if (index >= cachedMatches.length) { return { content: [{ type: 'text' as const, text: `Result #${number} does not exist. The last search returned ${cachedMatches.length} results. Choose a number between 1 and ${cachedMatches.length}.`, }], isError: true, } } const m = cachedMatches[index] const parts = [ `# ${number}. ${m.displayTitle}`, '', `**Match Score:** ${m.matchPercentage}%`, '', `## Opportunity Details`, `**Official Title:** ${m.title}`, `**Agency:** ${m.agency}`, `**Region:** ${m.region}${m.country ? ` (${m.country})` : ''}`, `**Type:** ${m.funding_type ?? 'Unknown'}`, `**Estimated Value:** ${m.estimated_value ?? 'Not disclosed'}`, `**Deadline:** ${m.deadline ?? 'Unknown'}`, `**Status:** ${m.status}`, `**Last Verified:** ${m.last_verified_at ?? 'Unknown'}`, '', `## Strategic Fit Memo`, (m.context as string) ?? 'Not available', '', `## Political Context Memo`, (m.politicalContext as string) ?? 'Not available', ] if (m.description) { parts.push('', `## Description`, m.description as string) } if (m.application_url) { parts.push('', `## Apply`, `${m.application_url}`) } if (m.keywords && (m.keywords as string[]).length > 0) { parts.push('', `**Keywords:** ${(m.keywords as string[]).join(', ')}`) } return { content: [{ type: 'text' as const, text: parts.join('\n') }], } }, - src/index.ts:48-48 (helper)The cachedMatches global variable stores enriched search results so get_opportunity can serve full details without an extra API call
let cachedMatches: Array<Record<string, unknown>> = []