Coding Agents (MCP)

Give Claude Code, Codex, Cursor or any MCP client read-only access to your Rails Pulse data, so an agent can find what is slow and why.

Overview

Rails Pulse ships with an MCP server so that a coding agent can look at the same data the dashboard shows: the slowest endpoints since the last deploy, the SQL inside them, the jobs that failed, and the exceptions that are firing. Ask the agent why checkout got slow and it can go and look, instead of guessing from the code.

Everything the agent can call is read-only. The MCP server talks to the JSON API over HTTP with its own token, which cannot record a deployment, change an exception’s status, or touch any other part of your app.

Setup

1. Set an API token in the app

# config/initializers/rails_pulse.rb
RailsPulse.configure do |config|
  config.api_token = ENV["RAILS_PULSE_API_TOKEN"]
  # or: Rails.application.credentials.dig(:rails_pulse, :api_token)
end

With no api_token, the JSON API refuses every request.

2. Add the mcp gem

The MCP server needs the mcp gem, which Rails Pulse does not pull into production. A development group is enough:

# Gemfile
group :development do
  gem "mcp", "~> 1.0"
end

Without it, rails-pulse mcp exits with a message saying what to add.

3. Point the CLI at your app

rails-pulse configure

This prompts for the app’s URL, the API token and the mount path (default /rails_pulse), makes a test request, and saves them to ~/.rails-pulse, readable only by you. Nothing is written to the project directory. The MCP server and the CLI share these credentials.

You can use environment variables instead, which take precedence over the file:

VariablePurpose
RAILS_PULSE_URLThe app’s base URL, such as https://yourapp.com
RAILS_PULSE_TOKENThe value of config.api_token
RAILS_PULSE_MOUNT_PATHWhere the engine is mounted, if not /rails_pulse
RAILS_PULSE_CONFIGRead a config file other than ~/.rails-pulse

4. Register the server with your agent

The server runs over stdio. For Claude Code:

claude mcp add rails-pulse -- bundle exec rails-pulse mcp

For other clients, add a server entry that runs bundle exec rails-pulse mcp from your app’s directory. For example, in Cursor’s .cursor/mcp.json:

{
  "mcpServers": {
    "rails-pulse": {
      "command": "bundle",
      "args": ["exec", "rails-pulse", "mcp"]
    }
  }
}

Tools

The server exposes eleven tools, all marked read-only:

ToolWhat it answers
rails_pulse_coverageWhich app and environment this is, what has been recorded and how recently, retention, and whether any requests were dropped
rails_pulse_routesThe tracked endpoints, with request volume, average latency and error counts
rails_pulse_slow_requestsThe slowest endpoints for a period, ranked by average response time
rails_pulse_endpointA detailed profile of one endpoint: latency distribution, error rate and status codes
rails_pulse_queriesThe most expensive SQL, with N+1 detection and the file and line each query came from
rails_pulse_errors4xx and 5xx responses grouped by endpoint
rails_pulse_exceptionsException groups with status, occurrence count, location and latest message
rails_pulse_exceptionOne exception group’s recent occurrences, with backtraces, request, filtered params and deploy SHA
rails_pulse_jobsBackground job failure rates, slow jobs and recent failures
rails_pulse_deploymentsRecent deployments with revision, start and finish time, metadata, and whether each one made things worse
rails_pulse_insightsWhat is past its thresholds in a summary period, and whether the thresholds themselves fit

Time windows

Most tools take a period of last_hour, last_24_hours or last_7_days. They also take since and until as ISO 8601 timestamps, which pin the window instead of measuring back from now. This is what makes a before-and-after comparison around a deploy repeatable. Explicit bounds win over period, a timestamp with no zone is read as UTC, and every tool reports the window it actually measured.

rails_pulse_insights is the exception: it reads one whole summary period, chosen by period (hour, day, week, month) and at, because a P95 cannot be combined across periods.

Exact lookups

An identifier from an alert or a log is a tool argument too, so the agent can jump straight to one record: hashed_sql on rails_pulse_queries, fingerprint on rails_pulse_exceptions (which then ignores status and the window), path and controller_action on rails_pulse_routes, revision on rails_pulse_deployments, and path_prefix on rails_pulse_errors, which groups requests no route matched by path.

From a slow endpoint to its SQL

rails_pulse_endpoint and rails_pulse_slow_requests return a route_id. Pass it to rails_pulse_queries as route and you get only the SQL issued while serving that endpoint, each query with the file and line it came from. That is how an agent gets from “this endpoint is slow” to “this is the query, and here is the code that runs it”.

No data is not the same as no problems

rails_pulse_coverage reports the oldest and newest data held for requests, job runs and exceptions, whether summaries are up to date, and whether the background writer dropped any requests. If a kind of data is not being tracked (for example config.track_jobs is off), it says so instead of reporting zero. Agents are told to call it first, and before reporting that nothing went wrong, so that “no failures recorded” is not read as “no failures”.

Teaching your agent to use it

Two commands write instructions that tell an agent when and how to use Rails Pulse:

rails-pulse install claude          # Claude Code skill: ~/.claude/skills/rails-pulse/SKILL.md
rails-pulse install agents          # writes ./AGENTS.md
rails-pulse install agents --append # adds a Rails Pulse section to an existing AGENTS.md

--append wraps its section in markers, so running it again replaces that section rather than adding a second copy, and leaves the rest of your AGENTS.md alone. rails-pulse install --list shows every integration and where it writes.

Example prompts

  • “Which endpoints got slower since yesterday’s deploy?”
  • “Why is OrdersController#index slow? Show me the queries behind it.”
  • “Are there any N+1 queries on the busiest routes?”
  • “What’s failing in background jobs this week?”
  • “We fixed the checkout query at 14:00. Compare the hour before and the hour after.”

Security

  • The MCP server never connects to your database. It reads from the JSON API, so it sees only what the API returns.
  • api_token grants read access only. It is refused by the deployments endpoint, so a token given to an agent cannot record a release. See Deployment Tracking.
  • Exception params and messages are filtered the same way they are in the dashboard.
  • Point the agent at the environment you mean to investigate. rails_pulse_coverage reports the application name and environment that answered, so numbers from staging are not mistaken for production.

Next Steps

  • CLI — the same data from a terminal or a CI script
  • JSON API — the endpoints both are built on