Skip to content

Connect Virtuous to Claude: Sync Pledges, Projects, and Grants

Learn how to build a managed MCP server to connect Virtuous CRM to Claude. Automate donor profiles, pledges, and grant workflows using natural language.

Nachi Raman Nachi Raman · · 9 min read
Connect Virtuous to Claude: Sync Pledges, Projects, and Grants

If you need to connect Virtuous to Claude to automate donor management, track pledges, manage project financials, or reconcile offline giving, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between Claude's JSON-RPC tool calls and the REST APIs exposed by Virtuous. You can either build, host, and maintain this infrastructure yourself, or use a managed integration platform like Truto to dynamically generate a secure, authenticated MCP server URL.

If your team uses ChatGPT, check out our guide on /connect-virtuous-to-chatgpt-manage-donors-gifts-and-communications/ or explore our broader architectural overview on /connect-virtuous-to-ai-agents-automate-events-tasks-and-volunteers/.

Giving a Large Language Model (LLM) read and write access to a nonprofit CRM like Virtuous is a complex engineering challenge. You are dealing with highly interconnected data models - contacts have individuals, individuals have contact methods, gifts belong to segments, and pledges are tied to projects. Every time Virtuous updates an endpoint or deprecates a field, a custom integration requires a code update. Truto eliminates this by dynamically deriving tool definitions directly from the integration's schemas.

This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for Virtuous, connect it natively to Claude, and execute complex donor operations using natural language.

The Engineering Reality of the Virtuous API

A custom MCP server is a self-hosted integration layer. While the open MCP standard provides a predictable way for models to discover tools, implementing it against Virtuous requires deep domain knowledge of their API quirks.

If you decide to build a custom Virtuous MCP server, here are the specific integration challenges you will face:

Destructive Update Operations Unlike APIs that support partial PATCH updates natively, many Virtuous update endpoints require the full data model. If you update a project using update_a_virtuous_project_by_id, excluding a property in the payload literally removes its value in the CRM. You cannot just send { "financialNeedAmount": 5000 } - you must retrieve the current object, merge the changes, and send back the entire schema. An LLM must be explicitly guided through this "read-modify-write" cycle via highly detailed JSON Schema descriptions.

Asynchronous Transaction Processing Virtuous maintains strict data integrity rules around contact deduplication and gift processing. While they offer synchronous create_a_virtuous_contact endpoints, their API documentation explicitly warns against using them. Instead, you are expected to use the Import Tool endpoints (e.g., create_a_virtuous_contact_transaction or virtuous_transactions_create_gift). These queue records for intelligent matching and batch processing at midnight. An LLM interacting with Virtuous must understand that a successful 200 OK from a transaction endpoint does not mean the ID is immediately available for querying.

Complex Filter Groups for Queries Virtuous does not use standard REST query parameters for filtering large datasets like pledges or campaigns. Instead, you must POST complex filter groups with conjunct logic (where 0 = And, 1 = Or) combined with specific operator options. Hand-coding an MCP tool that successfully translates an LLM's natural language request (e.g., "find all pledges over $5,000 from last year") into a Virtuous filter group is tedious and error-prone.

Truto handles this by automatically parsing the Virtuous API definitions and exposing formatted query schemas to the LLM, flattening the cognitive load required to build the tool payloads.

Step 1: Generate the Virtuous MCP Server

Truto scopes every MCP server to a specific integrated account - a single, authenticated instance of Virtuous connected to a specific tenant in your application. The generated URL contains a secure, cryptographically hashed token that inherently knows which account to use.

You can create this server via the Truto UI or programmatically via the API.

Method 1: Via the Truto UI

If you are configuring this manually for internal operations:

  1. Log in to your Truto dashboard and navigate to the integrated account page for your Virtuous connection.
  2. Click the MCP Servers tab.
  3. Click Create MCP Server.
  4. Configure the server (e.g., restrict to specific methods or tags).
  5. Copy the generated MCP server URL (it will look like https://api.truto.one/mcp/abc123def456...).

Method 2: Via the Truto REST API

If you are dynamically provisioning AI assistants for your users, you will generate the MCP server programmatically.

Make an authenticated POST request to the /integrated-account/:id/mcp endpoint:

curl -X POST https://api.truto.one/integrated-account/<virtuous_account_id>/mcp \
  -H "Authorization: Bearer YOUR_TRUTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Virtuous Donor Agent",
    "config": {
      "methods": ["read", "write"],
      "tags": ["crm", "fundraising"]
    }
  }'

The API returns a database record containing the ready-to-use URL:

