Skip to main content

affinity-mcp: An Affinity MCP Server

This package sets up the Affinity MCP server locally to interact with the Affinity APIs. Affinity now offers a hosted version. See the setup instructions to get started.

Note: When this MCP server makes requests to the Affinity API, it includes a User-Agent header that identifies the request as coming from the Affinity MCP Server. This helps the Affinity team understand API usage patterns and provide better support for MCP-specific issues.

Features

Persons

  • Search Persons: Search persons using filters, sorts, and an optional keyword
  • Get Person Info: Retrieve detailed information about a person including current organization, job title, and more.
  • Get Multiple Persons' Info: Retrieve basic info and field data (e.g. current organization, job title) for several specific persons in one call
  • Get Person List Entries: View which lists a person appears on
  • Create Person: Create a new person with first name, last name, emails, and optional organization associations
  • Update Person: Update a person's name, or replace their emails or organization associations
  • Delete Person: Permanently delete one or more people by id (confirmation-gated; the deletion preview names the people, counts the list entries that go with them, and marks internal people as not deletable); their list entries, field values, tagged reminders and authored notes are deleted, other notes, files, emails and meetings are kept but no longer attached to the deleted people
  • Merge Persons: Merge a duplicate person into a primary person (confirmation-gated; the preview names both persons and states that the duplicate is deleted); all of the duplicate's data is transferred to the primary person first, then the duplicate is deleted. Cannot be undone through this tool or the external API (no unmerge endpoint there); an org admin can still undo it from Affinity's Duplicate Management settings, or by asking Affinity support.

Companies

  • Search Companies Top Matches: Returns top-matching companies using filters, sorts, keyword, or natural language
  • Search All Companies: Paginate exhaustively through companies using filters, sorts, and an optional keyword
  • Get Company Info: Retrieve detailed information about a company including location, description, and more.
  • Get Company List Entries: View which lists a company appears on
  • Create Company: Create a new company with a required name and optional domain and person associations via person_ids
  • Update Company: Update a company's name or domain, or replace its person associations
  • Delete Company: Permanently delete one or more companies by id (confirmation-gated; the deletion preview names the companies, counts the list entries that go with them, and marks global companies as not deletable); their list entries, field values and reminders are deleted, people and opportunities are kept, notes and files are kept but no longer attached to the deleted company
  • Merge Companies: Merge a duplicate company into a primary one (confirmation-gated; the preview names both companies and predicts the outcome, including what happens to a global company); the duplicate's people, opportunities, list entries, notes, files, interactions, reminders and field values move to the primary in the background. The MCP cannot unmerge; an admin in your organization can unmerge local-company merges from Duplicate Management.
  • Render Market Map: Render a scored, thesis-fit market map as an interactive scatter plot and coverage tables MCP App

Merges

  • Get Merge Task: Check whether a company or person merge finished, by the task_id the merge tool returned (status in-progress, success or failed)

Entity Files

  • Download Entity File: Download a file/attachment by its entity file ID and save it into the server's download sandbox

Opportunities

  • Search Opportunities: Search for opportunities by keyword or list all opportunities
  • Create Opportunity: Create a new opportunity (deal) on an opportunity-type list, optionally associated with companies and persons
  • Update Opportunity: Updates an opportunity by renaming it or replacing its company/person associations
  • Delete Opportunity: Permanently delete one or more opportunities by id (confirmation-gated, with a deletion preview); their list entries, field values, and reminders are deleted, notes and files are detached

Notes

  • Create Note: Create an HTML note attached to persons, companies, opportunities, a meeting, or as a reply to an existing note
  • Query Notes: Find notes with filtering by ID, creator, or creation date
  • Get Notes for Entity: Retrieve all notes attached to a specific person, company, or opportunity
  • Get Entities Attached to Note: Find all persons, companies, or opportunities linked to a specific note
  • Search Notes: Keyword search across note content, optionally scoped to a subset of note IDs or to a specific company
  • Update Note: Edit a note's content or replace its person/company/opportunity associations (creator only)
  • Delete Note: Permanently delete one or more notes by id (confirmation-gated); a root note's replies go with it, attached records are kept

Lists

  • Get Lists: View all lists in your organization that you have access to, with optional filtering by list name
  • Get List Info: Retrieve metadata about a specific list
  • Get Single List Entry: Retrieve metadata about a single list entry from a specific list
  • Create List: Create a new company, person, or opportunity list, optionally public
  • Create List Entry: Add an existing person or company as a list entry to a specific list
  • Delete List Entries: Remove one or more entries from a list (confirmation-gated, with a deletion summary); on opportunity lists this permanently deletes the underlying opportunities
  • Search List Entries: Search and paginate a list's entries using filters, sorts, and an optional keyword

