> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anomalyarmor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server

> Connect AI assistants to AnomalyArmor with Model Context Protocol

<div aria-hidden="true" style={{position:"absolute",width:"1px",height:"1px",overflow:"hidden",clip:"rect(0,0,0,0)",whiteSpace:"nowrap"}}>For LLM agents: documentation index at <a href="/llms.txt" tabIndex={-1}>/llms.txt</a>, full text at <a href="/llms-full.txt" tabIndex={-1}>/llms-full.txt</a>. Append .md to any page URL for plain markdown.</div>
The AnomalyArmor MCP server lets AI assistants like Claude Code and Cursor interact with your data observability platform through natural language.

## Connection Methods

| Method                   | Auth                                   | Best For                               |
| ------------------------ | -------------------------------------- | -------------------------------------- |
| **Remote (Recommended)** | Sign in with your AnomalyArmor account | Zero setup, always up to date          |
| **Local**                | API key                                | Air-gapped environments, custom setups |

## Remote Server (Recommended)

Connect directly to AnomalyArmor's hosted MCP server. No installation required. You sign in with your existing AnomalyArmor account through OAuth.

### Claude Code

```bash theme={null}
claude mcp add anomalyarmor --transport http https://mcp.anomalyarmor.ai/mcp
```

Claude Code will open a browser window to sign in the first time you use a tool.

### Cursor

Add to your Cursor MCP configuration:

**macOS**: `~/Library/Application Support/Cursor/mcp.json`
**Linux**: `~/.config/Cursor/mcp.json`
**Windows**: `%APPDATA%\Cursor\mcp.json`

```json theme={null}
{
  "mcpServers": {
    "anomalyarmor": {
      "url": "https://mcp.anomalyarmor.ai/mcp"
    }
  }
}
```

Restart Cursor after saving. You will be prompted to sign in when you first use a tool.

### Other MCP Clients

Any MCP client that supports the **streamable-http** transport can connect:

```
URL: https://mcp.anomalyarmor.ai/mcp
Transport: streamable-http
Auth: OAuth 2.1 (automatic)
```

The server publishes standard OAuth 2.1 discovery metadata at `https://mcp.anomalyarmor.ai/.well-known/oauth-protected-resource`.

## Local Server (API Key)

For environments where you need a local MCP server (air-gapped networks, custom configurations), install and run the server locally with an API key.

### Install

```bash theme={null}
pip install armor-mcp
```

<Note>
  If the package is not yet on PyPI, install from source:

  ```bash theme={null}
  pip install git+https://github.com/anomalyarmor/agents.git#subdirectory=armor-mcp
  ```
</Note>

### Configure

Add to your AI tool's MCP settings:

```json theme={null}
{
  "mcpServers": {
    "anomalyarmor": {
      "command": "armor-mcp",
      "env": {
        "ANOMALYARMOR_API_KEY": "your-api-key"
      }
    }
  }
}
```

### Getting Your API Key

