CD

certinia/debug-log-analyzer-mcp

Developer tools
30 stars 0 forks 品質 45 トレンド 45

Apex Log MCP Server - AI-powered Salesforce Apex debug log analysis. Find performance bottlenecks, slow methods, SOQL bottlenecks, and governor limit issues.

概要

Instead of scrolling thousands of log lines, ask what's slow and why. Uses the same parser as the Apex Log Analyzer VS Code extension. Requires Node.js 22 or later. Add this to your MCP client config (claude_desktop_config.json, VS Code mcp.json, and so on): Then ask your assistant to analyze a log. apexlog_execute_anonymous also needs an org authenticated with the Salesforce CLI. - "Give me a summary of this debug log" - "Show me the 5 slowest methods in the default namespace" - "Are we approaching any governor limits in this transaction?" - "Run this Apex against my scratch org and analyze the performance" Keeping the server connected costs ~1,232 tokens, 0.6% of a 200K context. See Token Cost. The analysis tools take an absolute path to a .log file. Every tool returns one flat table, encoded as TOON. Nothing is repeated, and nothing is dropped to save space. A 0 means none, not "not measured". Only what did not happen is left out: fatal errors, lost log content, query plans.

README

Apex Log MCP Server

MCP Server to Analyze Salesforce Apex debug logs from your AI assistant. Finds slow methods, governor limit risks, and where a transaction spent its time.

Instead of scrolling thousands of log lines, ask what’s slow and why. Uses the same parser as the Apex Log Analyzer VS Code extension.

Quick Start

Requires Node.js 22 or later. Add this to your MCP client config (claude_desktop_config.json, VS Code mcp.json, and so on):

{
  "mcpServers": {
    "apex-log-mcp": {
      "command": "npx",
      "args": ["-y", "@certinia/apex-log-mcp"]
    }
  }
}

Then ask your assistant to analyze a log. apexlog_execute_anonymous also needs an org authenticated with the Salesforce CLI.

Example Prompts

  • “Give me a summary of this debug log”
  • “Show me the 5 slowest methods in the default namespace”
  • “Are we approaching any governor limits in this transaction?”
  • “Run this Apex against my scratch org and analyze the performance”

Keeping the server connected costs ~1,232 tokens, 0.6% of a 200K context. See Token Cost.

Tools Reference

The analysis tools take an absolute path to a .log file.

Every tool returns one flat table, encoded as TOON. Nothing is repeated, and nothing is dropped to save space.

A 0 means none, not “not measured”. Only what did not happen is left out: fatal errors, lost log content, query plans. Durations are in milliseconds to 3 decimal places, percentages to 1.

The server runs as a local process started by your client over stdio, no network calls and no API keys. Each log is parsed once, so follow up questions are faster.

apexlog_list_slow_operations

Ranks what a log spent its time on by self time - code units, methods, queries, searches, DML, flows and workflows in one table.

A default response returns:

  • capturedAt - {debugCategory, level}
  • operations - {debugCategory, type, name, namespace, callCount, durationTotalMs, durationSelfMs, durationSelfMaxMs, selfPercentage, soqlCount, dmlCount, soslCount, rowCount, thrownCount}
  • queryPlans - {operationRow, leadingOperationType, relativeCost, cardinality, sObjectCardinality}

Each response also gives durationTotalMs for the whole transaction, returnedSelfPercentage for the share these rows account for, and matchedCount for the rows that matched before paging.

durationSelfMaxMs is the slowest single call in a grouped row. Read it against durationSelfMs to tell one bad call from many small ones. It is absent when the row is already one call.

Two columns say what a row is, both taken straight from the log:

  • debugCategory - what Salesforce stamped on the event. It decided whether the event was logged at all, and it is the spelling apexlog_execute_anonymous takes.
  • type - the event type. The category cannot imply it: SOQL_EXECUTE_BEGIN, SOSL_EXECUTE_BEGIN and DML_BEGIN all sit under database.

