Skip to content

Connect DonorPerfect to Claude: Sync Giving and Tribute Records

Learn how to connect DonorPerfect to Claude using a managed MCP server to automate fundraising operations, giving records, and tribute workflows.

Uday Gajavalli Uday Gajavalli · · 10 min read
Connect DonorPerfect to Claude: Sync Giving and Tribute Records

If you need to connect DonorPerfect to Claude to automate donor communications, sync giving records, manage pledges, or oversee tribute campaigns, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between Claude's natural language tool calls and DonorPerfect's specialized legacy database operations. You can either build 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 sibling guide on connecting DonorPerfect to ChatGPT or explore our broader architectural overview on connecting DonorPerfect to AI Agents.

Giving a Large Language Model (LLM) read and write access to a sprawling nonprofit CRM like DonorPerfect is a distinct engineering challenge. You are not just dealing with standard REST CRUD operations. DonorPerfect relies heavily on specialized stored procedures, destructive updates, and unique pagination models. Every time you want an agent to log a gift, it needs to navigate complex data constraints.

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

The Engineering Reality of the DonorPerfect 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 DonorPerfect's underlying API requires navigating significant technical debt. DonorPerfect's API is fundamentally a wrapper around a SQL database, exposing stored procedures rather than resource-oriented REST endpoints.

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

Destructive Updates on Core Entities The most critical quirk of the DonorPerfect API is how it handles updates. Procedures like dp_savedonor and dp_savegift do not perform partial patches. Every field is overwritten. If your LLM tries to update a donor's phone number and omits the first_name and last_name in the payload, DonorPerfect interprets that as an instruction to clear the name fields. An LLM has no inherent context for this. Your MCP server must strictly enforce a "Read-Before-Write" pattern, fetching the entire record first and merging the changes before pushing the payload.

Dynamic SQL Pagination and Limits Unlike modern APIs that return standard cursor links, reading bulk data from DonorPerfect involves dynamic SQL queries. Listing addresses, gifts, or custom UDFs requires using an OFFSET and FETCH NEXT pattern limited to 500 rows per call. Your MCP server has to abstract this SQL-like pagination into standard MCP cursors so Claude can reliably page through constituent records without writing invalid queries.

Transparent Rate Limiting DonorPerfect enforces API quotas, and your agent will hit them if it attempts to scrape large donor lists or run bulk update loops. Truto does not absorb, retry, throttle, or apply backoff on rate limit errors. When DonorPerfect returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller. Truto normalizes the upstream rate limit info into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF spec. Your client or agent orchestration layer is strictly responsible for handling the backoff.

Complex Linkages for Tributes and Pledges Creating a tribute gift is not a single operation. You must first ensure the tribute exists, then create the gift, and finally associate the gift with the tribute using dp_tribAnon_AssocTribsToGift. If an LLM attempts to jam all this into a single payload, the API will reject it. The MCP tool schemas must explicitly define these boundaries.

Creating the DonorPerfect MCP Server

Truto abstracts DonorPerfect's stored procedures into standardized JSON-RPC 2.0 tools. A single integrated account in Truto can generate a unique MCP server URL that handles the authentication and tool translation automatically.

You can create this server in two ways: via the Truto UI for rapid prototyping, or via the API for programmatic, multi-tenant agent deployments.

Method 1: Via the Truto UI

For internal automation or testing, generating the server visually is the fastest path.

  1. Log into your Truto dashboard and navigate to your Integrated Accounts.
  2. Select your connected DonorPerfect account.
  3. Click the MCP Servers tab.
  4. Click Create MCP Server.
  5. Configure your server filters (e.g., restrict to methods: ["read", "write"]).
  6. Click Save and copy the generated MCP server URL (e.g., https://api.truto.one/mcp/a1b2c3d4e5f6...).

Method 2: Via the Truto API

If you are deploying AI agents for multiple nonprofit clients, you need to generate these servers programmatically. You can create an MCP server scoped to a specific tenant's DonorPerfect instance via a single REST call.

Make a POST request to /integrated-account/:id/mcp:

curl -X POST https://api.truto.one/integrated-account/<donorperfect_account_id>/mcp \
  -H "Authorization: Bearer YOUR_TRUTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "DonorPerfect Fundraising AI",
    "config": {
      "methods": ["read", "write", "custom"],
      "require_api_token_auth": false
    }
  }'

The API provisions the server and returns the secure URL:

{
  "id": "mcp_srv_998877",
  "name": "DonorPerfect Fundraising AI",
  "config": { "methods": ["read", "write", "custom"] },
  "expires_at": null,
  "url": "https://api.truto.one/mcp/a1b2c3d4e5f67890"
}

This URL contains a cryptographically hashed token that safely routes requests to that specific DonorPerfect environment.

