Skip to content

Virtuous MCP by usefulapi

by usefulapi.io · remote · no sign-in to list tools · v1.16.3 · published by io.usefulapi

Search donors and contacts, giving history, notes and projects, and log notes, tags and gifts.

Deletes · 4Changes · 1

20 tools: 4 can delete or cancel things, 1 change things and 15 only read.

Scanned Oct 21, 2026

1 check matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http virtuous-crm https://virtuous-crm.usefulapi.io/mcp

Findings

Matches of fixed checks, with the text they matched.

1 warn
  • The server marks "virtuous_query" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

    Matched text

    annotations: {"readOnlyHint":true}; The name "virtuous_query" says "query": a word for reading.

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

20 tools

Deletes or cancels 4Claude Code: deny
  • virtuous_add_contact_tagApply an existing tag to a contact (find the tagId with virtuous_list_tags).No findings

    Why it is in this group

    • The name "virtuous_add_contact_tag" says "add": a word for a change.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Apply an existing tag to a contact (find the tagId with virtuous_list_tags). Virtuous: POST /api/ContactTag.

    Annotations the server declares

    • title: Tag a contact
    • destructiveHint: true
  • virtuous_create_contact_noteAdd a note to a contact's timeline — a call, meeting, visit or other touchpoint.No findings

    Why it is in this group

    • The name "virtuous_create_contact_note" says "create": a word for a change.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Add a note to a contact's timeline — a call, meeting, visit or other touchpoint. Writes to the donor record. Virtuous: POST /api/ContactNote.

    Annotations the server declares

    • title: Log a note on a contact
    • destructiveHint: true
  • virtuous_create_contact_transactionSubmit a new or updated contact through Virtuous's import pipeline (the recommended way to add contacts).No findings

    Why it is in this group

    • The name "virtuous_create_contact_transaction" says "create": a word for a change.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Submit a new or updated contact through Virtuous's import pipeline (the recommended way to add contacts). It is matched against existing contacts by name, email, phone, address and reference, bundled into an import at midnight, and only committed when a user reviews the import and clicks Run — so nothing is created in real time and no duplicates are forced. Virtuous: POST /api/Contact/Transaction.

    Annotations the server declares

    • title: Submit a contact for import
    • destructiveHint: true
  • virtuous_create_gift_transactionRecord a gift (donation already received) through Virtuous's gift import pipeline — the method Virtuous recommends.No findings

    Why it is in this group

    • The name "virtuous_create_gift_transaction" says "create": a word for a change.
    • The input carries an amount (input.amount) and a currency, so it moves money.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    Record a gift (donation already received) through Virtuous's gift import pipeline — the method Virtuous recommends. The gift is matched to a contact, recurring gift or pledge, held until the nightly import, and only created when a user reviews the import and clicks Run. This records a gift; it does NOT charge anyone. Identify the donor with contact.id, contact.referenceId, or name/email details. Virtuous: POST /api/v2/Gift/Transaction.

    Annotations the server declares

    • title: Submit a gift for import
    • destructiveHint: true
Changes things 1Claude Code: ask
  • virtuous_queryRun a Virtuous query-builder query against one record type (contacts, gifts, campaigns, projects, tasks, grants, pledges, recurring gifts, events ...).1 finding

    Why it is in this group

    • The name "virtuous_query" says "query": a word for reading.
    • The description's first verb is "run": a word for a change.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.

    Findings

    • Warn

      The server marks "virtuous_query" read-only (readOnlyHint: true), and its own name, description or input give the class "write".

      Matched text

      annotations: {"readOnlyHint":true}; The name "virtuous_query" says "query": a word for reading.

      What this check looks for
    Description, as the server wrote it
    Run a Virtuous query-builder query against one record type (contacts, gifts, campaigns, projects, tasks, grants, pledges, recurring gifts, events ...). Conditions use parameter/operator names from virtuous_get_query_options. Returns { list, total }. For Contact and Gift, full_details returns full records instead of the abbreviated view. Virtuous: POST /api/<Resource>/Query.

    Annotations the server declares

    • title: Query records
    • readOnlyHint: true
