MCP: Connecting External Services

Notion, Figma, databases, Slack, and custom tools

Advanced 13 minBuilder
What you'll be able to do
  • Connect external services with `claude mcp add` and OAuth-authenticate them via `/mcp`
  • Choose the right scope (local/project/user) and load servers from config with `--mcp-config` and `--strict-mcp-config`
  • Explain MCP tool search: why definitions are deferred, how schemas load on demand, and how `ENABLE_TOOL_SEARCH` and `alwaysLoad` change that
  • Reference MCP resources with @ mentions and run MCP prompts as `/mcp__server__prompt` commands
  • Audit per-server context and cost with `/mcp` and `/usage`, and skip MCP entirely with `--bare`
At a glance

MCP (Model Context Protocol) lets Claude Code reach beyond your repo into Notion, Figma, Slack, Jira, databases, Google Drive, and custom tools. This lesson covers adding and authenticating servers, the config and scoping flags, OAuth, referencing MCP resources, and the tool-search mechanism that keeps dozens of MCP tools from flooding your context window.

  1. 1The mental model: a USB port for your tools
  2. 2Adding servers: claude mcp add and transports
  3. 3Scopes and loading from config files
  4. 4OAuth: authenticating remote servers via /mcp
  5. 5Tool search: why 200 MCP tools don't blow up your context
  6. 6Resources, prompts, and watching the cost

The mental model: a USB port for your tools

Out of the box, Claude Code knows your repository — files, git, the shell. It knows nothing about your Notion docs, your Figma designs, your Jira backlog, your Postgres database, or your Slack channels. The moment you find yourself copying data out of another tool and pasting it into chat, that is the signal you want MCP.

Model Context Protocol (MCP) is an open standard for AI-to-tool integrations. Think of it as a universal port: instead of Anthropic hand-building an integration for every service, any service can ship an MCP server that speaks the protocol, and Claude Code (the MCP client) plugs into it. Connect the server once and Claude can read and act on that system directly — no more paste-shuffling.

There are two pieces of vocabulary worth pinning down up front:

  • MCP server — the thing you connect to (Notion's server, GitHub's server, a local database script). It exposes tools (actions Claude can call), resources (data Claude can read with @), and prompts (canned commands).
  • Transport — how Claude talks to the server. HTTP is the recommended transport for remote cloud services; stdio runs a server as a local process on your machine; SSE is deprecated in favor of HTTP.

Once a server is connected, a request like "Add the feature in JIRA ENG-4521 and open a PR on GitHub" spans two external systems and your repo — Claude reads the issue, writes the code, and creates the PR, all in one loop.

Key insight

The 'I keep pasting this' heuristic

You don't need MCP for everything. The clean trigger from the docs: connect a server when you find yourself copying data into chat from another tool — an issue tracker, a monitoring dashboard, a design file. If you only touch a system once, paste is fine. If you touch it constantly, wire it up.

Watch out

Trust is part of the threat model

An MCP server can fetch external content, and that content can carry prompt-injection instructions. Only connect servers you trust. Browse vetted connectors in the Anthropic Directory (claude.ai/directory) rather than wiring up arbitrary endpoints, and remember that a server which reads the web is a path for hostile text to reach Claude.

Adding servers: claude mcp add and transports

You add servers from the terminal with claude mcp add. The flag that matters most is --transport, which picks how Claude connects.

Remote HTTP (recommended for cloud services). Most hosted servers — Notion, Stripe, Sentry, Slack — are remote HTTP:

bash
# Basic syntax
claude mcp add --transport http <name> <url>

# Real example: connect to Notion
claude mcp add --transport http notion https://mcp.notion.com/mcp

# With a static Bearer token in a header
claude mcp add --transport http secure-api https://api.example.com/mcp \
  --header "Authorization: Bearer your-token"

Local stdio (for tools that need direct system access). A stdio server is a local process Claude spawns and talks to over standard in/out. Note the -- that separates Claude's flags from the command Claude should run:

bash
# Basic syntax
claude mcp add [options] <name> -- <command> [args...]

# Example: a read-only PostgreSQL server
claude mcp add --transport stdio db -- npx -y @bytebase/dbhub \
  --dsn "postgresql://readonly:pass@prod.db.com:5432/analytics"

Managing what you've added:

bash
claude mcp list            # all configured servers
claude mcp get notion      # details for one server
claude mcp remove notion   # remove it

The official docs span the full menagerie of services — Notion, Figma, Slack, Jira, GitHub, Sentry, Google Drive, PostgreSQL, Airtable, and custom servers you build yourself — but they all reduce to the same three shapes above: a remote HTTP URL, a deprecated SSE URL, or a local stdio command.

Watch out

Option ordering: flags before the name, command after the --

Every option (--transport, --env, --scope, --header) must come before the server name; the -- then separates the name from the command and args passed to the server. claude mcp add --transport stdio --env KEY=value myserver -- python server.py --port 8080 runs python server.py --port 8080 with KEY=value in its environment. Putting flags after the name is the most common beginner error.

Tip

Custom and JSON-defined servers