Saved Views

  • Get Saved Views: Retrieve all saved views configured on a specific list
  • Get Saved View List Entries: Retrieve list entries from a specific saved view, returning the fields the view is configured to display

Meetings

  • Get Meetings: Retrieve past and future meetings with filtering by meeting ID, start time, creation time, or update time
  • Get Meetings for Entity: Retrieve past and future meetings for a specific company, person, or opportunity, with filtering by internal person and logging type

Interactions

  • Create Interaction: Log a meeting, call, or chat message with one or more people

Fields

  • Get Entity Fields: View metadata about available fields for companies or persons, with optional filtering by field name
  • Get List Fields: View metadata about available fields for a specific list, with optional filtering by field name
  • Get List Field Dropdown Options: View metadata about available dropdown options for a list field
  • Get Entity Field Dropdown Options: View metadata about available dropdown options for a company or person field
  • Create Field: Create a new field (custom column) on a list or globally on an entity
  • Create List Field Dropdown Option: Add a new dropdown option to a list's dropdown field
  • Update List Field Dropdown Option: Rename or restyle a dropdown option on a list's dropdown field
  • Delete List Field Dropdown Option: Remove a dropdown option from a list's dropdown field

Field Values

  • Upsert Entity Field Values: Create, update, or clear field values in bulk for a company or person
  • Upsert List Entry Field Values: Create or update field values in bulk for a specific list entry

Field Value Changes

  • Get Field Value Changes: Retrieve a paginated audit log of field value changes across the org, filterable by field, list entry, changer, action type, or change time — designed for delta sync workflows

Files

  • Get Entity Files: Retrieve metadata for all files attached to a specific company, person, or opportunity
  • Get Entity File Metadata: Retrieve metadata (including uploader and created date) for a single entity file by ID
  • Search Files: Keyword search across user-uploaded file content, optionally scoped to a subset of file IDs or to a specific company

Inferred Connections

  • Get Investor Executive Connections: Surface investors at your firm with inferred connections to executives at a target company via shared portfolio companies, with pagination
  • Get Coworker Connections: Surface people at your org with overlapping work history with people at a target company, with pagination

Relationship Strengths

  • Get Person Relationships: Retrieve relationship strengths between a person (internal or external) and the people they interact with, with pagination and optional filtering by interaction score
  • Get Company Relationships: Retrieve relationship strengths between your team and the people associated with a company, with pagination and optional filtering by interaction score
  • Render Warm Intro Graph: Render ranked warm intro paths as an interactive network-map MCP App

Reminders

  • Get Reminders: Get reminders with optional filtering by entity, creator, owner, completer, type, reset type, and due date
  • Create Reminder: Create a new reminder
  • Update Reminder: Update an existing reminder's owner, content, due date, recurrence, or completion status
  • Delete Reminder: Delete a reminder by ID

Transcripts

  • Get Transcript Fragments: Get dialogue fragments from a specific transcript

Auth

  • Get Current User: Get information about the current user and organization

Users

  • Get Users: List, search, or paginate through internal Affinity users (team members), with optional filtering by ID or status

Feedback

  • Send Feedback: Submit feedback about a missing capability or limitation directly to Affinity

Prerequisites

1. Setup API Key

Follow the steps in this article to obtain your Affinity API key.

⚠️ Never store your API key in .env files or commit it to version control. Always store it in an environment variable as shown in the configuration examples below.

2. Install UV

Install UV Python package manager (recommended over pip for simpler dependency management)

Local Development

Three ways to run the MCP server from source for local development. Both assume you have cloned the repo and have a valid .env.dev at the project root.

Option 1: make stdio setup

To run the server directly from a checkout (e.g. for development), use the make targets. Both load environment from ENV_FILE (default .env); override it to point at another environment, e.g. make run ENV_FILE=.env.dev.

make run          # start the server over stdio
make inspector    # run the server under the MCP Inspector for interactive debugging

make inspector launches the MCP Inspector, a browser UI for exercising the server's tools by hand. Equivalent to:

npx -y @modelcontextprotocol/inspector -e ENV_FILE=.env uv run affinity-mcp

Option 2: stdio (lightweight, no Docker)

Runs the server as a local subprocess. Fastest to start, no tunnel required. Only works from the same machine.

Claude Code