Only reads 15Claude Code: allow
  • virtuous_find_contactLook up a single contact by email address, or by an external reference (reference source + id, e.g.No findings

    Why it is in this group

    • The name "virtuous_find_contact" says "find": a word for reading.
    Description, as the server wrote it
    Look up a single contact by email address, or by an external reference (reference source + id, e.g. Stripe customer id). Give either email, or both reference_source and reference_id; if both are given Virtuous prioritises the reference. Virtuous: GET /api/Contact/Find.

    Annotations the server declares

    • title: Find a contact by email or reference
    • readOnlyHint: true
  • virtuous_get_contactFetch one contact (household, organization, foundation ...) with its address, giving summary (life-to-date, year-to-date, last gift), individuals and their contact methods, and cus…No findings

    Why it is in this group

    • The name "virtuous_get_contact" says "get": a word for reading.
    Description, as the server wrote it
    Fetch one contact (household, organization, foundation ...) with its address, giving summary (life-to-date, year-to-date, last gift), individuals and their contact methods, and custom fields. Virtuous: GET /api/Contact/{contactId}.

    Annotations the server declares

    • title: Get a contact
    • readOnlyHint: true
  • virtuous_get_current_organizationFetch the Virtuous organization this API key acts in — its name, time zone and culture, and whether the key's user is an administrator.No findings

    Why it is in this group

    • The name "virtuous_get_current_organization" says "get": a word for reading.
    Description, as the server wrote it
    Fetch the Virtuous organization this API key acts in — its name, time zone and culture, and whether the key's user is an administrator. A cheap way to confirm the key works. Virtuous: GET /api/Organization/Current.

    Annotations the server declares

    • title: Get the current organization
    • readOnlyHint: true
  • virtuous_get_giftFetch one gift in full: contact, type, date, amount and currency, batch, segment, grant, tribute, receipt date, designations to projects, premiums and custom fields.No findings

    Why it is in this group

    • The name "virtuous_get_gift" says "get": a word for reading.
    Description, as the server wrote it
    Fetch one gift in full: contact, type, date, amount and currency, batch, segment, grant, tribute, receipt date, designations to projects, premiums and custom fields. Virtuous: GET /api/Gift/{giftId}.

    Annotations the server declares

    • title: Get a gift
    • readOnlyHint: true
  • virtuous_get_projectFetch one project: code, type, status, balances, financial need, date range, life-to-date and calendar-year giving and gift/giver counts.No findings

    Why it is in this group

    • The name "virtuous_get_project" says "get": a word for reading.
    Description, as the server wrote it
    Fetch one project: code, type, status, balances, financial need, date range, life-to-date and calendar-year giving and gift/giver counts. Virtuous: GET /api/Project/{projectId}.

    Annotations the server declares

    • title: Get a project
    • readOnlyHint: true
  • virtuous_get_query_optionsList the parameters, their types, allowed operators and value options that virtuous_query accepts for one record type.No findings

    Why it is in this group

    • The name "virtuous_get_query_options" says "get": a word for reading.
    Description, as the server wrote it
    List the parameters, their types, allowed operators and value options that virtuous_query accepts for one record type. Call this BEFORE building a query. Virtuous: GET /api/<Resource>/QueryOptions.

    Annotations the server declares

    • title: Get query options
    • readOnlyHint: true
  • virtuous_list_contact_giftsList a contact's giving history: gift id, type, date, amount, segment and batch.No findings

    Why it is in this group

    • The name "virtuous_list_contact_gifts" says "list": a word for reading.
    Description, as the server wrote it
    List a contact's giving history: gift id, type, date, amount, segment and batch. Use virtuous_get_gift for designations and full detail. Virtuous: GET /api/Gift/ByContact/{contactId}.

    Annotations the server declares

    • title: List a contact's gifts
    • readOnlyHint: true
  • virtuous_list_contact_individualsList the individuals (people) that belong to a contact/household, with names, birth dates, and their emails and phones (contact methods).No findings

    Why it is in this group

    • The name "virtuous_list_contact_individuals" says "list": a word for reading.
    Description, as the server wrote it
    List the individuals (people) that belong to a contact/household, with names, birth dates, and their emails and phones (contact methods). Virtuous: GET /api/ContactIndividual/ByContact/{contactId}.

    Annotations the server declares

    • title: List a contact's individuals
    • readOnlyHint: true
  • virtuous_list_contact_notesList the notes logged on a contact — calls, meetings, emails and other touchpoints — with type, date, text and author.No findings

    Why it is in this group

    • The name "virtuous_list_contact_notes" says "list": a word for reading.
    Description, as the server wrote it
    List the notes logged on a contact — calls, meetings, emails and other touchpoints — with type, date, text and author. Virtuous: GET /api/ContactNote/ByContact/{contactId}.

    Annotations the server declares

    • title: List a contact's notes
    • readOnlyHint: true
  • virtuous_list_contact_tagsList the tags applied to a contact (contactTagId, tagId, name).No findings

    Why it is in this group

    • The name "virtuous_list_contact_tags" says "list": a word for reading.
    Description, as the server wrote it
    List the tags applied to a contact (contactTagId, tagId, name). Virtuous: GET /api/ContactTag/ByContact/{contactId}.

    Annotations the server declares

    • title: List a contact's tags
    • readOnlyHint: true
  • virtuous_list_eventsList the organization's events: name, type, location, start/end, invite and RSVP counts, attendance and total giving.No findings

    Why it is in this group

    • The name "virtuous_list_events" says "list": a word for reading.
    Description, as the server wrote it
    List the organization's events: name, type, location, start/end, invite and RSVP counts, attendance and total giving. Virtuous: GET /api/Event.

    Annotations the server declares

    • title: List events
    • readOnlyHint: true
  • virtuous_list_tagsList the organization's tags (id, name, tag group).No findings

    Why it is in this group

    • The name "virtuous_list_tags" says "list": a word for reading.
    Description, as the server wrote it
    List the organization's tags (id, name, tag group). Use this to find a tagId before virtuous_add_contact_tag. Virtuous: GET /api/Tag.

    Annotations the server declares

    • title: List tags
    • readOnlyHint: true
  • virtuous_search_contactsFind contacts whose name, email, phone or address fully or partially matches a search string.No findings

    Why it is in this group

    • The name "virtuous_search_contacts" says "search": a word for reading.
    Description, as the server wrote it
    Find contacts whose name, email, phone or address fully or partially matches a search string. Returns id, name, contact type, email, phone and address per match. Virtuous: POST /api/Contact/Search.

    Annotations the server declares

    • title: Search contacts
    • readOnlyHint: true
  • virtuous_search_projectsFind projects (funds / designations gifts are given to) by name or code, with their balances, financial need and life-to-date giving.No findings

    Why it is in this group

    • The name "virtuous_search_projects" says "search": a word for reading.
    Description, as the server wrote it
    Find projects (funds / designations gifts are given to) by name or code, with their balances, financial need and life-to-date giving. Virtuous: POST /api/Project/Search.

    Annotations the server declares

    • title: Search projects
    • readOnlyHint: true

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Install

Pinned to version 1.16.3. Values in angle brackets are yours to fill in.

claude mcp add --transport http virtuous-crm https://virtuous-crm.usefulapi.io/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__virtuous-crm__virtuous_get_current_organization",
      "mcp__virtuous-crm__virtuous_search",
      "mcp__virtuous-crm__virtuous_search_contacts",
      "mcp__virtuous-crm__virtuous_get_contact",
      "mcp__virtuous-crm__virtuous_find_contact",
      "mcp__virtuous-crm__virtuous_list_contact_individuals",
      "mcp__virtuous-crm__virtuous_list_contact_notes",
      "mcp__virtuous-crm__virtuous_list_contact_tags",
      "mcp__virtuous-crm__virtuous_list_contact_gifts",
      "mcp__virtuous-crm__virtuous_get_gift",
      "mcp__virtuous-crm__virtuous_list_tags",
      "mcp__virtuous-crm__virtuous_search_projects",
      "mcp__virtuous-crm__virtuous_get_project",
      "mcp__virtuous-crm__virtuous_list_events",
      "mcp__virtuous-crm__virtuous_get_query_options"
    ],
    "ask": [
      "mcp__virtuous-crm__virtuous_query"
    ],
    "deny": [
      "mcp__virtuous-crm__virtuous_create_contact_note",
      "mcp__virtuous-crm__virtuous_add_contact_tag",
      "mcp__virtuous-crm__virtuous_create_contact_transaction",
      "mcp__virtuous-crm__virtuous_create_gift_transaction"
    ]
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as virtuous-crm. Review it before you use it.