Watch for ENTERING_MANAGED_PKG. It is time a package spent where the log shows nothing, and it is often most of a transaction.

sortBy: "heapSelfNetBytes" ranks by retained heap instead of time, adding that column and returnedHeapPercentage. Both are absent otherwise. The figure is signed, so a row that released more than it took reads below zero. Heap is logged only at apexCode FINER and above, so check the apexCode row of capturedAt before trusting a zero.

capturedAt gives the level each category in the returned rows was logged at.

queryPlans is what the query optimizer decided about the queries behind those rows. A relativeCost above 1 means it will not treat the query as selective. Plans are absent when the log explained none, because explain lines need database FINEST.

operationRow points at a row of operations, counting from 1. Under a namespace, callerNamespace or debugCategory grouping a row is not one query, so the plan carries the query text in name instead.

Parameter Type Required Description
logFilePath string Yes Absolute path
debugCategory string[] No Rank only these debug log categories
type string[] No Rank only these log event types, e.g. SOQL_EXECUTE_BEGIN, DML_BEGIN, METHOD_ENTRY
namespace string[] No Rank only these namespaces
minSelfMs number No Drop operations below this self time (default: 0), whichever sortBy is used
limit number No Page size (default: 10); fewer if the page would be too large
offset number No Ranked rows to skip (default: 0). Advance it by the rows you got, which can be fewer than limit.
groupBy string No Fold repeats into one row; default name. callerNamespace attributes platform DML to the package that drove it. debugCategory folds a namespace’s event types together and so states no type or name. none ranks each call on its own. A grouped durationTotalMs is what the transaction takes back if the group never runs - never sum it across rows.
sortBy string No Default durationSelfMs. heapSelfNetBytes adds that column.

apexlog_get_summary

How long the transaction ran, where the time went, what it consumed, and whether the log is complete. Start here.

  • fatalErrors - {message, frames}
  • governorLimits - {limit, used, max}
  • limitsByNamespace - {namespace, limit, used}
  • categories - {debugCategory, level, operationCount, durationSelfMs, selfPercentage}

All thirteen governor limits are listed, zeros included.

limitsByNamespace shows what each namespace consumed. This is how you see a managed package spending your CPU time. It has no ceiling column, because a ceiling is per limit for the whole transaction and already sits in governorLimits.

categories covers all eleven, each with the level it was captured at, because the level is what a zero means:

  • database,NONE,0 - the queries were not logged.
  • database,FINEST,0 - no queries ran.
  • dataAccess,"",0 - the log’s header declared no level for it, which most logs do not.

dataAccess, wave and validation are always zero. No timed event carries them.

truncated says whether the log is complete. In a partial log, every figure is a floor. Where the platform cut it, truncatedBy says how - skipped-lines for a hole, max-size for a missing tail - and skippedBytes says how much went. Both are absent when a log merely stops mid-frame.

thrownCount counts the exceptions thrown, zero included.

fatalErrors appears once per failure that ended the transaction, with the innermost three frames and a trailing where there were more. It is the only field that says a transaction did not finish, because a fatal error need not breach any limit.

Parameter Type Required Description
logFilePath string Yes Absolute path

apexlog_list_limit_risks

The governor limits nearest their ceiling, worst first.

  • capturedAt - {debugCategory, level}
  • atRisk - {limit, used, max, usedPercentage}

threshold is reported beside the rows, so an empty table means nothing reached it rather than that the answer is missing.

capturedAt gives the level that gated each returned limit. Every limit but heap comes from apexProfiling; heapSize comes from apexCode.

Parameter Type Required Description
logFilePath string Yes Absolute path
threshold number No Report a limit once it is this percentage consumed (default: 80)

apexlog_execute_anonymous

Runs anonymous Apex against an authenticated org, saves the debug log locally, and returns the path. Pass that path to any analysis tool.

