Candid MCP

Live

API KEY

NONPROFIT DATA

AI

Candid holds the definitive database of US nonprofits, 990 filings, grant histories, foundation profiles, and giving patterns. Candid MCP gives your philanthropy research agent per-user API access, credentials vaulted, scoped, never in the prompt.

  • Acts as the user: Each researcher's Candid API key is scoped to their Candid subscription tier and query limits.
  • Credentials stay vaulted: AES-256, resolved at request time, never in LLM context.
  • Scoped before every call: User permissions enforced. 90-day audit trail on every data query.
Candid MCP
agent · Acme Q3
Run
Find foundations that fund climate tech nonprofits in the Western US with grants over $500K.
S
candid_grants_search
156ms
Philanthropy agent
14 foundations matched. Top 3: Schmidt Futures ($2.1M avg), Packard Foundation ($1.4M avg, CA focus), Heising-Simons ($900K avg, clean energy).
Sources: Candid grants database, 990 filings 2022–2024
candidmcp
14
18:29
Message Claude...

Tools your philanthropy agent reaches for on Candid, scoped per researcher.

CALL ANY TOOL
API key scoped per researcher. Every nonprofit and grants query attributed to the authorizing user.
candid_nonprofits_search
Search nonprofits
Search Candid's database of 1.8M+ US nonprofits by name, EIN, location, cause area, or NTEE code with full profile data.
Parameters
Name
Type
Required
Description
query
string
Optional
Organization name or keyword search
ntee_code
string
Optional
NTEE cause area code (e.g. A01 for arts)
state
string
Optional
Two-letter US state code
limit
integer
Optional
Max results to return
candid_grants_search
Search grants
candid_organization_get
Get organization
candid_990_filings_get
Get 990 filings
candid_funders_search
Search funders
Build your Agent
Drop the toolkit in, point it at the authorized grants professional, and your agent can access Candid nonprofit and foundation data from the first run.
import { ScalekitClient } from "@scalekit-sdk/node";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { z } from "zod";

const sk = new ScalekitClient(envUrl, clientId, clientSecret);

const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["candidmcp"], toolNames: ["candid_nonprofits_search", "candid_grants_search", "candid_organization_get"] },
pageSize: 100,
});

const lcTools = tools.map((t) => new DynamicStructuredTool({
name: t.tool.definition.name,
description: t.tool.definition.description,
schema: z.object({}).passthrough(),
func: async (args) => {
const { data } = await sk.tools.executeTool({
toolName: t.tool.definition.name,
identifier: "user_123",
params: args,
});
return JSON.stringify(data);
},
}));

const agent = createReactAgent({ llm, tools: lcTools });
import { ScalekitClient } from "@scalekit-sdk/node";
import OpenAI from "openai";

const sk = new ScalekitClient(envUrl, clientId, clientSecret);
const openai = new OpenAI();

const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["candidmcp"], toolNames: ["candid_nonprofits_search", "candid_grants_search", "candid_organization_get"] },
pageSize: 100,
});

const llmTools = tools.map((t) => ({
type: "function",
function: {
name: t.tool.definition.name,
description: t.tool.definition.description,
parameters: t.tool.definition.input_schema,
},
}));

const resp = await openai.responses.create({
model: "gpt-4o", input: prompt, tools: llmTools,
});
import { ScalekitClient } from "@scalekit-sdk/node";
import Anthropic from "@anthropic-ai/sdk";

const sk = new ScalekitClient(envUrl, clientId, clientSecret);
const anthropic = new Anthropic();

const { tools } = await sk.tools.listScopedTools("user_123", {
filter: { connectionNames: ["candidmcp"], toolNames: ["candid_nonprofits_search", "candid_grants_search", "candid_organization_get"] },
pageSize: 100,
});

const llmTools = tools.map((t) => ({
name: t.tool.definition.name,
description: t.tool.definition.description,
input_schema: t.tool.definition.input_schema,
}));

const msg = await anthropic.messages.create({
model: "claude-sonnet-4-6", max_tokens: 1024,
tools: llmTools,
messages: [{ role: "user", content: prompt }],
});
import { Agent } from "@google/adk/agents";
import {
MCPToolset, StreamableHTTPConnectionParams,
} from "@google/adk/tools/mcp";

const toolset = new MCPToolset({
connectionParams: new StreamableHTTPConnectionParams({
url: "https://mcp.scalekit.com/candidmcp",
headers: { Authorization: `Bearer ${userScopedToken}` },
}),
});

