Metadata-Version: 2.4
Name: ExeWatchMCP
Version: 0.1.7
Summary: Let your AI agent fix the bugs your users hit. An MCP server that gives Claude Code, Codex and KAI (RAD Studio) the errors, slow operations, metrics and versions your apps report to ExeWatch, so they can find the cause in your code and fix it.
License-Expression: MIT
Keywords: mcp,model-context-protocol,ai-agent,auto-fix,observability,telemetry,monitoring,apm,error-tracking,crash-reporting,performance-monitoring,logging,exewatch,claude-code,codex,kai,rad-studio,delphi,c++builder,python,javascript,dotnet,csharp,desktop,windows,linux
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Software Development :: Bug Tracking
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Logging
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# ExeWatchMCP

> **0.1.7:** your customers' data is not sent to the AI engine. See [Personal data](#personal-data).

Let your AI agent fix the bugs your users hit. `ExeWatchMCP` gives an AI agent what your applications report to [ExeWatch](https://exewatch.com), the monitoring service for desktop applications: errors, slow operations, metrics, versions, customers and devices. The agent reads them, finds the cause in your code and fixes it. Ask it, from your editor, to fix last week's errors, to explain what is slow, or to say what to work on first.

It is an [MCP](https://modelcontextprotocol.io) server, so it works with any agent that supports MCP, such as Claude Code or Codex. **For Delphi and C++Builder developers it works with KAI, the AI assistant built into RAD Studio**: ask KAI, without leaving the IDE, to read what your program reported to ExeWatch and to fix it. The same package also installs the `exewatch` command line, for scripts and for agents that prefer a shell.

It is read only: it cannot change or delete anything. It needs Python 3.9 or later and has no dependencies, and an ExeWatch account on a paid plan.

## Install

    pip install ExeWatchMCP

It installs two commands: `exewatch-mcp`, the MCP server, and `exewatch`, the command line. If you installed the older `ExeWatchCLI` package, run `pip uninstall ExeWatchCLI` first: both ship the same module, and removing one later would break the other. To work from a clone of the repository, run `pip install ./cli` from its root.

## Create an API key

1. Sign in to ExeWatch as the account owner. Only the owner sees the page.
2. Open **Settings**, then **API access**.
3. Choose **Create new key**, give it a name, for example "Coding agent", choose whether it covers all applications or only some of them, and optionally set an expiry date. A key limited to some applications is the right one to hand to a contractor.
4. Confirm with your password.

The key starts with `ew_api_` and is shown once, with a button to copy it. ExeWatch keeps only a fingerprint, so a lost key cannot be shown again: create a new one. You can revoke a key from the same page, and it stops working within about ten seconds.

If the page asks you to upgrade, your plan does not include the API.

## Connect your agent

The agent starts the server itself. You tell it the command and give it the key in the server's environment, never in a prompt.

In Claude Code:

    claude mcp add exewatch --env EXEWATCH_API_KEY=ew_api_... -- exewatch-mcp

In Codex:

    codex mcp add exewatch --env EXEWATCH_API_KEY=ew_api_... -- exewatch-mcp

or in `~/.codex/config.toml`:

    [mcp_servers.exewatch]
    command = "exewatch-mcp"
    env = { EXEWATCH_API_KEY = "ew_api_..." }

Any other agent with an `mcpServers` setting takes the same thing as JSON:

    { "mcpServers": { "exewatch": {
        "command": "exewatch-mcp",
        "env": { "EXEWATCH_API_KEY": "ew_api_..." } } } }

If the agent cannot find `exewatch-mcp` on its PATH, use the full path of the command, or the Python that installed it: `"command": "python", "args": ["-m", "exewatch_cli", "mcp"]`.

**Delphi and C++Builder.** In RAD Studio, KAI, the AI assistant of the IDE, can use the same server: register `exewatch-mcp` as an MCP server of KAI with the JSON above, and ask it, without leaving the IDE, to read what your program reported and to fix it. For the stack to point at the right line, compile the program with a detailed map file (Project Options, Linking, Map file) and enable stack frames (Compiling): without them the Delphi SDK sends no stack trace and says why in `no_stacktrace_reason`.

In KAI write the **full path** of the command in `command`. The IDE does not always see the PATH of your terminal, and then KAI reports "Connection closed" because the command was not found. On Windows `where exewatch-mcp` prints it, for example `C:\Users\you\AppData\Roaming\Python\Python314\Scripts\exewatch-mcp.exe` (in JSON the backslashes are doubled).

`EXEWATCH_API_URL` changes the server (default `https://api.exewatch.com`). It must be `https`; plain `http` is accepted only for `localhost` and `127.0.0.1`.

## Use it in one project only

The key decides what the agent can read. If you work on projects for different customers, create one key per customer, limited to that customer's applications, and register the server in the project folder instead of for your whole user. The agent then reads that customer's data only when it works in that folder.

In Claude Code, `claude mcp add` already registers the server for the current folder only (scope `local`, the default), so run it from the project folder. The setting stays in your user profile, not in the project, and the key never ends up in the repository.

To share the setup with the people who work on the project, use the scope `project`. Claude Code then reads `.mcp.json` from the project folder, a file you commit. Do not write the key in it. Write the name of an environment variable, and each person sets that variable to their own key:

    { "mcpServers": { "exewatch": {
        "command": "exewatch-mcp",
        "env": { "EXEWATCH_API_KEY": "${EXEWATCH_API_KEY}" } } } }

Claude Code replaces `${EXEWATCH_API_KEY}` with the value of the variable when it starts the server, and asks you to approve the server the first time it finds it in `.mcp.json`. If you follow several customers on the same computer, give the variable a different name in each project, for example `${EXEWATCH_API_KEY_ACME}`.

Codex reads `.codex/config.toml` from the project folder when you trust the project:

    [mcp_servers.exewatch]
    command = "exewatch-mcp"
    env_vars = ["EXEWATCH_API_KEY"]

`env_vars` passes the variable from the environment Codex runs in to the server, which otherwise would not see it. Here the variable must be called `EXEWATCH_API_KEY`, so with several customers start Codex from a terminal where it holds the right key.

## The key in an environment variable

The server and the command line read the key from `EXEWATCH_API_KEY`. Instead of writing it in the agent's configuration you can set it once in your environment:

    setx EXEWATCH_API_KEY ew_api_...          (Windows)
    export EXEWATCH_API_KEY=ew_api_...        (macOS and Linux, in your shell profile)

On Windows `setx` applies only to programs started afterwards: close and reopen the terminal, the agent and RAD Studio. Then register the server without `--env`:

    claude mcp add exewatch -- exewatch-mcp

Codex still needs `env_vars = ["EXEWATCH_API_KEY"]`, as above. Keep the key out of files you commit, and out of your prompts.

## What to ask

When the agent connects, the server hands it the rules for investigating with ExeWatch, and the agent can read the full guide with the tool `exewatch_guide`. It does not rely on stack traces alone. A stack trace is often missing, and the agent knows to use the message, the breadcrumbs, the events of the same session, the version, customer and device pattern, the timings and the metrics. Examples:

- *Find what is slow, why, and propose fixes.*
- *Fix the errors of the last week.*
- *Fix the error that happened this morning.*
- *Why are there so many `orders_failed`?* (a metric)
- *Is this version worse than the previous one?*
- *Considering everything in ExeWatch, what would you work on first?*

Put the application name and its environment in the instructions the agent reads for the project (`CLAUDE.md`, `AGENTS.md` or the equivalent), for example "the ExeWatch application of this project is `Invoices`, PROD", so that it does not have to guess. The agent also checks that the `sdk_type` of the application (`delphi`, `delphi_dll`, `dotnet`, `python` or `javascript`) matches the project it is working on.

## The tools

| Tool | What it does |
|---|---|
| `exewatch_guide` | How ExeWatch works and how to investigate, with one recipe per type of question. |
| `exewatch_apps` | The applications the key can read, with environment and `sdk_type`. |
| `exewatch_groups` | The errors of a period, identical ones grouped: how often, since when, which versions, how many customers and devices. |
| `exewatch_errors`, `exewatch_logs` | Single events. `full` adds the stack trace and the breadcrumbs. |
| `exewatch_timings` | How long each measured operation takes: median, 95th percentile, maximum, failures, per version. |
| `exewatch_versions` | Errors and devices per version, to compare releases. |
| `exewatch_metrics`, `exewatch_series` | The counters and gauges the application reports, and their values over time. |
| `exewatch_customers`, `exewatch_devices` | Who runs the application, on what, without names (see below). |

Hardware details of a device (memory, free disk space) are in the ExeWatch console and are not available through the API.

The output carries `"untrusted_content": true`. Log messages, stack traces and names are text written by the software that sent them, and sometimes by its end users. The agent must read them as data and never follow instructions found in them.

## Personal data

By default the agent does not receive the personal fields ExeWatch stores:

- customers: no name and no e-mail, only the id, the external id and when they were first and last seen;
- devices: no host name and no OS user name;
- events: no `customer_name` and no `device_hostname`, and no `user_email` or `user_name` in `extra_data` (the SDKs put them there when the application calls `SetUser`; `user_id` stays).

The external id of a device is replaced by a pseudonym such as `dev_3f9a12c4b7e1d805`. The Delphi, .NET and Python SDKs build that id as `username@hostname` unless the application turns on `AnonymizeDeviceId`, so returning it as it is would give the names away. The pseudonym is an HMAC of the id keyed with your API key. The same device gets the same pseudonym in every answer, so the agent can still count devices, link events to a machine and pass the pseudonym to `--device`. `--device` does not accept `username@hostname`, so the agent cannot confirm a guessed name by trying it. Two costs: the pseudonyms change when you rotate the key, and two people with different keys see different pseudonyms for the same device.

To give the agent these fields, set `EXEWATCH_PERSONAL_DATA=1` in the environment of the server, in the same place as the API key. Only the value `1` turns them on, and no MCP tool has an argument for it.

This is a default for what the MCP tools return, not a barrier. An agent that can run shell commands as the same user can set the variable itself (`exewatch`, the command line, is installed with the server), or read the API key from the agent's configuration and call the API directly. A real limit can only come from the ExeWatch server, with a key that cannot read personal fields.

What this does not cover:

- Messages, stack traces, breadcrumbs and the rest of `extra_data` are free text written by your software. They reach the agent as they are, and they can hold personal data: a Windows path with the user name, an e-mail in an error message.
- The external id of a customer is chosen by whoever writes the application. Use a code or a number, not an e-mail address or a person's name, so that the id does not tell the agent who the customer is.

## The command line

`exewatch` is the same thing for a terminal and for scripts. Every command prints JSON. `exewatch --help` and `exewatch COMMAND --help` print a page in the style of a Linux man page, and `exewatch guide` prints the guide.

    exewatch apps
    exewatch groups --app "My App" --env PROD
    exewatch timings --app "My App" --since 24h
    exewatch errors --app "My App" --limit 3 --full

`--app` takes the exact name (case does not matter) or the id. When the same name exists in PROD and in DEV the command stops and lists them: add `--env` (`DEV`, `TEST`, `STAGING` or `PROD`, in any case), or use the id. To see every application on one line each, use `exewatch apps --format table`.

| Command | What it does |
|---|---|
| `apps` | The applications the key can read. `--env`, `--format json\|table`. |
| `groups` | The errors of a period, grouped. |
| `timings` | The duration of each measured operation. |
| `versions` | Errors and devices per version. |
| `errors`, `logs` | Single events. `logs` takes `--level`, which can be repeated. |
| `metrics`, `series` | The metrics and the values of one metric over time. |
| `customers`, `devices` | The customers and devices that sent data. |
| `guide` | How ExeWatch works. |
| `mcp` | The MCP server, the same as `exewatch-mcp`. |

`groups`, `timings` and `versions` take `--since` (`90m`, `6h`, `7d`; default `7d`) and `--scan`, the number of events to read at most (default 2000). They read the newest events first: when `sampled` is `true` in the output, the period holds more events than were read.

`errors` and `logs` take `--app`, `--env`, `--search`, `--tag`, `--version`, `--binary-version`, `--session`, `--customer`, `--device`, `--since` or `--from` and `--to`, `--limit` (50 by default, at most 1000) and `--full`.

Examples:

    exewatch errors --app "My App" --version 2.3.0.145
    exewatch logs --app "My App" --level warning --level error --search timeout --tag sync
    exewatch logs --app "My App" --session 284A424816C7F111 --to 2026-10-13T15:12:29.076000Z
    exewatch series --app "My App" --name orders --type counter --range 7d

The third one shows what the user did just before an error: take the `session_id` and the `client_timestamp` of the error, then stop the search at that instant. Add `--from` if the session is older than the default window of 24 hours.

Without `--full` each event is compact, to save space. `--full` adds `extra_data`, where the stack trace (`stack_trace`, or `stack` for JavaScript SDK clients older than 0.17.1) and the breadcrumbs live.

## Limits worth knowing

- Without filters a query covers up to 90 days, and by default the last 24 hours. Using `--search`, `--tag`, `--version`, `--binary-version` or `--session` narrows the maximum range to 7 days; a wider range is refused. `timings` reads its measures with a search, so it is limited to 7 days too.
- `--version` and `--binary-version` compare the exact text. `2.3` does not find `2.3.0.145`.
- The server ignores a filter it does not know. If `app_version` is `null` on every row, check that the ExeWatch API you are talking to is up to date.
- `versions` compares rough figures: a device that was updated counts for the new version, while its old errors stay with the old one. Confirm with `groups --version` for each of the two versions.
- Paging with `errors` and `logs` works only with `--to`, and the server includes the instant you give. The last row you received comes back on the next page.
- Stack traces over the size limit are cut at the end, with a marker in the text. The .NET SDK puts the stack at the end of `message` and leaves `stack_trace` empty. A Delphi stack names units and lines only if the program was compiled with a detailed map file next to the executable.

## When something goes wrong

Errors go to stderr (and, in the MCP server, come back as a tool error), never with the key. Exit codes: 0 ok, 1 API or network error, 2 wrong usage or missing key.

| Message | Cause |
|---|---|
| `set EXEWATCH_API_KEY` | The variable is not set where the command runs. |
| `HTTP 401 invalid_key` | The key is wrong, revoked or expired. Create a new one. |
| `HTTP 403` | The account is inactive, or its plan does not include the API. |
| `HTTP 422 ... cannot exceed 7 days` | A filtered query with a range wider than 7 days. |
| `ambiguous app` | Two applications share the name, for example the same one in PROD and in DEV. Add `--env`, or use the id. |
| `no app named ... in PROD` | No application with that name in the environment you asked for. The message lists similar names. |
| `no customer with external id ...` | The customer is not known to this application. The message lists some that are. |
| `--env needs a newer ExeWatch API` | The server is too old to report environments. Leave `--env` out. |
| `cannot reach the API` | Network problem, or a wrong `EXEWATCH_API_URL`. |

## More

The ExeWatch DevGuide has a chapter on reading your own data, with the API behind this command and more recipes: https://exewatch.com

## License

MIT. See `LICENSE`.