The response also gives the org username, its alias if set, the org type, and a summary of the run. Logs go to .apex-log-mcp/ by default - add it to your .gitignore. Production orgs are gated: see Production safety.

Parameter Type Required Description
apex string Yes The anonymous Apex to be executed
targetOrg string No Alias or username of the target Salesforce org. Uses the project default if not specified.
outputDir string No Directory to save the debug log file. Defaults to .apex-log-mcp/ in the project root.
debugLevel string | object No Trace flag log levels. “default” restores the defaults; a bare level sets every category to it; an object sets only the categories named and leaves the rest unchanged. Defaults: apexCode, apexProfiling, visualforce, workflow FINE; callout, system, validation DEBUG; database FINEST; nba, wave INFO.

An object debugLevel looks like this:

{ "database": "FINEST", "apexCode": "FINE" }

Levels are NONE, ERROR, WARN, INFO, DEBUG, FINE, FINER, FINEST.

Example prompts:

  • “Execute this Apex and show me the log: System.debug('Hello');
  • “Run a query for all Accounts and analyze the performance”
  • “Execute this Apex with all debug levels set to FINEST”
  • “Run this Apex against my QA org with database logging set to FINEST”

Token Cost

Every request carries all four tool definitions, whether you call them or not. Each figure below is a whole definition: name, title, description, input schema and annotations.

Tool Tokens
apexlog_list_slow_operations ~530
apexlog_execute_anonymous ~407
apexlog_list_limit_risks ~150
apexlog_get_summary ~145
Total ~1,232 (0.6% of a 200K context), -19% vs 1.x ~1,529

Only the total compares with 1.x: per tool it would compare different tools, since apexlog_list_slow_operations replaced one that took three selection parameters and ranked methods where this one takes eight and ranks every timed event.

A call itself is about 15 tokens - a tool name and a log path - so what a call costs is what it returns.

Cost does not grow with the log size. The figures below are measured against a 40 KB slice of the Apex Log Analyzer sample log. On the full 19.7 MB original, apexlog_get_summary returns ~374 tokens instead of ~364, and apexlog_list_limit_risks the same ~35.

Tool Response 1.x Change
apexlog_get_summary ~325 ~293 +11%
apexlog_list_slow_operations ~396 ~408 -3%
apexlog_list_limit_risks ~35 ~84 -58%

Configuration

The Quick Start config gives you all four tools.

Production safety

apexlog_execute_anonymous runs arbitrary Apex, so the server identifies the org before running anything:

Org type Identified by Behaviour
sandbox IsSandbox, no trial expiry Runs
scratch IsSandbox with a trial expiry Runs
trial Not a sandbox, has a trial expiry Runs
developer Developer Edition Runs
production Anything else Confirmation required
unknown The org could not be queried Confirmation required

For a production org, --allow-production-orgs runs it anyway. Otherwise the server asks you to confirm, naming the org and showing the Apex. That needs a client that supports elicitation; without one the call is refused, and the message names both ways to proceed. Each confirmation authorizes one run.

An org that cannot be identified is treated as production, so a network or permissions problem can never quietly downgrade one.

Server flags

Flag Description
--allow-production-orgs Treat production orgs like any other - no confirmation, no refusal. Only set this if production targets are intentional.
--no-apex-execution Refuse every Apex execution. The tool stays visible so agents know it exists. The three analysis tools are unaffected.

For an analysis-only deployment:

{
  "mcpServers": {
    "apex-log-mcp": {
      "command": "npx",
      "args": ["-y", "@certinia/apex-log-mcp", "--no-apex-execution"]
    }
  }
}

Documentation

Contributing

See the Contributing Guide, Developing to set up your environment, and the Code of Conduct.

License

BSD 3-Clause. Copyright © Certinia Inc. All rights reserved.

View this README on GitHub

インストール

npx -y @certinia/apex-log-mcp

設定

{ "mcpServers": { "apex-log-mcp": { "command": "npx", "args": ["-y", "@certinia/apex-log-mcp"] } } }