{
  "id": "mcp_token_xyz987",
  "name": "Virtuous Donor Agent",
  "url": "https://api.truto.one/mcp/a1b2c3d4e5f6g7h8...",
  "expires_at": null
}

Step 2: Connect the Server to Claude

Once you have the URL, connecting it to Claude requires zero additional coding. The URL natively supports the JSON-RPC 2.0 protocol expected by MCP clients.

Method A: Via the Claude Desktop UI

  1. Open Claude Desktop.
  2. Go to Settings -> Integrations (or Developer settings).
  3. Click Add MCP Server.
  4. Paste your Truto MCP URL.
  5. Click Add.

Claude will immediately call the /initialize and tools/list endpoints on the server to discover the available Virtuous operations.

Method B: Via the Manual Configuration File

If you are orchestrating Claude Desktop manually or building a custom LangChain/LangGraph agent, you can define the server in your configuration file using the Server-Sent Events (SSE) transport layer.

Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "virtuous_crm": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sse",
        "--url",
        "https://api.truto.one/mcp/a1b2c3d4e5f6g7h8..."
      ]
    }
  }
}

Hero Tools for Virtuous Automation

Truto dynamically parses the Virtuous API documentation to expose over 100 tools. We focus on the most impactful "hero tools" that drive real business value for nonprofit automation.

Retrieves abbreviated contact records based on keyword searches. This is the starting point for almost every agentic workflow, allowing Claude to resolve a human name to a Virtuous id.

"Find the Virtuous contact record for John Smith. I need his internal ID and current address."

2. virtuous_contacts_list_full

Fetches complete contact details, including nested individuals, custom fields, tags, and gift history URLs. This is a heavy endpoint but provides maximum context to the LLM.

"Get the full contact profile for ID 45992. Summarize their giving tags and list all individuals associated with this household."

3. virtuous_transactions_create_gift

Creates a gift transaction in Virtuous via the v2 import endpoint. Because this tool leverages Virtuous's native intelligent contact and gift matching algorithms, it is far safer for an LLM to use than the direct create_a_virtuous_gift endpoint.

"Log a new gift transaction for $1,000 against contact ID 45992. Set the gift type as 'Check' and tag the notes with 'Year End Campaign'."

4. list_all_virtuous_pledge_v_2

Queries pledges using filter groups. This tool enables complex reporting operations, allowing Claude to find overdue pledges, active recurring giving commitments, or high-value unfulfilled asks.

"Pull a list of all pledges where the status is active and the amount pledged is over $10,000. Give me a summary of expected fulfillment dates."

5. list_all_virtuous_grants

Queries the grant pipeline, returning details on submission dates, anticipated award amounts, and receiving organization IDs.

"List all active grants in the pipeline. Identify any grants that have a due date in the next 30 days and summarize their anticipated award amounts."

6. create_a_virtuous_contact_note

Appends interaction notes to a contact profile. Highly useful for logging meeting summaries or auto-generated email touchpoints.

"Add a note to contact ID 45992. Set the type to 'Meeting' and write a brief summary: Met for coffee to discuss the Q3 capital campaign. Donor is highly receptive."

For the complete list of available operations, schemas, and endpoint behaviors, visit the Virtuous integration page.

Workflows in Action

When Claude is equipped with Truto's MCP tools, it acts as an autonomous CRM administrator. Here is how Claude executes multi-step workflows based on simple human prompts.

Workflow 1: High-Net-Worth Donor Briefing

Major gift officers need rapid context before a meeting. Instead of manually clicking through the Virtuous UI, they can simply ask Claude for a brief.

"I am meeting with Eleanor Abernathy this afternoon. Build a quick briefing document covering her total giving history, any outstanding pledges, and the last three notes on her account."

sequenceDiagram
    participant User as User
    participant Claude as Claude Desktop
    participant MCP as Truto MCP
    participant API as Virtuous API

    User->>Claude: "Build briefing for Eleanor Abernathy"
    Claude->>MCP: Call `virtuous_contacts_search`<br>{"keyword": "Eleanor Abernathy"}
    MCP->>API: GET /api/Contact/Search
    API-->>MCP: Contact ID: 8841
    MCP-->>Claude: JSON Contact ID
    
    Claude->>MCP: Call `virtuous_contacts_list_full`<br>{"id": 8841}
    MCP->>API: GET /api/Contact/8841
    API-->>MCP: Full Profile Data
    MCP-->>Claude: JSON Context

    Claude->>MCP: Call `list_all_virtuous_pledge_v_2`<br>{"contactId": 8841}
    MCP->>API: POST /api/v2/Pledge/Query
    API-->>MCP: Active Pledges
    MCP-->>Claude: JSON Pledges

    Claude->>MCP: Call `virtuous_contact_notes_get_by_contact`<br>{"bycontact_id": 8841}
    MCP->>API: GET /api/Contact/{id}/Notes
    API-->>MCP: Notes Array
    MCP-->>Claude: JSON Notes

    Claude-->>User: Outputs formatted briefing document

