Metadata-Version: 2.4
Name: platform-engineering-mcp
Version: 1.0.0
Summary: Platform engineering MCP server — Backstage catalog annotation, Snyk integration, and more
License: MIT
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp[cli]>=1.3.0
Requires-Dist: pydantic-settings>=2.3.0
Requires-Dist: pydantic>=2.7.0
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: ruamel-yaml>=0.18.6
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# platform-engineering-mcp

A Model Context Protocol (MCP) server for platform engineering teams. The first capability automates Backstage catalog annotation with Snyk security metadata — more tools will follow.

---

## What it does

When Backstage scans your repositories it looks for a `catalog-info.yaml` file. To surface Snyk security posture alongside a component, that file needs two annotations:

```yaml
metadata:
  annotations:
    snyk.io/org-id: "<snyk-org-uuid>"
    snyk.io/project-id: "<snyk-project-uuid>"
```

This MCP server gives Claude (or any MCP client) tools to:

1. **Discover** which Snyk org and project correspond to a repository.
2. **Annotate** the repository's `catalog-info.yaml` (creating the file if absent).
3. **Open a pull request** with the changes — nothing is ever merged automatically.

Supports **Azure DevOps** (primary) and **GitHub**.

---

## Tools

### Snyk discovery
| Tool | Description |
|---|---|
| `snyk_list_orgs` | List all Snyk orgs accessible to your token |
| `snyk_list_projects` | List projects in a Snyk org, optionally filtered by repo name |
| `snyk_find_project_for_repo` | Auto-discover the Snyk project matching a repository URL |

### SonarQube discovery
| Tool | Description |
|---|---|
| `sonarqube_search_projects` | Search for SonarQube projects by name/key to find the right project key |
| `sonarqube_get_project` | Verify a specific SonarQube project key exists |

### Grafana discovery
| Tool | Description |
|---|---|
| `grafana_search_dashboards` | Search dashboards by name or tag |
| `grafana_list_tags` | List all dashboard tags — use to build `grafana/dashboard-selector` values |
| `grafana_get_dashboard` | Fetch a dashboard by UID to get its full URL |

### Backstage annotation (opens PRs)
| Tool | Description |
|---|---|
| `backstage_annotate_repo` | Annotate with explicit Snyk org/project IDs |
| `backstage_annotate_repo_auto` | One-call: discover Snyk IDs from repo URL then annotate |
| `backstage_annotate_ado_plugin` | Add Azure DevOps plugin annotations (`dev.azure.com/*`) |
| `backstage_annotate_sonarqube` | Add SonarQube annotation (`sonarqube.org/project-key`) |
| `backstage_annotate_grafana` | Add Grafana annotations (`grafana/dashboard-selector`, etc.) |

---

## Quick start

### 1. Install

```bash
pip install -e ".[dev]"
```

Or with `uv`:

```bash
uv pip install -e ".[dev]"
```

### 2. Configure

Copy `.env.example` to `.env` and fill in your tokens:

```bash
cp .env.example .env
```

| Variable | Required | Description |
|---|---|---|
| `SNYK_TOKEN` | ✅ | Snyk personal or service-account token |
| `SNYK_ORG_ID` | optional | Default Snyk org (skips org listing on every call) |
| `AZURE_DEVOPS_PAT` | ✅ for ADO | PAT with Code Read+Write and PR Contribute scopes |
| `AZURE_DEVOPS_ORG_URL` | ✅ for ADO | e.g. `https://dev.azure.com/my-org` |
| `GITHUB_TOKEN` | ✅ for GitHub | PAT or fine-grained token with `repo` and `pull_requests` scopes |
| `SONARQUBE_URL` | ✅ for SonarQube | Base URL of your SonarQube instance, e.g. `https://sonarqube.example.com` |
| `SONARQUBE_TOKEN` | ✅ for SonarQube | User or service-account token (Project Search permission required) |
| `GRAFANA_URL` | ✅ for Grafana | Base URL of your Grafana instance, e.g. `https://grafana.example.com` |
| `GRAFANA_TOKEN` | ✅ for Grafana | API key or service account token (Viewer role minimum) |

### 3. Run the server

```bash
platform-engineering-mcp
```

Or directly:

```bash
python -m platform_engineering_mcp.server
```

### 4. Connect to Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "platform-engineering": {
      "command": "platform-engineering-mcp",
      "env": {
        "SNYK_TOKEN": "your-snyk-token",
        "SNYK_ORG_ID": "optional-default-org-id",
        "AZURE_DEVOPS_PAT": "your-ado-pat",
        "AZURE_DEVOPS_ORG_URL": "https://dev.azure.com/your-org",
        "GITHUB_TOKEN": "your-github-token",
        "SONARQUBE_URL": "https://sonarqube.example.com",
        "SONARQUBE_TOKEN": "your-sonarqube-token",
        "GRAFANA_URL": "https://grafana.example.com",
        "GRAFANA_TOKEN": "your-grafana-token"
      }
    }
  }
}
```

---

## Usage examples

### Auto-annotate a repo with Snyk (one call)
```
backstage_annotate_repo_auto(
    repo="my-project/my-service",
    repo_url="https://dev.azure.com/my-org/my-project/_git/my-service",
    provider="azure_devops"
)
```

### Add Azure DevOps plugin annotations
```
backstage_annotate_ado_plugin(
    repo="my-project/my-service",
    provider="azure_devops",
    ado_project="my-project",
    ado_repo="my-project/my-service",
    ado_build_definition="my-ci-pipeline"
)
```

### Discover and add SonarQube annotation
```
# 1. Find your project key
sonarqube_search_projects(
    sonarqube_url="https://sonarqube.example.com",
    sonarqube_token="my-token",
    query="my-service"
)

# 2. Annotate
backstage_annotate_sonarqube(
    repo="my-project/my-service",
    provider="azure_devops",
    sonarqube_project_key="my-service_main"
)
```

### Discover and add Grafana annotations
```
# 1. Find the right tag
grafana_list_tags(grafana_url="https://grafana.example.com", grafana_token="my-token")

# 2. Annotate
backstage_annotate_grafana(
    repo="my-project/my-service",
    provider="azure_devops",
    dashboard_selector="tag:my-service",
    overview_dashboard="https://grafana.example.com/d/abc123/my-service-overview",
    alert_label_selector="service=my-service"
)
```

### Dry run (inspect changes without pushing)
```
backstage_annotate_ado_plugin(
    repo="my-project/my-service",
    provider="azure_devops",
    ado_project="my-project",
    dry_run=True
)
```

---

## Development

```bash
# Run tests
pytest

# Lint
ruff check src tests

# Format
ruff format src tests
```

---

## Roadmap

This is the first of many platform engineering tools planned for this MCP server. Upcoming capabilities include:

- Service catalogue bulk scan (report which repos are missing annotations)
- Kubernetes resource annotation helpers
- Golden-path template enforcement checks
- DORA metrics collection hooks

---

## Licence

MIT
