CCAF logo

Domain 2 · Task 2.4

MCP Server Integration

Integrate MCP servers into Claude Code and agent workflows.

MCP (Model Context Protocol) is an open protocol that connects external systems to Claude through three primitives: tools (take action), resources (read for context), and prompts (reusable templates). Integrating servers well is mostly about scope and secrets: shared, committed tooling belongs in project-level .mcp.json; personal/experimental servers belong in user-level ~/.claude.json; and credentials are injected via environment-variable expansion so they never land in version control.

Key concept

Shared + committed → .mcp.json. Personal → ~/.claude.json. Secrets → env-var expansion (${GITHUB_TOKEN}). Standard integration → reuse a community server, not a custom one.

What you need to know

Scope: project vs user

Where a server is configured decides who gets it:

  • Project scope — .mcp.json at the repo root, checked into version control. It is shared with the whole team and is where standard, shared tooling goes.
  • User scope — ~/.claude.json, not shared. This is for personal or experimental servers.

Project- and user-scoped servers are available simultaneously. On connection, all configured servers' tools are discovered automatically and tools from all connected servers are usable at the same time — you don't wire them up per call.

json
// .mcp.json at the project root (committed, shared with the team)
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    }
  }
}

Secrets via env-var expansion

Never commit credentials. Use environment-variable expansion — ${GITHUB_TOKEN} — inside .mcp.json so the config can live in the repo while the actual secret stays in each contributor's environment. The expansion works in the command, args, env, and (for HTTP servers) url/headers fields, and a ${VAR:-default} form supplies a fallback. This is what lets shared tooling be reproducible across the team and CI without leaking secrets into source control.

Reuse community servers; build custom sparingly

For standard integrations — GitHub, Jira, Slack — prefer an existing community MCP server. Building a custom server for something a maintained community server already covers is wasted effort and ongoing maintenance. Reserve custom servers for unique, team-specific workflows that no off-the-shelf server handles. (Deploying and hosting servers is out of exam scope; the decision you're tested on is *reuse vs build*.)

Resources and MCP tool adoption

Two integration levers matter beyond scope:

  • Expose content catalogs as resources. Resources are read-only context (issue summaries, doc hierarchies, DB schemas) that give the agent an immediate "map" of available data, reducing exploratory tool calls. Tools take actions; resources provide readable context.
  • Strengthen MCP tool descriptions for adoption. If the agent keeps preferring a built-in tool (like Grep) over a more capable MCP tool, the fix is to enhance the MCP tool's description to explain its unique capabilities and outputs — the same description-driven selection principle from Task 2.1.

Exam traps

The trapThe reality
It's fine to put the API token directly in .mcp.json since the team needs it to connect.Committing secrets in .mcp.json leaks them. Use ${ENV} expansion so the config is shareable but the secret stays in the environment.
A team-shared MCP server should be configured in ~/.claude.json so everyone can enable it.~/.claude.json is user-scoped and not shared. Shared, committed servers go in the project-root .mcp.json.
Integrating Jira (or GitHub) means building a custom MCP server for it.Standard integrations should reuse a community server. Build custom servers only for unique, team-specific workflows.
The agent ignores a capable MCP tool and uses Grep instead, so the MCP tool must be broken.Selection is description-driven. Strengthen the MCP tool's description to explain its unique capability so the model prefers it.

Practice scenario

Real questions from the bank that test this topic — the correct answer is highlighted.

You need to expose a corporate Postgres database to Claude via MCP. Constraints: the MCP server must run inside your VPC (so it can reach the DB), must support multiple concurrent Claude clients across the company, and authentication should integrate with your existing OAuth provider.

Which MCP transport is appropriate?

Astdio — Claude spawns the server as a subprocess; simplest setup
BHTTP-based transport (SSE / streamable HTTP) — server hosted in your VPC, multi-client capableCorrect
CWebSocket — full duplex; required for multi-client MCP
DLocal file IPC — fastest option for VPC-internal communication

Why: stdio (A) only works for local subprocesses Claude spawns — it can't serve multiple remote clients across a company. The HTTP-based transports (SSE and the newer streamable HTTP) are designed for hosted MCP servers with multi-client support and authentication integration. WebSocket (C) is not an MCP standard transport. File IPC (D) doesn't work across machines and isn't an MCP transport.

Your MCP server exposes information about a company's customer database. The schema and table list change rarely (once a month at most) and are the same regardless of which question is being asked. Individual customer records change constantly and must be fetched per query.

What's the right MCP primitive for each?

ASchema/tables as a tool; customer records as resources
BBoth as tools — resources are for static documentation only
CSchema/tables as resources; customer records as toolsCorrect
DBoth as resources — clients query resources by URI on demand

Why: Resources in MCP represent stable, addressable content the host can load into context — schemas, configuration, documentation. Tools are for actions and dynamic queries that depend on parameters. A stable schema and table list belong as a resource; per-query customer record lookups belong as a tool ( get_customer , search_customers ). A inverts the mapping. B is wrong — resources aren't strictly for documentation but they aren't for dynamic per-query lookups either. D loses the action/query semantics customer record fetches need.

Build exercise

Wire a shared MCP server into a project

~40 min
  1. 1
    Create a .mcp.json at the repo root configuring a community GitHub MCP server via npx.

    Why: Project-scope .mcp.json is the shareable, version-controlled home for team tooling.

  2. 2
    Inject the token with "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" } and confirm the raw token never appears in the file.

    Why: Env-var expansion keeps secrets out of the repo while the config stays committable.

    You should see: The server connects using the environment's token; the committed file contains only ${GITHUB_TOKEN}.

  3. 3
    Add a personal/experimental server to ~/.claude.json and verify both it and the project server's tools are discovered simultaneously.

    Why: Project- and user-scoped servers coexist; all tools are discovered at connection time.

  4. 4
    Expose a content catalog (e.g. issue summaries or a DB schema) as an MCP resource and observe fewer exploratory tool calls.

    Why: Resources give the agent a map of available data, cutting wasted discovery calls.

    You should see: The agent reads the catalog directly instead of probing with multiple tool calls.

  5. 5
    Reproduce the agent preferring Grep over a capable MCP tool, then strengthen the MCP tool's description and re-test.

    Why: Tool adoption is description-driven — a richer description shifts selection toward the MCP tool.

Sources

Drill Tool Design & MCP Integration

Practice only this domain’s questions, untimed, with instant explanations.