# MCP Configuration Guide

This document provides comprehensive guidance for configuring Model Context Protocol (MCP) servers with Claude Code for the Flyer Crawler project.

## Table of Contents

1. [What is MCP](#what-is-mcp)
2. [Server Overview](#server-overview)
3. [Configuration Locations](#configuration-locations)
4. [Global Settings Configuration](#global-settings-configuration)
5. [Project-Level Configuration](#project-level-configuration)
6. [Server Setup Instructions](#server-setup-instructions)
7. [Bugsink MCP](#bugsink-mcp)
8. [PostgreSQL MCP](#postgresql-mcp)
9. [Gitea MCP](#gitea-mcp)
10. [Other MCP Servers](#other-mcp-servers)
11. [Troubleshooting](#troubleshooting)
12. [Best Practices](#best-practices)

---

## What is MCP

Model Context Protocol (MCP) is a standardized protocol that allows AI assistants like Claude to interact with external tools and services. MCP servers expose capabilities (tools) that Claude can invoke to:

- Query databases
- Manage containers
- Access file systems
- Interact with APIs (Gitea, Bugsink, etc.)
- Store and retrieve knowledge graph data
- Inspect caches and key-value stores

**Why We Use MCP:**

| Benefit            | Description                                                              |
| ------------------ | ------------------------------------------------------------------------ |
| Direct Integration | Claude can directly query databases, inspect containers, and access APIs |
| Context Awareness  | Tools provide real-time information without manual copy-paste            |
| Automation         | Complex workflows can be executed through tool chains                    |
| Consistency        | Standardized interface across different services                         |

---

## Server Overview

The Flyer Crawler project uses the following MCP servers:

| Server             | Tool Prefix                | Purpose                                            | Config Location |
| ------------------ | -------------------------- | -------------------------------------------------- | --------------- |
| `gitea-projectium` | `mcp__gitea-projectium__*` | Gitea API at gitea.projectium.com                  | Global          |
| `gitea-torbonium`  | `mcp__gitea-torbonium__*`  | Gitea API at gitea.torbonium.com                   | Global          |
| `podman`           | `mcp__podman__*`           | Container management                               | Global          |
| `filesystem`       | `mcp__filesystem__*`       | File system access                                 | Global          |
| `memory`           | `mcp__memory__*`           | Knowledge graph persistence                        | Global          |
| `redis`            | `mcp__redis__*`            | Redis cache inspection                             | Global          |
| `bugsink`          | `mcp__bugsink__*`          | Production error tracking (bugsink.projectium.com) | Global          |
| `localerrors`      | `mcp__localerrors__*`      | Dev container error tracking (localhost:8000)      | Project         |
| `devdb`            | `mcp__devdb__*`            | Development PostgreSQL database                    | Project         |

---

## Configuration Locations

Claude Code uses **two separate configuration systems** for MCP servers:

### Global Configuration

**Location (Windows):**

```text
C:\Users\<username>\.claude\settings.json
```

**Used For:**

- Production services (HTTPS endpoints)
- Servers shared across all projects
- Container management (Podman)
- Knowledge graph (Memory)

### Project-Level Configuration

**Location:**

```text
<project-root>/.mcp.json
```

**Used For:**

- Localhost services (HTTP endpoints)
- Development databases
- Project-specific tools

### When to Use Each

| Scenario                          | Configuration          |
| --------------------------------- | ---------------------- |
| Production APIs (HTTPS)           | Global `settings.json` |
| Shared tools (memory, filesystem) | Global `settings.json` |
| Localhost services (HTTP)         | Project `.mcp.json`    |
| Development databases             | Project `.mcp.json`    |
| Per-project customization         | Project `.mcp.json`    |

**Important:** Localhost MCP servers work more reliably in project-level `.mcp.json` than in global `settings.json`. See [Troubleshooting](#localhost-servers-not-loading) for details.

---

## Global Settings Configuration

### File Format

```json
{
  "mcpServers": {
    "server-name": {
      "command": "path/to/executable",
      "args": ["arg1", "arg2"],
      "env": {
        "ENV_VAR": "value"
      },
      "disabled": true
    }
  }
}
```

**Configuration Options:**

| Field      | Required | Description                               |
| ---------- | -------- | ----------------------------------------- |
| `command`  | Yes      | Path to executable or command             |
| `args`     | No       | Array of command-line arguments           |
| `env`      | No       | Environment variables for the server      |
| `disabled` | No       | Set to `true` to disable without removing |

### Example Global Configuration

```json
{
  "mcpServers": {
    "memory": {
      "command": "D:\\nodejs\\npx.cmd",
      "args": ["-y", "@modelcontextprotocol/server-memory"]
    },
    "filesystem": {
      "command": "d:\\nodejs\\node.exe",
      "args": [
        "c:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@modelcontextprotocol\\server-filesystem\\dist\\index.js",
        "d:\\gitea"
      ]
    },
    "podman": {
      "command": "D:\\nodejs\\npx.cmd",
      "args": ["-y", "podman-mcp-server@latest"],
      "env": {
        "DOCKER_HOST": "npipe:////./pipe/podman-machine-default"
      }
    },
    "redis": {
      "command": "D:\\nodejs\\npx.cmd",
      "args": ["-y", "@modelcontextprotocol/server-redis", "redis://localhost:6379"]
    },
    "bugsink": {
      "command": "d:\\nodejs\\node.exe",
      "args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
      "env": {
        "BUGSINK_URL": "https://bugsink.projectium.com",
        "BUGSINK_TOKEN": "<40-char-hex-token>"
      }
    },
    "gitea-projectium": {
      "command": "d:\\gitea-mcp\\gitea-mcp.exe",
      "args": ["run", "-t", "stdio"],
      "env": {
        "GITEA_HOST": "https://gitea.projectium.com",
        "GITEA_ACCESS_TOKEN": "<your-token>"
      }
    },
    "gitea-torbonium": {
      "command": "d:\\gitea-mcp\\gitea-mcp.exe",
      "args": ["run", "-t", "stdio"],
      "env": {
        "GITEA_HOST": "https://gitea.torbonium.com",
        "GITEA_ACCESS_TOKEN": "<your-token>"
      }
    }
  }
}
```

---

## Project-Level Configuration

### File Location

Create `.mcp.json` in the project root:

```text
d:\gitea\flyer-crawler.projectium.com\flyer-crawler.projectium.com\.mcp.json
```

### File Format

```json
{
  "mcpServers": {
    "server-name": {
      "command": "path/to/executable",
      "args": ["arg1", "arg2"],
      "env": {
        "ENV_VAR": "value"
      }
    }
  }
}
```

### Current Project Configuration

```json
{
  "mcpServers": {
    "localerrors": {
      "command": "d:\\nodejs\\node.exe",
      "args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
      "env": {
        "BUGSINK_URL": "http://127.0.0.1:8000",
        "BUGSINK_TOKEN": "<40-char-hex-token>"
      }
    },
    "devdb": {
      "command": "D:\\nodejs\\npx.cmd",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://postgres:postgres@127.0.0.1:5432/flyer_crawler_dev"
      ]
    }
  }
}
```

---

## Server Setup Instructions

### Memory (Knowledge Graph)

**Package:** `@modelcontextprotocol/server-memory`

**Purpose:** Persists knowledge across sessions - project context, credentials, known issues.

**Configuration:**

```json
"memory": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "@modelcontextprotocol/server-memory"]
}
```

**Key Tools:**

- `mcp__memory__read_graph` - Read entire knowledge graph
- `mcp__memory__search_nodes` - Search for specific entities
- `mcp__memory__create_entities` - Add new knowledge

### Filesystem

**Package:** `@modelcontextprotocol/server-filesystem`

**Purpose:** Provides file system access to specified directories.

**Configuration:**

```json
"filesystem": {
  "command": "d:\\nodejs\\node.exe",
  "args": [
    "c:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@modelcontextprotocol\\server-filesystem\\dist\\index.js",
    "d:\\gitea"
  ]
}
```

**Note:** The last argument(s) specify allowed directories.

### Podman/Docker

**Package:** `podman-mcp-server`

**Purpose:** Container management - list, start, stop, inspect containers.

**Configuration:**

```json
"podman": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "podman-mcp-server@latest"],
  "env": {
    "DOCKER_HOST": "npipe:////./pipe/podman-machine-default"
  }
}
```

**Key Tools:**

- `mcp__podman__container_list` - List running containers
- `mcp__podman__container_logs` - View container logs
- `mcp__podman__container_inspect` - Detailed container info
- `mcp__podman__image_list` - List images

### Redis

**Package:** `@modelcontextprotocol/server-redis`

**Purpose:** Inspect Redis cache, set/get values, list keys.

**Configuration:**

```json
"redis": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "@modelcontextprotocol/server-redis", "redis://localhost:6379"]
}
```

**Key Tools:**

- `mcp__redis__get` - Get value by key
- `mcp__redis__set` - Set key-value pair
- `mcp__redis__list` - List keys matching pattern
- `mcp__redis__delete` - Delete key(s)

---

## Bugsink MCP

Bugsink is a self-hosted error tracking service. We run two instances:

| Instance    | URL                              | MCP Server    | Purpose                      |
| ----------- | -------------------------------- | ------------- | ---------------------------- |
| Production  | `https://bugsink.projectium.com` | `bugsink`     | Production error tracking    |
| Development | `http://localhost:8000`          | `localerrors` | Dev container error tracking |

### Installation

The `bugsink-mcp` package is **NOT published to npm**. Clone and build from source:

```bash
# Clone the repository
git clone https://github.com/j-shelfwood/bugsink-mcp.git d:\gitea\bugsink-mcp

# Install and build
cd d:\gitea\bugsink-mcp
npm install
npm run build
```

**Repository:** https://github.com/j-shelfwood/bugsink-mcp

### Configuration

**Production (Global `settings.json`):**

```json
"bugsink": {
  "command": "d:\\nodejs\\node.exe",
  "args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
  "env": {
    "BUGSINK_URL": "https://bugsink.projectium.com",
    "BUGSINK_TOKEN": "<40-char-hex-token>"
  }
}
```

**Development (Project `.mcp.json`):**

```json
"localerrors": {
  "command": "d:\\nodejs\\node.exe",
  "args": ["d:\\gitea\\bugsink-mcp\\dist\\index.js"],
  "env": {
    "BUGSINK_URL": "http://127.0.0.1:8000",
    "BUGSINK_TOKEN": "<40-char-hex-token>"
  }
}
```

**Required Environment Variables:**

| Variable        | Description                                  |
| --------------- | -------------------------------------------- |
| `BUGSINK_URL`   | Full URL to Bugsink instance (with protocol) |
| `BUGSINK_TOKEN` | 40-character hex API token                   |

**Important:**

- Variable is `BUGSINK_TOKEN`, NOT `BUGSINK_API_TOKEN`
- Do NOT use `npx` - the package is not on npm
- Use `http://127.0.0.1:8000` not `http://localhost:8000` for localhost

### Creating API Tokens

Bugsink 2.0.11 does NOT have a "Settings > API Keys" menu in the UI. Tokens must be created via Django management command.

**For Dev Container (localhost:8000):**

```bash
MSYS_NO_PATHCONV=1 podman exec \
  -e DATABASE_URL=postgresql://bugsink:bugsink_dev_password@postgres:5432/bugsink \
  -e SECRET_KEY=dev-bugsink-secret-key-minimum-50-characters-for-security \
  flyer-crawler-dev sh -c 'cd /opt/bugsink/conf && \
  DJANGO_SETTINGS_MODULE=bugsink_conf \
  PYTHONPATH=/opt/bugsink/conf:/opt/bugsink/lib/python3.10/site-packages \
  /opt/bugsink/bin/python -m django create_auth_token'
```

**For Production (via SSH):**

```bash
ssh root@projectium.com "cd /opt/bugsink && bugsink-manage create_auth_token"
```

Both commands output a 40-character lowercase hex token (e.g., `a609c2886daa4e1e05f1517074d7779a5fb49056`).

### Key Tools

- `mcp__bugsink__test_connection` / `mcp__localerrors__test_connection` - Verify connection
- `mcp__bugsink__list_projects` - List all projects
- `mcp__bugsink__list_issues` - List issues for a project
- `mcp__bugsink__get_issue` - Get issue details
- `mcp__bugsink__get_stacktrace` - Get event stacktrace as Markdown

### Testing Connection

```typescript
// Production
mcp__bugsink__test_connection();
// Expected: "Connection successful: Connected successfully. Found N project(s)."

// Development
mcp__localerrors__test_connection();
// Expected: "Connection successful: Connected successfully. Found N project(s)."
```

---

## PostgreSQL MCP

**Package:** `@modelcontextprotocol/server-postgres`

**Purpose:** Execute SQL queries against the development database.

### Configuration

Add to project-level `.mcp.json`:

```json
"devdb": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": [
    "-y",
    "@modelcontextprotocol/server-postgres",
    "postgresql://postgres:postgres@127.0.0.1:5432/flyer_crawler_dev"
  ]
}
```

### Connection String Format

```text
postgresql://[user]:[password]@[host]:[port]/[database]
```

**Examples:**

```text
# Development (local container)
postgresql://postgres:postgres@127.0.0.1:5432/flyer_crawler_dev

# Test database
postgresql://flyer_crawler_test:password@127.0.0.1:5432/flyer_crawler_test
```

### Database Information

| Property              | Value                    |
| --------------------- | ------------------------ |
| Container             | `flyer-crawler-postgres` |
| Image                 | `postgis/postgis:15-3.4` |
| Host (from Windows)   | `127.0.0.1`              |
| Host (from container) | `postgres`               |
| Port                  | `5432`                   |
| Database              | `flyer_crawler_dev`      |
| User                  | `postgres`               |
| Password              | `postgres`               |

### Usage Examples

```typescript
// List all tables
mcp__devdb__query({ sql: "SELECT tablename FROM pg_tables WHERE schemaname = 'public'" });

// Count records
mcp__devdb__query({ sql: 'SELECT COUNT(*) FROM flyers' });

// Check table structure
mcp__devdb__query({
  sql: "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'flyers'",
});

// Find recent records
mcp__devdb__query({
  sql: 'SELECT id, name, created_at FROM flyers ORDER BY created_at DESC LIMIT 10',
});
```

### Prerequisites

1. **PostgreSQL container must be running:**

   ```bash
   podman ps | grep flyer-crawler-postgres
   ```

2. **Port 5432 must be mapped:**

   ```bash
   podman port flyer-crawler-postgres
   # Expected: 5432/tcp -> 0.0.0.0:5432
   ```

3. **Database must exist:**
   ```bash
   podman exec flyer-crawler-postgres psql -U postgres -c "\l" | grep flyer_crawler_dev
   ```

---

## Gitea MCP

**Binary:** `gitea-mcp` (compiled Go binary)

**Purpose:** Interact with Gitea repositories, issues, pull requests.

### Configuration

```json
"gitea-projectium": {
  "command": "d:\\gitea-mcp\\gitea-mcp.exe",
  "args": ["run", "-t", "stdio"],
  "env": {
    "GITEA_HOST": "https://gitea.projectium.com",
    "GITEA_ACCESS_TOKEN": "<your-token>"
  }
}
```

### Getting Access Token

1. Log in to Gitea web interface
2. Go to **Settings > Applications**
3. Under **Generate New Token**, enter a name
4. Select required scopes (typically `read:user`, `write:repository`, `write:issue`)
5. Click **Generate Token**
6. Copy the token immediately (shown only once)

### Key Tools

- `mcp__gitea-projectium__list_my_repos` - List accessible repositories
- `mcp__gitea-projectium__list_repo_issues` - List issues in a repo
- `mcp__gitea-projectium__get_issue_by_index` - Get issue details
- `mcp__gitea-projectium__create_issue` - Create new issue
- `mcp__gitea-projectium__create_pull_request` - Create PR
- `mcp__gitea-projectium__get_file_content` - Read file from repo
- `mcp__gitea-projectium__list_branches` - List branches

### Example Operations

```typescript
// List repositories
mcp__gitea - projectium__list_my_repos({ page: 1, pageSize: 20 });

// Get issue
mcp__gitea -
  projectium__get_issue_by_index({
    owner: 'username',
    repo: 'repository-name',
    index: 42,
  });

// Create issue
mcp__gitea -
  projectium__create_issue({
    owner: 'username',
    repo: 'repository-name',
    title: 'Bug: Something is broken',
    body: '## Description\n\nSteps to reproduce...',
  });
```

---

## Other MCP Servers

### Sequential Thinking

**Package:** `@modelcontextprotocol/server-sequential-thinking`

**Purpose:** Structured step-by-step reasoning for complex problems.

```json
"sequential-thinking": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
}
```

### Playwright (Browser Automation)

**Package:** `@anthropics/mcp-server-playwright`

**Purpose:** Browser automation for testing and scraping.

```json
"playwright": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "@anthropics/mcp-server-playwright"]
}
```

### Sentry (Cloud Error Tracking)

**Package:** `@sentry/mcp-server`

**Purpose:** Error tracking for Sentry instances (NOT Bugsink).

```json
"sentry": {
  "command": "D:\\nodejs\\npx.cmd",
  "args": ["-y", "@sentry/mcp-server"],
  "env": {
    "SENTRY_AUTH_TOKEN": "<your-sentry-token>"
  }
}
```

**Note:** Bugsink has a different API than Sentry. Use `bugsink-mcp` for Bugsink instances.

---

## Troubleshooting

### Localhost Servers Not Loading

**Symptoms:**

- `mcp__localerrors__*` or `mcp__devdb__*` tools not available
- No error messages in logs
- Server silently skipped during startup

**Root Cause:**
Claude Code's global `settings.json` has issues loading localhost stdio MCP servers on Windows. The exact cause may be related to:

- Multiple servers using the same underlying package
- Localhost URL filtering
- Windows-specific MCP loader bugs

**Solution:**
Use **project-level `.mcp.json`** for all localhost MCP servers. This bypasses the global config loader entirely.

**Working Pattern:**

- Global `settings.json`: Production HTTPS servers
- Project `.mcp.json`: Localhost HTTP servers

### Server Name Collision

**Symptoms:**

- Second server with similar name never starts
- No error logged - server silently filtered out

**Root Cause:**
Claude Code may skip MCP servers when names share prefixes (e.g., `bugsink` and `bugsink-dev`).

**Solution:**
Use completely distinct names:

- `bugsink` for production
- `localerrors` for development (NOT `bugsink-dev` or `devbugsink`)

### Connection Timed Out

**Error:** `Connection timed out after 30000ms`

**Causes:**

- Server takes too long to start
- npx download is slow
- Server crashes during initialization

**Solutions:**

1. Move important servers earlier in config
2. Use pre-installed packages instead of npx:
   ```json
   "command": "d:\\nodejs\\node.exe",
   "args": ["path/to/installed/package/dist/index.js"]
   ```
3. Check server can start manually

### Environment Variable Issues

**Common Mistakes:**

| Wrong                   | Correct                 |
| ----------------------- | ----------------------- |
| `BUGSINK_API_TOKEN`     | `BUGSINK_TOKEN`         |
| `http://localhost:8000` | `http://127.0.0.1:8000` |

**Verification:**
Test server manually with environment variables:

```bash
cd d:\gitea\bugsink-mcp
set BUGSINK_URL=http://127.0.0.1:8000
set BUGSINK_TOKEN=<your-token>
node dist/index.js
```

Expected output:

```
Bugsink MCP server started
Connected to: http://127.0.0.1:8000
```

### PostgreSQL Connection Refused

**Solutions:**

1. Check container is running:

   ```bash
   podman ps | grep flyer-crawler-postgres
   ```

2. Verify port mapping:

   ```bash
   podman port flyer-crawler-postgres
   ```

3. Test connection:

   ```bash
   podman exec flyer-crawler-postgres psql -U postgres -d flyer_crawler_dev -c "SELECT 1"
   ```

4. Check for port conflicts:
   ```bash
   netstat -an | findstr 5432
   ```

### Verifying Configuration

**List loaded servers:**

```bash
claude mcp list
```

**Check debug logs (Windows):**

```text
C:\Users\<username>\.claude\debug\*.txt
```

Look for MCP server startup messages. Missing servers indicate configuration problems.

---

## Best Practices

### 1. Keep Configs Organized

- **Global config:** Shared/production servers
- **Project config:** Local development servers
- **Never duplicate** the same server in both

### 2. Order Servers by Importance

Place essential servers first in configuration:

1. `memory` - Knowledge persistence
2. `filesystem` - File access
3. `podman` - Container management
4. Other servers...

### 3. Use Direct Node Execution

For faster startup, avoid npx and use direct node execution:

```json
// Slow (npx downloads on each start)
"command": "D:\\nodejs\\npx.cmd",
"args": ["-y", "package-name"]

// Fast (pre-installed)
"command": "d:\\nodejs\\node.exe",
"args": ["path/to/installed/dist/index.js"]
```

### 4. Disable Instead of Delete

Use `"disabled": true` to troubleshoot without losing configuration:

```json
"problem-server": {
  "command": "...",
  "disabled": true
}
```

### 5. Test Manually First

Before adding to config, verify server works:

```bash
cd /path/to/mcp-server
set ENV_VAR=value
node dist/index.js
```

### 6. Store Secrets Securely

- Use the memory MCP to store API tokens for future sessions
- Never commit `.mcp.json` with real tokens (add to `.gitignore`)
- Use environment variables where possible

### 7. Restart After Changes

MCP configuration changes require a full VS Code restart (not just window reload).

---

## Quick Reference

### Available MCP Packages

| Server              | Package/Source                                     | npm?                   |
| ------------------- | -------------------------------------------------- | ---------------------- |
| memory              | `@modelcontextprotocol/server-memory`              | Yes                    |
| filesystem          | `@modelcontextprotocol/server-filesystem`          | Yes                    |
| redis               | `@modelcontextprotocol/server-redis`               | Yes                    |
| postgres            | `@modelcontextprotocol/server-postgres`            | Yes                    |
| sequential-thinking | `@modelcontextprotocol/server-sequential-thinking` | Yes                    |
| podman              | `podman-mcp-server`                                | Yes                    |
| gitea               | `gitea-mcp` (binary)                               | No                     |
| bugsink             | `j-shelfwood/bugsink-mcp`                          | No (build from source) |
| sentry              | `@sentry/mcp-server`                               | Yes                    |
| playwright          | `@anthropics/mcp-server-playwright`                | Yes                    |

### Common Tool Prefixes

| Server         | Tool Prefix               | Example                                |
| -------------- | ------------------------- | -------------------------------------- |
| Memory         | `mcp__memory__`           | `mcp__memory__read_graph`              |
| Filesystem     | `mcp__filesystem__`       | `mcp__filesystem__read_file`           |
| Podman         | `mcp__podman__`           | `mcp__podman__container_list`          |
| Redis          | `mcp__redis__`            | `mcp__redis__get`                      |
| Bugsink (prod) | `mcp__bugsink__`          | `mcp__bugsink__list_issues`            |
| Bugsink (dev)  | `mcp__localerrors__`      | `mcp__localerrors__list_issues`        |
| PostgreSQL     | `mcp__devdb__`            | `mcp__devdb__query`                    |
| Gitea          | `mcp__gitea-projectium__` | `mcp__gitea-projectium__list_my_repos` |

---

## Related Documentation

- [CLAUDE.md - MCP Servers Section](../../CLAUDE.md#mcp-servers)
- [DEV-CONTAINER-BUGSINK.md](../DEV-CONTAINER-BUGSINK.md)
- [BUGSINK-SYNC.md](../BUGSINK-SYNC.md)
- [sql/master_schema_rollup.sql](../../sql/master_schema_rollup.sql)

---

_Last updated: January 2026_