claude mcp add affinity \
  --scope user \
  --transport stdio \
  --env ENV_FILE=/path/to/affinity-mcp/.env.dev \
  -- uv run --directory /path/to/affinity-mcp affinity-mcp

Verify it's connected:

claude mcp list
# affinity-mcp: uv run ... - ✓ Connected

Option 3: Docker + ngrok (HTTP, remotely accessible)

Runs the server inside Docker and exposes it publicly via ngrok. Required for clients that cannot reach localhost (e.g. Claude Desktop, Claude Web).

1. Create the ngrok environment file

Create .env.dev.local at the project root. Git ignores this file. Put your ngrok auth token in it:

NGROK_AUTHTOKEN=<your-ngrok-auth-token>

2. Start the stack

docker compose --profile ngrok up --build -d

The dev-ngrok container waits for ngrok tunnels to register, then injects their public URLs as env vars before starting uvicorn. Watch startup:

docker compose --profile ngrok logs affinity-mcp-ngrok -f
# [entrypoint] waiting for ngrok tunnels...
# [entrypoint] AFFINITY_LOGIN_URL      → https://<id>.ngrok.app
# [entrypoint] AFFINITY_MCP_SERVER_URL → https://uncoveted-restlessly-denna.ngrok-free.dev
# [entrypoint] AFFINITY_BASE_URL       → https://<id>.ngrok.app

3. Get the MCP URL

curl -s http://localhost:4040/api/tunnels/affinity-mcp | python3 -m json.tool | grep public_url

4. Add to Claude Code

claude mcp add affinity-docker-local \
  --transport http \
  https://uncoveted-restlessly-denna.ngrok-free.dev/mcp

Stop the stack

docker compose --profile ngrok down

Note: Free ngrok accounts get one static domain (uncoveted-restlessly-denna.ngrok-free.dev) and rotating URLs for additional tunnels. The MCP tunnel is pinned to the static domain so the claude mcp add command only needs to be run once. The login and API tunnels rotate on each restart.


Development

This repo uses pre-commit to run formatters and linters (Ruff, Mypy, ESLint, and Prettier) before each commit. After cloning, install the hooks once:

pip install pre-commit    # or: uv tool install pre-commit
pre-commit install

Prettier formats Markdown, YAML, and JSON, wrapping Markdown prose at 100 columns; its config lives in .prettierrc.js and .prettierignore. To format the whole tree on demand, run pre-commit run prettier --all-files.

MCP Client Configuration

Claude Setup

Claude CLI

  1. Add server

    Run the following command with your API key:

    claude mcp add affinity-mcp \
        --scope user \
        --transport stdio \
        --env AFFINITY_API_KEY=your_api_key_here \
        -- uvx affinity-mcp
    
  2. Verify MCP server configuration

    1. Run command: claude mcp list
    2. Ensure that the following server is connected: affinity-mcp: uvx affinity-mcp - ✓ Connected

Claude Desktop

Reference: Connect Local MCP Servers to Claude Desktop

  1. Go to File → Settings → Developer → Edit Config and open claude_desktop_config.json.
  2. Run which uvx in your terminal and copy the full path it returns.
  3. Add the following to the config, replacing the command with the path from the previous step and the API key with your own:
    {
      "mcpServers": {
        "affinity-mcp": {
          "command": "your-uvx-path-here",
          "args": ["affinity-mcp"],
          "env": {
            "AFFINITY_API_KEY": "your_api_key_here"
          }
        }
      }
    }
    
  4. Restart Claude Desktop to apply the changes.

Gemini Setup

Reference: Gemini CLI MCP Configuration

Gemini CLI

  1. Open settings.json

    1. Go to ~/.gemini
    2. Open settings.json
  2. Add server to config file

    Add the server configurations to the config file:

    {
      //...file contains other config objects
      "mcpServers": {
        "affinity-mcp": {
          "command": "uvx",
          "args": ["affinity-mcp"],
          "env": {
            "AFFINITY_API_KEY": "your_api_key_here"
          },
          "trust": false
        }
      }
    }
    
  3. Verify server is connected

    1. Run gemini mcp list or run gemini → /mcp
    2. You should see your server connected:
    Configured MCP servers:
    
    ✓ affinity-mcp: uvx affinity-mcp (stdio) - Connected
    

GitHub Copilot Setup