Connecting the MCP Server to Claude

Once you have your Truto MCP URL, connecting it to Claude is a straightforward process. Because Truto handles the server hosting, you do not need to deploy local Node.js or Python environments. You can connect it via the Claude UI or through a configuration file.

Method A: Via the Claude UI

If you are using Claude Desktop or Claude for Enterprise:

  1. Open Claude and navigate to Settings.
  2. Go to Integrations (or Connectors depending on your plan tier).
  3. Click Add MCP Server (or Custom Connector).
  4. Give the connector a name (e.g., "DonorPerfect Prod").
  5. Paste your Truto MCP URL into the endpoint field.
  6. Click Add. Claude will immediately handshake with the server, negotiate protocol version 2024-11-05, and list the available DonorPerfect tools.

Method B: Via the Configuration File

For automated deployments or developer environments using Claude Desktop, you can configure the server manually via the claude_desktop_config.json file. Because Truto provides a remote HTTP endpoint, you use the official Server-Sent Events (SSE) adapter to connect.

Edit your configuration file (located at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows):

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

Restart Claude Desktop. The application will execute the npx wrapper to establish an SSE connection to Truto's JSON-RPC endpoint.

DonorPerfect Hero Tools for AI Agents

Truto automatically derives MCP tools from DonorPerfect's underlying integration schema. We do not expose every raw stored procedure by default - we curate them to ensure the LLM has strict, documented schemas for query and body parameters.

Here are the highest-leverage tools available to Claude for automating fundraising operations.

Searching for constituents is the starting point of almost every workflow. This tool maps to the dp_donorsearch procedure and allows wildcards (%) for fuzzy matching.

Usage Note: Always encourage the LLM to search for a donor before attempting to create a new one to prevent duplicate constituent records in the CRM.

"Claude, check if we have a donor named 'John Smith' or 'J. Smith' in the system. Search by last name and email to be sure."

2. update_a_donor_perfect_donor_by_id

This tool modifies an existing constituent record. It maps to the dp_savedonor procedure.

Usage Note: As noted in the engineering reality section, this update is fully destructive. Claude must first call get_single_donor_perfect_donor_by_id, parse the entire existing JSON object, apply the necessary changes, and send the full object back to this update tool.

"Claude, update John Smith's record to change his primary phone number to 555-0199. Make sure you fetch his current profile first and include all his existing data in your update payload so we don't accidentally wipe his address."

3. create_a_donor_perfect_gift

Logs a new financial transaction against a donor record. This handles main gifts, split gifts, and soft credits.

