Testing · CI/CD Pipeline

Test & Deploy With Confidence

MCP Inspector for manual testing. pytest for automated tests. GitHub Actions for CI/CD. OpenTelemetry for monitoring.

Testing with MCP Inspector

MCP Inspector is a web UI that connects to your running server and lets you test every tool interactively.

fastmcp dev server.py
# Opens Inspector at http://localhost:5173

Check: tool schemas render correctly, parameters validate, errors return proper MCP error codes.

Automated Testing with pytest

# tests/test_server.py
import pytest
from fastmcp import Client

@pytest.fixture
async def client():
    async with Client("app:mcp") as c:
        yield c

@pytest.mark.asyncio
async def test_search_docs(client):
    result = await client.call_tool("search_docs", {"query": "deployment"})
    assert "Found results" in result.text

@pytest.mark.asyncio
async def test_search_docs_empty_query(client):
    with pytest.raises(Exception):
        await client.call_tool("search_docs", {"query": ""})

@pytest.mark.asyncio
async def test_list_tools(client):
    tools = await client.list_tools()
    tool_names = [t.name for t in tools]
    assert "search_docs" in tool_names
pytest tests/ -v --cov=. --cov-report=term-missing

CI/CD Pipeline — GitHub Actions

name: Test & Deploy MCP Server

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: pytest tests/ -v --cov=. --cov-report=xml --cov-fail-under=80
      - uses: codecov/codecov-action@v4

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker image
        run: docker build -t your-registry/fastmcp-server:${{ github.sha }} .
      - name: Push to registry
        run: |
          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
          docker push your-registry/fastmcp-server:${{ github.sha }}
      - name: Deploy
        run: |
          ssh deploy@your-server "docker pull your-registry/fastmcp-server:${{ github.sha }} && docker compose up -d"

Gate: tests must pass with ≥80% coverage before deployment. Push to main triggers auto-deploy.

Monitoring with OpenTelemetry

FastMCP v3 has native OpenTelemetry support. Export to Prometheus/Grafana, Datadog, or any OTEL-compatible backend.

mcp = FastMCP("MonitoredServer", instrumentation="opentelemetry")
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_SERVICE_NAME=fastmcp-server
MetricWhat to watch
Latency p50/p95/p99Tool call duration distribution
Error rate% of tool calls returning MCP errors
Tool call volumeCalls/minute per tool (detect abuse)
Auth failuresFailed authentication attempts (detect attacks)

FAQ

Does this CI/CD pipeline work with GitLab CI or Bitbucket Pipelines?

The YAML syntax differs but the structure is portable: test job → build Docker → push → deploy. The pytest commands, Dockerfile, and coverage thresholds are identical. The Pro Guide includes ready-to-use GitLab CI (.gitlab-ci.yml) and Bitbucket (bitbucket-pipelines.yml) templates with the same gates.

How do I test before deploying — can I run this locally?

Yes. Run pytest tests/ -v --cov=. --cov-report=term-missing locally before pushing. The GitHub Actions job mirrors this exactly — if it passes on your machine, it'll pass in CI. Use fastmcp dev server.py to open MCP Inspector locally and manually test tools before writing automated tests.

Can I skip MCP Inspector and just use curl or a REST client?

Not directly — MCP uses JSON-RPC over SSE or Streamable HTTP, not REST. Inspector is purpose-built for this protocol and shows tool schemas, errors, and responses in MCP format. The Pro Guide includes a pytest helper that wraps the MCP client for headless API-level testing if you prefer that to the GUI.

How do I set up OpenTelemetry if I already use Datadog/Prometheus?

Set OTEL_EXPORTER_OTLP_ENDPOINT to your collector's ingest URL. For Datadog, add the Datadog Exporter to your OTEL Collector config. For Prometheus, use the OTLP-to-Prometheus bridge in the OTEL Collector. The Pro Guide includes collector configs for Datadog, Grafana Cloud, and self-hosted Prometheus.

Pipeline Ready in 30 Minutes

The Production Manual includes all four testing layers with advanced patterns: canary deployments, multi-environment pipelines (staging → prod), Prometheus alert rules with thresholds, Datadog/Grafana OTEL collector configs, and incident response automation.

From $39, lifetime updates. Free 14-day refund, no lock-in.

Get the Production Manual