Metadata-Version: 2.4
Name: lumoz-mcp
Version: 0.2.0
Summary: Lumoz MCP server for observability data, signals, and problem/RCA investigation and resolution
Author-email: Lumoz AI <support@lumoz.ai>
Project-URL: Homepage, https://lumoz.ai
Keywords: mcp,observability,rca,lumoz
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: mcp<2.0.0,>=1.0.0
Requires-Dist: requests>=2.28.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pre-commit>=3.0.0; extra == "dev"

# Lumoz MCP Server

MCP server for Lumoz observability data and RCA resolution reporting. Connect
it to Claude, Cursor, GitHub Copilot, Codex, or any other MCP-compatible
client to query traces, signals, and problems, and to drive RCA generation
and fix reporting directly from your AI tool.

## Getting an API Key

1. Log in to the [Lumoz console](https://console.lumoz.ai).
2. Go to **Settings → API Keys** (org admin required).
3. Click **Create Key**, name it (e.g. `MCP - my laptop`), and save it.
4. Copy the key shown as `client_id:client_secret` — you won't be able to see
   the secret again after closing the dialog.

The default scopes granted (`read:telemetry`, `write:telemetry`) are
sufficient for every tool in this server, including the ones that write RCA
feedback and fix reports.

## Claude / Cursor / Codex / Copilot Config

Requires [`uv`](https://docs.astral.sh/uv/getting-started/installation/)
installed locally — `uvx` runs the server without a separate install step.

```json
{
  "mcpServers": {
    "lumoz": {
      "command": "uvx",
      "args": ["lumoz-mcp"],
      "env": {
        "LUMOZ_API_KEY": "client_id:client_secret"
      }
    }
  }
}
```

Paste in the key from the step above and you're done — the server talks to
Lumoz's production API by default. Add this block to your client's MCP
config file (e.g. Claude Desktop's `claude_desktop_config.json`, or the
equivalent settings file for Cursor/Copilot/Codex), then restart the client.

## Tools

- Data: `list_services`, `list_traces`, `get_trace`, `get_trace_spans`, `get_span`
- Signals: `list_signal_definitions`, `list_signals`, `get_signal`, `list_traces_for_signal`, `list_trace_signals`
- Problems: `list_problems`, `get_problem`, `list_problem_signals`, `generate_rca`, `report_fix`, `submit_problem_feedback`
- RCA: `list_rcas`, `get_rca`, `submit_rca_feedback`

## Inventory Discovery

Use `list_services()` without an `environment` argument to discover all service
and environment combinations visible to the authenticated tenant. Omitting
`environment` is intentional: it returns every service row across all
environments.

Hosts should call this first when they need valid `service_id` and `environment`
values:

```json
{}
```

Each returned service row includes `service_id`, `service_name`, and
`environment`. Pass `environment` only when you want to filter inventory to one
environment. `include_summary=true` is the exception: summary metrics require a
specific environment.

## Signal Discovery

Use `list_signals(service_id, environment)` to discover valid `signal_key`
values. Signals are backed by classifier results, but hosts should use the
signal vocabulary in tool calls.

Common flows:

```json
{
  "service_id": "123",
  "environment": "prod"
}
```

- `list_traces_for_signal(service_id, signal_key="error_detection", environment=environment)`
  lists traces where the error signal fired.
- `list_traces_for_signal(service_id, signal_key="workflow_anomaly", environment=environment)`
  lists traces matching the workflow anomaly signal.
- `list_trace_signals(service_id, trace_id, environment)` lists all signals
  attached to one trace, including error_detection. Each signal's `details`
  usually already carries `error_message`/`error_code`/`span_id`.
- `get_span(service_id, trace_id, span_id, environment)` gets full detail
  (text fields, exception_stacktraces) for one specific span — use the
  `span_id` from a signal's `details` rather than scanning every span via
  `get_trace_spans`.

Use `list_signal_definitions()` to look up what a `signal_key`/`classifier_key`
actually means — each row has a human-readable `description`, `category`
(`builtin` or `custom`), `match_type`, and `polarity`. It returns the full
catalog (built-in signals plus this tenant's custom ones), not just signals
that have fired, so call it whenever a problem, RCA, or signal result
references a `signal_key` you need to explain to a user, e.g. while writing up
or acting on `get_rca` output. Pass `service_id`/`environment` to narrow custom
signals to one service/env; built-ins are always included.

Built-in signals also break down into `subtypes` — the specific sub-reason a
signal fired (e.g. `loop_detection` → `exact_tool_call_loop`,
`retry_storm_loop`, `reason_act_thrash`), each with its own `description` and
`default_severity`. `subtype_source_field` names which field on the signal
record (`primary_subtype` or `primary_event_key`) holds the value to match
against a subtype's `key`. When a signal record has a subtype, quote that
subtype's description instead of the classifier's general one — it explains
the actual mechanism, not just the category.

## Problem and RCA Discovery

Problems are groups of detected trace signals sharing the same signature.
Drill down progressively:

1. `list_problems(service_id, environment)` — paginated, newest-first, each
   row includes a `latest_rca` summary if one has been generated.
2. `get_problem(service_id, problem_id, environment)` — full detail, including
   every generated RCA (`rcas`) and the lifecycle/feedback audit trail (`events`).
3. `get_rca(rca_id, service_id, environment)` — the complete RCA writeup (root
   cause, evidence pattern, recommended fixes), plus the trace `signals` it
   covers and its own feedback/lifecycle audit trail (`events`).

`list_rcas(service_id, environment)` browses generated RCAs directly, across
all problems, without going through `list_problems` first.

If a problem has no RCA yet, `generate_rca(problem_id, service_id, environment)`
creates one (or returns the existing one if already generated).

## Problem and RCA Feedback

`submit_problem_feedback` and `submit_rca_feedback` record a `thumbs_up` or
`thumbs_down` vote (optionally with `note`/`reason`) against a problem or an
RCA, respectively:

```json
{
  "service_id": "123",
  "rca_id": "rca-1",
  "environment": "prod",
  "vote": "thumbs_down",
  "reason": "Recommended fix didn't address the root cause."
}
```

## RCA Fix Reporting

`report_fix` marks an existing problem resolved and records the fix
description. This is one-way — there is no unresolve/reopen action:

```json
{
  "service_id": "123",
  "problem_id": "problem-1",
  "environment": "prod",
  "description": "Added timeout handling around vector search fallback."
}
```

## Troubleshooting

- **`environment is required`** — every tool that scopes to a service needs
  an explicit `service_id`/`environment` on each call; there's no
  `LUMOZ_ENVIRONMENT`/`LUMOZ_SERVICE_ID` fallback. Call `list_services()`
  first to find a valid pair, then pass both on subsequent calls.
- **Client doesn't pick up the server after editing config** — most MCP
  clients only read their config file at startup; fully restart the client,
  don't just reload a window.

