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
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.
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:
- Grab the replica IDs from the live tail and try those first.
- 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.
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
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.
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.
-
1Empty first call
Credentials land on the root org, which often has zero environments
-
2List the groups
Environments live on business groups. Grab the right id
-
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.
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.”
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