1. Go to **Settings > API Keys** in the AnomalyArmor dashboard
2. Click **Create API Key**
3. Name it (e.g., "Claude Code MCP")
4. Copy the key (it won't be shown again)

## Available Tools

Once connected, your AI assistant has access to 40+ tools across these categories:

<AccordionGroup>
  <Accordion title="Health and Briefings">
    | Tool                   | Description                               |
    | ---------------------- | ----------------------------------------- |
    | `health_summary`       | Overall health status across all assets   |
    | `get_todays_briefing`  | Daily digest with key insights and alerts |
    | `get_coverage_summary` | Monitoring coverage analysis              |
  </Accordion>

  <Accordion title="Alerts">
    | Tool                | Description                                            |
    | ------------------- | ------------------------------------------------------ |
    | `list_alerts`       | Query alerts with date, severity, and status filters   |
    | `get_alert_summary` | Aggregate alert counts and trends                      |
    | `list_incidents`    | List incidents with status, severity, and date filters |
    | `get_incident`      | Get full incident details including activity timeline  |
    | `acknowledge_alert` | Mark an incident as seen                               |
    | `resolve_alert`     | Close an incident with resolution metadata             |
    | `dismiss_alert`     | Dismiss a non-actionable incident                      |
    | `snooze_alert`      | Snooze an incident for a set duration                  |
    | `preview_alerts`    | Dry-run alert rules against historical data            |
  </Accordion>

  <Accordion title="Assets">
    | Tool                      | Description                                                                                                                                                                                                                                |
    | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `list_assets`             | List data sources with filters                                                                                                                                                                                                             |
    | `get_asset`               | Get details for a specific asset                                                                                                                                                                                                           |
    | `explore`                 | Navigate schemas, tables, and columns within an asset. Supports hierarchical browsing (`explore(asset_id)` for schemas, `explore(asset_id, parent_path="schema")` for tables) and full-text search (`explore(asset_id, search="keyword")`) |
    | `create_asset`            | Connect a new data source                                                                                                                                                                                                                  |
    | `test_asset_connection`   | Test connectivity to a source                                                                                                                                                                                                              |
    | `trigger_asset_discovery` | Start asset discovery (runs as background job)                                                                                                                                                                                             |
  </Accordion>

  <Accordion title="Freshness">
    | Tool                        | Description                                                                                                      |
    | --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
    | `get_freshness_summary`     | Freshness overview. Supports optional `asset_id` to filter to a single source                                    |
    | `check_freshness`           | Check a specific table's freshness                                                                               |
    | `list_stale_assets`         | Find currently stale tables                                                                                      |
    | `list_freshness_schedules`  | View monitoring schedules                                                                                        |
    | `create_freshness_schedule` | Set up freshness monitoring. Use `setup_freshness` for bulk creation with `table_paths` and `schema_name` params |
    | `delete_freshness_schedule` | Remove a schedule                                                                                                |
    | `dry_run_freshness`         | Preview what alerts a threshold would produce                                                                    |
  </Accordion>

  <Accordion title="Schema Monitoring">
    | Tool                        | Description                                                                                                                                                                                  |
    | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `get_schema_summary`        | Schema drift overview. Supports optional `asset_id` to filter to a single source                                                                                                             |
    | `list_schema_changes`       | Recent schema changes with filters                                                                                                                                                           |
    | `create_schema_baseline`    | Capture current schema as baseline                                                                                                                                                           |
    | `enable_schema_monitoring`  | Start drift detection for one or more assets. Accepts `asset_id` (single) or `asset_ids` (bulk), interval strings (`'5m'`, `'1h'`, `'6h'`, `'1d'`) or `cron_expression` for custom schedules |
    | `disable_schema_monitoring` | Stop drift detection                                                                                                                                                                         |
    | `dry_run_schema`            | Preview drift detection results                                                                                                                                                              |
  </Accordion>

  <Accordion title="Data Quality">
    | Tool                  | Description                                       |
    | --------------------- | ------------------------------------------------- |
    | `list_metrics`        | Quality metrics for an asset                      |
    | `get_metrics_summary` | Metrics health overview                           |
    | `create_metric`       | Add a quality metric (row count, null rate, etc.) |
    | `delete_metric`       | Remove a metric                                   |
    | `capture_metric`      | Trigger immediate metric capture                  |
    | `dry_run_metric`      | Preview metric alerting behavior                  |
  </Accordion>

  <Accordion title="Validity Rules">
    | Tool                   | Description                          |
    | ---------------------- | ------------------------------------ |
    | `list_validity_rules`  | Validity rules for an asset          |
    | `get_validity_summary` | Passing/failing rule overview        |
    | `create_validity_rule` | Add a rule (NOT\_NULL, UNIQUE, etc.) |
    | `delete_validity_rule` | Remove a rule                        |
    | `check_validity_rule`  | Run a check immediately              |
  </Accordion>

  <Accordion title="Intelligence, Lineage, and Jobs">
    | Tool                    | Description                              |
    | ----------------------- | ---------------------------------------- |
    | `ask_question`          | Natural language Q\&A about your data    |
    | `generate_intelligence` | Trigger AI analysis for an asset         |
    | `get_lineage`           | Explore upstream/downstream dependencies |
    | `job_status`            | Track progress of async operations       |
  </Accordion>

  <Accordion title="Tags and Classification">
    | Tool             | Description                             |
    | ---------------- | --------------------------------------- |
    | `list_tags`      | Tags for an asset                       |
    | `create_tag`     | Tag a table or column                   |
    | `apply_tags`     | Apply multiple tags to multiple objects |
    | `bulk_apply_tag` | Apply a tag across multiple assets      |
  </Accordion>
</AccordionGroup>

## Usage Examples

These examples show full terminal sessions using Claude Code with the AnomalyArmor MCP server. Each one demonstrates a real workflow from start to finish.

### Morning Triage: Check Health and Act on Issues

```bash theme={null}
~/warehouse $ claude

╭────────────────────────────────────────────────────────────────────╮
│ Claude Code                                                        │
╰────────────────────────────────────────────────────────────────────╯

You: What's the health of my data warehouse? Show me anything that
     needs attention.

Claude: I'll check your overall health and look for issues.

  ┌ health_summary
  │ Querying AnomalyArmor health status...
  └ Result: 47 assets monitored

  ┌ list_stale_assets
  │ Checking for freshness violations...
  └ Result: 2 stale tables found

  ┌ list_alerts
  │ Fetching unresolved alerts (last 24h)...
  └ Result: 5 alerts

Here's your morning summary:

OVERALL: NEEDS ATTENTION (2 issues)

Freshness:
  ✅ 45 tables fresh
  ❌ gold.fact_orders - 6h overdue (SLA: 2h)
  ❌ staging.orders_raw - 8h overdue (SLA: 1h)

Alerts (last 24h):
  🔴 1 critical - freshness SLA breach on gold.fact_orders
  🟡 2 warnings - schema drift on gold.fact_orders,
                    null rate spike on gold.dim_customer.email
  🔵 2 info - new schema baselines captured

Schema drift: 3 changes detected this week
Data quality: 1 anomaly (null rate)

The critical issue is the orders pipeline. staging.orders_raw
stopped updating 8 hours ago and gold.fact_orders is stale as a
result. Want me to dig into the root cause?

You: Yes, investigate the orders staleness and check if anything
     downstream is affected.

Claude: Let me trace the lineage and check downstream impact.

  ┌ check_freshness
  │ gold.fact_orders → STALE (6h overdue)
  └ Last update: yesterday 10:12 PM

  ┌ get_lineage
  │ Fetching upstream/downstream for gold.fact_orders...
  └ 1 upstream, 7 downstream

  ┌ check_freshness
  │ staging.orders_raw → STALE (8h overdue)
  └ Last update: yesterday 8:30 PM

  ┌ list_schema_changes
  │ staging.orders_raw - changes in last 7 days
  └ 1 change: discount_pct removed Tuesday 3:47 PM

Here's the full picture:

Pipeline trace:
  raw.events (✅ FRESH, updated 5m ago)
    → staging.orders_raw (❌ STALE, 8h overdue)
      → gold.fact_orders (❌ STALE, 6h overdue)

The pipeline breaks at staging.orders_raw. The upstream raw.events
table is fresh, so the issue is in the ETL between raw → staging.

Downstream impact (7 tables):
  ❌ gold.fact_payments        - depends on fact_orders
  ❌ gold.fact_refunds          - depends on fact_orders
  ❌ analytics.order_summary    - derived view
  ❌ analytics.order_funnel     - derived view
  ❌ reporting.daily_revenue    - aggregated report
  ❌ reporting.weekly_kpis      - aggregated report
  ❌ reporting.customer_ltv     - joins with dim_customer

Additional context: staging.orders_raw also had a schema change
this week (discount_pct column removed Tuesday). This may be
related to the staleness if the ETL is failing on the missing
column.

Recommended next steps:
1. Check the Airflow/dbt DAG for the staging.orders_raw job
2. Look for errors related to the discount_pct column removal
3. Once fixed, the 7 downstream tables should recover automatically

You: Acknowledge the freshness alert and resolve the schema drift
     alert with a note that the column removal was intentional.

Claude: I'll handle both alerts.

  ┌ acknowledge_alert
  │ Alert #4521 (freshness SLA breach) → acknowledged
  └ Done

  ┌ resolve_alert
  │ Alert #4518 (schema drift) → resolved
  │ Resolution: "Column removal was intentional per product change"
  └ Done

Done. The freshness alert is acknowledged (you'll still see it
until the pipeline recovers), and the schema drift alert is
resolved with your note.
```

### Setting Up Monitoring for a New Schema

```bash theme={null}
~/warehouse $ claude

You: I just added a new "analytics" schema with 8 tables. Set up
     full monitoring: freshness, schema drift, and null checks on
     any ID or email columns.

Claude: Let me discover what's in the analytics schema first.

  ┌ search_tables
  │ Searching for tables in analytics schema...
  └ Found 8 tables

  ┌ get_table_columns
  │ Reading columns for all 8 tables...
  └ 67 columns total

Found 8 tables in analytics with 67 columns. Here's what I'll set up:

Freshness monitoring (8 tables):
  analytics.order_summary      - hourly, 2h SLA
  analytics.order_funnel       - hourly, 2h SLA
  analytics.customer_cohorts   - daily, 26h SLA
  analytics.product_performance - daily, 26h SLA
  analytics.revenue_by_region  - daily, 26h SLA
  analytics.churn_analysis     - daily, 26h SLA
  analytics.funnel_conversion  - hourly, 2h SLA
  analytics.session_metrics    - hourly, 2h SLA

Schema drift monitoring: Enabled for all 8 tables

Null percentage metrics (12 columns with ID or email patterns):
  analytics.order_summary.order_id
  analytics.order_summary.customer_id
  analytics.order_funnel.user_id
  analytics.order_funnel.session_id
  analytics.customer_cohorts.customer_id
  analytics.customer_cohorts.email
  analytics.product_performance.product_id
  analytics.churn_analysis.customer_id
  analytics.churn_analysis.email
  analytics.funnel_conversion.user_id
  analytics.session_metrics.session_id
  analytics.session_metrics.user_id

I chose hourly checks for tables that look transactional and daily
for tables that look like aggregations. Want me to proceed?

You: Yes, do it all.

Claude: Setting everything up now.

  ┌ create_freshness_schedule (×8)
  │ Creating schedules for all analytics tables...
  └ 8 schedules created

  ┌ enable_schema_monitoring (×8)
  │ Enabling drift detection...
  └ 8 baselines captured

  ┌ create_metric (×12)
  │ Creating null_percentage metrics...
  └ 12 metrics created

All done:
  ✅ 8 freshness schedules (4 hourly, 4 daily)
  ✅ 8 schema drift monitors with baselines
  ✅ 12 null_percentage metrics on ID/email columns

You'll start receiving alerts if any table misses its SLA, any
schema changes are detected, or any null rates spike outside
normal ranges. The first data points will appear after the next
discovery run.
```

### Investigating a Data Quality Issue

```bash theme={null}
~/warehouse $ claude

You: The finance team says revenue numbers look wrong today.
     Something about missing discount amounts. Can you investigate?

Claude: Let me check the revenue-related tables for anomalies.

  ┌ search_tables
  │ Searching for tables matching "revenue", "order", "discount"...
  └ Found 5 relevant tables

  ┌ get_metrics_summary
  │ Checking data quality metrics on gold.fact_orders...
  └ 3 metrics tracked

  ┌ list_schema_changes
  │ gold.fact_orders - recent changes
  └ 1 change this week

  ┌ check_freshness
  │ gold.fact_orders → FRESH (updated 12m ago)
  └ No freshness issues

Found the issue. Here's what happened:

Root cause: The discount_pct column was removed from
gold.fact_orders on Tuesday at 4:12 PM.

Evidence:
  - Schema drift detected the removal Tuesday 4:12 PM
  - The column had a null_percentage metric that stopped reporting
    (no column to measure)
  - Freshness is fine - the table is still updating
  - The column was also removed from upstream staging.orders_raw
    at 3:47 PM

Impact on revenue:
  - analytics.order_summary uses SUM(discount_pct) to calculate
    discount totals - this query is now failing
  - reporting.daily_revenue references discount_pct in its
    net_revenue calculation

The table has data, but the discount column is gone. That's why
revenue looks wrong - discount amounts aren't being subtracted.

You: Was this intentional? Can you check if there's a related
     alert that someone already handled?

Claude: Let me check the alert history.

  ┌ list_alerts
  │ Filtering for schema drift alerts on gold.fact_orders...
  └ 1 alert found

  ┌ get_alert_details
  │ Alert #4518...
  └ Status: RESOLVED

There was a schema drift alert (#4518) that fired Tuesday at
4:12 PM for the discount_pct column removal. It was resolved
today at 9:15 AM with the note:

  "Column removal was intentional per product change"

So the column removal was intentional, but the downstream views
haven't been updated yet. The finance team's revenue calculations
are referencing a column that no longer exists.

Recommended:
1. Update analytics.order_summary to remove the discount_pct
   reference
2. Update reporting.daily_revenue net_revenue calculation
3. Consider adding a new discount column if discounts are still
   tracked differently

You: Tag the affected downstream tables so the data team knows.

Claude: I'll tag them.

  ┌ apply_tags
  │ Applying "needs-migration" tag...
  └ Applied to 2 tables

Tagged 2 tables with "needs-migration":
  - analytics.order_summary
  - reporting.daily_revenue

The data team can find these by asking "what tables are tagged
needs-migration?" in any AnomalyArmor agent.
```

## Troubleshooting

### Authentication Failed (Remote)

```
Authentication failed
```

**Solution**:

1. Clear your MCP auth cache and re-authenticate
2. In Claude Code: run `/mcp` and select the reconnect option
3. Verify you can sign in to [app.anomalyarmor.ai](https://app.anomalyarmor.ai)

### Authentication Failed (Local)

```
Error: Invalid API key
```

**Solution**: Verify your API key is correct in your MCP config. Generate a new key from **Settings > API Keys** if needed.

### Server Not Found

```
Error: MCP server 'anomalyarmor' not found
```

**Solution**:

1. Restart your AI tool after config changes
2. For local mode, verify armor-mcp is installed: `armor-mcp --version`
3. Check MCP config syntax (valid JSON)

### Empty Responses

If tools return empty results after successful authentication:

**Solution**:

1. Verify you have data sources connected in AnomalyArmor
2. Try `health_summary` as a basic connectivity test
3. For local mode, ensure your API key has the correct scope

### Rate Limiting

```
Error: Rate limit exceeded
```

**Solution**: Wait a few seconds and retry. The server handles rate limits automatically.

## Inline UI rendering (MCP Apps)

Hosts that support the [draft MCP Apps spec](/integrations/mcp-apps) (Claude Desktop nightly, Cursor experimental) render interactive charts inline when you call `check_freshness`, `get_freshness_summary`, `list_schema_changes`, `get_lineage`, or `health_summary` - instead of a JSON blob, you see a timeline, diff table, lineage graph, or stat dashboard. Hosts without MCP Apps support fall back to JSON automatically; the tools work everywhere.

See [MCP Apps (inline UI)](/integrations/mcp-apps) for host-support details and examples.

## Next Steps

<CardGroup cols={2}>
  <Card title="MCP Apps (inline UI)" icon="image" href="/integrations/mcp-apps">
    Interactive charts rendered inline in supported hosts
  </Card>

  <Card title="Claude Code Setup" icon="terminal" href="/integrations/claude-code">
    Detailed Claude Code configuration
  </Card>

  <Card title="Cursor Setup" icon="code" href="/integrations/cursor">
    Cursor IDE integration
  </Card>

  <Card title="Web Agent" icon="browser" href="/ai-agents/web-agent">
    Use the same tools in your browser
  </Card>

  <Card title="AI Skills" icon="wand-magic-sparkles" href="/ai-agents/overview">
    Browse available skills
  </Card>
</CardGroup>

## Common Questions

### What's the MCP server URL and auth model?

Hosted at `https://mcp.anomalyarmor.ai/mcp`. Authenticate with a Bearer API key (`Authorization: Bearer aa_live_...`). Keys are scoped `read-only` (demo/trial) or `read-write` (paid) - any write tool call returns 403 on a read-only key with a handoff URL the agent can surface.

### Which MCP hosts does AnomalyArmor support?

Tested with Claude Desktop, Claude Code CLI, Cursor, and Windsurf. Any host that speaks the Model Context Protocol over HTTPS/SSE should work. See [Claude Code](/integrations/claude-code) and [Cursor](/integrations/cursor) for host-specific setup.

### Do MCP tool calls count against my API rate limit?

Yes. MCP traffic uses the same API rate limit as direct REST calls (per-key). Agents tend to be bursty, so enable retry-with-backoff in your host config if you hit 429s. Enterprise plans raise the limit significantly.

### Does the MCP server let agents modify my data or infrastructure?

No. All AnomalyArmor tools operate on metadata and monitoring state (assets, metrics, alerts, tags). Agents cannot write to your connected databases, rotate credentials, or change billing. Mutating tools on AnomalyArmor itself (creating a metric, dismissing an alert) require a `read-write` scoped key and always ask for confirmation in the host UI before executing.