Usage Note: You must provide the donor_id, record_type (e.g., 'G' for gift, 'S' for soft credit), gift_date, and amount. If this gift is a payment against a pledge, you must also pass the plink (the pledge's original gift ID).

"Claude, log a new $5,000 major gift from Sarah Jenkins received today via wire transfer. Tag it to the '2026 Annual Fund' campaign."

4. create_a_donor_perfect_pledge

Creates a recurring commitment (record type 'P').

Usage Note: This does not create the actual payments. It creates the parent pledge record, which returns a gift_id. Subsequent payments must be created using create_a_donor_perfect_gift linked to this ID.

"Claude, setup a new 5-year pledge for Michael Chang for $50,000 total, billed annually starting next month."

5. create_a_donor_perfect_tribute

Creates a new tribute (In Honor Of / In Memory Of) entity in the system via dp_tribAnon_Create.

Usage Note: Creating a tribute is separate from logging the money. You must create the tribute here, get its ID, log the financial gift, and then use create_a_donor_perfect_gift_tribute to link them together.

"Claude, create an 'In Memory Of' tribute for 'Eleanor Vance'. Once created, associate it with the $500 gift I just had you log for Tom Vance."

6. donor_perfect_queries_execute

Allows the LLM to run read-only SQL SELECT statements directly against DonorPerfect tables (like DP, DPGIFT, DPADDRESS).

Usage Note: This is incredibly powerful for complex reporting requests. It limits output to 500 rows per call. The LLM must use OFFSET and FETCH NEXT if it needs to paginate through large datasets.

"Claude, run a query against the DPGIFT table to find all gifts over $1,000 made in the last 30 days, and group them by the solicit code."

For the complete tool inventory, including tools for managing contacts, UDFs, checkboxes, and payment methods, review the DonorPerfect integration page.

Workflows in Action

Let's look at how Claude strings these tools together to execute multi-step fundraising operations that would normally require a human navigating multiple screens in the DonorPerfect UI.

Scenario 1: Processing an In-Memory Tribute Gift

A development officer receives an email about a memorial gift and asks Claude to process it end-to-end.

"Claude, we just received a $250 check from Robert Ford in memory of Arnold Weber. Please find Robert in the system, log the gift for today, create the tribute for Arnold if it doesn't exist, and link them together."

Execution Steps:

  1. Claude calls donor_perfect_donors_search to find Robert Ford's donor_id.
  2. Claude calls donor_perfect_tributes_search to check if an "Arnold Weber" tribute already exists.
  3. Finding none, Claude calls create_a_donor_perfect_tribute to instantiate the memorial.
  4. Claude calls create_a_donor_perfect_gift to log the $250 check under Robert Ford's ID.
  5. Finally, Claude calls create_a_donor_perfect_gift_tribute passing the new gift_id and the tribute_id to establish the relationship.
sequenceDiagram
    participant User
    participant Claude as Claude Agent
    participant DP as DonorPerfect API

    User->>Claude: "Log $250 gift from Robert in memory of Arnold"
    Claude->>DP: Call donor_perfect_donors_search
    DP-->>Claude: Returns donor_id 45892
    Claude->>DP: Call create_a_donor_perfect_tribute
    DP-->>Claude: Returns tribute_id 104
    Claude->>DP: Call create_a_donor_perfect_gift
    DP-->>Claude: Returns gift_id 99341
    Claude->>DP: Call create_a_donor_perfect_gift_tribute<br>(gift 99341, tribute 104)
    DP-->>Claude: Success
    Claude-->>User: "Gift and tribute successfully logged and linked."

Scenario 2: Updating a Donor Profile Safely

A major gifts officer needs to update a donor's contact information based on a recent meeting.

"Claude, I just met with Sarah Jenkins. She moved. Update her secondary seasonal address to 123 Palm Drive, Miami FL 33101. Also, add a note to her main profile that she prefers to be called 'Sally'."

Execution Steps:

  1. Claude calls donor_perfect_donors_search to find Sarah Jenkins.
  2. Claude calls get_single_donor_perfect_donor_by_id to retrieve her complete, current profile schema.
  3. Claude modifies the JSON object in memory, changing the preferred name field to 'Sally', while explicitly retaining her primary address, phone numbers, and giving history.
  4. Claude calls update_a_donor_perfect_donor_by_id and passes the full, merged object back to safely overwrite the record.
  5. Claude calls create_a_donor_perfect_address to add the new seasonal address record to the DPADDRESS table.

Security and Access Control

When exposing a CRM containing sensitive donor financial data to an AI model, security configuration is paramount. Truto provides several mechanisms to lock down your DonorPerfect MCP servers:

  • Method Filtering: You can configure the config.methods array to restrict the server to ["read"]. This allows Claude to query donor profiles and run SQL reports without any risk of altering or deleting financial records.
  • Tag Filtering: You can use config.tags to expose only specific subsets of tools, such as ["gifts"] or ["donors"], limiting the agent's blast radius.
  • Expiration (expires_at): You can assign a strict time-to-live for the MCP server. When the timestamp passes, the server URL is automatically invalidated and deleted from Truto's KV storage. Perfect for temporary contractor access.
  • API Token Authentication: By enabling require_api_token_auth, possessing the MCP URL is no longer enough. The client must also inject a valid Truto API token in the Authorization header, ensuring only verified systems can invoke the tools.

Building Faster with Managed Infrastructure

Connecting Claude to DonorPerfect opens up massive operational efficiencies for nonprofit development teams. Agents can automate gift entry, draft personalized acknowledgment letters based on tribute data, and run complex donor queries on demand.

However, building this integration from scratch means writing complex wrappers around destructive SQL procedures, maintaining stateful pagination loops, and handling rate limit backoffs. By using Truto to generate a managed MCP server, you abstract away the legacy API debt. Your agents get clean, schema-enforced JSON-RPC tools, and your engineering team gets to focus on building better fundraising workflows instead of maintaining API boilerplates.

FAQ

Can Claude execute raw SQL against DonorPerfect?
Yes, Truto exposes a donor_perfect_queries_execute tool that allows Claude to run read-only SQL SELECT statements against DonorPerfect tables (like DP, DPUDF, DPGIFT). Data is paginated 500 rows at a time.
How do we handle DonorPerfect API rate limits?
Truto passes upstream 429 Too Many Requests errors directly to Claude with standard headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). Your agent or client application is responsible for implementing retry and backoff logic.
Does updating a DonorPerfect record clear existing fields?
Yes. DonorPerfect updates (like dp_savedonor) are destructive. If you omit a field from your update payload, the system clears it. Always read the record first and pass all existing values alongside your updates.
How does Truto handle DonorPerfect's XML endpoints?
Truto abstracts the underlying XML stored procedures (like dp_savemultivalue_xml) into standardized REST-like JSON RPC operations, so Claude only needs to pass standard JSON arguments.

More from our Blog