What happens: Claude dynamically chains four tools. It resolves the human name to an ID, retrieves the full profile, pulls pledge data, and scrapes the notes. It then synthesizes the raw JSON into a highly readable human briefing document.

Workflow 2: Grant Submission and Project Reconciliation

When a development director finalizes a grant submission, multiple systems must be updated to reflect the anticipated revenue.

"I just submitted the $50k Gates Foundation grant for the Clean Water Initiative. Log the grant in Virtuous, then update the Clean Water project financials to reflect this new anticipated balance."

flowchart TD
    A["User Prompt: Log grant and<br>update project balances"] --> B["Claude calls:<br>create_a_virtuous_grant"]
    B --> C{"Success?"}
    C -- Yes --> D["Claude calls:<br>virtuous_projects_search<br>(Find 'Clean Water')"]
    C -- No --> E["Claude reports error"]
    D --> F["Claude calls:<br>get_single_virtuous_project_by_id"]
    F --> G["Claude extracts full project schema"]
    G --> H["Claude calls:<br>update_a_virtuous_project_by_id<br>(Injects new financialNeedAmount)"]
    H --> I["Outputs success to User"]

What happens: Claude handles the complex destructive update logic automatically. After creating the grant, it searches for the project, performs a GET to pull the full project schema into context, modifies only the financial fields, and issues the PUT request with the complete model. This prevents accidental data deletion.

Handling Rate Limits

Virtuous enforces API rate limits to protect server resources. It is critical to understand how this is handled architecturally.

Factual note on rate limits: Truto does not retry, throttle, or apply backoff on rate limit errors. When the upstream Virtuous API returns an HTTP 429 (Too Many Requests), Truto passes that error directly back to the caller. Truto normalizes the upstream rate limit information into standardized HTTP headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification.

The caller (in this case, your LLM agent framework or Claude Desktop) is entirely responsible for reading these headers and implementing its own retry or exponential backoff logic.

Security and Access Control

Giving an LLM direct access to a CRM database is risky. You do not want a hallucinated prompt to bulk-delete campaigns. Truto MCP servers include built-in governance to mitigate this risk.

  • Method Filtering: When creating the MCP server, you can pass "methods": ["read"]. Truto will intercept the tool generation process and exclude all create, update, and delete endpoints. Claude will only be aware of get and list tools, making the server strictly read-only.
  • Tag Filtering: Virtuous tools can be heavily scoped. You can pass "tags": ["grants"] to ensure the server only exposes endpoints related to grant management, completely hiding contact details and employee info.
  • Require API Token Auth: By default, possession of the MCP server URL is enough to authenticate. For production environments, you can set require_api_token_auth: true. The client must then pass a valid Truto API token in the Authorization header to execute tools.
  • Expiration (TTL): If you are spinning up temporary agents for specific data-cleansing jobs, set an expires_at timestamp. Cloudflare KV and internal alarms will automatically destroy the token and server infrastructure when the clock runs out.

Rethink Nonprofit Data Operations

Connecting Virtuous to Claude via a managed MCP server transforms how your team interacts with donor data. Instead of building rigid, point-to-point automation scripts, you are giving an LLM a complete map of the Virtuous API and letting it reason through the operations.

Truto handles the OAuth token lifecycles, the dynamic tool generation, the pagination normalization, and the JSON schema translations. You focus on building better prompts.

FAQ

How does Truto handle Virtuous API rate limits?
Truto does not retry, throttle, or apply backoff on rate limit errors. If Virtuous returns an HTTP 429, Truto passes that error directly to Claude, normalizing the rate limit info into standardized IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). Your LLM framework must handle the retry logic.
Do I need to write custom integration code to expose Virtuous tools?
No. Truto dynamically generates tool definitions by parsing the integration's documented API resources and schemas. If Virtuous has a documented endpoint, Truto exposes it as a formatted JSON-RPC tool for the MCP server.
How do I prevent Claude from deleting critical donor data?
You can configure your Truto MCP server with method filtering (e.g., restricting the server to 'read' operations only) or tag filtering to limit access strictly to specific resources like projects or campaigns.
How are Virtuous update payloads handled by the MCP server?
Virtuous uses destructive updates - excluding a property removes its value. When Claude updates a record, it must pass the full object schema. Truto's dynamically generated tool schemas explicitly define these requirements to guide the LLM.

More from our Blog