If you already have a JSON config, claude mcp add-json <name> '<json>' adds it directly. To scaffold your own server, the official mcp-server-dev plugin (/plugin install mcp-server-dev@claude-plugins-official) has Claude build a remote HTTP or local stdio server for you. You can even expose Claude Code itself as a server with claude mcp serve.

Scopes and loading from config files

Where a server's configuration lives determines which projects see it and whether your team shares it. Set this with --scope:

ScopeLoads inShared with team?Stored in
local (default)Current project onlyNo~/.claude.json
projectCurrent project onlyYes, via version control.mcp.json in project root
userAll your projectsNo~/.claude.json
bash
claude mcp add --transport http stripe https://mcp.stripe.com               # local (default)
claude mcp add --transport http paypal --scope project https://mcp.paypal.com/mcp  # team-shared
claude mcp add --transport http hubspot --scope user https://mcp.hubspot.com/anthropic  # everywhere

Project scope is the team play. It writes a .mcp.json at the repo root that you commit to version control, so every teammate gets the same tools. For safety, Claude prompts for approval before using project-scoped servers from .mcp.json (reset those choices with claude mcp reset-project-choices).

Loading servers ad hoc with --mcp-config. Instead of registering servers permanently, you can point a single session at a config — a file (or several), or inline JSON:

bash
claude --mcp-config ./mcp.json                    # load servers from a file
claude --mcp-config '{"mcpServers":{...}}'         # or inline JSON

--strict-mcp-config ignores everything else. Normally --mcp-config servers load in addition to your local/project/user servers. Add --strict-mcp-config and Claude uses only the servers from --mcp-config — nothing from ~/.claude.json or .mcp.json. This is the clean, reproducible setup for CI and scripts, where you want a known-exact tool surface and no surprise servers leaking in.

Tip

Precedence when names collide

If the same server name is defined in several places, Claude connects once using the highest-precedence definition (it does not merge fields). The order is: local → project → user → plugin-provided → claude.ai connectors. Scopes match by name; plugins and connectors match by endpoint URL/command.

Note

Env-var expansion keeps secrets out of git

.mcp.json supports ${VAR} and ${VAR:-default} expansion in command, args, env, url, and headers. This is how a team commits a shared .mcp.json while each member's API key stays in their own environment — e.g. "Authorization": "Bearer ${API_KEY}". Never paste real secret values into a committed config.

OAuth: authenticating remote servers via /mcp

Most cloud servers (Notion, Slack, Sentry, Jira) need you to log in before Claude can act on your account. Claude Code supports OAuth 2.0, and the flow is almost entirely hands-off.

  1. Add the server as usual:
    bash
    claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
  2. Run /mcp inside Claude Code. The server shows up flagged as needing authentication (Claude marks a remote server this way when it returns 401 Unauthorized or 403 Forbidden).
  3. Complete the login in your browser, then return to the terminal. That's it.
text
/mcp

The /mcp panel is your control center for connections: it lists every connected server, shows the tool count next to each, lets you authenticate OAuth servers, and offers Clear authentication to revoke access. Tokens are stored securely (system keychain on macOS) and refreshed automatically, so you log in once.

A few real-world wrinkles worth knowing:

  • OAuth works on HTTP servers, not stdio (which runs locally and uses its own credentials).
  • If the browser redirect fails after you log in, copy the full callback URL from the address bar and paste it into the URL prompt that appears in Claude Code.
  • Some servers need a fixed callback port (--callback-port 8080) or pre-registered credentials (--client-id, --client-secret) when they don't support automatic Dynamic Client Registration.
  • You can pin OAuth scopes with an oauth.scopes field in .mcp.json to restrict a server to a security-approved subset (e.g. "channels:read chat:write search:read" for Slack).

Tip

claude.ai connectors come along for free

If you logged into Claude Code with a Claude.ai subscription, MCP servers you added at claude.ai/customize/connectors are automatically available — /mcp lists them with a claude.ai indicator. Caveat: they load only when your active auth method is your Claude.ai subscription, not when ANTHROPIC_API_KEY, a gateway token, or Bedrock/Vertex is active. If a connector is missing, run /status to check which auth is live.

Resources, prompts, and watching the cost

Beyond tools (actions), MCP servers can expose two more things, plus you'll want to keep an eye on what all this costs in context.

Resources — read data with @ mentions. Just like you reference a file with @path/to/file, you reference an MCP resource with an @ mention. Type @ and connected servers' resources appear in the autocomplete alongside files. The reference format is @server:protocol://resource/path:

text
Can you analyze @github:issue://123 and suggest a fix?
Please review the API docs at @docs:file://api/authentication
Compare @postgres:schema://users with @docs:file://database/user-model

