# MCP Integrations

<SlideStart />

## What is MCP?

MCP stands for Model Context Protocol. It is an open standard that lets Claude Code connect to external tools and data sources through a defined server protocol. An MCP server exposes a set of **tools** that Claude can call — read from a database, query an API, run a search, fetch a document. From Claude's perspective, an MCP tool looks exactly like a built-in tool such as Bash or Read. The protocol standardizes how those tools are described, called, and responded to.

The architecture has three moving parts: the Claude Code client, the MCP server, and the external system that server wraps.

<DiagramViewer title="MCP architecture">
```d2
direction: right

claude: Claude Code
client: MCP Client
server: MCP Server
external: {
  db: Database
  api: API
  tool: Tool
}

claude <-> client
client <-> server
server <-> external.db
server <-> external.api
server <-> external.tool
```
</DiagramViewer>

Claude Code acts as the MCP client. It sends a tool call with structured inputs to the MCP server, which handles the request against the external system and returns a structured response. Claude never touches the external system directly — all communication goes through the server.

<SlideEnd />

<SlideStart />

## Why use MCP in Claude Code?

Before MCP, giving Claude access to an internal system meant writing a skill that told Claude to construct a specific `curl` command, pass the right headers, handle authentication inline, and parse whatever JSON came back. That works for a one-off task. It breaks when the API changes, when a colleague uses the same skill against a different environment, or when the endpoint requires more than one call to get a useful result.

MCP separates the integration logic from the instructions. You write a server once. The server exposes typed tools with defined inputs and outputs. Claude calls those tools the same way it calls Bash — with validated parameters, without needing to know anything about the underlying API.

There is another advantage that matters specifically in team settings: MCP servers are reusable across any MCP-compatible client. A server your team writes for Claude Code today can be used by other tools that adopt the same protocol. You write the integration once and share it.

<SlideEnd />

<SlideStart />

## MCP vs creating manual skills

Consider a common DS/ML task: querying a feature store to retrieve training features for a given entity.

**Manual skill approach.** You write a skill file that instructs Claude to run a specific `curl` command against the feature store REST API, substitute the entity ID into the URL, set the `Authorization` header using a token it reads from the environment, and then parse the JSON array from the response. Claude follows the instructions, but there is no type checking on inputs, no schema for the response, and the skill breaks silently if the endpoint path or response shape changes.

**MCP approach.** You write a `feature-store` MCP server that exposes a single tool: `get_features`. Claude calls it with named, typed parameters and receives a structured object back. The server handles authentication, retries, and response parsing internally.

Here is what an MCP tool definition looks like in Python using the official SDK:

```python title="feature_store_server.py"
@server.list_tools()
async def list_tools():
    return [
        {
            "name": "get_features",                          # [1]
            "description": "Fetch features for a given entity from the feature store.",
            "inputSchema": {                                 # [2]
                "type": "object",
                "properties": {
                    "entity_id": {"type": "string"},
                    "feature_names": {
                        "type": "array",
                        "items": {"type": "string"}
                    }
                },
                "required": ["entity_id", "feature_names"]
            }
        }
    ]
```

1. The tool name is what Claude uses when it decides to call this tool. Keep names short and verb-noun.
2. The input schema is a standard JSON Schema object. Claude uses it to construct valid calls — no prompt engineering required to get the right shape.

When Claude calls `get_features`, it passes `entity_id` and `feature_names` as structured arguments. The server validates them against the schema before executing anything.

<SlideEnd />

<SlideStart />

## MCP servers available by default

Claude Code does not bundle MCP servers, but the MCP community maintains a set of official servers that cover the most common integrations. These install on demand via `npx`. The ones most relevant to DS/ML work:

| Server | Package | What it gives Claude |
|--------|---------|----------------------|
| PostgreSQL | `@modelcontextprotocol/server-postgres` | Run SQL queries against a Postgres database |
| SQLite | `@modelcontextprotocol/server-sqlite` | Query local SQLite files |
| Filesystem | `@modelcontextprotocol/server-filesystem` | Structured file operations beyond the built-in Read/Write tools |
| GitHub | `@modelcontextprotocol/server-github` | Issues, pull requests, repository search |
| Brave Search | `@modelcontextprotocol/server-brave-search` | Live web search |

To enable a server, add it to `.claude/settings.json` under `mcpServers`. Each entry specifies the command to launch the server and any arguments it needs:

```json title=".claude/settings.json"
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
    }
  }
}
```

Once the config is saved, restart your Claude Code session. The server starts automatically and its tools appear in Claude's tool list for the duration of that session.

For credentials, use environment variables. The `env` field in the server config accepts references to your shell environment:

```json title=".claude/settings.json"
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_URL": "${POSTGRES_URL}"
      }
    }
  }
}
```

Set `POSTGRES_URL` in your shell or in a `.env` file that is not committed to git.

<SlideEnd />

<SlideStart />

## Dos and don'ts

| Do | Don't |
|----|-------|
| Use MCP for stable, typed integrations with internal systems | Use MCP for one-off scripts — a skill is simpler |
| Restrict MCP server permissions to read-only when possible | Give write access without careful review |
| Test MCP tools in isolation before using them in Claude sessions | Assume Claude will handle MCP errors gracefully |
| Document what each MCP tool does in CLAUDE.md | Leave MCP tools undocumented |
| Keep MCP server config in `.claude/settings.json` committed to git | Store credentials in settings.json |

<Callout type="danger">
  Never store API keys, database passwords, or any credentials directly in `.claude/settings.json`. That file is committed to git and will end up in version history. Use environment variables and reference them with `${VAR_NAME}` in the `env` field.
</Callout>

<SlideEnd />