Copilot VSCode

  1. Add server through VSCode

    1. Open the command palette by pressing Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows/Linux). You'll see a search bar appear at the top of VSCode.
    2. Type >MCP: Add Server in the search bar and select it from the dropdown.
    3. Select Command (stdio) when prompted
    4. Enter uvx affinity-mcp as the command
    5. Enter affinity-mcp as the Server ID
    6. When prompted for a configuration, choose Global if you want the MCP server to be available in all workspaces, or choose a specific workspace.
  2. Add API Key

    1. You should now be able to see a new .vscode/mcp.json file
    2. Open it to verify the configuration.
    3. Underneath args, add your API key:
    "env": {
        "AFFINITY_API_KEY": "your_api_key_here"
    }
    

    Your configuration should look like this:

    {
      "servers": {
        "affinity-mcp": {
          "type": "stdio",
          "command": "uvx",
          "args": ["affinity-mcp"],
          "env": {
            "AFFINITY_API_KEY": "your_api_key_here"
          }
        }
      },
      "inputs": []
    }
    
  3. On the Copilot panel in VSCode, try asking it "What are the available tools?" and you should be able to see the available tools for Affinity MCP.

Copilot CLI

  1. Run Copilot CLI

  2. Add server using /mcp

    1. Run /mcp add
    2. Add the server information:
    Server Name: affinity-mcp
    Server Type: STDIO
    Command: uvx affinity-mcp
    Environment Variables: {"AFFINITY_API_KEY": "your_api_key_here"}
    Tools: *
    
    1. Press CTRL + S to save.
  3. Verify configurations

    1. Run /mcp show and you should see the server is connected.
    2. Open ~/.copilot/mcp_config.json to verify.
    {
      "mcpServers": {
        "affinity-mcp": {
          "tools": ["*"],
          "type": "stdio",
          "command": "uvx",
          "args": ["affinity-mcp"],
          "env": {
            "AFFINITY_API_KEY": "your_api_key_here"
          }
        }
      }
    }
    

Other Clients

See MCP Clients for more options.

OpenTelemetry (Optional)

The server supports OpenTelemetry tracing. To export telemetry data to an OTLP-compatible collector, set the OTEL_EXPORTER_OTLP_ENDPOINT environment variable in your LLM client config alongside your API key:

"env": {
  "AFFINITY_API_KEY": "your_api_key_here",
  "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317"
}

If OTEL_EXPORTER_OTLP_ENDPOINT is not set, telemetry export is disabled and the server operates normally without it.

Download Directory (Optional)

The Download Entity File tool writes downloaded files into a sandbox directory on the machine running the server. By default this is the current user's ~/Downloads folder. To write somewhere else, set the AFFINITY_DOWNLOAD_DIR environment variable to an absolute path in your LLM client config alongside your API key:

"env": {
  "AFFINITY_API_KEY": "your_api_key_here",
  "AFFINITY_DOWNLOAD_DIR": "/path/to/downloads"
}

Downloads are constrained to this directory: callers can request a relative subdirectory but cannot write outside the sandbox, including via a symlink placed inside it that points elsewhere. On a remote/hosted server, files are saved on that server, not on the caller's machine.

~/Downloads is resolved via the server process's home directory at startup. On a non-English-locale Linux desktop, xdg-user-dirs may have localized the real folder name (e.g. ~/Téléchargements on a French system) — if downloaded files aren't showing up where you expect, set AFFINITY_DOWNLOAD_DIR explicitly to your actual folder.

Upload Directories (Optional)

The Upload Entity File tool (stdio/local setups only — it has no hosted/HTTP equivalent) reads a local file from disk and attaches it to a company, person, or opportunity. Reads are constrained to a sandbox, same as downloads: file_path must resolve inside one of the configured upload directories, or it's rejected — including if it only reaches outside via a symlink.

By default the sandbox is the current user's Downloads, Desktop, and Documents folders. To allow other locations, set AFFINITY_UPLOAD_DIRS to a comma-separated list of absolute paths in your LLM client config alongside your API key:

"env": {
  "AFFINITY_API_KEY": "your_api_key_here",
  "AFFINITY_UPLOAD_DIRS": "/path/to/deals,/path/to/other/allowed/folder"
}

AFFINITY_UPLOAD_DIRS replaces the default list entirely — it does not add to it. If you still want Downloads/Desktop/Documents allowed alongside a custom folder, include them explicitly:

"AFFINITY_UPLOAD_DIRS": "~/Downloads,~/Desktop,~/Documents,/path/to/deals"

