09 · MCP 101: Connecting AI to Tools

The Model Context Protocol (MCP) is an open standard for connecting AI applications to external tools and data. It is often called "USB-C for AI": build a connector once and it works in many AI apps.

Level 150 minTrack 8 · MCP & integrationLast verified 2026-10

By the end of this page you can

The problem: N × M integrations

Without MCP: every app × every tool With MCP: one protocol IDE Chat app CLI agent GitHub Database Docs 3 × 3 = 9 custom integrations IDE Chat app CLI agent MCP GitHub Database Docs 3 + 3 = 6 implementations
MCP turns an N×M integration problem into N+M. A tool vendor writes one MCP server, and every MCP-capable app can use it.

MCP was introduced in late 2024 as an open specification. It was quickly adopted across the industry: IDEs (VS Code, JetBrains IDEs, Xcode), chat apps, terminal agents, and frameworks. It is now the default way to give AI apps access to tools and data. The specification is versioned by date, and new revisions appear periodically.

Architecture: host, client, server

Host (AI application) IDE, chat app, CLI agent + the LLM MCP client #1 MCP client #2 MCP client #3 Server: Metals (local, stdio/HTTP) Server: Postgres (local, stdio) Server: Issue tracker (remote, HTTP) JSON-RPC
One host creates one client per server connection. Servers can run locally (launched as a process) or remotely (over HTTP).
RoleWhat it isExamples
HostThe AI application the user interacts with. Owns the LLM, the UI, permissions and security.VS Code, IntelliJ IDEA, Xcode, a chat desktop app, a terminal agent
ClientA connector inside the host that talks to one server.Built into the host, invisible to you
ServerA program that exposes capabilities (tools, data, prompts) over MCP.Git, GitHub, databases, file systems, browsers, Metals (Scala), Xcode, docs search

The primitives

Server features: what servers offer

PrimitiveControlled byWhat it isExample
ToolsModelFunctions the model can call to do things or fetch data.compile_project, run_query, create_issue
ResourcesApplication / userRead-only data identified by a URI that can be attached as context.file:///schema.sql, db://tables/orders
PromptsUserReusable prompt templates the server offers, often shown as slash commands./review-migration

Client features: what servers can ask the host for

PrimitiveWhat it does
SamplingThe server asks the host's LLM to generate text, so the server needs no model or API key of its own. The user stays in control.
ElicitationThe server asks the user for extra input mid-task ("Which environment: staging or prod?").
RootsThe host tells the server which directories/projects it may work within.

Most of your early use of MCP will be tools. The rest becomes important when you build servers (Level 3).

Transports

stdio (local)

The host launches the server as a child process and talks over standard input/output. Simple, fast and private. Typical for local tools: git, file system, database on your laptop, language servers.

Streamable HTTP (remote)

The server runs as a web service, either locally on a port or in the cloud. Supports many users, authentication (OAuth-based authorization) and streaming. Typical for SaaS integrations.

What actually goes over the wire

MCP uses JSON-RPC 2.0 messages. A simplified exchange:

{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [
  { "name": "word_count",
    "description": "Count words in a text. Use when the user asks how long a text is.",
    "inputSchema": { "type": "object",
      "properties": { "text": { "type": "string" } }, "required": ["text"] } }
] } }
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
  "params": { "name": "word_count", "arguments": { "text": "Scala is fun" } } }
{ "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "3" } ] } }

There is also an initial handshake where client and server agree on the protocol version and declare their capabilities. SDKs handle all of this for you.

Configuring MCP servers

Each host has its own configuration file or command, but they all need the same information: a name, a transport, and either a command to launch (stdio) or a URL (HTTP), plus optional environment variables or headers.

{
  "servers": {
    "metals": {
      "type": "http",
      "url": "http://localhost:<port>/mcp"
    },
    "postgres-dev": {
      "type": "stdio",
      "command": "uvx",
      "args": ["some-postgres-mcp-server", "--read-only"],
      "env": { "DATABASE_URL": "${input:devDbUrl}" }
    }
  },
  "inputs": [
    { "id": "devDbUrl", "type": "promptString", "description": "Dev DB URL", "password": true }
  ]
}
{
  "mcpServers": {
    "my-tools": { "command": "python", "args": ["/path/to/server.py"] }
  }
}
# examples - check your agent's docs for exact syntax
claude mcp add --transport stdio xcode -- xcrun mcpbridge
codex mcp add my-tools -- python /path/to/server.py
Scala developers: Metals MCP Recent versions of Metals (the Scala language server) can start an MCP server that gives agents compiler-backed tools: compile files and modules, inspect symbols and types, find usages, run tests, format, and more. Enable it in Metals settings (e.g. metals.startMcpServer) and Metals can generate the MCP config for supported editors. A standalone metals-mcp launcher (installable via Coursier) also exists for headless use with CLI agents. See page 10.

A tiny MCP server in Python

To demystify servers, here is a complete server using the official Python SDK. Level 3 covers building servers properly, including Scala/JVM.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("word-tools")

@mcp.tool()
def word_count(text: str) -> int:
    """Count words in a text. Use when the user asks how long a text is."""
    return len(text.split())

@mcp.tool()
def to_snake_case(name: str) -> str:
    """Convert a camelCase or PascalCase identifier to snake_case."""
    import re
    return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()

if __name__ == "__main__":
    mcp.run()  # stdio transport by default

Register it in your host (for example "command": "python", "args": ["word_tools.py"]) and ask: "How many words are in this paragraph?" The agent will call word_count. Notice that the docstrings become the tool descriptions the model reads.

Debugging tip The official MCP Inspector (npx @modelcontextprotocol/inspector) is a web UI that connects to a server and lets you list and call its tools by hand. Use it to test a server before plugging it into an agent.

MCP vs related concepts

ConceptWhat it isRelationship to MCP
Function / tool callingThe model API feature that lets a model request a call to a defined function.MCP is built on top: it standardises how tools are discovered and executed across apps.
Plugins / extensionsApp-specific integration mechanisms.MCP is portable across apps. Many plugin systems now bundle MCP servers.
SkillsPackaged instructions and scripts.Complementary: a skill teaches how, MCP provides access. A skill can say "use the db tool to…".
ACP (Agent Client Protocol)Connects editors to coding agents.Different direction: ACP = editor ↔ agent, MCP = agent ↔ tools.
A2A (Agent2Agent)Agents talking to other agents.Complementary: A2A = agent ↔ agent.
LSP (Language Server Protocol)Editors ↔ language intelligence.MCP was inspired by LSP's "one protocol, many clients" idea.

Security essentials

An MCP server is code running with your permissions A local stdio server runs as a process on your machine with your user's access. A remote server receives whatever data the agent sends it. Treat installing an MCP server like installing any software, and give it only the access it needs.
Try it (25 min)
  1. Install the Python SDK (uv add mcp or pip install mcp) and save word_tools.py.
  2. Test it in the MCP Inspector: list tools, call to_snake_case("OrderLineItem").
  3. Register it in your IDE or CLI agent and ask a question that should trigger it.
  4. Bonus: improve a tool description and see whether the agent picks the tool more reliably.

Key takeaways