Practical Setup · No Theory

MCP Implementation Playbooks: The Setup Guide.

Most content explains what the protocol is. Almost none tells you which of the four real implementation paths fits your situation, or what breaks when you try.

✍️ By Zach Bailey ⏱️ 12 min read ⚡ System Integration Playbook

Model Context Protocol (MCP) standardizes how AI models interact with databases, local code environments, and third-party APIs. But setting up MCP isn't one task. It's four distinct tasks depending on your project scope, team, and security requirements.

TL;DR

Want to connect Slack, Drive, or a DB locally in Claude Desktop or Claude Code? Go to Playbook 1 or 2. Need a shared server for your team without sharing API keys? Use Playbook 3 (OAuth routing). Have a custom internal API to expose? Run Playbook 4. Always read "The Failure Modes Nobody Mentions" before editing config files.

Jump to any playbook

Playbook 1: Local MCP on Claude Desktop

This is the right starting point if you've never run an MCP server and want to confirm the whole thing works before writing code.

Step 1 — Find your config file

Claude Desktop only reads MCP configuration from one file, which is read once on application launch. Locations depend on your OS:

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json

Step 2 — Add a server block

Expose your local filesystem to Claude by adding a server block to the JSON config file. Here is a minimal entry:

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents"]
    }
  }
}

Step 3 — Fully quit and relaunch

Minimize is not enough. You must fully quit the app. On Windows, check the system tray because Claude Desktop keeps running in the background. On macOS, use Cmd+Q.

Step 4 — Verify with a direct ask

Don't ask "is MCP working." Ask Claude to list the specific tools the server exposes, e.g., "What filesystem tools do you have access to right now?" If the tools don't show up, check for JSON formatting errors.

Playbook 2: MCP for Coding Agents

If your actual goal is to let your CLI agent query databases or index local docs while it works, you want MCP wired into your terminal environment.

The mechanics are identical to Playbook 1 (same mcpServers JSON block), but the configuration is local to the project repo rather than global. A project-level agent config should only expose the tools needed for that repository. Giving standing access to your entire filesystem in a coding agent is a major security risk.

💡

Verification step: Run the official MCP Inspector before trusting any third-party server. Install it with npx @modelcontextprotocol/inspector to call tools directly and see raw request/response payloads.

Playbook 3: Remote, Hosted MCP Servers

Use this playbook when you want your entire team using a shared SaaS server (Slack, Notion, Jira) without each developer managing individual API keys.

Remote MCP servers run over HTTP rather than stdio process pipes. Authentication relies on OAuth 2.1 — developers authenticate through a browser login, and the host platform holds a scoped token. This allows you to revoke access for one user without rotating shared keys, and scope permissions to match the user's role.

⚠️

Security Gap: Hosted servers can expose more database tables or workspace directories than your organizational policy intends. Read the specific server's documentation and configure the resource allow-list before turning it on for the team.

Playbook 4: Building Your Own Server

Build a custom server only when you've verified that nothing in the community registry (which has passed 200+ implementations) covers your proprietary data source.

typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/shared/protocol.js";

const server = new Server(
  { name: "my-internal-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "get_account_status",
    description: "Look up account status by customer ID",
    inputSchema: {
      type: "object",
      properties: { customerId: { type: "string" } },
      required: ["customerId"]
    }
  }]
}));

// Run transport loop...

Three Rules for Production-Ready Servers

  1. Validate every input server-side: Never assume LLMs send well-formed arguments. Schema validation (Zod in TypeScript, Pydantic in Python) is mandatory to catch hallucinated parameters.
  2. Return structured errors, not exceptions: A thrown exception gives the model nothing to reason about. Returning a typed error block (like { error: "RATE_LIMIT_EXCEEDED", retryAfter: 60 }) lets it retry or inform the user.
  3. One server, one clear purpose: Avoid creating a single mega-server. Smaller, single-purpose servers are easier to audit and keep within the context window limits.

Failure Modes & Security Checklist

The Failure Modes Nobody Mentions

Keep these in mind when configuring your environment:

Security Checklist

Verify these answers before connecting any third-party server:

Production AI workflows, every Tuesday.

Model benchmarks, gateway playbooks, and the exact architectures we test in production. Free forever.