const agent = new Agent({
name: "agent", model: "gemini-2.0-flash",
tools: await toolset.getTools(),
});
Try these prompts
Paste any prompt into your grants research agent to start pulling foundation and nonprofit data from Candid.
Search & recall
Copy the prompt
Copied
Find foundations that fund [cause area] in [geographic region].
Copy the prompt
Copied
Show recent grants awarded to organizations similar to ours in the last 2 years.
Copy the prompt
Copied
Get the giving history and priorities for [foundation name].
Research & analysis
Copy the prompt
Copied
Find the top 10 funders in [issue area] by total grant dollars in the past 3 years.
Copy the prompt
Copied
Show the nonprofit financials and Form 990 data for [organization name].
Copy the prompt
Copied
Identify foundations with open grant cycles accepting applications in the next 60 days.
SEE HOW AUTH WORKS
Grants professionals authorize Candid once. Their API key stays vaulted, every data query is scoped to their subscription, and every access is logged.
1
Authorize
Your user connects
Candid MCP
once. We tie it to their identity and the meetings they approved — no shared bot account, no org-wide access
Who:
user ‘A’
when:
Once per user
access:
Limited to user
2
Store
Their
Candid MCP
token lives in a vault scoped to them. User A's meetings are never reachable by an agent acting for user B, even on the same connection
vault:
encrypted
scope:
per-user
tokens:
auto-refreshed
3
Resolve
When your agent calls a
Candid MCP
tool, we fetch the right token server-side. It never touches your agent, never appears in the LLM context, never shows up in your logs
speed:
~40ms
check:
before every call
seen by:
nobody
4
Audit
Every
Candid MCP
tool call is logged — who triggered it, which meeting was fetched, what came back. 90 days of history, tied to the user who authorized it
history:
90 days
export:
SIEM-ready
logged:
every call
Test other agents
Same per-user auth pattern across other nonprofit and philanthropy data connectors.
No items found.
Why Scalekit
Secure your agent's access. Connectors ship in minutes
One vault for every research database. Candid today, Crunchbase and LinkedIn tomorrow.
01.
Shared tokens break per-user analytics
A shared token looks fine in a demo. In production every call looks like a service account. Scalekit resolves the real user credential so attribution, audit, and scope stay accurate.
// shared token
 audit → bot_service_account
 user_filter → broken

 // scalekit
 audit → user_abc
 scope → enforced ✓
02.
Authentication is not authorization
03.
Multi-tenancy is architectural
04.
Candid MCP today. Others tomorrow.
“Our agents act across Salesforce, Gong, Google Drive, and more, on behalf of every customer. Scalekit behind the scenes meant we can keep adding tools without ever rebuilding how credentials or tool calling work.”
Venu Madhav Kattagoni
Head of Engineering / Von
FAQs
Frequently Asked Questions
Does the agent use a shared Candid API key or per-user keys?
Per-user keys. Each researcher provisions their own Candid API key and Scalekit vaults it under their identity. Query usage is tracked per user against their Candid subscription limits.
Where is the Candid API key stored?
In Scalekit's AES-256 vault, namespaced per tenant. Keys resolve at request time and never appear in prompts, logs, or LLM completions.
Can I limit which Candid data types the agent can query?
Yes. Use listScopedTools to restrict the agent to nonprofit search and profile lookup, blocking 990 financial data queries for users without the appropriate Candid subscription tier.
What happens when a researcher's Candid key is revoked?
The next tool call fails closed for that user. Other researchers in the tenant remain unaffected. The revocation event is logged with timestamp.
Can the agent search Candid for multiple organizations in one workflow?
Yes. The agent can chain candid_nonprofits_search, candid_organization_get, and candid_990_filings_get across multiple entities in a single workflow. Each call runs under the same user credential with quota tracked per-user.
Start in your coding agent
Up and running in one command
Install the Scalekit skill in your editor of choice. Connector, auth, tools, prompt, all wired up
Claude Code REPL
/plugin marketplace add scalekit-inc/claude-code-authstack
/plugin install agentkit@scalekit-auth-stack
Cursor Code REPL
# ~/.cursor/mcp.json
{
""mcpServers"": {
""candidmcp"": {
""url"": ""https://mcp.scalekit.com/candidmcp"",
""headers"": { ""Authorization"": ""Bearer $SCALEKIT_TOKEN"" }
}
}
}
Codex Code REPL
# ~/.codex/config.toml
[mcp_servers.candidmcp]
url = ""https://mcp.scalekit.com/candidmcp""
auth_env = ""SCALEKIT_TOKEN""
Copilot Code REPL
# .vscode/mcp.json
{
""servers"": {
""candidmcp"": {
""url"": ""https://mcp.scalekit.com/candidmcp"",
""type"": ""http""
}
}
}