JProfiler
JProfiler MCP 서버
JProfiler는 Model Context Protocol을 통한 AI 에이전트 통합 기능을 갖춘 Java 프로파일러입니다. AI 코딩 어시스턴트에서 직접 CPU 핫스팟, 메모리 할당, JDBC 쿼리, HTTP 호출 등을 프로파일링하세요.
설치
Claude Code
claude mcp add jprofiler -- npx -y @ej-technologies/jprofiler-mcpCursor
cursor.directory에 등록되어 있습니다.
Codex
codex mcp add jprofiler -- npx -y @ej-technologies/jprofiler-mcpGemini CLI
gemini mcp add jprofiler npx -y @ej-technologies/jprofiler-mcp@latest기타 MCP 클라이언트
클라이언트 구성의 MCP 서버 명령으로 다음 npx 호출을 사용하세요:
npx -y @ej-technologies/jprofiler-mcp@latestJSON 구성 파일을 사용하는 클라이언트(Claude Desktop, Windsurf, VS Code 등)의 경우:
{
"mcpServers": {
"jprofiler": {
"command": "npx",
"args": ["-y", "@ej-technologies/jprofiler-mcp"]
}
}
}선택적 인수
--filter <patterns>— 포함할 도구 이름 패턴의 쉼표로 구분된 목록--subsystems <list>— 활성화할 하위 시스템의 쉼표로 구분된 목록--max-depth <n>— 최대 호출 트리 확장 깊이
Related MCP server: Github MCP Server Java
라이선스
JProfiler는 라이선스가 필요합니다. 처음 사용할 때 10일 무료 평가판을 시작하거나 기존 라이선스 키를 입력할 수 있습니다. https://www.ej-technologies.com/store/jprofiler 에서 구매하세요.
Available Tools
8 toolsattachA
Attach to a running JVM by PID or to a JVM inside a Docker container. Records performance data for the following subsystems: cpu, jdbc, jpa, mongo_db, cassandra, http_server, http_client, ws, jndi, jms, kafka_consumer, rmi, grpc, ai, process until check_status is called with 'stopRecording: true', or allocation data when "recordingConfig": {"recordAllocations": true} is passed. Pass "recordingConfig": {"recordMonitors": true} to additionally record monitor and lock events. You can use list_jvms to discover JVMs.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | No | The PID of a local JVM process, or the container PID (NSpid) of a JVM inside the specified container. If a container is specified and this is omitted, the topmost JVM in the container is used. | |
| recordingConfig | No | What to record in this session. Every key is optional and omitted keys keep their defaults - set only the keys this analysis needs, such as recordMonitors for lock contention analysis, recordAllocations for allocation sites, triggers for automatic captures during the recording, or advanced.methodCallRecordingType instrumentation when invocation counts are needed. | |
| containerNameOrId | No | The name or ID of a Docker container. When specified, profiling attaches to a JVM inside this container. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It does disclose a valuable behavioral trait: this starts a persistent recording session that runs until explicitly stopped via check_status. But it says nothing about overhead, failure modes (target not attachable, JVM already attached, missing permissions), or what the call hands back, which the agent needs to proceed to check_status/attached_action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and target, then the recording-scope sentence, then the discovery hint. The single long enumeration of subsystems is dense but earns its place by telling the agent what data will exist afterwards.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-required-param, deeply nested tool with no output schema, the description covers the essentials: target selection, what gets recorded, how recording terminates, and where to find PIDs. The main omission is that the agent is not told what a successful attach returns or whether follow-up calls need a session identifier.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the nested recordingConfig is exhaustively documented inline, so the baseline is 3. The description's mentions of recordAllocations, recordMonitors and the default subsystem list restate what the schema already explains, adding little new meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and target: attach profiling to a *running* JVM, by PID or one inside a Docker container. The word 'running' implicitly separates it from prepare_profiling, and the recording scope (subsystem list, allocation vs performance) is spelled out, so the agent knows exactly what the call accomplishes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit discovery path ('use list_jvms to discover JVMs') and states how the recording ends (check_status with stopRecording, or an allocation-mode session). However, it never contrasts attach with prepare_profiling or states when not to attach (e.g. JVM already attached, JVM not yet started), which is the key sibling ambiguity here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
attached_actionA
Perform a point-in-time action on the connected JVM: thread and monitor dumps, heap marking and heap dumps, MBean snapshots, and starting or stopping subsystem recording. Requires a recording session started with attach or prepare_profiling. The action names and parameters are the same as for the actions of recordingConfig.triggers.
| Name | Required | Description | Default |
|---|---|---|---|
| cpu | No | Optional for 'startRecording'/'stopRecording': include CPU recording. | |
| label | No | Optional for 'mbeanSnapshot' and 'threadDump': label shown in the mbean.snapshots resp. threads.dumps dataset. In triggers the default is a name derived from the event. | |
| action | Yes | The action to perform on the attached JVM. 'threadDump': the current state and stack trace of every thread, grouped like in the JProfiler thread dumps view - use it when the app is slow but CPU usage is low, and take two dumps to find threads stuck at the same stack trace. 'monitorDump': the currently held and waited-on monitors with the involved threads and stack traces, plus deadlock detection over the current wait/own graph - deadlocks never appear in recorded monitor history because deadlocked events never finish, this dump is the way to find them, and no monitor recording is needed for it; attach-mode dumps show java.util.concurrent locks only, not intrinsic (synchronized) monitors. 'markHeap': mark all current heap objects as old, objects allocated afterwards count as new in heap dumps taken later in this session (generation argument of the heap datasets) - use it to bracket an operation of interest. 'mbeanSnapshot': capture the current JMX MBean attribute values into the session snapshot, for exploration usually unfiltered. 'heapDump': take a heap dump that becomes part of the session snapshot while the recording keeps running - expensive on large heaps, use create_heap_dump instead to stop the recording and analyze the heap immediately. 'startRecording'/'stopRecording': start or stop the recording of subsystems in this session, at least one of 'cpu', 'allocations', 'monitors', 'probes', 'complexity' is required - this does not end the session, use check_status with stopRecording for that. Dumps and snapshots taken by these actions become part of the session snapshot and are served by the threads.dumps, monitor.current, mbean.snapshots and heap.* datasets after the recording is stopped. For captures at events or from JVM start, configure actions with the same names in recordingConfig.triggers of attach or prepare_profiling. | |
| filter | No | Optional for 'mbeanSnapshot': regular expression matched against the domain and each property value of the MBean object names: "java.lang|com.mycompany.*" captures all MBeans in those domains, "Memory" the java.lang:type=Memory MBean. Without a filter all MBeans are captured, the right choice for exploration. | |
| fullGc | No | Optional for 'heapDump': run a full GC before the dump so only live objects are captured. Default true. | |
| probes | No | Optional for 'startRecording'/'stopRecording': probe names to start or stop, e.g. ["jdbc"], "custom:<fully qualified probe class name>" for custom probes of the profiled application, or "script:<name>" for a script probe defined in recordingConfig.advanced.scriptProbes. | |
| monitors | No | Optional for 'startRecording'/'stopRecording': include monitor recording. | |
| complexity | No | Optional for 'startRecording'/'stopRecording': include complexity recording - requires recordingConfig.advanced.complexityMethods in the same session. Use it to bound the measurement window, for example scoped to a method with a methodInvocation trigger, or to exclude a warmup phase. | |
| allocations | No | Optional for 'startRecording'/'stopRecording': include allocation recording. | |
| includeVirtualThreads | No | Optional for 'threadDump': take a virtual thread dump that includes all virtual threads and the thread container hierarchy in addition to the platform threads. Default false (platform threads only). Virtual threads require JDK 21+. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so well: it discloses the recording-session prerequisite, that dumps and snapshots become part of the session snapshot and are served by datasets after recording stops, and that startRecording/stopRecording does not end the session. The action-level details further explain expensive operations, attach-mode limitations, default full GC behavior, and virtual-thread requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main description is three front-loaded sentences with no wasted text: it names the capability, states the prerequisite, and gives the trigger-related cross-reference. The extensive action detail lives in the schema where it belongs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a ten-parameter tool with no annotations and no output schema, the definition is largely complete: it explains the session prerequisite, where captured data goes, and how recording start/stop differs from ending a session. Minor gaps remain around error behavior and explicit return mechanics, but the core operational context is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all ten parameters in detail, including action-specific meanings and defaults. The main description adds a useful cross-reference that action names and parameters match recordingConfig.triggers, but does not independently add syntax or semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: perform a point-in-time action on the connected JVM, and enumerates the action families (thread/monitor dumps, heap marking/dumps, MBean snapshots, subsystem recording). It also distinguishes this from the recording workflow by requiring a session started with attach or prepare_profiling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly states the prerequisite: a recording session started with attach or prepare_profiling. The action parameter schema supplies explicit context for each action, including alternatives such as create_heap_dump for immediate heap analysis and check_status with stopRecording to end the session, though the main description itself does not broadly compare this tool to siblings like query or load_snapshot.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_statusA
Check the status of a profiling session and discover which subsystems were recorded. Can be used to stop recording. When the data is ready provides information about the recorded subsystems (e.g. cpu, jdbc, http_client).
| Name | Required | Description | Default |
|---|---|---|---|
| stopRecording | No | Optionally request the recording to be stopped now. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description must cover behavioral traits. It discloses the ability to stop recording, but does not explain side effects, permissions, or data readiness conditions beyond 'when the data is ready'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no redundant words. The primary purpose is front-loaded in the first sentence, and additional capability in the second.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one optional parameter and no output schema, the description is adequate but lacks details on the output format or error conditions, which would be helpful for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter stopRecording is fully described in the schema (100% coverage). The tool description adds no further nuance, so it meets the baseline without adding value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it checks profiling session status and discovers subsystems, with optional stop recording. This distinguishes from sibling tools like prepare_profiling or create_heap_dump.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description mentions 'Can be used to stop recording' implying a specific use case, but lacks explicit guidance on when to use vs alternatives or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_heap_dumpA
Dump the heap of a locally running JVM or of a JVM inside a Docker container and load it for analysis. If allocation data is recorded for the JVM, the heap dump includes per-object allocation data. A recording session delivers a single heap dump, for a later dump attach again. You must call check_status to check the loading progress and - after this returns 'data_ready' - retrieve data with the query tool. You can use list_jvms to discover JVMs.
| Name | Required | Description | Default |
|---|---|---|---|
| pid | No | The PID of a local JVM process, or the container PID (NSpid) of a JVM inside the specified container. If a container is specified and this is omitted, the topmost JVM in the container is used. | |
| containerNameOrId | No | The name or ID of a Docker container. When specified, profiling attaches to a JVM inside this container. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the load and does disclose key behavior: the operation is asynchronous (poll check_status until 'data_ready'), one dump per recording session, and allocation data is only included when recorded. It omits cost/size/time implications, failure modes (no JVM found, container not running), and whether the dump is persisted or discarded.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five compact sentences, front-loaded with the action and followed by the workflow. Each sentence carries information (state, sequencing, constraint), though the session/attach caveat could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description compensates by explaining that results are not returned directly and must be fetched via check_status plus the query tool. For a zero-required-param dump trigger this is nearly complete; only error/edge-case behavior is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so pid and containerNameOrId (including the NSpid and topmost-JVM fallback semantics) are already fully documented in the schema. The description adds only the hint that list_jvms can be used to discover JVM identifiers, which is marginal. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Dump the heap of a locally running JVM or of a JVM inside a Docker container') plus the post-condition ('load it for analysis'). It also routes to siblings (list_jvms, check_status, query), so an agent can distinguish it from attach/load_snapshot without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit sequencing: call check_status, wait for 'data_ready', then retrieve with query; use list_jvms to discover JVMs. Also notes one heap dump per recording session and that a later dump requires attaching again. It never explicitly excludes the sibling attach/load_snapshot paths, which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_jvmsA
List locally running JVMs or JVMs running in a Docker container with their command line and PID. Use the information to call attach or create_heap_dump.
| Name | Required | Description | Default |
|---|---|---|---|
| containerNameOrId | No | Optionally specify the name or ID of a Docker container. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It explains what is returned and where it looks, but does not disclose side effects, permissions, or whether the operation is safe to repeat. It vaguely describes query behavior without explicit reassurance of non-destructiveness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no wasted words. The first sentence states the core purpose; the second gives usage guidance. It is efficiently front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description covers return contents (command line and PID). It could be improved by specifying the output format (e.g., array of objects). Still, it's complete enough for a simple list tool that feeds into other tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the one optional parameter. The description adds value by explaining the parameter's role in filtering to Docker containers, and implicitly that absence means local JVMs. This goes beyond the schema's terse description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists locally running JVMs or those in Docker containers, providing command line and PID. It uses specific verbs and resources, and distinguishes from sibling tools like attach and create_heap_dump which are actions to take after listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Use the information to call attach or create_heap_dump,' providing clear context for when to use this tool. However, it does not mention when not to use it or other alternatives, which would be helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
load_snapshotA
Load an existing .jps, .hprof, or .jfr file for analysis. You must call check_status to check the loading progress and - after this returns 'data_ready' - retrieve data with the query tool. To compare two performance snapshots, load both in a single call: set filePath to the run to analyze and baselineFilePath to the baseline; the differences are then reported in the hotspots and call trees of that run.
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | The absolute path to the snapshot file | |
| baselineFilePath | No | An optional baseline snapshot for performance comparisons |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the asynchronous loading protocol (must poll before querying) and that comparison differences surface in hotspots and call trees of the analyzed run. It does not cover failure modes (bad path, unsupported file, large-file limits) or whether loading is idempotent, leaving a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, followed by the required follow-up workflow and then the comparison option. Dense but every clause carries actionable information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-param loader with no output schema, the description covers the purpose, the mandatory polling step, the retrieval tool, and comparison semantics. Only error/precondition behavior is absent, which is a modest gap for a tool whose output is consumed via query.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented. The description goes beyond the schema by explaining what baselineFilePath actually does behaviorally – differences are reported in the hotspots and call trees of the primary run, not the baseline. That adds real meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (load), the resource (snapshot file), and enumerates the supported formats (.jps, .hprof, .jfr) with the goal (for analysis). This clearly separates it from siblings like query or check_status, which are downstream steps.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit mandatory workflow: call check_status to poll progress and only retrieve data with query after 'data_ready'. It also describes the alternative comparison mode (set baselineFilePath) and when to use it. Both when-to-use and sequencing are spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prepare_profilingA
Prepare a profiling session by retrieving a JVM parameter to be added to a Java process call to record performance data with stack traces for the following subsystems: cpu, jdbc, jpa, mongo_db, cassandra, http_server, http_client, ws, jndi, jms, kafka_consumer, rmi, grpc, ai, process. The result is a JSON object containing a 'jvmParameter' to be added (quoted) to the Java process at startup. Add it verbatim and do not create or modify any files; the configuration is already set up for you. If the result contains 'additionalJvmParameters' (discovery of injected custom probes), add each element as a separate VM argument as well. Keep this MCP server running and run the Java process. It waits for the server to connect before application startup. During recording, attached_action can perform live actions. The recording is saved automatically when the JVM terminates, after the optional maximum duration, or when check_status is called with 'stopRecording: true'. Then call check_status to access the data - do not load the saved snapshot file yourself. Saving disconnects from the JVM. Use attach with its PID for another recording if it is still running.
| Name | Required | Description | Default |
|---|---|---|---|
| delay | No | An optional recording delay in seconds measured from the successful connection to the JVM. | |
| maximumDuration | No | An optional maximum recording duration in seconds measured from recording startup. If not specified, data will be saved at JVM termination or when check_status is called with 'stopRecording: true'. | |
| recordingConfig | No | What to record in this session. Every key is optional and omitted keys keep their defaults - set only the keys this analysis needs, such as recordMonitors for lock contention analysis, recordAllocations for allocation sites, triggers for automatic captures during the recording, or advanced.methodCallRecordingType instrumentation when invocation counts are needed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses the return shape (JSON with 'jvmParameter' and optional 'additionalJvmParameters'), that parameters must be added verbatim, the no-file-modification constraint, that the server blocks until connection, when the recording is saved (JVM termination, maximumDuration, or stopRecording), and that saving disconnects from the JVM.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the operational steps follow logically. It is a dense single paragraph that runs long, but nearly every sentence carries actionable constraint information (verbatim add, keep server running, wait for connection, save triggers).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-param tool with a very rich nested schema and no annotations or output schema, the description supplies the missing lifecycle detail: connection blocking, save triggers, disconnection semantics, and follow-up via check_status. Nothing an agent needs to invoke it correctly appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the nested schema is extremely detailed, so the schema does the heavy lifting. The description adds only light context (maximumDuration as an optional recording bound, delay implications), so a baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Prepare a profiling session by retrieving a JVM parameter') and enumerates the exact purpose (recording performance data with stack traces). It clearly delineates itself from attach by framing this as the startup-parameter step versus attaching to an already-running PID.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear workflow context: add the returned parameter at startup, keep the MCP server running, then use attach with a PID for further recordings, and call check_status to retrieve data. It names the relevant siblings (attach, check_status, attached_action) and their conditions, though it does not explicitly state when *not* to use this tool versus attach beyond implication.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryA
Query a performance or heap dataset with a jq expression and return the result. The dataset is materialized lazily and cached per session. Each query is independent, there is no current object: builtins take explicit ids bound from earlier results, e.g. .instances[0].id as $id | {value: preview($id), keptAliveBy: pathToRoot($id).paths[0].path | map(.class)}
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | The expansionId of a row from a previous hotspots, callTree, allocation, probe.events, probe.controlObjects or threads.dumps query for the expand dataset, or the id of a biggest object from heap.biggestObjects for the retained dataset | |
| op | No | The filter operation for field: string comparisons (contains, startsWith, endsWith, equals, regexp), object fields (null, nonNull), numeric equals or a from/to range | |
| to | No | Inclusive upper bound for a numeric range filter or the end of the time window in seconds since recording start (telemetry.series, monitor.*) | |
| set | No | Optional for heap.instances, heap.sizes and heap.inspectionResult: a set value from a previous heap result, the operation runs on that object set instead of a class or the whole heap; class, packageFilter and the value filter cannot be combined, filterScript and generation still apply | |
| args | No | Arguments for parametric datasets, see the jprofiler://datasets resource or the datasets list in check_status | |
| from | No | Inclusive lower bound for a numeric range filter or the start of the time window in seconds since recording start (telemetry.series, monitor.*) | |
| line | No | Optional for telemetry.series: restrict the series to one line by name | |
| name | No | Optional for mbean.snapshots: an MBean object name, requires the snapshot argument | |
| sort | No | Optional for probe.events: the global selection and output order - 'duration' (default) keeps and returns the slowest events, 'startTime' the most recent ones | |
| text | No | Optional for probe.events and probe.controlObjects: text filter matched against the event description and all text payloads or the object name and text properties, comma-separated alternatives, matching per matchMode | |
| class | No | Required for heap.instances: the class to list instances of, a name value from heap.classes (after the first query, omitting it continues with the last used class) | |
| field | No | Optional value filter on heap.instances: a field path like customer.name or orders[].id | |
| limit | No | Optional row limit for heap.instances, javascript.origins, monitor.history and threads.list, the defaults and caps are documented per dataset in the check_status catalog | |
| scope | No | Optional for javascript.origins: 'recorded' (default) lists only the origins whose requests reached the profiled application, 'all' every origin the browser extension reported, with a recorded flag per row | |
| state | No | Optional for probe.controlObjects: 'open' (default) lists only objects still open, 'closed' only closed objects, 'all' both, 'collectedWithoutClose' (only jdbc with leak recording) connections that were garbage collected without close | |
| types | No | Optional for probe.events: event type names to include, comma-separated or as a JSON array, e.g. the type values of previous rows (open/close names or probe-specific names like 'Statement execution') | |
| value | No | The comparison value for field and op | |
| column | No | Optional for probe.eventHistogram: the measured value, 'duration' (default), 'throughput' for file/socket probes, or a numeric payload property name from probe.events rows | |
| metric | No | Optional for performance datasets of probe subsystems that record a size or token measurement (file, socket, AI): the measurement the hotspots and call tree are ranked by. 'duration' (default) measures event durations, the alternatives are listed in the probeMetrics section of check_status (e.g. write_throughput). Value properties in the result are then named by the metric unit (bytes, tokens) instead of micros. Cannot be combined with threadStatus | |
| thread | No | Optional for performance datasets: restrict the analysis to selected threads. 'all' (default) merges all threads, 'virtual' merges all virtual threads into one, an integer thread id selects a single thread - use a threadId from threads.list rows (the same ids the monitor datasets use). Cannot be combined with threadGroup | |
| dataset | Yes | The dataset to query. The jprofiler://datasets resource documents all datasets with arguments, row formats and examples, check_status lists them with availability for the current session | |
| groupBy | No | Optional for monitor.stats: the aggregation grouping, default monitors | |
| minCount | No | Optional for performance.outliers: only methods with at least this many invocations, default 10 | |
| snapshot | No | Optional for mbean.snapshots: the index of an MBean snapshot from the catalog | |
| threadId | No | Optional for monitor.history and monitor.graph: restrict to one waiting or owning thread id from monitor.stats | |
| eventType | No | Optional for monitor.history: restrict to one event type | |
| matchMode | No | Optional for probe.events and probe.controlObjects: how text is matched, default contains | |
| maxEvents | No | Optional for probe.events: page size of the global top-N selection, default 1000, max 10000 | |
| maxMicros | No | Optional for probe.events: maximum event duration in microseconds | |
| maxPoints | No | Optional for telemetry.series and monitor.timeline: number of consolidated points per line, default 120, max 500 | |
| minMicros | No | Optional for probe.events: minimum event duration in microseconds | |
| monitorId | No | Optional for monitor.history and monitor.graph: restrict to one monitor id from monitor.stats | |
| subsystem | No | The subsystem to analyze, a value from availableSubsystems in check_status (e.g. cpu, jdbc). If the session recorded a single subsystem it is used automatically | |
| telemetry | No | Required for telemetry.series: the telemetry to fetch, an id from telemetry.list (e.g. heap, cpu, threads, heap/PS Eden Space, gc/G1 Young Generation, custom/<name>, jdbc/<group>) | |
| expression | Yes | The jq expression, passed as a plain JSON string without surrounding quotes. . returns the dataset unchanged. Datasets are objects, the rows are in the hotspots, callTree, classes or biggestObjects array. Filtering, sorting, projection and aggregation belong in the expression. Examples: .hotspots | sort_by(-.percent) | .[0:10], .hotspots | map({method, percent, expansionId}) | .[0:5] (keep expansionId for drill-downs) or .hotspots | group_by(.method | split(".")[0]) | map({pkg: .[0].method, hotspots: length}) (delivered rows only, exact rollups of the complete recording come from the aggregation parameter). Project tree rows one level at a time: .callTree | map({method, micros, children: [(.children // [])[] | .method]}) - children and callers are omitted on leaves and omitted arrays cannot be iterated, and multi-step values in an object construction must be wrapped in parens: {key: (expr | filter)}. Drill down with the builtin expand(expansionId) inline: .hotspots | sort_by(-.percent) | .[0] | {method, callers: expand(.expansionId).callers}. Retained classes of a biggest object with the builtin retained(id): .biggestObjects | sort_by(-.retainedSize) | .[0] | {class, retained: retained(.id).classes}. Combined size analysis of an object set with the builtin sizes([ids]): .biggestObjects | {top: .[0:3] | map(.class), sizes: sizes([.[0:3][].id])}. References of a heap object with the builtins incoming(id)/outgoing(id): .instances[0] | {name, heldBy: incoming(.id).referrers | map(.class)}. GC root paths with pathToRoot(id) and value previews with preview(id): .instances[0] | {name, value: preview(.id), keptAliveBy: pathToRoot(.id).paths[0].path | map(.class)}. Capture the input before binding variables: . as $rows | ((map(.micros) | add) as $t | ...), wrap generators in constructions with [...]. Keep results small: project fields and slice with .[0:N]. | |
| filterPath | No | Optional with filterScript: a field path like customer.name or orders[].id, the script is evaluated on the objects the path navigates to instead of the instances of the class | |
| generation | No | Optional on heap.classes, heap.biggestObjects and heap.instances: restrict to objects allocated after (new) or before (old) the last markHeap action of the recorded session | |
| ignoreCase | No | Ignore case for string comparisons, default false | |
| inspection | No | Required for heap.inspectionResult: the inspection to run, an id from heap.inspections | |
| limitBytes | No | Optional byte budget for the result, default 24000. Larger results are truncated and marked as such | |
| maxBuckets | No | Optional for probe.eventHistogram: maximum bucket count, default 100, max 1000 - the histogram adapts its bucket size to stay below | |
| maxObjects | No | Optional for probe.controlObjects: maximum number of objects per state, default 200, max 2000 | |
| aggregation | No | Optional for performance and allocation datasets: the rollup level of the tree nodes. 'method' (default) aggregates per method, 'class' per class, 'package' per package, 'component' by Spring, JEE and JPA component class (controllers, services, repositories, empty for apps without such components). Class, package and component rollups are exact, they include everything below the row cutoffs of the method view, and they shrink huge deep trees to an overview. Drill back in with 'method' and a packageFilter | |
| groupScript | No | Required for the custom_grouping inspection: a Java script evaluated per object that returns the group key string, null skips the object. Read the jprofiler://api/heap-scripts resource for the script API before writing a script | |
| threadGroup | No | Optional for performance datasets: restrict the analysis to one thread group, a group value from threads.list rows (platform threads only, virtual threads have no groups). Cannot be combined with thread | |
| filterScript | No | Optional for heap.instances and heap.sizes: a Java script evaluated per object, keeping objects where it returns true - for predicates the value filter cannot express. Read the jprofiler://api/heap-scripts resource for the script API before writing a script | |
| minMaxMicros | No | Optional for performance.outliers: only methods whose slowest invocation took at least this many microseconds, default 10000 | |
| threadStatus | No | Optional for performance datasets: the thread state whose time is counted. 'running' (default for cpu) counts only time while the thread is scheduled by the OS, waiting on sockets, locks or other threads is not included. 'all' (default for probes) counts wall clock time in all states. 'net_io' counts time waiting on network or file I/O, the state of slow database or REST calls. 'waiting' and 'blocked' count time waiting on other threads or blocked on a monitor, for inter-thread handoff and lock contention analysis. Only 'all' and 'running' carry invocation counts for cpu. Not available for JFR probe subsystems | |
| packageFilter | No | Optional package filter to focus on classes of interest (heap datasets and performance subsystems), comma-separated or as a JSON array | |
| payloadFilter | No | Optional filter on payload descriptions (SQL statements, URLs) for probe subsystems, applied to hotspots and call trees before the row cutoffs. Each pattern keeps descriptions that contain it, case-sensitive, * and ? are literal characters (a lone * means no filter), comma-separated or as a JSON array, a pattern with a comma needs the array form | |
| controlObjectId | No | Optional for probe.events: restrict to the events of one control object, a controlObjectId from probe.controlObjects or probe.events rows | |
| minDurationMicros | No | Optional for monitor.history: minimum event duration in microseconds |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden. It usefully discloses that datasets are materialized lazily and cached per session, and that queries are independent rather than operating on a mutable current object. It does not explicitly state that the operation is read-only, whether it can cause side effects, how errors are surfaced, or any permission or rate-limit considerations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, followed by concise behavioral context and a compact jq example. The example earns its place by showing the explicit-id binding pattern required for builtins. The only inefficiency is the overly narrow 'performance or heap dataset' phrasing in the opening sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 52-parameter tool with no output schema, the schema itself provides very rich parameter documentation and points to external dataset resources. The description supplies the critical jq-expression model and builtin usage pattern that an agent needs in order to construct queries correctly. It is still somewhat thin on result behavior and dataset availability, but the structured schema compensates for much of that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3 even without additional parameter explanations. The description reinforces the expression parameter with builtin examples and the 'no current object' model, but most dataset and argument semantics are already covered in the schema. It adds limited meaning beyond the structured parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a clear verb-resource pairing: query a dataset using a jq expression and return the result. It distinguishes the tool from lifecycle-oriented siblings such as prepare_profiling and check_status. However, it says 'performance or heap dataset' even though the schema supports telemetry, monitor, probe, threads, GC, and other datasets, so the stated scope is narrower than the actual tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains that each query is independent and that there is no 'current object', which is useful operating guidance. It also demonstrates how to bind ids from earlier results for builtins. It does not explicitly say when to use this tool versus check_status, load_snapshot, or ad-hoc query alternatives, nor does it state any exclusions beyond the no-current-object model.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v16.3.0- Added
attach - Added
attached_action - Added
check_status - Added
load_snapshot - Changed
prepare_profiling3 fields changed- changed
Input schema / properties / delay / descriptionPrevious value: -"An optional recording delay in seconds measured from the jvm start."New value: +"An optional recording delay in seconds measured from the successful connection to the JVM." - changed
Input schema / properties / maximumDuration / descriptionPrevious value: -"An optional maximum recording duration in seconds. If not specified, data will be saved at JVM termination or when check_status is called with 'stopRecording: true'."New value: +"An optional maximum recording duration in seconds measured from recording startup. If not specified, data will be saved at JVM termination or when check_status is called with 'stopRecording: true'." - added
Input schema / properties / recordingConfigAdded value: +{ + "description": "What to record in this session. Every key is optional and omitted keys keep their defaults - set only the keys this analysis needs, such as recordMonitors for lock contention analysis, recordAllocations for allocation sites, triggers for automatic captures during the recording, or advanced.methodCallRecordingType instrumentation when invocation counts are needed.", + "properties": { + "advanced": { + "description": "Settings that are off by default. Only change them for a concrete reason, never speculatively - more data is not better, and a wrong value can silently lose data. Valid reasons are e.g. check_status reporting possibleInlineAsyncTypes, an application that hands work to thread pools, coroutines or event dispatch threads, an analysis that needs invocation counts, or a previous recording showing that the default filters hide relevant code. The keys without a description correspond to session configuration attributes (such as splittingCap for the call tree split cap mentioned in capped_split warnings) and are documented in the resource jprofiler://config/session.", + "properties": { + "allocTreeRecordingType": { + "enum": [ + "live", + "liveAndGcNoClassResolution", + "liveAndGc" + ], + "type": "string" + }, + "allocationSamplingInterval": { + "type": "integer" + }, + "annotateCustomPayloads": { + "type": "boolean" + }, + "asyncBufferPercentage": { + "type": "integer" + }, + "asyncNativeSampling": { + "type": "boolean" + }, + "asyncThreadResolution": { + "type": "boolean" + }, + "complexityMethods": { + "description": "Measure how the invocation time of the given methods scales with an input size computed per invocation by a script: the complexity.methods dataset then holds the recorded (input size, time) points and curve fits, answering questions like 'is this method O(n^2) in the payload size'. This is the second step after performance.hotspots has identified a suspicious method whose inputs vary in size - re-record with this setting pointing at that method. Example: [{\"method\": \"com.example.Service.process(java.util.List)\", \"script\": \"return param0.size();\"}]. Works with any methodCallRecordingType. Recording starts with the session and stops before the snapshot is saved; bound the measurement window with startRecording/stopRecording actions (\"complexity\": true) in triggers or attached_action. The script API is documented in the jprofiler://api/method-scripts resource.", + "items": { + "properties": { + "method": { + "description": "The method whose scaling is measured, in the format com.foo.Bar.method(long, java.lang.String), with () for no parameters. The method does not have to match the package filter.", + "type": "string" + }, + "script": { + "description": "Java code returning the input size of the invocation as a long, for example 'return param0.size();' for a collection parameter. Same environment as 'splitMethods' scripts (scriptContext, clazz, currentObject, param0, param1, ...).", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "descriptorCap": { + "type": "integer" + }, + "exactSamplingMonitorCallStacks": { + "type": "boolean" + }, + "exceptionalCap": { + "type": "integer" + }, + "exceptionalMethods": { + "description": "Methods whose slowest invocations are kept as separate, individually expandable nodes in performance.callTree (marked with exceptionalRun) instead of being merged into the average. Use after performance.outliers shows a method whose maxMicros deviates strongly from its avgMicros. Format: com.foo.Bar.method(long, java.lang.String), exactly as printed in the method field of performance.outliers; the argument list is required, use () for no parameters. Requires methodCallRecordingType 'instrumentation'. Not recorded for virtual threads.", + "items": { + "type": "string" + }, + "type": "array" + }, + "exceptionalTimeType": { + "enum": [ + "all", + "running", + "waiting", + "blocking", + "netio" + ], + "type": "string" + }, + "filter": { + "description": "Comma-separated list of project packages to profile (e.g. 'com.example.app,org.service'). A wrong package silently excludes relevant code from the recording.", + "type": "string" + }, + "hotspotPayloadCap": { + "type": "integer" + }, + "inlineAsyncTypes": { + "description": "Record async request tracking for the given types, one or more of executor, kotlin_coroutines, awt, swt, virtual_thread, platform_thread. Async executions are then inlined under their call sites in the call tree and hotspot datasets. Off by default because tracking adds overhead - enable when analyzing applications that hand work to thread pools, coroutines or event dispatch threads, or when check_status reports possibleInlineAsyncTypes after a previous recording.", + "items": { + "enum": [ + "executor", + "kotlin_coroutines", + "awt", + "swt", + "virtual_thread", + "platform_thread" + ], + "type": "string" + }, + "type": "array" + }, + "instrumentNativeMethods": { + "type": "boolean" + }, + "internalExcludes": { + "type": "boolean" + }, + "libraryDebugParameters": { + "type": "string" + }, + "lineNumbers": { + "type": "boolean" + }, + "methodCallRecordingType": { + "description": "How CPU method calls are recorded. 'sampling' (default) takes periodic call stack samples: very low overhead that does not depend on the package filter, accurate times, but no invocation counts, and methods shorter than the sampling period or called rarely can be missed. 'instrumentation' modifies the bytecode of profiled classes to track method entry and exit: the only mode with exact invocation counts (the count field in the performance datasets) and reliable timing of small, frequently called methods, and it makes allocation stack traces exact; the cost is high overhead and distorted CPU times in CPU-bound code, so it requires a package filter (filter in this object) that restricts instrumentation to the relevant packages. 'async_sampling' samples asynchronously without safepoint bias: the most accurate CPU times for highly multithreaded CPU-bound code, but only on macOS and Linux with a HotSpot JVM (otherwise the agent falls back to sampling), no wall clock times (threadStatus all has no effect) and no invocation counts. Use instrumentation when the analysis needs call counts, otherwise keep the default.", + "enum": [ + "instrumentation", + "sampling", + "async_sampling" + ], + "type": "string" + }, + "payloadCap": { + "type": "integer" + }, + "probeConfig": { + "additionalProperties": { + "type": "object" + }, + "description": "Probe-specific settings: a map of subsystem name to a map of attribute name to value, applied to the probe configuration of the recording. Examples: {\"jdbc\": {\"preparedStatementParameters\": true}} records prepared statement parameters in the jdbc hotspots, {\"http_server\": {\"split\": false}} disables URL call tree splitting of the HTTP server probe, {\"http_server\": {\"splitType\": \"script\", \"requestResolvers\": [\"...\"]}} splits the call tree by script-computed request names. Custom probes of the profiled application use the key \"custom:<fully qualified probe class name>\" with the attributes \"events\" (record individual events for the probe.events dataset) and \"injected\" (prepare_profiling and attach pass the probe discovery VM parameter), e.g. {\"custom:com.example.MyProbe\": {\"events\": true, \"injected\": true}} - unknown attributes of custom probes are errors. Script probes defined in 'scriptProbes' use the key \"script:<name>\" with the attribute \"events\". Attribute names and values are those of the JProfiler session configuration, the reference with all attributes of all probes is the resource jprofiler://config/probes. Unknown attributes are silently ignored, the applied settings are reported as probeSettings in check_status.", + "type": "object" + }, + "probeFileMBCap": { + "type": "integer" + }, + "recordArrayAlloc": { + "type": "boolean" + }, + "retainStackForHotspotConsolidation": { + "type": "boolean" + }, + "sampleUnmountedVirtualThreads": { + "type": "boolean" + }, + "samplingFrequency": { + "type": "integer" + }, + "samplingNoFilters": { + "type": "boolean" + }, + "samplingPayloadCallStacks": { + "type": "boolean" + }, + "scriptClassPath": { + "description": "Additional compile classpath for all scripts in this object ('splitMethods', 'complexityMethods' and script properties in 'probeConfig'): absolute paths to JAR files, to directories containing JAR files, or wildcard patterns like /path/to/lib/*.jar. Only needed when a script references classes beyond the JDK and the JProfiler classes, typically application classes. Used for compilation on this machine only - at runtime the classes must be present in the profiled JVM, which is normally the case for application classes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "scriptProbes": { + "description": "Define script probes: lightweight probes declared as scripts, compiled by this server and pushed to the profiled JVM - no code, build or deployment in the profiled application, works on attach. Each probe intercepts the given methods, the script computes the payload string per invocation. Defining a script probe records it: it appears as subsystem 'script:<name>' with payload hot spots in performance.hotspots/callTree; individual events are recorded with 'probeConfig': {\"script:<name>\": {\"events\": true}}. Example: [{\"name\": \"Order processing\", \"methods\": [{\"method\": \"com.example.Shop.processOrder(int)\", \"script\": \"return \\\"order \\\" + param0;\"}]}]. Script probes cannot split the call tree, access return values or create control objects, custom event types or telemetries - for those write a custom probe, see jprofiler://probes/custom. The script API is documented in the jprofiler://api/method-scripts resource.", + "items": { + "properties": { + "annotatePayloads": { + "description": "Optional: annotate the CPU call tree with the payload strings. Default false.", + "type": "boolean" + }, + "description": { + "description": "Optional explanation of the probe's purpose.", + "type": "string" + }, + "methods": { + "items": { + "properties": { + "method": { + "description": "The intercepted method, in the format com.foo.Bar.method(long, java.lang.String), with () for no parameters. The method does not have to match the package filter.", + "type": "string" + }, + "script": { + "description": "Java code returning the payload string for the invocation, or null for no payload. Same environment as 'splitMethods' scripts (scriptContext, clazz, currentObject, param0, param1, ...).", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "name": { + "description": "The probe name. The probe is recorded as subsystem 'script:<name>'.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "splitMethods": { + "description": "Split the call tree below the given methods by a script-computed key: each distinct returned string gets its own subtree (type method_split in performance.callTree), for example to analyze request handling per message type. Example: [{\"method\": \"com.example.Handler.onMessage(javax.jms.Message)\", \"script\": \"return param0.getJMSType();\"}]. Works with any methodCallRecordingType. The script runs on every invocation of the method, so do not split extremely hot methods. The number of distinct keys per split location is capped ('splittingCap', see jprofiler://config/session), further keys are merged into a capped_split node. The script API is documented in the jprofiler://api/method-scripts resource.", + "items": { + "properties": { + "method": { + "description": "The method below which the call tree is split, in the format com.foo.Bar.method(long, java.lang.String), with () for no parameters. The method does not have to match the package filter.", + "type": "string" + }, + "script": { + "description": "Java code returning the split key string, or null to leave the invocation unsplit. Available parameters: scriptContext (com.jprofiler.api.agent.ScriptContext, stores per-script state with putObject/getObject and putLong/getLong), clazz (the Class of the declaring class), currentObject (the instance the method is invoked on, null for static methods), param0, param1, ... (the declared method parameters in order). Parameters are statically typed when their class is on the compile classpath and Object otherwise - add application JARs with 'scriptClassPath' to get static typing.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "splittingCap": { + "type": "integer" + }, + "utilConcurrentHandling": { + "type": "boolean" + } + }, + "type": "object" + }, + "blockingThresholdMicros": { + "description": "Optional minimum duration in microseconds for blocked monitor events when 'recordMonitors' is true, shorter events are discarded. Default 1000", + "type": "integer" + }, + "recordAllocations": { + "description": "Record allocation data with call stacks instead of performance data. The two are exclusive because recording both distorts the results. Valuable on its own via the allocation datasets, and a heap dump taken in such a session additionally carries per-object allocation sites (heap.allocation* datasets). Allocation data is sampled, not exact. Default false", + "type": "boolean" + }, + "recordMonitors": { + "description": "Also record monitor and lock events: threads blocked on monitors, waiting in Object.wait or parked, with stack traces. Composes with performance and allocation recording and enables the monitor.* datasets for contention, lock-order inversion and deadlock analysis. Default false", + "type": "boolean" + }, + "subsystems": { + "description": "The subsystems to record in this session. Subsystems not listed are not recorded. Built-in values: cpu, jdbc, jpa, mongo_db, cassandra, http_server, http_client, ws, jndi, jms, kafka_consumer, rmi, grpc, ai, socket, file, process, gc. Custom probes of the profiled application (embedded or injected probe classes) are recorded as 'custom:<fully qualified probe class name>', e.g. custom:com.example.MyProbe. Script probes are not listed here, they are defined in 'advanced.scriptProbes' and recorded as 'script:<name>'. Default: cpu, jdbc, jpa, mongo_db, cassandra, http_server, http_client, ws, jndi, jms, kafka_consumer, rmi, grpc, ai, process, gc.", + "items": { + "type": "string" + }, + "type": "array" + }, + "triggers": { + "description": "Actions executed automatically when an event occurs during the recording. Use them for conditions that interactive tool calls cannot catch: recordings from JVM start, long-running sessions and transient states like heap spikes, or work scoped to a method with 'methodInvocation'. MBean snapshots and heap dumps captured by triggers become part of the session snapshot and are queried like manually captured ones. Example: {\"on\": \"timer\", \"intervalSeconds\": 60, \"actions\": [{\"type\": \"mbeanSnapshot\"}]}", + "items": { + "properties": { + "actions": { + "description": "The actions to run when the event fires, in order.", + "items": { + "properties": { + "allocations": { + "description": "Optional for 'startRecording'/'stopRecording': include allocation recording.", + "type": "boolean" + }, + "complexity": { + "description": "Optional for 'startRecording'/'stopRecording': include complexity recording - requires recordingConfig.advanced.complexityMethods in the same session. Use it to bound the measurement window, for example scoped to a method with a methodInvocation trigger, or to exclude a warmup phase.", + "type": "boolean" + }, + "cpu": { + "description": "Optional for 'startRecording'/'stopRecording': include CPU recording.", + "type": "boolean" + }, + "filter": { + "description": "Optional for 'mbeanSnapshot': regular expression matched against the domain and each property value of the MBean object names: \"java.lang|com.mycompany.*\" captures all MBeans in those domains, \"Memory\" the java.lang:type=Memory MBean. Without a filter all MBeans are captured, the right choice for exploration.", + "type": "string" + }, + "fullGc": { + "description": "Optional for 'heapDump': run a full GC before the dump so only live objects are captured. Default true.", + "type": "boolean" + }, + "includeVirtualThreads": { + "description": "Optional for 'threadDump': take a virtual thread dump that includes all virtual threads and the thread container hierarchy in addition to the platform threads. Default false (platform threads only). Virtual threads require JDK 21+.", + "type": "boolean" + }, + "label": { + "description": "Optional for 'mbeanSnapshot' and 'threadDump': label shown in the mbean.snapshots resp. threads.dumps dataset. In triggers the default is a name derived from the event.", + "type": "string" + }, + "monitors": { + "description": "Optional for 'startRecording'/'stopRecording': include monitor recording.", + "type": "boolean" + }, + "probes": { + "description": "Optional for 'startRecording'/'stopRecording': probe names to start or stop, e.g. [\"jdbc\"], \"custom:<fully qualified probe class name>\" for custom probes of the profiled application, or \"script:<name>\" for a script probe defined in recordingConfig.advanced.scriptProbes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "seconds": { + "description": "Required for 'sleep': the wait time in seconds.", + "type": "integer" + }, + "type": { + "description": "'mbeanSnapshot': capture the current JMX MBean attribute values into the session snapshot (mbean.snapshots dataset). 'heapDump': take a heap dump that becomes part of the session snapshot (heap.* datasets) - expensive, use it with rare events like 'stop' or a high 'heapThreshold', not with 'timer' or 'start'. 'threadDump': take a thread dump that becomes part of the session snapshot (threads.dumps dataset) - cheap, suitable for 'timer' and threshold triggers. 'monitorDump': capture the currently held and waited-on monitors with the involved threads and stack traces (monitor.current dataset) - only the latest dump is kept, repeated fires overwrite it, so prefer events like 'stop' or thresholds over 'timer'. 'markHeap': mark all current heap objects as old, so a heap dump taken later distinguishes objects allocated afterwards (generation 'new' in the heap.* datasets). 'startRecording'/'stopRecording': start or stop recording of subsystems, at least one of 'cpu', 'allocations', 'monitors', 'probes', 'complexity' is required. 'waitForFinish': only for 'methodInvocation', splits the actions into on-entry and on-exit. 'sleep': wait, delays the following actions.", + "enum": [ + "mbeanSnapshot", + "heapDump", + "threadDump", + "monitorDump", + "markHeap", + "startRecording", + "stopRecording", + "waitForFinish", + "sleep" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "type": "array" + }, + "count": { + "description": "Optional for 'on': 'timer': fire at most this many times. Default unlimited.", + "type": "integer" + }, + "intervalSeconds": { + "description": "Required for 'on': 'timer': the period in seconds.", + "type": "integer" + }, + "method": { + "description": "Required for 'on': 'methodInvocation': the method in the format com.foo.Bar.method(long, java.lang.String) as printed by the performance.outliers dataset; the argument list is required, use () for no parameters. Method triggers instrument only the named method and work with any method call recording type, including the default sampling. Recursive calls fire only once per outermost invocation.", + "type": "string" + }, + "offsetSeconds": { + "description": "Optional for 'on': 'timer': delay of the first fire in seconds. Default 0. With a 0 offset the first fire can land before the application has registered its MBeans or reached its working state, a small offset like 1 avoids a mostly empty first capture.", + "type": "integer" + }, + "on": { + "description": "When the actions run: 'start' when the recording starts (after the optional delay for prepare_profiling, right after attaching for attach), 'stop' when the recording stops (JVM exit, maximumDuration or check_status with stopRecording for prepare_profiling, check_status with stopRecording for attach), 'timer' periodically, 'heapThreshold' when the used heap stays above 'percent' of the maximum heap, 'cpuThreshold' when the CPU usage stays above 'percent'. Threshold triggers fire at most about once a minute while the condition holds. 'methodInvocation' fires when the method given in 'method' is entered; with 'waitForFinish' in the actions, the actions before it run on method entry and the actions after it on method exit. A subsystem started by a method trigger is not started automatically at recording start, so the trigger defines the recording scope.", + "enum": [ + "start", + "stop", + "timer", + "heapThreshold", + "cpuThreshold", + "methodInvocation" + ], + "type": "string" + }, + "percent": { + "description": "Required for 'heapThreshold' and 'cpuThreshold': the threshold in percent. Choose a high value such as 80, the actions fire every time the condition holds.", + "type": "integer" + } + }, + "required": [ + "on", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "waitingThresholdMicros": { + "description": "Optional minimum duration in microseconds for waiting and parked monitor events when 'recordMonitors' is true, shorter events are discarded. Default 100000", + "type": "integer" + } + }, + "type": "object" +}
- Added
query
6 tool updates
v16.2.0- Removed
attach - Removed
check_status - Removed
expand_performance_hotspot - Removed
get_heap_data - Removed
get_performance_hotspots - Removed
load_snapshot
9 tool updates
v16.1.9- Changed
attach2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
check_status2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
create_heap_dump2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
expand_performance_hotspot2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
get_heap_data2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
get_performance_hotspots2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
list_jvms2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
load_snapshot2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
- Changed
prepare_profiling2 fields changed- removed
Input schema / $defsRemoved value: -{} - removed
Input schema / definitionsRemoved value: -{}
9 tool updates
v0.1.0- First observed
attach - First observed
check_status - First observed
create_heap_dump - First observed
expand_performance_hotspot - First observed
get_heap_data - First observed
get_performance_hotspots - First observed
list_jvms - First observed
load_snapshot - First observed
prepare_profiling
TDQS
Scored across 8 tools
Most tools target distinct stages of the profiling workflow: discovery, session start, attachment, status, heap dump, snapshot loading, and querying. There is some overlap between check_status and attached_action around controlling recording, and between create_heap_dump and attached_action's heap-dump actions, but the descriptions make the intended boundaries reasonably clear.
The set is mostly snake_case, with verb_noun names such as prepare_profiling, load_snapshot, check_status, create_heap_dump, and list_jvms. However, query and attach are bare verbs, and attached_action is an adjective_noun form rather than an imperative verb, so the convention is readable but not fully consistent.
Eight tools is well scoped for a JVM profiling server: each covers a distinct part of the lifecycle from discovering JVMs to recording, loading snapshots, and querying results. There are no obviously redundant tools or missing slots that would suggest the count is off.
The surface covers the full expected workflow: list_jvms for discovery, prepare_profiling and attach for starting sessions, check_status and attached_action for control, create_heap_dump for heap capture, load_snapshot for existing files, and query for analysis. No major lifecycle operation appears to be missing.
Maintenance
Related MCP Connectors
Ship better Java with your coding agent.
The Polar Signals MCP server enables AI assistants to connect directly with performance profiling data, allowing users to analyze application performance through natural language queries. Key capabilities include querying CPU performance and memory usage, exploring profiling metadata like profile types and labels, and providing AI-driven code optimization suggestions directly within development environments like Claude Code or Cursor.
Scout Monitoring data for AI assistants: slow endpoints, traces, N+1 queries, and errors.
AI-powered codebase analysis — call graphs, security, dead code, complexity. 150+ tools.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAutomates Java Maven testing workflows with decision table-based test generation, security vulnerability scanning, JaCoCo coverage analysis, and Git automation.-
- AlicenseNot gradedqualityDmaintenanceA Java implementation of the GitHub MCP (Model Context Protocol) Server using Spring AI. This server provides MCP-compatible tools for interacting with the GitHub API.MIT
- AlicenseAqualityCmaintenanceMCP server for profiling Java applications via JDK utilities (jcmd, jfr, jps). Enables AI assistants to diagnose performance, analyze threads, and inspect JFR recordings without manual CLI usage.2640 npm10MIT
- AlicenseAqualityCmaintenanceLive .NET runtime diagnostics for AI assistants. Ask Claude to diagnose memory leaks, GC pressure, LOH fragmentation, and thread starvation in any running .NET process — no code changes required.72MIT