Skip to content
back to journal

mcp server

How to Use MCP Servers in Cursor (2026 Setup Guide)

The actual working config for ~/.cursor/mcp.json — two transports, env-var secrets, the 5-minute setup flow, and the debugging loop for the red dot.

Ralph DuinApril 17, 20267 min read

How to Use MCP Servers in Cursor (2026 Setup Guide)

TL;DR — Cursor reads MCP servers from ~/.cursor/mcp.json. Two transport modes (stdio, HTTP). Secrets go in env, referenced via ${env:NAME}. Red dot = missing env var 90% of the time. This post is my actual working config plus the five-minute setup that catches every mistake I've made over the last year.

I run 8 MCP servers in Cursor every day. This is the setup that actually works — no theory, no marketing, just the config file and the debugging loop. For the broader pattern of when to build MCP, read MCP Server vs REST API. For production-grade architecture, read MCP Server Architecture.

The one file that matters: ~/.cursor/mcp.json

Everything lives here. Create the file if it doesn't exist:

mkdir -p ~/.cursor
touch ~/.cursor/mcp.json

A minimal working config with one HTTP and one stdio server:

{
  "mcpServers": {
    "Context7": {
      "url": "https://mcp.context7.com/mcp",
      "headers": { "CONTEXT7_API_KEY": "${env:CONTEXT7_API_KEY}" }
    },
    "Fly": {
      "command": "npx",
      "args": ["-y", "@flydotio/mcp"]
    }
  }
}

Two transports:

  • HTTP (url + headers) — hosted multi-tenant servers. Cursor POSTs JSON-RPC. Bearer tokens go in headers.
  • stdio (command + args) — local child process. Cursor spawns it and talks over stdin/stdout. Good for tools that need your filesystem or dev env.

Env var interpolation: ${env:VAR_NAME} reads from your shell env. ${input:thing} prompts you in Cursor on first use. Never inline a raw token. I've seen MCP configs committed to GitHub with live API keys — don't be that person.

My actual production config (redacted)

{
  "mcpServers": {
    "Supabase":    { "url": "https://mcp.supabase.com/mcp?project_ref=<ref>&features=database%2Cdocs" },
    "GitHub":      { "url": "https://api.githubcopilot.com/mcp/",
                     "headers": { "Authorization": "Bearer ${input:github_mcp_pat}" } },
    "Context7":    { "url": "https://mcp.context7.com/mcp",
                     "headers": { "CONTEXT7_API_KEY": "${env:CONTEXT7_API_KEY}" } },
    "AppHandoff":  { "url": "https://apphandoff.com/api/mcp",
                     "headers": { "Authorization": "Bearer ${env:APPHANDOFF_TOKEN}" } },
    "Fly":         { "command": "npx", "args": ["-y", "@flydotio/mcp"] },
    "Playwright":  { "command": "npx", "args": ["-y", "@playwright/mcp@latest"] },
    "shadcn":      { "command": "npx", "args": ["shadcn@latest", "mcp"] },
    "Infisical":   { "command": "npx", "args": ["-y", "@infisical/mcp"],
                     "env": { "INFISICAL_TOKEN": "${env:INFISICAL_TOKEN}" } }
  }
}

Full breakdown of what each one does in 12 Real MCP Server Examples.

The 5-minute setup flow

  1. Edit ~/.cursor/mcp.json. Add one server to start — Context7 is the safest first pick (free tier, no consequences).
  2. Export the env var in your shell profile. .zshrc / .bashrc:
    export CONTEXT7_API_KEY="c7sk-..."
    
  3. Restart Cursor. Fully quit (Cmd-Q), not just reload the window. MCP discovery runs on start.
  4. Open Cursor settings → Features → MCP. Each server shows a colored dot. Green = tools/list succeeded. Red = something's wrong.
  5. Ask the agent "what MCP tools do you have?" in a new chat. Real answer = you're wired up. Generic answer = restart didn't pick up the config.

If step 4 is red, go to the debugging section below.

stdio vs HTTP: picking the right transport

SituationTransport
Tool needs to read/write your filesystemstdio
Tool runs a subprocess on your machine (Playwright, npm, shell)stdio
Hosted SaaS with multi-tenant auth (Supabase, GitHub, Context7)HTTP
You want the same config on your teammate's machineHTTP
Prototyping your own MCPstdio (switch to HTTP before shipping)

stdio is easier to debug (you can run the command by hand in a terminal). HTTP scales better (multiple agents, multiple machines). My rule: stdio for local-only tools, HTTP for anything hosted.

MCP vs traditional Cursor rules / snippets