The referenced resource is fetched and attached before Claude responds. (You may also see the older @mcp_resource:protocol://path form referenced elsewhere — the current docs use @server:protocol://resource/path.)

Prompts — canned commands as slash commands. Servers can ship reusable prompts that surface as slash commands in the exact format /mcp__<server>__<prompt>. Type / to discover them; pass arguments space-separated:

text
/mcp__github__list_prs
/mcp__github__pr_review 456
/mcp__jira__create_issue "Bug in login flow" high

Names are normalized (spaces become underscores), and the prompt's result is injected straight into the conversation.

Watch per-server cost. MCP tools, results, and definitions all consume context and tokens. Two commands keep you honest:

  • /mcp — shows the tool count per connected server, so you can spot a server flooding you with tools.
  • /usage (aliases /cost, /stats) — session cost plus a breakdown by skill, subagent, plugin, and MCP server. This is where you discover one chatty server is eating your budget.

Skipping MCP entirely with --bare. When you want a fast, minimal session with no MCP discovery at all — plus no hooks, skills, plugins, auto-memory, or CLAUDE.md — launch with --bare. It leaves only Bash/Read/Edit and sets CLAUDE_CODE_SIMPLE. Perfect for a quick one-off where MCP startup would just be overhead.

bash
claude --bare -p "summarize the git log of the last 10 commits"

Tip

The --channels preview: servers that push to you

An MCP server can also act as a channel that pushes messages into your session — CI results, monitoring alerts, Telegram/Discord chats — so Claude reacts to external events while you're away. Opt a channel in at startup with the (preview) --channels flag, e.g. claude --channels plugin:notifier@mkt. It needs claude.ai authentication. This is the inverse of normal MCP: events flow toward Claude, not requests away from it.

Watch out

MCP output can be large

Claude Code warns when an MCP tool returns more than 10,000 tokens; the default hard cap is 25,000 (MAX_MCP_OUTPUT_TOKENS to raise it). A database or log-query server can dump enormous results — a reason to prefer read-only, scoped queries and to watch /usage after big tool calls.

Try it: Wire up a server, watch the context, and connect two systems

Goal: connect a real MCP server, prove that tool search keeps your context lean, and run a task that spans two systems.

  1. Connect a remote server. Pick something you have an account for — GitHub, Sentry, or Notion. Add it (e.g. claude mcp add --transport http sentry https://mcp.sentry.dev/mcp), then run claude mcp list and claude mcp get <name> to confirm it registered.
  2. Authenticate. Start Claude, run /mcp, and complete the browser OAuth login. Confirm the server shows as connected and note the tool count beside it.
  3. Measure the context cost. Run /context and /usage. With tool search on (the default), note that even a tool-heavy server barely dents your context. For contrast, restart with ENABLE_TOOL_SEARCH=false claude, re-run /context, and compare — you should see the MCP tools now loaded upfront.
  4. Use a resource and a prompt. @-mention a resource (e.g. @github:issue://<number>) and watch it get attached. Type / and find an MCP prompt in the /mcp__<server>__<prompt> format; run it with an argument.
  5. Scope it for a team. Re-add one server with --scope project, open the generated .mcp.json, and confirm it lives at the repo root. Edit it to use ${VAR} expansion for any token so no secret is committed.
  6. Reflect. Which server gave you the most tools, and did you set alwaysLoad on anything? When would --strict-mcp-config or --bare have been the right call for a scripted run? Write three sentences.

Key takeaways

  1. 1MCP connects Claude Code to external services (Notion, Figma, Slack, Jira, GitHub, databases, Google Drive, custom). Add with `claude mcp add --transport http|stdio`, where remote services use HTTP and local processes use stdio after a `--` separator.
  2. 2Scope controls reach and sharing: `--scope local` (default, private), `project` (team-shared `.mcp.json` in git), `user` (all your projects). Load servers ad hoc with `--mcp-config`; `--strict-mcp-config` uses only those, ignoring registered servers.
  3. 3Run `/mcp` to authenticate OAuth servers (flagged on 401/403), check status, see per-server tool counts, and clear auth. Tokens are stored securely and refreshed automatically; OAuth applies to HTTP servers.
  4. 4Tool search (on by default) defers MCP tool schemas — only names load at startup, schemas load on demand via `ToolSearch` — so dozens of tools barely touch context. It needs Sonnet 4+/Opus 4+ (not Haiku). `ENABLE_TOOL_SEARCH=false` loads everything; `alwaysLoad: true` keeps one server's tools always visible.
  5. 5Reference MCP resources as `@server:protocol://resource/path` (e.g. `@github:issue://123`); MCP prompts surface as `/mcp__<server>__<prompt>` commands with space-separated arguments.
  6. 6Audit per-server context cost with `/mcp` and `/usage`; skip MCP discovery (and hooks/skills/plugins/memory) entirely with `--bare`.

Quiz

Lock in what you learned

Check your understanding

0 / 4 answered

1.You run `claude mcp add notion --transport http https://mcp.notion.com/mcp` and it errors. What's wrong?

2.Your team wants everyone on the repo to get the same MCP servers automatically when they clone it. Which scope, and why?

3.You've connected five MCP servers exposing ~200 tools total, but your context usage barely moved at startup. Then you switch to a Haiku model and tools start failing. What's going on?

4.Which of these correctly references an MCP resource and runs an MCP prompt, respectively?

Go deeper

Hand-picked sources to keep learning