Skip to main content
Glama
zayedu

poke-plaid-mcp

by zayedu

poke-plaid-mcp

A custom MCP server that hooks your investment portfolio into Poke via Plaid.

Why this exists. Poke can't see your Wealthsimple / brokerage portfolio — there's no public API and no built-in Plaid integration:

"we don't support plaid out of the box right now … but since you're a cracked dev, you could easily build a custom mcp server that hooks into plaid's api and upload it." — Poke

So here it is. Link any brokerage/retirement account through Plaid once, point Poke at this server, and ask things like "what's my portfolio worth?", "what are my biggest winners?", or "how much did I get in dividends this month?".

It works in two modes:

  • Mock mode (default, no credentials needed) — serves a realistic sample Wealthsimple-style portfolio so you can wire up Poke and try every tool right now.

  • Plaid mode — set PLAID_CLIENT_ID / PLAID_SECRET and link your real accounts.


Tools exposed to Poke

Tool

What it does

check_connection

Confirms the data source is connected and lists linked institutions.

list_accounts

All linked investment/brokerage/retirement accounts + last-known balances.

get_balances

Up-to-date balances (forces a fresh read from the institution when supported).

portfolio_summary

Net-worth-style snapshot: total value + unrealized gain/loss by currency, per-account breakdown, allocation by asset type, and top holdings.

list_holdings

Every position: ticker, name, quantity, price, market value, cost basis, unrealized gain/loss. Filter by account / min value; sort by value or gain.

list_investment_transactions

Buys, sells, dividends, contributions, fees, transfers over a date range.

get_dividend_income

Total dividends over a period, broken down by security and currency, plus each payment.

All tools are read-only and never move money.


Related MCP server: Questrade MCP Server

Quick start (mock mode — 60 seconds)

npm install
npm run dev

The server starts on http://localhost:3000. Verify it end-to-end:

npm run test:mcp    # boots the server, drives it with a real MCP client, calls every tool

Then connect it to Poke. Everything works with sample data until you add Plaid credentials.


Using your real portfolio (Plaid)

1. Get Plaid API keys