Cursor already has rules (.cursor/rules/*.mdc) and inline context. Why add MCP?

  • Rules are static. They're instructions the agent reads every turn.
  • MCP tools are dynamic. The agent calls them when it decides the current task needs that data.

Rules = "here's how we write code." MCP = "go look at what the current production database actually contains right now." You want both.

If you're still relying on copy/paste of schema + docs into chat, you're doing the job MCP was built to eliminate.

Debugging the red dot

The red dot means tools/list failed. In order of how often it's the cause:

  1. Env var not set. Restart Cursor from a shell that has the var exported. macOS GUI apps do not pick up .zshrc unless you launched Cursor from the terminal (open -a Cursor) or set it via launchctl setenv.
  2. Typo in the command for stdio. Run the exact command + args from your terminal — if it errors, your config will error identically.
  3. Wrong URL for HTTP. Curl it with the header:
    curl -s -X POST "$URL" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
    
    If curl returns tools, Cursor should too. If it doesn't, the URL or token is wrong.
  4. Package not found for stdio. npx -y with a wrong package name hangs. Pin the exact name + version.
  5. Tool handshake timeout. Some MCPs are slow on first spawn (npm download). Wait 10 seconds and reload.

Cursor's MCP panel has a "view logs" link next to each server. Read those first. The logs tell you exactly which JSON-RPC call failed.

Environment variables the right way

Three escalating levels of safety:

  • Dev (quick): export CONTEXT7_API_KEY=... in your shell profile. Fine for solo work.
  • Shared dev: Infisical or 1Password CLI — pull the secret at shell init. Then the same mcp.json works across machines without the secrets leaking.
  • Prod-adjacent: Use ${input:name} in mcp.json so Cursor prompts you on first use and stores the value in its keychain. Good for rotating tokens.

One tripwire: macOS GUI apps don't inherit .zshrc exports by default. Either launch Cursor from terminal (open -a Cursor), or set the env globally via launchctl setenv. This is the #1 "why doesn't my MCP work" I see from new users.

Three workflows that justify the setup

1. "What did we ship yesterday?" — Cursor asks GitHub MCP for yesterday's merged PRs, summarizes, drafts a changelog entry. 10 seconds.

2. "Why is checkout broken on prod?" — Cursor asks Fly MCP for the last 60s of logs, Supabase MCP for the last 10 orders rows, Context7 for Stripe webhook spec. Root-cause hypothesis in under a minute.

3. "Scaffold a new admin page using our existing patterns." — Cursor asks shadcn MCP for the right components, filesystem MCP for an existing page as reference, writes the new page, runs the linter. Done in one prompt.

None of these would be MCP-worthy if you only wanted them once. They're MCP-worthy because you do them 40 times a week.

One real trace (what the agent actually does)

Here's a verbatim sequence from a Cursor session on this repo's backend last week — "why did our contact form fail at 3:14 EST?":

  1. Cursor calls Fly.logs (stdio) with app=inspired-api, since=3h — pulls ~60KB of log output.
  2. Cursor filters to the 3:14 window and finds a 502 with mailgun proxy timeout.
  3. Cursor calls Supabase MCP (HTTP) → SELECT * FROM contact_submissions ORDER BY created_at DESC LIMIT 5 — confirms the row never got written (submission never reached the DB).
  4. Cursor calls GitHub MCP → search_code repo:... mailgun proxy timeout — finds the retry config and the Fly secret expected.
  5. Cursor calls Infisical MCP → lists secrets in prod, notices MAILGUN_API_KEY was rotated but not redeployed.

Five tool calls, ~90 seconds, no context-switch. None of it touched the web UI of Fly, Supabase, GitHub, or Infisical. That's the whole pitch for MCP in Cursor — your agent becomes the debugging console.

What's next: remote MCPs and SSE

Cursor added streamable HTTP transport + SSE support over the last year — remote MCPs are now first-class. The upshot: you can deploy an MCP server to Fly or Cloudflare Workers, hand teammates the URL + token, and they get the same tools you do without installing anything.

I deploy most client MCPs this way through AppHandoff. See MCP Server Architecture for what production-grade remote MCP deployment looks like (rate limits, circuit breakers, response caps, structured errors).

Working config checklist

  • ~/.cursor/mcp.json exists
  • At least one HTTP and one stdio server added
  • Env vars exported in a shell profile your Cursor session sees
  • Secrets never inlined
  • Restart Cursor after every config edit
  • Green dots on every server
  • You've asked the agent "what tools do you have?" and it listed them

If all boxes are ticked and it still doesn't work — something's wrong with the specific server, not your config. Swap it for a different one and re-verify.

Want help building your own?

If your team has an internal system that should speak MCP, or you've hit a wall debugging one you built, describe it here. I ship production MCP servers and maintain several of the ones in this post.

Related posts