public-charity-check
Verify if a nonprofit qualifies as a public charity with IRS tax-deductible status using its EIN number to confirm donation eligibility.
Instructions
Verify if a nonprofit organization qualifies as a "public charity" according to the IRS. Public charities are eligible to receive tax-deductible donations under section 501(c)(3).
This tool returns:
- Whether the organization is classified as a public charity
- Tax deductibility status for donations
- EIN confirmation
Use this tool to quickly verify if donations to an organization are tax-deductible.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ein | Yes | The charity's EIN (Tax ID) in format XX-XXXXXXX or XXXXXXXXX (e.g., '13-1837418' or '131837418') |
Implementation Reference
- src/tools/public-charity-check.ts:33-104 (handler)The primary handler function `handlePublicCharityCheck` that implements the core logic of the tool. It validates the input EIN using Zod schema, checks rate limits, queries the charityAPIClient, processes the response, formats it with `formatPublicCharityCheckResponse`, and returns MCP-formatted result or error.export async function handlePublicCharityCheck(args: unknown): Promise<CallToolResult> { try { logger.debug("Public charity check requested", { args }); // Validate input const input = PublicCharityCheckInputSchema.parse(args); logger.debug("Input validated", { ein: input.ein }); // Check rate limit if (!(await rateLimiter.checkRateLimit('public_charity_check'))) { const resetTime = rateLimiter.getResetTime('public_charity_check'); const resetDate = new Date(resetTime).toISOString(); return { content: [ { type: "text", text: `Rate limit exceeded for public charity check. Please try again after ${resetDate}.`, } as TextContent, ], isError: true, }; } // Make API call logger.info("Checking public charity status", { ein: input.ein }); const response = await charityAPIClient.checkPublicCharity(input.ein); if (!response.data) { throw new CharityAPIError("No data returned from CharityAPI", 404); } // Format response const result = response.data; const output: PublicCharityCheckOutput = { ein: result.ein || input.ein, isPublicCharity: result.public_charity || false, deductible: result.public_charity || false, }; // Create formatted text response const formattedText = formatPublicCharityCheckResponse(output); logger.info("Public charity check completed successfully", { ein: input.ein, isPublicCharity: output.isPublicCharity }); return { content: [ { type: "text", text: formattedText, } as TextContent, ], }; } catch (error) { logger.error("Public charity check failed", { args, error }); const mcpError = handleMCPError(error); return { content: [ { type: "text", text: mcpError.message, } as TextContent, ], isError: true, }; } }
- The tool definition `PUBLIC_CHARITY_CHECK_TOOL` exporting the name, description, and inputSchema required for MCP protocol compliance.export const PUBLIC_CHARITY_CHECK_TOOL = { name: "public-charity-check", description: ` Verify if a nonprofit organization qualifies as a "public charity" according to the IRS. Public charities are eligible to receive tax-deductible donations under section 501(c)(3). This tool returns: - Whether the organization is classified as a public charity - Tax deductibility status for donations - EIN confirmation Use this tool to quickly verify if donations to an organization are tax-deductible. `.trim(), inputSchema: { type: "object" as const, properties: { ein: { type: "string", description: "The charity's EIN (Tax ID) in format XX-XXXXXXX or XXXXXXXXX (e.g., '13-1837418' or '131837418')", pattern: "^\\d{2}-?\\d{7}$", }, }, required: ["ein"], }, };
- src/tools/index.ts:9-55 (registration)The `registerAllTools` function that registers the public-charity-check tool (imported at line 4) into the MCP server for both `listTools` (line 15) and `callTool` handlers (lines 29-30).export function registerAllTools(server: Server) { try { // Register tools list handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ CHARITY_LOOKUP_TOOL, PUBLIC_CHARITY_CHECK_TOOL, CHARITY_SEARCH_TOOL, LIST_ORGANIZATIONS_TOOL, ], })); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case CHARITY_LOOKUP_TOOL.name: return await handleCharityLookup(args); case PUBLIC_CHARITY_CHECK_TOOL.name: return await handlePublicCharityCheck(args); case CHARITY_SEARCH_TOOL.name: return await handleCharitySearch(args); case LIST_ORGANIZATIONS_TOOL.name: return await handleListOrganizations(args); default: throw new Error(`Unknown tool: ${name}`); } }); logger.info("All charity tools registered successfully", { tools: [ CHARITY_LOOKUP_TOOL.name, PUBLIC_CHARITY_CHECK_TOOL.name, CHARITY_SEARCH_TOOL.name, LIST_ORGANIZATIONS_TOOL.name, ], }); } catch (error) { logger.error("Failed to register tools", { error }); throw error; } }
- Helper function `formatPublicCharityCheckResponse` that formats the API response into a user-friendly Markdown string.function formatPublicCharityCheckResponse(result: PublicCharityCheckOutput): string { let response = `# Public Charity Status Check\n\n`; response += `**EIN:** ${result.ein}\n`; response += `**Public Charity Status:** ${result.isPublicCharity ? '✅ Yes' : '❌ No'}\n`; response += `**Tax-Deductible Donations:** ${result.deductible ? '✅ Yes' : '❌ No'}\n\n`; if (result.isPublicCharity) { response += `This organization is recognized as a public charity under IRS section 501(c)(3). `; response += `Donations to this organization are generally tax-deductible for donors who itemize deductions.`; } else { response += `This organization is not classified as a public charity. `; response += `Donations may not be tax-deductible, or the organization may not be found in the IRS database.`; } return response; }
- src/schemas/charity-schemas.ts:24-78 (schema)Zod schemas for input validation (`PublicCharityCheckInputSchema` lines 24-26) and output typing (`PublicCharityCheckOutputSchema` lines 74-78), used in the handler for parsing and type safety.export const PublicCharityCheckInputSchema = z.object({ ein: EINSchema, }); // Charity search tool input schema export const CharitySearchInputSchema = z.object({ query: z.string() .min(3, "Search query cannot be empty") .max(200, "Search query cannot exceed 200 characters") .optional(), city: z.string() .optional() .transform((val) => val === "" ? undefined : val) .refine((val) => val === undefined || (val.length <= 100), "City name cannot exceed 100 characters"), state: z.string() .optional() .transform((val) => val === "" ? undefined : val) .transform((val) => val?.toUpperCase()) .refine((val) => val === undefined || (val.length === 2 && /^[A-Za-z]{2}$/.test(val)), "State must be a 2-letter abbreviation (e.g., CA, ca, NY, ny)"), }); // List organizations tool input schema export const ListOrganizationsInputSchema = z.object({ since: z.string() .refine((dateStr) => { const date = new Date(dateStr); return !isNaN(date.getTime()); }, "Since must be a valid ISO date string") .transform((dateStr) => new Date(dateStr)), }); // Output schemas for type safety export const CharityLookupOutputSchema = z.object({ ein: z.string(), name: z.string(), city: z.string().optional(), state: z.string().optional(), country: z.string().optional(), deductibilityCode: z.string().optional(), deductibilityDetail: z.string().optional(), status: z.string().optional(), classification: z.string().optional(), activity: z.string().optional(), organization: z.string().optional(), ruling: z.string().optional(), foundation: z.string().optional(), }); export const PublicCharityCheckOutputSchema = z.object({ ein: z.string(), isPublicCharity: z.boolean(), deductible: z.boolean().optional(), });