Skip to main content

What matters most to you in Delaware County? Take the survey →

← Back to Documentation

MCP Server

A Model Context Protocol server that gives AI assistants full access to the Campaign CRM. Built on the official MCP SDK, it wraps the REST API so that tools like Claude Desktop and Claude Code can manage contacts and track engagement through natural language.

Requires authentication. The MCP server connects to the API using a Sanctum bearer token. You'll need a running instance of the application and a valid API token.


Setup

1. Install dependencies

cd mcp-server && npm install

2. Generate an API token

php artisan app:generate-api-token

3. Configure your client

Add the server to your MCP client configuration. The server reads CONTACTS_API_TOKEN and CONTACTS_API_URL from the project's .env file automatically.

Claude Code (.mcp.json)

{
  "mcpServers": {
    "contacts": {
      "command": "node",
      "args": ["mcp-server/index.js"]
    }
  }
}

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "indigo-nebula-contacts": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-server/index.js"],
      "env": {
        "CONTACTS_API_TOKEN": "your-token-here",
        "CONTACTS_API_URL": "http://localhost:8000"
      }
    }
  }
}

Remote Access

Claude.ai web and Claude Mobile via Streamable HTTP

The remote server exposes all 48 tools over HTTPS using the Streamable HTTP transport, enabling access from Claude.ai web and Claude Mobile without any local setup.

Private CRM data. This endpoint connects directly to the campaign CRM. The Sanctum bearer token is server-side only and never visible to clients, but the endpoint is publicly reachable. Consider restricting to Anthropic IP ranges if needed.

Connect from Claude.ai

  1. Go to claude.ai → Settings → Connectors
  2. Click Add Custom Connector
  3. Enter the URL: https://ryangrissinger.com/mcp
  4. Save — tools will appear in your next conversation

Claude Mobile syncs automatically once the connector is saved via the web interface.

Health check

curl https://ryangrissinger.com/mcp/health

Deployment

The remote server runs as a pm2 process on the same server as the Laravel app, proxied through Nginx.

# Start (first time)
pm2 start mcp-server/remote.js --name mcp-remote

# Check status
pm2 status mcp-remote

# View logs
pm2 logs mcp-remote

Env vars required: CONTACTS_API_TOKEN, CONTACTS_API_URL, and optionally MCP_REMOTE_PORT (default 3100).

Nginx proxy block

location /mcp {
    proxy_pass http://127.0.0.1:3100/mcp;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection '';
    proxy_buffering off;
    proxy_cache off;
    chunked_transfer_encoding on;
}

Tools

48 tools across 12 resource groups

Contacts

9 tools
list_contacts List all contacts with pagination
search_contacts Search by name, email, or notes
get_contact Get full details including related data
add_contact Create a new contact
update_contact Update an existing contact
delete_contact Soft-delete a contact
restore_contact Restore a soft-deleted contact
export_contacts Export all contacts as CSV
import_contacts Import contacts from CSV content

Roles

3 tools

volunteer, donor, door_knocker, phone_banker, event_host, sign_location, endorser, advisor, committee_member, precinct_captain

list_contact_roles List roles for a contact
add_contact_role Add a role to a contact
remove_contact_role Remove a role from a contact

Skills

3 tools

social_media, graphic_design, web_development, writing, public_speaking, fundraising, event_planning, data_entry, canvassing, legal, accounting, photography, videography, translation

list_contact_skills List skills for a contact
add_contact_skill Add a skill to a contact
remove_contact_skill Remove a skill from a contact

Interactions

5 tools

door_knock, phone_call, text_message, email, event, meeting, social_media, mail, other

list_interactions List interactions for a contact
add_interaction Log a new interaction
get_interaction Get interaction details
update_interaction Update an interaction
delete_interaction Delete an interaction

Donations

5 tools

cash, check, credit_card, online, in_kind, other

list_donations List donations for a contact
add_donation Record a new donation
get_donation Get donation details
update_donation Update a donation
delete_donation Delete a donation

Yard Signs

5 tools

requested, placed, removed, damaged, stolen, returned

list_yard_signs List yard signs for a contact
add_yard_sign Request or place a yard sign
get_yard_sign Get yard sign details
update_yard_sign Update yard sign status
delete_yard_sign Delete a yard sign

Donor Ask Statuses

5 tools

not_asked, planned, asked, pledged, donated, declined

list_donor_ask_statuses List ask statuses for a contact
add_donor_ask_status Create a donor ask record
get_donor_ask_status Get ask status details
update_donor_ask_status Update ask status
delete_donor_ask_status Delete an ask status

Activity Logs

3 tools
list_activity_logs List activity logs for a contact
add_activity_log Add an activity log entry
get_activity_log Get activity log details

Intelligence Profile

1 tool

Long-form markdown intelligence profile attached 1:1 to a contact (background, relationships, motivations).

set_contact_profile Create or update a contact intelligence profile

Donor Research

1 tool

Runs the FEC OpenFEC API search for a contact, computes partisan lean and giving capacity, writes findings back to the contact and the activity log.

research_contact_finances FEC search + analysis + write-back

Journal

5 tools

Campaign knowledge base. Entries support project grouping, contact linking, and community tagging.

list_journal_entries List journal entries (filterable)
get_journal_entry Get a journal entry with linked contacts
add_journal_entry Create a journal entry
update_journal_entry Update a journal entry
delete_journal_entry Delete a journal entry

Fundraising

3 tools

1:1 fundraising profile per contact. Tier (1/2/3/not_now) is auto-derived from donor_grade and giving_capacity unless tier_manual_override is set. Ask cycle: planned, asked_1, asked_2, asked_3, committed, received, declined, recurring.

set_fundraising_profile Create or update a fundraising profile
get_fundraising_profile Read a fundraising profile
list_fundraising_profiles List profiles with filters

Architecture

Runtime
Node.js with the official @modelcontextprotocol/sdk
Transports

stdio — Claude Desktop and Claude Code (local process)

Streamable HTTP — Claude.ai web and Claude Mobile (remote HTTPS)

Auth
Laravel Sanctum bearer token — server-side only, never exposed to clients
Source

mcp-server/index.js — stdio entry point

mcp-server/remote.js — HTTP entry point

mcp-server/tools.js — shared tool definitions and handlers