search-grants
Search for government grants using keywords to find funding opportunities, eligibility details, and deadlines.
Instructions
Search for government grants based on keywords
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query for grants (e.g., 'Artificial intelligence', 'Climate change') | |
| page | No | Page number for pagination (default: 1) | |
| grantsPerPage | No | Number of grants per page (default: 3) |
Implementation Reference
- src/index.ts:149-228 (handler)Executes the 'search-grants' tool: parses arguments, queries the grants.gov API via POST request with filters and pagination, handles responses, errors, and formats output using helper functions.if (request.params.name === "search-grants") { try { const args = request.params.arguments as { query?: string; page?: number; grantsPerPage?: number } | undefined; const searchQuery = args?.query ? String(args.query).trim() : "Artificial intelligence"; const page = args?.page || 1; const grantsPerPage = args?.grantsPerPage || 3; console.error(`Debug: Starting search with query: ${searchQuery}, page: ${page}, grantsPerPage: ${grantsPerPage}`); const url = 'https://api.simpler.grants.gov/v1/opportunities/search'; const searchData = { filters: { opportunity_status: { one_of: ["forecasted", "posted"] } }, pagination: { order_by: "opportunity_id", page_offset: page, page_size: grantsPerPage, sort_direction: "descending" }, query: searchQuery }; const response = await axios.post<GrantsAPIResponse>(url, searchData, { headers: { 'accept': 'application/json', 'X-Auth': API_KEY, 'Content-Type': 'application/json' } }); if (!response.data?.data) { return { content: [{ type: "text", text: "No results found or invalid response format" }] }; } const grants = response.data.data; if (grants.length === 0) { return { content: [{ type: "text", text: `No grants found matching "${searchQuery}"` }] }; } const summaryText = createSummary(grants, searchQuery, page, grantsPerPage); return { content: [{ type: "text", text: summaryText }] }; } catch (error) { console.error('Debug: Error occurred:', error); if (axios.isAxiosError(error)) { console.error('Debug: Axios error response:', error.response?.data); return { content: [{ type: "text", text: `API Error: ${error.response?.data?.message || error.message}` }] }; } return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}` }] }; } }
- src/index.ts:126-143 (schema)Input schema definition for the 'search-grants' tool, specifying query (required), page, and grantsPerPage parameters.inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query for grants (e.g., 'Artificial intelligence', 'Climate change')" }, page: { type: "number", description: "Page number for pagination (default: 1)" }, grantsPerPage: { type: "number", description: "Number of grants per page (default: 3)" } }, required: ["query"] }
- src/index.ts:121-146 (registration)Registers the 'search-grants' tool in the MCP server's listTools handler, including its name, description, and input schema.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [{ name: "search-grants", description: "Search for government grants based on keywords", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query for grants (e.g., 'Artificial intelligence', 'Climate change')" }, page: { type: "number", description: "Page number for pagination (default: 1)" }, grantsPerPage: { type: "number", description: "Number of grants per page (default: 3)" } }, required: ["query"] } }] }; });
- src/index.ts:54-97 (helper)Helper function to format detailed information for a single grant into a structured text block.const formatGrantDetails = (grant: Grant) => { return ` OPPORTUNITY DETAILS ------------------ Title: ${grant.opportunity_title} Opportunity Number: ${grant.opportunity_number} Agency: ${grant.agency_name} (${grant.agency_code}) Status: ${grant.opportunity_status} FUNDING INFORMATION ------------------ Award Floor: ${grant.summary.award_floor ? `$${grant.summary.award_floor.toLocaleString()}` : 'Not specified'} Award Ceiling: ${grant.summary.award_ceiling ? `$${grant.summary.award_ceiling.toLocaleString()}` : 'Not specified'} Category: ${grant.category} DATES AND DEADLINES ------------------ Posted Date: ${grant.summary.post_date || 'N/A'} Close Date: ${grant.summary.close_date || 'N/A'} CONTACT INFORMATION ------------------ Agency Contact: ${grant.summary.agency_contact_description || 'Not provided'} Email: ${grant.summary.agency_email_address || 'Not provided'} Phone: ${grant.summary.agency_phone_number || 'Not provided'} ELIGIBILITY ------------------ ${grant.summary.applicant_eligibility_description ? grant.summary.applicant_eligibility_description.replace(/<[^>]*>/g, '').trim() : 'Eligibility information not provided'} ADDITIONAL INFORMATION ------------------ More Details URL: ${grant.summary.additional_info_url || 'Not available'} Description: ${grant.summary.summary_description ? grant.summary.summary_description.replace(/<[^>]*>/g, '').trim() : 'No description available'} ========================================================================== `; };
- src/index.ts:99-119 (helper)Helper function to create a paginated summary of grant search results, using formatGrantDetails for each grant.const createSummary = (grants: Grant[], searchQuery: string, page: number = 1, grantsPerPage: number = 3) => { const startIdx = (page - 1) * grantsPerPage; const endIdx = startIdx + grantsPerPage; const displayedGrants = grants.slice(startIdx, endIdx); const totalPages = Math.ceil(grants.length / grantsPerPage); return `Search Results for "${searchQuery}": OVERVIEW -------- Total Grants Found: ${grants.length} Showing grants ${startIdx + 1} to ${Math.min(endIdx, grants.length)} of ${grants.length} Page ${page} of ${totalPages} DETAILED GRANT LISTINGS ---------------------- ${displayedGrants.map(formatGrantDetails).join("\n")} Note: Showing ${grantsPerPage} grants per page. Total grants available: ${grants.length} `; };