Skip to main content
Glama
wilderfield

plaid-mcp

by wilderfield

plaid-mcp

Servidor MCP de Plaid persistente para un asistente de IA (Elowen) que se ejecuta en un contenedor efímero.

plaid-mcp es un servicio de larga duración alojado externamente que posee el secreto de Plaid y los tokens de acceso cifrados para cada institución vinculada. El asistente llama a las herramientas mcp__plaid__* en tiempo de ejecución; nunca ve los tokens de acceso sin procesar, solo valores opacos de item_id y account_id que Plaid ya considera públicos.

Elowen (ephemeral container)
  └─ calls mcp__plaid__* tools
        └─ plaid-mcp (persistent, nanoclaw-hosted)
              ├─ Plaid SDK + PLAID_SECRET (never leaves this service)
              ├─ access_token store (SQLite, AES-256-GCM at rest)
              └─ /link/start, /link/callback (HTTPS, browser-facing)
                    └─ Plaid REST API / Plaid Link JS

Superficies

Un único proceso de Node.js expone dos superficies completamente separadas:

  1. Servidor MCP. Ya sea stdio (el agente genera este binario como un subproceso) o http (HTTP transmitible en POST /mcp, protegido por token bearer). Elija con MCP_TRANSPORT. Para el caso de uso de presupuesto familiar descrito anteriormente, querrá http para que una flota de contenedores de agentes efímeros pueda compartir un servidor persistente.

  2. Mini-aplicación de enlace HTTPS en /link/*. Se utiliza solo durante el flujo de enlace bancario único: el usuario abre una URL que le proporciona el asistente, inicia sesión en su banco dentro de Plaid Link y listo. Después de eso, el navegador nunca vuelve a ser necesario para esa institución.

Related MCP server: plaid-mcp

Herramientas MCP

Herramienta

Qué hace

list_linked_institutions()

Cada elemento vinculado, con indicador de salud needs_relink (llama a /item/get por elemento).

list_accounts(item_id?)

Lista de cuentas en caché (tipo, subtipo, máscara, último saldo) para una o todas las instituciones.

get_balances(account_ids?)

Saldos en tiempo real a través de /accounts/balance/get (punto final de pago de Plaid).

get_transactions(start_date, end_date, account_ids?, cursor?)

Transacciones por rango de fechas, ~250 por página, cursor de paginación opaco.

search_transactions(query, since?, until?, min_amount?, max_amount?, category?)

Búsqueda de transacciones filtrada del lado del servidor. Devuelve filas compactas.

get_monthly_summary(month, group_by?)

Totales mensuales pre-agregados agrupados por category o merchant. Mantiene el contexto del LLM pequeño.

get_investment_holdings(account_ids?)

Instantánea de posición (ticker, cantidad, valor de mercado, base de costo).

get_investment_transactions(start_date, end_date, account_ids?)

Compras/ventas/dividendos en una ventana.

get_liabilities(account_ids?)

TAE/extractos de tarjetas de crédito, préstamos estudiantiles, detalles de hipotecas.

initiate_link(institution_hint?)

Devuelve { url, session_id, expires_at }: proporcione la URL al usuario.

link_status(session_id)

Sondea hasta que sea succeeded (con un nuevo item_id), failed o expired.

remove_institution(item_id)

Revoca el elemento de Plaid y elimina el token local.

Todas las respuestas de las herramientas son JSON dentro de un único elemento de contenido text (funciona en todos los clientes MCP, incluidos los que no muestran structuredContent).

Flujo de enlace único

  1. Elowen llama a initiate_link({ institution_hint: "Chase" }). El servidor:

    • llama a Plaid /link/token/create,

    • almacena una fila en link_sessions (estado pending),

    • devuelve { url: "https://<LINK_BASE_URL>/link/start?s=<uuid>&sig=<hmac>", session_id, expires_at }.

  2. Elowen envía la URL al usuario.

  3. El usuario la abre en un navegador. La página carga Plaid Link JS desde la CDN oficial con ese link_token y presenta un botón "Open Plaid Link".

  4. El onSuccess de Plaid Link envía mediante POST { public_token, institution } más el ID de sesión firmado de vuelta a /link/callback.

  5. /link/callback intercambia public_tokenaccess_token + item_id, cifra el token de acceso con AES-256-GCM, lo persiste y marca la sesión como succeeded.

  6. Elowen sondea link_status(session_id), ve succeeded con el item_id y continúa.

Los parámetros de la URL firmada (s, sig) tienen una clave HMAC-SHA256 mediante LINK_SESSION_SECRET. La fila de la base de datos es la fuente de verdad: el HMAC simplemente rechaza de forma económica las solicitudes basura antes de que toquemos SQLite.

Configuración

Toda la configuración se realiza mediante variables de entorno (cargadas desde .env).

Variable

Requerido

Predeterminado

Descripción

PLAID_CLIENT_ID

Desde el panel de control de Plaid

PLAID_SECRET

Desde el panel de control de Plaid. Nunca sale de este servicio.

PLAID_ENV

No

sandbox

sandbox

development

production

PLAID_API_VERSION

No

2020-09-14

Versión de API fijada

PLAID_PRODUCTS

No

transactions

Lista separada por comas. Común: transactions,investments,liabilities

PLAID_COUNTRY_CODES

No

US

Lista separada por comas de códigos de país ISO

PLAID_USER_ID

No

family-default

client_user_id estable enviado a Plaid

PLAID_ENCRYPTION_KEY

32 bytes hex (openssl rand -hex 32). Clave AES-256-GCM para tokens en reposo.

LINK_SESSION_SECRET

≥ 32 bytes hex. Clave HMAC para URLs de enlace firmadas.

LINK_SESSION_TTL_SECONDS

No

900

Tiempo de vida de la sesión de enlace

LINK_BASE_URL

URL base HTTPS pública a la que accederá el navegador (ej. https://plaid.example.com)

PORT

No

3333

Puerto HTTP. TLS termina aguas arriba en nanoclaw.

ADMIN_TOKEN

No

Si se establece, protege las rutas de introspección /link/admin/*

MCP_TRANSPORT

No

http

stdio

http

MCP_BEARER_TOKEN

Sí si MCP_TRANSPORT=http

Bearer requerido en POST /mcp

DB_PATH

No

./data/plaid-mcp.sqlite (Docker: /data/plaid-mcp.sqlite)

Ruta de SQLite. Monte un volumen persistente aquí.

LOG_LEVEL

No

info

Nivel de registro de Pino. Todos los registros van a stderr.

Genere secretos con:

make keys

Almacenamiento

SQLite (better-sqlite3) en $DB_PATH. Dos tablas son importantes:

  • items: item_id PK, access_token_blob BLOB cifrado, nombre/id de la institución, estado, expiración del consentimiento.

  • link_sessions: de corta duración, expiran automáticamente cuando se leen después de su expires_at y durante un barrido en segundo plano de 60 segundos.

Los tokens de acceso se almacenan como [1-byte version][12-byte IV][16-byte GCM tag][N-byte ciphertext]. El descifrado falla si la etiqueta GCM no se verifica.

Modelo de seguridad

  • El transporte HTTP de MCP requiere Authorization: Bearer $MCP_BEARER_TOKEN en cada solicitud. Sin esto, la flota de agentes expondría cada cuenta bancaria vinculada a Internet.

  • Las rutas /link/* orientadas al navegador están firmadas (HMAC) y vinculadas a una sesión de corta duración respaldada por la base de datos.

  • Se espera que TLS termine aguas arriba (en nanoclaw / Caddy / lo que sea su borde). El contenedor habla HTTP plano internamente; expóngalo solo a través del proxy.

  • Cada token de Plaid está cifrado en reposo. Incluso con el archivo SQLite en mano, un atacante sin PLAID_ENCRYPTION_KEY no puede usar los tokens.

  • Las herramientas MCP nunca devuelven tokens de acceso al agente. Solo cadenas opacas de item_id / account_id cruzan el límite de MCP.

Desarrollo local

npm install
make setup           # creates .env from env.example
make keys >> .env    # append fresh PLAID_ENCRYPTION_KEY / LINK_SESSION_SECRET / MCP_BEARER_TOKEN
# edit .env: PLAID_CLIENT_ID, PLAID_SECRET, LINK_BASE_URL
npm run dev          # tsx with hot reload

Para pruebas de enlace local, necesitará un túnel HTTPS (el onSuccess de Plaid Link no se activará desde http://localhost). cloudflared, ngrok o un proxy inverso Caddy real funcionan; cualquier nombre de host público que le den va en LINK_BASE_URL.

Docker

make build
make up
make logs

El archivo compose monta ./data:/data para que la base de datos SQLite sobreviva a los reinicios. En una implementación de nanoclaw, reemplace ese montaje de enlace con el volumen persistente gestionado por el clúster.

Conexión del agente a una instancia alojada

Dentro de la configuración del cliente MCP del contenedor del agente:

{
  "mcpServers": {
    "plaid": {
      "url": "https://plaid-mcp.your-domain.example/mcp",
      "headers": {
        "Authorization": "Bearer <MCP_BEARER_TOKEN>"
      }
    }
  }
}

El agente obtiene el token bearer a través de cualquier mecanismo de inyección de secretos que nanoclaw ya utilice para sus otros secretos de agente. Nunca ve PLAID_SECRET ni ningún token de acceso.

Licencia

Interna.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Self-hosted MCP server enabling Claude to query bank accounts, balances, and transactions through Plaid with OAuth and TLS.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A local MCP server that provides read-only SQL access to financial accounts via Plaid, enabling natural language queries about transactions, balances, and holdings.
    MIT
  • F
    license
    A
    quality
    C
    maintenance
    Personal finance MCP server that integrates Plaid bank data with local SQLite memory for conversational budgeting, goal tracking, and transaction management.
    15
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that exposes banking data (connections, accounts, balances, transactions) and agent skills, allowing AI agents to query and refresh financial data via stdio.
    139
    6
    Apache 2.0