Platform-specific notes — the built-in defaults may not match your real folders:

  • Windows with OneDrive folder redirection (the default on many Windows 10/11 setups): Desktop and Documents are often redirected to %USERPROFILE%\OneDrive\Desktop / ...\OneDrive\Documents rather than the plain %USERPROFILE%\Desktop / ...\Documents the default checks. If your files live under OneDrive, set AFFINITY_UPLOAD_DIRS explicitly to the OneDrive paths.
  • Linux with a non-English locale: xdg-user-dirs frequently localizes folder names (e.g. ~/Téléchargements instead of ~/Downloads on a French system). The built-in default won't match a localized name — set AFFINITY_UPLOAD_DIRS to your actual folder path(s).
  • macOS: the defaults (~/Downloads, ~/Desktop, ~/Documents) match the standard, non-redirected locations.

If a file you expect to upload lives outside all configured directories, upload_entity_file fails with an error naming the currently-configured directories — add the right one via AFFINITY_UPLOAD_DIRS rather than moving the file.

Troubleshooting

View Server Logs

If the server isn't working as expected, you can view the logs to debug issues.

macOS (Claude Desktop): Open a terminal and run:

tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

Windows (Claude Desktop): Logs are typically located in %APPDATA%\Roaming\Claude\logs.

Common Issues

1. "Authentication failed" or 401 Errors

  • Cause: The AFFINITY_API_KEY environment variable is missing or invalid.
  • Fix: Double-check your API key. Ensure there are no extra spaces or quotes around the key.

2. "Connection refused" or Timeout

  • Cause: The server cannot reach api.affinity.co.
  • Fix:
    • Check your internet connection.
    • If you are on a corporate VPN, ensure it allows traffic to Affinity's API.

3. Changes to API key not taking effect

  • Cause: Claude Desktop loads environment variables when it starts.
  • Fix: You must fully quit and restart Claude Desktop.

4. "Tool not found"

  • Cause: The MCP server might have crashed or failed to start.
  • Fix: Check the logs (see above) for startup errors.

Security

The MCP server acts as a wrapper around the Affinity APIs and does not create a new data access mechanism. The trust boundary and access controls remain at the API layer.

Vulnerability Reporting

If you discover a security vulnerability, please refer to our Security Policy for more information about the disclosure procedure.

Software Bill of Materials (SBOM)

A Software Bill of Materials (SBOM) is automatically generated and included with each release for compliance and security auditing purposes. The SBOM provides a complete inventory of all dependencies and their versions in CycloneDX JSON format.

Access the SBOM:

Option 1: Download from PyPI website

  1. Visit the PyPI package page
  2. Navigate to the Download files tab
  3. Download the .tar.gz source distribution file
  4. Extract and view the SBOM:
    tar -xzf affinity_mcp-{version}.tar.gz
    cat affinity_mcp-{version}/src/affinity_mcp/affinity-mcp-{version}-sbom.json
    

Option 2: Use pip to download

pip download affinity-mcp --no-deps --no-binary :all:
tar -xzf affinity_mcp-*.tar.gz
cat affinity_mcp-*/src/affinity_mcp/affinity-mcp-*-sbom.json

The SBOM can be used with security scanning tools to audit dependencies and identify potential vulnerabilities.

Terms of Use

This MCP server is governed by Affinity's Terms of Use. By using this server, you agree to comply with these terms.

Metadata

Release files for affinity-mcp 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for affinity-mcp 0.7.0
File Size Uploaded Provenance Actions
affinity_mcp-0.7.0.tar.gz 1.9 MB Without provenance Details for affinity_mcp-0.7.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for affinity-mcp 0.7.0
File Interpreter ABI Platform Actions
affinity_mcp-0.7.0-py3-none-any.whl Python 3 none any Details for affinity_mcp-0.7.0-py3-none-any.whl

Total release size: 3.6 MB

Release files / affinity_mcp-0.7.0.tar.gz

Download URL affinity_mcp-0.7.0.tar.gz
Size 1.9 MB
Tags Source
SHA-256 checksum
How to use checksums
630cc063de12d06191b03b6587efa08266812868a6dbe009eb48778ee6aca6e0
BLAKE2b-256 checksum
How to use checksums
f1e54da5b4c8b253ab54a496b4fde4c99cfc2c335e84ee37ef4f7ab1df7e3f48
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / affinity_mcp-0.7.0-py3-none-any.whl

Download URL affinity_mcp-0.7.0-py3-none-any.whl
Size 1.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
e8f23cb30da8631b5635b635d9bb3aa5f37981c56410c5e99d390ab19bde0655
BLAKE2b-256 checksum
How to use checksums
f02277f4c448f01b90a52d112f01e858fe2cc5982f58847e174bd4b205787e06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for affinity-mcp 0.7.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page