Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

io.github.gaozhao1989/pyjab-mcp

PYPI · PYJAB-MCP

Drive Java desktop apps from an AI agent, through the JVM's own accessibility tree

Available components

+3 this week 86 Trust /100

Last scanned (38 minutes ago)

Scores higher than 88% of PyPI servers

Category Browser Automation

Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security100
  • No malware found by supply-chain analysis.Pass
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs setuptools.build_meta at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
  • 1 of 29 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency97
  • Source repository is publicly reachable at the declared URL. View diagnostics → Pass
  • Cryptographically verified build provenance (signed, bound to gaozhao1989/pyjab-mcp). View diagnostics → Pass
  • Clear OSI-approved license (MIT).Pass
  • Actively maintained (last published 23 days ago).Pass
  • Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability62
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 5768 tokens (~360/item across 16 items; 16 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management70
  • Stability observed for 21 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage71
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 0% of tool parameters carry a description.Fail
  • Structured output schemas are declared (94% of tools); any adoption earns full credit.Pass
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
  • An AI judge read all 17 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a current MCP spec version (2026-07-28).Pass
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 5 Nov 26 +15
    • Malware scan: unverified → pass ▲ security
  • 4 Nov 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.

  • 2 Nov 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 57 to 60. That category is still filling its 30-day observation window: 17 days of observed history at the previous scan, 18 at this one. The score rises as the window fills, whether or not the server changes.

  • 31 Oct 26 −14
    • Malware scan: pass → unverified ▼ security
  • 29 Oct 26 +16
    • Malware scan: unverified → pass ▲ security
  • 27 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 37 to 40. That category is still filling its 30-day observation window: 11 days of observed history at the previous scan, 12 at this one. The score rises as the window fills, whether or not the server changes.

  • 26 Oct 26 −15
    • Malware scan: pass → unverified ▼ security
  • 25 Oct 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 5 Nov 2026 · Analysed pypi/pyjab-mcp@0.3.1

Provenance Verified

A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.

Result Verified
Ecosystem pypi
Reason Verified
Discovered via Registry attestation endpoint
Source repo gaozhao1989/pyjab-mcp
Certificate issuer https://token.actions.githubusercontent.com
Certificate SAN https://github.com/gaozhao1989/pyjab-mcp/.github/workflows/release.yml@refs/tags/v0.3.1
Rekor log index 3229795201
Predicate type PyPI publish attestation https://docs.pypi.org/attestations/publish/v1
Subject digest sha256:2e681342d8286a60928640764427f95124a4a5f11a4dc1b823b91eb4c495a96b

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted setuptools.build_meta

Background: Why install scripts are a supply-chain risk →

Dependencies 29 packages
Packages resolved 29
No linked repository 1
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 16 exposed · ~5,665 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
java_attach_window ~296

Bind to one Java window and return a session id for later calls. Use this after java_list_windows, once you know which window to drive. Give either an exact ``hwnd`` or a ``title``; a title may be an fnmatch pattern (``"*Report*"``) exactly as pyjab matches it. Pass ``hwnd`` when several windows share a title pattern. Binding is also what arms Java Access Bridge for this server: pyjab loads the DLL, hooks the events and registers the JAB prototypes on the thread doing the binding, so the first attach is slower than the later ones. This never modifies, restarts or injects into the application, and it does not own the process: the application keeps running whatever happens to this session. Args: title: Window title, matched with fnmatch. Ignored when ``hwnd`` is given. hwnd: Window handle from java_list_windows. Takes precedence over ``title``. Returns: A session id, and the window it is bound to. Pass the session id to java_snapshot. Errors: ``is_error`` when the window cannot be bound, naming what was tried. A window that is not a Java window, or a title that never appears, is the usual reason; java_list_windows shows what JAB can see.

NameTypeReqDescription
hwnd–––
titlestring––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_click ~334

Click an element: a button, a menu item, a check box, a link, a tree node. By default this uses the element's **accessibility action**, which is what the application itself exposes: no mouse moves, no window comes to the front, and it works where there is no interactive desktop. Use `simulate=True` when the accessibility action is ignored — it drives real mouse input, which requires the window to come to the front and cannot work from a service session, and it needs real geometry (cells in some tables report `bounds = -1`, and there is no point to click). The element is checked before it is clicked: role, name, position among siblings and bounds are compared against what the snapshot recorded, and if anything differs **nothing is clicked** — the difference is reported instead. That is deliberate: a click that lands on whatever moved into the position is worse than a message. Args: session_id: From java_attach_window. handle: The element to click. click: "left", "double" or "right". simulate: Drive real mouse input instead of the accessibility action. Returns: What was clicked and how, so the next call knows what state the window is in. Errors: ``is_error`` for an unknown handle, for an element that changed since the snapshot, and for a ``click`` value that is not one of the three.

NameTypeReqDescription
clickstring––
handlestringyes–
session_idstringyes–
simulateboolean––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_diagnostics ~262

Report whether this machine can drive a Java application right now. Use this first when anything fails, and after installing a JVM or enabling Java Access Bridge. It reports the platform, the interpreter, the installed pyjab and which of its public APIs are present, whether Java Access Bridge is enabled, where the bridge DLL is, and the state of the bridge thread. It is read-only and never writes to the environment: it does not enable Java Access Bridge, because a diagnostics tool that changes what it is reporting on is worse than none. Args: load_bridge: When true, also start the bridge thread first and report whether it came up. This is the end-to-end check; it is off by default so that a mere report cannot load a DLL. Returns: A multi-line report. A line that could not be measured says ``UNAVAILABLE (reason)`` and is never reported as zero or as "missing" -- "nothing is there" and "I could not read" are different answers. Errors: None for the environment itself: an unusable environment is what this tool reports, so it does not fail because of one.

NameTypeReqDescription
load_bridgeboolean––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_fill_form ~273

Fill several fields in one call: a list of ``{"handle": ..., "value": ...}``. A form is usually several fields, and setting them one at a time costs a round trip each. This is the same verification and the same typing, applied in order, with one reply that says what happened to every field. It **does not stop at the first failure**. A form that is half filled with no report is worse than one that is half filled with one: every field is attempted, and each line says whether it worked and why not. Args: session_id: From java_attach_window. fields: ``[{"handle": "e:1a2b", "value": "admin"}, ...]``, applied in order. simulate: Type real keystrokes instead of using the accessibility action. Returns: One line per field — set, or the reason it was not — and a count. Errors: ``is_error`` only for an unknown session, an empty list, or a malformed entry. A field that fails is reported in the reply, because that is a result rather than a failed call.

NameTypeReqDescription
fieldsarrayyes–
session_idstringyes–
simulateboolean––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_find ~445

Search an attached window and get a handle for each match. Use this when a snapshot is too large to read, or when you know what the control is called and do not want to walk the tree to find it. A snapshot shows you the shape of the window; this asks a question about it. Give **exactly one** selector. `name` and `description` are exact matches -- for a substring use `xpath` with `contains()`, which is pyjab's locator syntax: `//push button[@name=contains('Save')]`. `states` takes a comma-joined list such as `"enabled,showing"`. Every match gets a handle, and a handle is checked before it is used: the locator recorded here is resolved again later and compared against the role, name, position and bounds seen now. If a match cannot be given a locator that finds it again, it is listed **without** a handle rather than with one that might resolve to something else. Args: session_id: From java_attach_window. name: Exact accessible name. role: Role, as pyjab spells it: "push button", "text", "check box", "table". description: Exact accessible description, for controls with no name. states: Comma-joined states, e.g. "enabled,showing". xpath: A pyjab locator, for substrings, unions and paths. max_results: Stop after this many matches. Returns: One line per match with its handle and locator, or a measurement that nothing matched -- with the selector that found nothing in it, so the next attempt can be narrower rather than identical. Errors: ``is_error`` for an unknown session id, for no selector or more than one, or when the window can no longer be read.

NameTypeReqDescription
descriptionstring––
max_resultsinteger––
namestring––
rolestring––
session_idstringyes–
statesstring––
xpathstring––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_focus_window ~508

Bring an attached window to the front, and report whether it actually came forward. Use it before `java_send_keys`, whose chord goes to whichever window has the keyboard focus: **attaching a window does not give it focus** (measured in pyjab#180), so a shortcut can otherwise land somewhere else entirely. **The reply is the point, not the action.** "I asked for focus" and "the window is now in front" are two different facts, and this tool answers with the second one. It does so by reading back the state pyjab left behind, because Windows' `SetForegroundWindow` has no useful return of its own. So there are three answers, not two: * the window **is** the foreground window now; * it **is not** — a normal answer rather than a failure, because Windows refuses foreground activation from a non-interactive session (a service, a scheduled task) and no amount of retrying changes that. An error would be wrong here: nothing failed, and the caller has a fact it can act on; * pyjab answered something that is neither `True` nor `False`, so this server **cannot say** — reported as such rather than filed under "did not come forward", because "I could not tell" is not a measurement. It is not free: **when the window is not already in front**, pyjab sends a space keystroke first, which is what Windows' foreground-activation rules require of a process that wants the foreground — and that keystroke goes to whatever currently has the focus. A caller that cannot tolerate a stray keystroke elsewhere should not call this. This needs pyjab 1.11.0, which released `JABDriver.focus()`. The call is probed rather than assumed, like every pyjab capability here: an install below the pin is told which release has it instead of raising an `AttributeError`. Args: session_id: From java_attach_window. Returns: Whether the window is now the foreground window, said plainly, with the next step. Errors: ``is_error`` only for an unknown session, or a pyjab below the pin — which…

NameTypeReqDescription
session_idstringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_get_element ~214

Everything known about one element, and whether it is still the same element. Use this after java_snapshot or java_find to look at one control in detail, or to confirm that a handle still points at what it did. The handle is resolved again and compared against what was recorded when it was handed out; if anything differs -- role, name, position among siblings, bounds -- this reports the difference instead of presenting the element as if nothing had changed. Args: session_id: From java_attach_window. handle: An ``e:...`` handle from a snapshot or a find. Returns: The element's role, name, description, states, bounds, index and depth, its locator, and the verification result. Errors: ``is_error`` for an unknown handle (the message says to take a fresh snapshot), for a handle belonging to another session, or when the element has changed.

NameTypeReqDescription
handlestringyes–
session_idstringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_get_table ~413

Read a Java table, a page of rows at a time. Use this on a handle for a `table` element -- from java_snapshot or java_find. This is the tool a platform-level automation cannot replace: it reads the table's own accessibility interface, so cell text, row and column counts come from the JVM rather than from pixels or from a bridge that does not carry them. It never returns the whole table. A large table is 200 rows in pyjab's own test application and thousands in a real one, so the read is paged by `row_start` and bounded by `row_count` and `max_cells`, and the reply says what it left out and how to ask for it. Cells are not just text. A cell with no text interface is shown as `-`, and a cell that could not be read is shown as `?` with a count: "this cell has no text" and "I could not read this cell" are different answers, and reporting the second as the first would invent an empty table. Args: session_id: From java_attach_window. handle: A handle for the table element. row_start: First row to read, 0-based. row_count: How many rows to read. max_cells: Hard cap on cells read in one call, whatever the rows ask for. Returns: The table's row and column counts, then one line per row, then what was left out. Errors: ``is_error`` for an unknown handle, an element that changed since the snapshot, or an element that is not a table -- which is reported with what it is instead, so a wrong handle and a stale handle do not look the same.

NameTypeReqDescription
handlestringyes–
max_cellsinteger––
row_countinteger––
row_startinteger––
session_idstringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_get_text ~278

Read the text of an element: a label, a text field, a table cell, a document. Use this on a handle from a snapshot or a find. The same verification applies, so a text field that has been replaced since the snapshot reports the change instead of returning whatever is there now. Long values are cut, and the cut is reported: the reply says how much of the whole text it carries and what the whole text's length is, so a partial read is never presented as the value. Args: session_id: From java_attach_window. handle: An ``e:...`` handle from a snapshot or a find. start: Character to start at, 0-based. length: How many characters to return. Returns: The slice of the element's text, with its length and whether it was cut. Errors: ``is_error`` for an unknown handle, a handle from another session, an element that has changed, or an element with no text at all -- which is reported as such, because "this control has no text" and "this control is empty" are different answers.

NameTypeReqDescription
handlestringyes–
lengthinteger––
session_idstringyes–
startinteger––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_list_windows ~210

List the Java windows Java Access Bridge can see on this machine. Use this to find out whether the application is visible to JAB at all, and to get a title or hwnd for java_attach_window. If the application is not in this list, nothing else will work and the problem is the attachment or the environment, not a locator -- run java_diagnostics next. Only windows of Java applications are listed; this is not a general Windows window list. Returns: One line per window, with hwnd, pid and title. "No Java windows are visible" is a measurement and is reported as such, not as an empty string. Errors: ``is_error`` with an actionable message when pyjab cannot answer. On pyjab 1.9.0 the listing runs through the documented ``pyjab-inspect windows --json``, because the function behind it is not public API yet; the message says so when even that is unavailable.

Input schema present but exposes no named parameters.

NameTypeReqDescription
resultstringyes–

No examples provided.

java_screenshot ~280

A PNG of the window, or of one element inside it. Use it when the accessibility tree is not enough — a chart, a canvas, a layout problem — and remember what it cannot do: **a picture is not readable structure.** Anything you want to act on should be found in the tree with java_snapshot or java_find, because that is where the handles and the names are. Canvas-drawn interfaces are the case where this is the only thing that works, and the only thing that is not there. With a handle, the element is verified first, for the same reason an action is: a picture of whatever moved into the position would mislead exactly as a click on it would. Args: session_id: From java_attach_window. handle: Optional element to photograph instead of the whole window. Returns: The image itself, as an image content block. Nothing else: a caption would be text, and everything a caller needs to know is in the arguments it passed. Errors: ``is_error`` for an unknown session or handle, an element that changed, or a window whose geometry is not reported — there is nothing to grab then, and saying so beats an empty image.

NameTypeReqDescription
handlestring––
session_idstringyes–

No output schema declared.

No examples provided.

java_select ~330

Select an option in a combo box, list or tab set — or a row or cell in a table. Two shapes, and which one you want is told by the arguments: * `option="Tennis"` selects by the text the application shows, for a combo box, a list or a tab. * `row=2` selects a whole table row, and `row=2, column=1` selects one cell. Table selection goes through the table's own accessible selection, which is the path the application responds to — pyjab's docs are explicit that the cells `get_cell()` returns often report `bounds = -1` and cannot be clicked. The element is verified before anything is selected, exactly as java_click describes. Args: session_id: From java_attach_window. handle: The combo box, list, tab set or table. option: Text to select. Ignored when a row is given. row: Row index to select, 0-based. column: Column index, for one cell rather than the whole row. simulate: Use simulated input where the action supports it. Returns: What was selected, and how. Errors: ``is_error`` for an unknown handle, an element that changed, an option the control does not have, or neither an option nor a row given.

NameTypeReqDescription
column–––
handlestringyes–
optionstring––
row–––
session_idstringyes–
simulateboolean––
NameTypeReqDescription
resultstringyes–

No examples provided.

java_send_keys ~535

Send a keyboard shortcut — ``alt+y``, ``ctrl+shift+s`` — to the window. Use it for an action the application only exposes as a chord: a menu accelerator, a toolbar shortcut, a keystroke a canvas-drawn control listens for. **Nothing is focused and nothing is clicked.** The chord goes to whichever window currently has the keyboard focus. That is deliberate on pyjab's side: clicking a control to focus its window would activate that control, and a shortcut usually exists to avoid exactly that. So if a call seems to do nothing, the window probably does not have focus — and **attaching does not focus it** (measured in pyjab#180). Call `java_focus_window(session_id=...)` first and read what it reports: it says whether the window *came forward*, which is the fact this tool needs. (Before that tool existed this reply said to click something harmless first; that workaround is gone from the shipped text, because it activated whatever it landed on and went through a locator that could have gone stale — which is the thing a shortcut exists to avoid.) Chords are written with `+` between key names and are case-insensitive: `ctrl`, `alt`, `shift`, `tab`, `enter`, `escape`, `spacebar`, the arrow keys, and single letters or digits. A name that is not a key is an error rather than a silent no-op — a wrong chord acts on somebody else's application and cannot be taken back. This needs pyjab 1.11.0, which released `JABDriver.send_keys` (gaozhao1989/pyjab#168 went in after 1.10.0). The call is probed rather than assumed, like every pyjab capability here: an install below the pin is told which release has the method instead of raising an `AttributeError`. Args: session_id: From java_attach_window. keys: The chord, such as "alt+y". Returns: What was sent, and the reminder that a shortcut's effect has to be looked for — this tool cannot see what the application did with it. Errors: ``is_error`` for an unknown session, a chord whose key names pyjab does not re…

NameTypeReqDescription
keysstringyes–
session_idstringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_set_text ~263

Type into a text field, text area or editable combo box. This sets the text rather than appending to it, and it waits for the field to report the new value before returning, so a following read sees what was typed. By default it goes through the accessibility action; `simulate=True` types real keystrokes instead, which is the fallback when the action is refused. Use java_fill_form instead when several fields need values: it is one round trip and it reports each field separately. The element is verified before anything is typed, exactly as java_click describes. Args: session_id: From java_attach_window. handle: The field to type into. value: The text to set. simulate: Type real keystrokes instead of using the accessibility action. Returns: What was set, and a reminder to re-read the field to confirm. Errors: ``is_error`` for an unknown handle, an element that changed, or a field that refused the text — the message says to try ``simulate=True`` when that is the likely answer.

NameTypeReqDescription
handlestringyes–
session_idstringyes–
simulateboolean––
valuestringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_snapshot ~528

The bounded tree view of an attached window, one line per element, with handles. This is the tool to reach for first after attaching: it shows what is in the window, what each element is called, and a handle (``[e:1a2b]``) for every element a later call can name. Pass a handle to a tool that acts on elements; pass a session id here. The view is deliberately bounded, and it says so when it was cut short. A Java window can hold thousands of nodes, and returning one puts hundreds of thousands of tokens into the conversation, so read in rings: snapshot at depth 2, then snapshot again if you need to see inside something. Handles are positions, not references: nothing is held between calls. Each handle records the element's role, name, position among siblings and bounds, and a later call re-finds the element and checks those before doing anything. If the window moved on -- a list reloaded, a dialog replaced a panel -- the handle fails with the difference rather than acting on whatever is there now. Args: session_id: From java_attach_window. depth: How many levels below the window to read. 2 is a good default; raise it only when the elements you want are not visible at 2. max_nodes: Hard cap on rendered elements. When it is reached the reply says so and names the way to narrow the next read. only_interactive: Drop pure layout scaffolding (panes, panels, viewports). Set it to false when you need the structure rather than the controls, or when an element you expect is missing -- filtering is the usual reason. fields: Extra per-element fields to print: any of states (the default), bounds, description, children, index, depth. Role and name are always printed, because they are what a handle checks itself against. Returns: One line per element, indented by depth, plus a truncation notice when the view was cut short and a count of elements that have no handle. Errors: ``is_error`` for an unknow…

NameTypeReqDescription
depthinteger––
fields–––
max_nodesinteger––
only_interactiveboolean––
session_idstringyes–
NameTypeReqDescription
resultstringyes–

No examples provided.

java_wait_for ~496

Wait for something to happen, instead of asking too early and being told no. Three conditions, chosen by what you pass: * `window_title="A Dialog"` — wait until a Java window with that title (fnmatch, so `"*Progress*"` works) exists. Use it after an action that opens one. * `handle=..., text_equals="Saved"` — wait until that element's text *is* this. * `handle=...` alone — wait until its text *changes* from what it reads when the wait starts, and report both values. **A timeout is a result, not an error.** The reply says the condition was not met and what was seen instead, because "not yet" is information an agent can act on — it can wait longer, look somewhere else, or take a snapshot — while an error reads as a failed call. pyjab's own waits raise; this one reports, and the difference is deliberate for a tool a model is driving. The waiting happens here rather than inside pyjab, and that is also deliberate: the bridge has exactly one owning thread, so a wait that ran *on* it would block every other call for its whole duration. This polls between calls instead, which also means a client can cancel it. Args: session_id: From java_attach_window. window_title: Title (fnmatch) of a window to wait for. handle: An element whose text to watch. text_equals: The text to wait for, with a handle. timeout: Give up after this many seconds. poll_interval: Seconds between checks. A window wait re-lists the Java windows on every poll; on an install below the pin that listing is the ``pyjab-inspect`` subprocess rather than a bridge call, so raise this. Returns: Whether the condition was met, how long it took, and what was seen. Errors: ``is_error`` only for an unknown session or handle, or for no condition at all. A timeout is reported in the reply, not as an error.

NameTypeReqDescription
handlestring––
poll_intervalnumber––
session_idstringyes–
text_equalsstring––
timeoutnumber––
window_titlestring––
NameTypeReqDescription
resultstringyes–

No examples provided.

Install

How do I install the io.github.gaozhao1989/pyjab-mcp server?

io.github.gaozhao1989/pyjab-mcp runs locally as a PyPI package, launched with uvx pyjab-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · pyjab-mcp

# add to Claude Code
claude mcp add gaozhao1989-pyjab-mcp -- uvx pyjab-mcp
Common questions

What is the io.github.gaozhao1989/pyjab-mcp server?

io.github.gaozhao1989/pyjab-mcp is listed in the public MCP registry as io.github.gaozhao1989/pyjab-mcp. Drive Java desktop apps from an AI agent, through the JVM's own accessibility tree. This page covers its PyPI package (pyjab-mcp).

Is the io.github.gaozhao1989/pyjab-mcp server safe to use?

io.github.gaozhao1989/pyjab-mcp scores 86 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the io.github.gaozhao1989/pyjab-mcp server expose?

io.github.gaozhao1989/pyjab-mcp exposes 16 tools: java_diagnostics, java_list_windows, java_attach_window, java_snapshot, java_find, and 11 more. Their descriptions and schemas cost roughly 5,665 tokens of context every time the server is loaded.

Is the io.github.gaozhao1989/pyjab-mcp server still maintained?

io.github.gaozhao1989/pyjab-mcp is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

What licence is the io.github.gaozhao1989/pyjab-mcp server under?

io.github.gaozhao1989/pyjab-mcp declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.