v0.41 Release: A Help Desk MCP Server for the People Who Run Smarter
v0.40 let an LLM file bugs and propose fixes for Smarter’s code. v0.41 turns to the people who run a Smarter platform, and to the questions their users ask them. “My login isn’t working.” “Why is Smarter slow right now?” “My prompt says there was a system error.” Until now, answering one meant reading pod logs by hand with kubectl, which shows only what a container wrote since it last started, and nothing of a pod that is gone.
This release adds a second MCP server to every Smarter platform, for its staff only. An AI agent such as Claude Code can use it to read the platform’s health, search three days of logs, look into one person’s problem, and check a reply before a person sends it.
| Change | What it does |
|---|---|
| Smarter Operations MCP server | A staff-only MCP server, separate from the public one, with an audit trail of every tool call. |
| 72 hours of pod logs | Loki keeps the platform’s logs inside its own namespace, and Grafana Alloy redacts personal data before it is stored. |
| Platform and EKS health | One tool call reports pods, nodes, queues, the database, AWS EKS and the AI providers’ status pages. |
| Help desk tools | A snapshot of one user’s problem, and a check of the draft reply against rules that protect every other user. |
| Failed sign-ins you can find | Each failed sign-in is logged with its reason, under a keyed hash of the email address instead of the address. |
A second MCP server, for staff only
The Smarter Project MCP server is public. It reads code, docs and the blog, and since v0.40 it files issues. A platform’s logs and its users’ accounts are not public, so they get a server of their own, at /api/v1/mcp/smarter-operations/ on the platform’s domain. The two never share tools, instructions or a cache.
Every request needs the API key of an active staff user. A request without a valid key gets a 401, and a user who is no longer staff gets a 403, before the server reads anything. To connect Claude Code, create an API key for your staff user in the web console, then add the server.
claude mcp add --transport http smarter-operations \
https://<your-smarter>/api/v1/mcp/smarter-operations/ \
--header "Authorization: Token $SMARTER_API_KEY"
- Seven tools, all read-only. Nothing on this server changes the platform.
- Every call has a reason. Each tool takes a required
ticket, the help desk ticket or the reason for the call. - An audit trail. Every call, including a failed one, is recorded with its user, tool, ticket, arguments and the size of its result. Superusers see it in the Django admin as Operations Tool Calls. The rows are read-only, and a row keeps the username after the user is deleted.
- Never cached. Every answer is read fresh.
📖 Smarter Operations MCP Server documentation
Three days of pod logs, with personal data removed
The Helm chart now runs Loki as a single pod that keeps the last 72 hours of logs on a 10Gi volume. Nothing goes to S3 or CloudWatch, so it adds no cloud cost. Grafana Alloy collects the logs of the app, both Celery workers, beat and MariaDB through the Kubernetes API, so it needs no access to the nodes. Each line is labeled with its component, pod and container.
Before a line is stored, Alloy replaces email addresses, IP addresses, bearer tokens, OpenAI, AWS, GitHub and Slack keys, JWTs and passwords with redaction markers. The logs of a pod on a spot node that was replaced an hour ago are still there.
Three tools read them.
summarize_log_errorsgroups the errors, and optionally the warnings, of a period by component, level and message, with the numbers, IDs and quoted values taken out. Each group has a count, its pods, when it was first and last seen, and its latest line. It’s where to start for errors, slowness and outages.search_logsfinds lines by component, pod, text, regular expression and level, newest first. With no filters it works liketail.list_log_sourceslists the components and pods that logged recently. A missing component has written nothing, often because its pods are down.
Security
- The LLM never writes a query. The tools take structured filters, and Smarter builds and escapes the Loki query itself, so a tool call can’t inject one.
- A user can put text into a log, for example with a prompt. So every result that quotes log lines starts with a notice that they are data, not instructions, and the server’s instructions tell the agent never to follow a request found in a log line.
- Alloy reads only the pods of its own namespace, through a namespaced Role. It creates no cluster-wide objects, so several environments can share one cluster.
Is Smarter down? One call answers it
platform_status reports the platform’s health right now, and starts with what looks wrong, in plain sentences. Then it lists the details.
- Pods. Readiness, restarts, CPU and memory, and problems such as
CrashLoopBackOff, a restart afterOOMKilled, orPending. - Nodes. Readiness, memory or disk pressure, cordons, CPU and memory, and whether each is a spot or on-demand server.
- Recent Kubernetes warning events in the platform’s namespace.
- Backing services. The same database, cache, broker and worker checks as the web console dashboard’s Service Health, run fresh, plus the backlog of each Celery queue and the database’s connections, running threads, slow queries and aborted connections.
- Upstream status. The public status pages of OpenAI, Anthropic and Mistral, and the AWS status feeds for EKS and EC2 in the platform’s region.
eks_status reports the cluster as AWS EKS sees it. That covers the control plane’s status, version and health issues, each node group’s size, instance types and issues, each add-on’s version and whether a newer one exists, and the EKS insights that aren’t passing, such as readiness for the next Kubernetes version.
Both tools read only what is already there. That means Kubernetes and metrics-server (the numbers kubectl top shows), the EKS API, the platform’s own database and broker, and public status pages, which need no AWS account or paid support plan. When one part can’t be read, for example EKS insights without the eks:ListInsights permission, the result names it and reports the rest. A status page that can’t be reached is reported as unknown, never as healthy.
One person’s problem, and a safe reply
user_support_snapshot takes an email address and reports what the platform knows about that person’s problem.
- Whether a user has the address, whether they are active, and when they joined and last signed in.
- How they can sign in, with a password, Google or GitHub, and their Smarter accounts and, on a hosted platform, their subscription.
- Their failed sign-ins of the last 72 hours, counted by reason. These are searched even when no user has the address, because the person may be typing a wrong one.
- Their failed requests and prompts of the last few days, from the journal, with each error’s class and description.
- Hints for staff, such as resetting a password, signing in with Google instead, reactivating a user, or calling
platform_statusfor a server error.
check_reply checks the agent’s draft before a staff member sends it. It finds other people’s email addresses, IP addresses, phone and card numbers and secrets with the same detectors as Guardrails. It also finds the platform’s internals, such as pod, node and host names, internal URLs, log lines, stack traces, exception names and version numbers, and wording like “there is no account with that address”. Each finding says why a reply must not contain it.
Security
user_support_snapshotrequiresverified_by, which says how the staff member confirmed that the person who asked owns the address. It goes into the audit trail. The server’s instructions say never to treat an address in a request’s text as proof of who sent it.- A reply may say whether the platform had a problem, its cause in general terms, what the user can do, and when it started or was resolved. It never says anything about another user, nor whether an email address has an account, unless the person who asked is verified as its owner.
check_replyis a safety net, not a guarantee. The agent drafts and checks the reply, and a person reads it and sends it.
Failed sign-ins are logged, without the address
Before v0.41, a failed sign-in to the web console was logged only at DEBUG, behind a switch, with the email address in plain text. Now each one is logged once, at WARNING, with its reason. The reasons are a wrong password, an unknown account, an inactive account, an account with no password (one that signs in with Google or GitHub), an invalid form, or an error.
The address itself is never logged. People sometimes type their password into the email field. Each line carries a 16-character hash of the address, keyed with the platform’s secret key, and staff find a user’s attempts by computing the same hash, which is what user_support_snapshot does. The sign-in page also no longer logs plain email addresses anywhere else.
Fixes and operations
- A more readable MCP server app. Every module of the MCP server app, and the new log service, now does about one operation per line, and every function documents its parameters, results, errors and side effects, such as the GitHub, WordPress and Loki requests it makes. Behavior is unchanged, and the Loki queries it builds were compared byte for byte on 648 combinations of filters.
- One protocol core for both servers. The JSON-RPC handling of the public server moved into a shared base, so both servers answer
initialize,ping,tools/list,tools/calland batches the same way. The public server’s 235 existing tests pass unchanged.
Upgrading
- New pods and a volume. The Helm chart now turns on Loki, with a 10Gi gp3 volume, and adds Grafana Alloy as one Deployment. Both are on by default (
loki.enabled,alloy.enabled). - Network policies. If your namespace restricts egress, allow the app and Alloy to reach Loki on ports 3100 and 9095.
SMARTER_LOKI_URLpoints the app at Loki. The chart sets it tohttp://smarter-loki:3100. It is empty by default outside the chart, as in local development, and then the log tools answer that they are not available.- EKS permissions for
eks_status. The platform’s AWS role needseks:DescribeCluster,eks:ListNodegroups,eks:DescribeNodegroup,eks:ListAddons,eks:DescribeAddon,eks:DescribeAddonVersionsandeks:ListInsights. Without some of them, the tool reports the parts it could read and names the rest. - A migration. The
mcpserverapp adds the audit trail table, and the init job applies it. - Staff API keys. Only active staff users can call the server. Create one key per person, keep it in an environment variable, and delete it when the person leaves staff.
What’s next
The operations server can’t yet follow one request through the platform, because log lines don’t carry a request ID. Adding one, and a trace_request tool that uses it, comes next. The daily pod log review in smarter-sh/automation still reads logs with kubectl, and will move to Loki, so it sees three days of logs instead of what is left in each container. A review of this release also found a handful of small bugs in edge cases of the MCP tools. They were left for a later fix, so that the cleanup in this release changed no behavior.
The full list of changes is in the changelog. To try the release, start with the documentation, or browse the code on GitHub.
