Brahim Bousnguar

Notes · Article

The official MuleSoft MCP server can't read your logs, so I built one that can

By · · 4 min read

Listen · 4:59 · read by an AI voice

Listen to this article0:00 / 4:59

Read by an AI voice · MP3

MuleSoft has an official MCP server. It scaffolds projects, generates flows, deploys apps. What it can't do is the one thing I need when something breaks in prod: read the logs.

So I built mulewatch. It's an open-source MCP server that gives Claude, Cursor or any MCP client your Anypoint logs, live and archived. Read-only. One line to run: npx -y mulewatch.

I first built a version of this for my day job. This one is the cleaned-up, works-for-anyone release.

Building vs. running

The official server is for building Mule apps, and it's good at that. But it expects a local Mule project open in your IDE. When a flow fails in prod, you usually don't have one open. You have Runtime Manager in a browser tab.

mulewatch covers the other half of the job: figuring out what happened. Logs, deployed apps, API Manager instances, Exchange assets. Nothing that writes.

Building

Official server

Scaffolds projects, generates flows, deploys apps

Expects a local Mule project open in your IDE

vs

Running

mulewatch

Logs, deployed apps, API Manager, Exchange

Nothing that writes

Two halves of the same job. The official server helps you build the app; mulewatch reads what happened once it runs. The red line is the one you're looking for.

The live tail forgets fast

The logs you see in Runtime Manager are a live tail: a small rolling buffer per app. On a busy app it scrolls out in minutes, whatever startTime you pass. If the problem happened last night, it's already gone.

The real history lives in the Anypoint Monitoring Archive API. It stores logs in 10-minute files that land about 10 minutes after each window closes, and keeps them for a long time. You need Anypoint Monitoring enabled on the org.

Live taila small rolling buffer per app

Monitoring Archive10-minute files, kept a long time

last nightnow

NeedsAnypoint Monitoring enabled on the org.

A schematic, not to scale. The red mark is last night's problem: gone from the live tail, still in the archive. The dashed file at the end is the window that hasn't landed yet.

The fun part: finding the right replica

Here's the catch. The archive isn't indexed per app. It's indexed per replica, as {appName}_{replicaId}, and every redeploy creates new replicas. So you can't just ask for "the logs of order-sync-api on 9 August". You need to know which pod was running that day.

The app I tested on had 669 replica entities in the archive. The API allows 60 requests a minute. Probing all of them is about 11 minutes of waiting before you read a single line.

Turns out you almost never need to. Pods usually live until the next redeploy, so the replica running right now probably wrote the recent logs too. mulewatch does this:

  1. Grab the replica IDs from the live tail and try those first.
  2. No files for that date? The app was redeployed since. Fall back to scanning every replica it ever had, capped by maxEntities.

On that test, searching today probed 1 replica, found 127 archive files and parsed 2,859 log lines. A date from before the last redeploy fell back to the full scan, as it should. The client also stays under the rate limit and backs off on 429, so a long search gets slower instead of failing.

Probe every replica

~11 min

669 replicas, indexed as {appName}_{replicaId}

60 requests a minute

Waiting before the first line

vs

Live tail first

1 probe

The replica running now, from the live tail

127 archive files found

2,859 log lines parsed

Redeployed sinceNo files for that date: scan every replica the app ever had, capped by maxEntities.

One square per replica, all 669, from the app I tested on. The scan on the left is what a full probe means at the rate limit; on the right, the one square that answered for today.

Read-only, on purpose

I don't want an LLM restarting production Mule apps. So there's no deploy, stop, restart or policy tool in mulewatch. None. If you need those, use the official server next to it.

You can also lock the whole server to the environments you trust:

ANYPOINT_ALLOWED_ENVIRONMENTS=Dev,Sandbox

Anything outside the list gets refused, with the reason. Pair it with a connected app that only sees those environments and prod is out of reach twice.

Reads

  • logs
  • deployed apps
  • API Manager
  • Exchange

Writes

  • deploy
  • stop
  • restart
  • policy

Allow-listANYPOINT_ALLOWED_ENVIRONMENTS=Dev,Sandbox

  • Devin the list

    read

  • Sandboxin the list

    read

  • Prodoutside the list

    1 allow-list2 connected app

    refused

To deploy or restartUse the official server next to it.

No tool that writes, and an allow-list that refuses anything outside it, with the reason. The second gate on Prod is a connected app that only sees Dev and Sandbox.

The thing that'll trip you up

Environments live on business groups, not on the root org. Connected-app credentials resolve to the root org, which often has zero environments. So your first call comes back empty and you think the credentials are broken. They're not.

Call anypoint_list_business_groups, grab the right id, set ANYPOINT_ORG_ID. Done.

Same energy for scopes: Anypoint answers a missing scope with a bare 403. mulewatch catches it and tells you which scope you're probably missing.

  1. 1Empty first call

    Credentials land on the root org, which often has zero environments

  2. 2List the groups

    Environments live on business groups. Grab the right id

  3. 3Set the org id

    Point it at that group and the environments show up

The fixCall anypoint_list_business_groups, then set ANYPOINT_ORG_ID.

A bare 403mulewatch catches it and names the scope you're probably missing.

The yellow square is where your credentials point. On the left it's the root org, with nothing under it to read; on the right it's the business group that holds the environments.

Try it

Create a connected app ("acts on its own behalf"), give it read scopes, and add this to Claude Desktop, Cursor or OpenClaw:

{
  "mcpServers": {
    "mulewatch": {
      "command": "npx",
      "args": ["-y", "mulewatch"],
      "env": {
        "ANYPOINT_CLIENT_ID": "your_connected_app_client_id",
        "ANYPOINT_CLIENT_SECRET": "your_connected_app_client_secret"
      }
    }
  }
}

Or in Claude Code:

claude mcp add mulewatch --env ANYPOINT_CLIENT_ID=... --env ANYPOINT_CLIENT_SECRET=... -- npx -y mulewatch

Run anypoint_whoami first to see what it's connected to. Then just ask: "show me the ERROR lines of order-sync-api in Prod yesterday between 1 and 3 a.m."

1 · Anypoint

Connected app

  • Acts on its own behalf
  • Read scopes

2 · Your client

npx -y mulewatch

  • Claude Desktop, Cursor or OpenClaw
  • Or claude mcp add in Claude Code

3 · First call

Check

  • anypoint_whoami
  • See what it's connected to

Then ask“Show me the ERROR lines of order-sync-api in Prod yesterday between 1 and 3 a.m.”

Three steps to a first answer. It's v0.1 and Apache-2.0; everything but API Manager was tested against a live org.

It's v0.1, Apache-2.0, on npm and the MCP registry. Everything is tested against a live org except API Manager, because my test app didn't have the View APIs Configuration scope. If you run MuleSoft, try it and tell me what breaks. Issues and PRs are open on GitHub.

MuleSoft and Anypoint Platform are Salesforce trademarks. mulewatch is an independent project.

Plain text: mulewatch-anypoint-logs-mcp.md · Atom feed · All notes

Contact

Say hello.

b.bousnguar@gmail.com

SAP Commerce Cloud, MuleSoft and Salesforce integration · Nantes · EN / FR