Create a free account at dashboard.plaid.com and grab your client_id and sandbox/production secret from Developers → Keys. Investments data requires the Investments product (request access in the dashboard if it isn't already enabled).

2. Configure

cp .env.example .env

Fill in at least:

PLAID_CLIENT_ID=your_client_id
PLAID_SECRET=your_secret
PLAID_ENV=sandbox            # or: production
PLAID_PRODUCTS=investments
PLAID_COUNTRY_CODES=US,CA    # CA covers Wealthsimple
TOKEN_ENCRYPTION_KEY=<a long random string>   # encrypts access tokens at rest
MCP_API_KEY=<a random string>                  # require this key on the /mcp endpoint
npm run dev

Open http://localhost:3000/setup, click Connect, and complete Plaid Link. Your bank credentials go straight to Plaid — never to this server. The resulting access token is encrypted and stored in ./data/items.json.

Sandbox shortcut (no browser): with PLAID_ENV=sandbox you can link a test institution from the CLI:

npm run link:sandbox            # default sandbox institution
npm run link:sandbox ins_XXXXX  # a specific one

You can link multiple institutions; all of them are aggregated across every tool.


Connecting to Poke

Poke talks to this server over Streamable HTTP at /mcp. Pick one:

Keeps your financial data and Plaid tokens on your machine. Start the server, then in another terminal:

npx poke@latest tunnel http://localhost:3000/mcp -n "Plaid Portfolio"

Leave both running. Poke syncs the tools automatically. Say "check my portfolio connection" in Poke to confirm.

Option B — Hosted server

Deploy somewhere public (see Deployment), then add it at poke.com/integrations/new:

  • Name: Plaid Portfolio

  • MCP Server URL: https://your-host.example.com/mcp

  • API Key: the value of MCP_API_KEY (sent as a Bearer token)

…or via the CLI:

npx poke@latest mcp add https://your-host.example.com/mcp -n "Plaid Portfolio" -k "$MCP_API_KEY"

Option C — Shareable recipe (Poke Kitchen)

To package this for others, create a recipe at poke.com/kitchen with this server as a required MCP integration and some onboarding context (e.g. first message: "What's my portfolio worth?").


Deployment

Any host that runs a Node service works (Fly.io, Render, Railway, a VPS, …).

docker build -t poke-plaid-mcp .
docker run -p 3000:3000 --env-file .env -v "$PWD/data:/app/data" poke-plaid-mcp

The image sets HOST=0.0.0.0 and NODE_ENV=production, so it won't start without MCP_API_KEY (by design). For a hosted deployment set: MCP_API_KEY, TOKEN_ENCRYPTION_KEY, SETUP_TOKEN, and PUBLIC_BASE_URL=https://your-host. Then link accounts at https://your-host/setup?token=YOUR_SETUP_TOKEN.

Persist /app/data (the volume above) so your linked-account tokens survive restarts. On platforms with an ephemeral filesystem, use a mounted disk/volume.


Configuration reference

Var

Default

Notes

PORT

3000

HTTP/MCP port.

HOST

127.0.0.1

Bind interface. Loopback by default (LAN-safe, works with poke tunnel). Set 0.0.0.0 for containers/hosting.

NODE_ENV

development

In production, the server refuses to start if bound publicly without MCP_API_KEY, or using Plaid without TOKEN_ENCRYPTION_KEY.

PUBLIC_BASE_URL

http://localhost:PORT

Also seeds the Host/Origin allowlist. Set to your public URL when hosted.

MCP_API_KEY

(empty)

If set, /mcp requires Authorization: Bearer <key> (or x-api-key). Required for internet-facing use.

SETUP_TOKEN

(empty)

Token required to use /setup* (pass as ?token=). Required to expose setup on a public host.

ALLOWED_HOSTS / ALLOWED_ORIGINS

(empty)

Extra allowlist entries (loopback + PUBLIC_BASE_URL are always allowed).

ALLOW_ANY_HOST

false

Disable Host-header allowlisting (behind a Host-rewriting proxy). Origin checks stay on.

PLAID_CLIENT_ID / PLAID_SECRET

(empty)

Leave blank for mock mode.

PLAID_ENV

sandbox

sandbox or production.

PLAID_PRODUCTS

investments

Comma-separated Plaid products.

PLAID_COUNTRY_CODES

US,CA

Comma-separated country codes.

PLAID_APP_NAME

Poke Portfolio

Shown in Plaid Link.

TOKEN_STORE_PATH

./data/items.json

Where encrypted tokens live.

TOKEN_ENCRYPTION_KEY

(empty)

AES-256-GCM key for tokens at rest. Required in production w/ Plaid.


Security

This server touches your financial data, so it's locked down by default:

  • Read-only. No tool can move money — only account/holding/transaction reads.

  • Loopback by default. Binds to 127.0.0.1, so a local install is never exposed to your LAN. poke tunnel still reaches it. Hosting requires HOST=0.0.0.0.

  • /mcp auth via MCP_API_KEY (timing-safe Bearer check). In production, the server refuses to start if bound publicly without a key.

  • /setup* auth via SETUP_TOKEN. Without a token, setup is only reachable from localhost (and disabled entirely on a public host).

  • DNS-rebinding / cross-origin protection. Requests with a disallowed Origin are rejected, and the Host header is allowlisted — a malicious website in your browser can't drive the server. Server-to-server callers (Poke, the tunnel) are unaffected.

  • Tokens encrypted at rest with AES-256-GCM (TOKEN_ENCRYPTION_KEY); token file is written 0600. The data/ dir is git-ignored — never commit it.

  • Secrets are redacted from logs. Your bank login is entered in Plaid Link and never touches this server. TLS is provided by the tunnel / your host.

  • npm audit: 0 known vulnerabilities.

For an internet-facing deployment, set all of: HOST=0.0.0.0, NODE_ENV=production, MCP_API_KEY, TOKEN_ENCRYPTION_KEY, SETUP_TOKEN, and PUBLIC_BASE_URL.


How it works

Poke ──HTTP(S) /mcp──▶  Express + MCP (Streamable HTTP, stateless)
                             │
                             ▼
                        PortfolioProvider
                        ┌────────────┴────────────┐
                     PlaidProvider            MockProvider
                     (real Plaid API)      (sample portfolio)

The MCP tool layer is provider-agnostic: it always receives normalized holdings/accounts/transactions, so swapping mock ↔ Plaid changes nothing about the tools Poke sees.

Project structure

src/
  index.ts              # bootstrap
  server.ts             # Express app: /mcp (auth), /health, /setup
  mcp.ts                # MCP server + tool definitions
  portfolio-math.ts     # portfolio + dividend aggregation (pure functions)
  config.ts             # env config, mock/plaid mode selection
  logger.ts             # redacting JSON logger
  store.ts              # encrypted access-token storage
  providers/
    types.ts            # normalized domain types + PortfolioProvider interface
    plaid.ts            # Plaid client, normalization, Link helpers
    mock.ts             # realistic sample data
    index.ts            # provider selection
  routes/link.ts        # Plaid Link setup endpoints
  public/setup.html     # Plaid Link setup UI
scripts/
  sandbox-link.ts       # link a Plaid sandbox institution (no browser)
  test-mcp.ts           # end-to-end MCP smoke test

Notes on Wealthsimple

Wealthsimple has no public portfolio API, which is the whole reason for this server. Plaid's coverage of Wealthsimple's investments data varies by account type and region — if Plaid can link your Wealthsimple account with the Investments product, this server surfaces it. If not, you can link any other Plaid-supported brokerage, and the mock mode always works for building/testing the Poke experience.

License

MIT

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zayedu/poke-plaid-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server