Skip to main content
Glama

MCPymol — talk to PyMOL

PyPI Python License: MIT

Nucleosome core particle (1AOI) rendered in MCPymol's ghost-heart style

MCPymol is a Model Context Protocol server that lets you drive PyMOL with natural language. Load structures, set up analytical views, measure things, and explore proteins by talking to Claude or Gemini. The image above was made by typing "show me a nucleosome" into Claude Code. That was the whole prompt.

PyMOL is great, but its syntax is famously obscure — and despite the name, it isn't quite Python. MCPymol is for people who'd rather just look at structures.

What you get

  • A vocabulary the LLM understands. Tools like fetch_structure, ligand_view, interface_view, mutation_view, conservation_view do high-level setup in one call: pick the biological assembly, hide solvent, color sensibly, label the right residues, draw the right H-bonds.

  • Renders the model can see. render ray-traces and hands the image straight back, so the assistant can look at what it made and fix it — rather than writing a PNG it has no way to inspect.

  • 87 PyMOL primitives exposed as individual tools (show, hide, color, select, distance, align, spectrum, …) so the model can compose finer motions when the high-level tools don't quite fit. 135 tools in total, every parameter documented in the tool schema. When even that runs out, execute_pymol_command passes a raw PyMOL command straight through and waits for it, returning what PyMOL printed and, if PyMOL rejected a line, which one and why.

  • Predicted structures. A UniProt accession fetches from AlphaFold DB and colors by pLDDT confidence in the official palette — via fetch_structure or fetch_alphafold directly.

  • Scene introspection. list_objects, list_chains, list_ligands and structure_info let the model check what's actually loaded before guessing, count_atoms catches a selection that matches nothing — otherwise invisible until the render comes out blank — and atom_properties reaches occupancy and altlocs that no per-residue view can show.

  • Your own files too. load_structure opens a local PDB/mmCIF — a model you built, a docking pose, an MD frame — through the same prep and styling as a fetched entry.

  • Smart structure prep. Fetching a PDB code grabs the biological assembly when one exists, then runs a BFS heuristic over chain–chain contacts (multimer_cutoff, default 8 Å) so sprawling functional multimers like the CRP pentamer or ferritin cage stay whole while crystallographic copies get dropped. Waters and crystallization additives are hidden automatically.

  • Two-process bridge. PyMOL's GUI has its own Python; MCPymol works by running a tiny TCP listener inside PyMOL plus a separate FastMCP server outside it.

Related MCP server: PubMed MCP Server

How it talks

┌──────────────┐   MCP / stdio    ┌────────────────┐  JSON over TCP  ┌──────────────┐
│ Claude /     │ ───────────────▶ │ mcpymol server │ ◀────:9876────▶ │ PyMOL GUI    │
│ Gemini CLI   │                  │   (FastMCP)    │                 │  (plugin.py) │
└──────────────┘                  └────────────────┘                 └──────────────┘

The plugin half runs inside PyMOL and dispatches to pymol.cmd. The bridge half is what the MCP client launches. They talk over a local TCP socket because PyMOL's GUI ships its own Python interpreter, which cannot import the packages the MCP server needs — so the two halves cannot live in one process.

Both halves must run on the same machine: several tools hand files between them through the filesystem.

Try it

"Fetch ubiquitin (1ubq) and show it as a cartoon, then show me the render." "Color the alpha helices red and the beta sheets blue." "What ligands are in 1HSG?" "Show the binding pocket around MK1 in 1HSG." "Highlight mutations E6V, K16E, and V67F in hemoglobin (4HHB)." "Run a Poisson-Boltzmann electrostatics calculation on 1LYZ." "Get the AlphaFold model for P69905 and tell me how confident it is." "Superpose 1AKE onto 4AKE and show me where adenylate kinase moves." "Make me a turntable animation of the nucleosome."

Tip: if the model isn't sure what's loaded, ask it to list the objects — it'll call list_objects and ground itself before guessing names.

What can I ask?

Organised by the question, not the tool.

Question

Tool

What is this structure — resolution, method, organism?

structure_info

What's the sequence, and how does it map to the residue numbering?

get_sequence

What's loaded / what chains / what ligands?

list_objects, list_chains, list_ligands

Can I open my own file rather than a PDB code?

load_structure

What are this atom's occupancy / altloc / B-factor?

atom_properties

What holds this ligand in its pocket, and how tightly?

contact_report, then ligand_view to see it

How big is this interface, and which residues matter?

interface_report, then interface_view

Where do these two structures differ?

superposition_view

How far apart / what angle / how much surface?

distance, angle, dihedral, sasa, rms_cur

Which parts are conserved? Flexible? Confident?

conservation_view, bfactor_view, plddt_view

Is this atom really there, or is it half-occupied?

occupancy_view, altloc_view

How much do the members of this ensemble disagree?

ensemble_spread_view, then morph_states if they share a topology

How good is this cryo-EM model, per residue?

qscore_view

What's the voxel size / geometry of this map?

map_info — reads the header only

Can I see the density around this ligand?

load_map, then density_view

Which parts of this map are actually well resolved?

local_resolution_view

What does it look like?

render — returns the image, so the model can see it

Can I keep this scene?

save_session / load_session

Can I print it?

print_ribbon_view + print_export

The pattern that works best: report first, then draw. contact_report tells you Asp30 makes a salt bridge at 2.7 Å; ligand_view then shows you where it sits. Asking only for the picture gets you a picture you have to interpret yourself.

Requirements

  • PyMOL — developed against Open-Source PyMOL 3.1 (brew install pymol on macOS; on Linux, conda install -c conda-forge pymol-open-source or apt-get install pymol on Ubuntu 26.04+). Debian/Ubuntu 22.04 and 24.04 ship PyMOL 2.5 via apt, which works across the standard tools and views (only print_ribbon_view(..., spine_in_strands=False) requires PyMOL 3.1). The Schrödinger Incentive build works if its embedded Python is 3.10 or newer (print(sys.version) inside PyMOL); older Incentive 2.x builds are not supported. MCPymol drives an existing PyMOL installation and does not bundle one.

  • Python 3.11+ for the bridge (separate from PyMOL's internal Python). On Ubuntu 22.04 where system python3 is 3.10, uv tool install --python 3.12 mcpymol fetches a compatible Python automatically.

  • An MCP client — Claude Code, Claude Desktop, or Gemini CLI.

Optional, per feature:

For

You also need

poisson_boltzmann_view

apbs and pdb2pqr on PATH

print_export, print_ribbon_view

the print extra (uv tool install 'mcpymol[print]'); on Linux also sudo apt-get install libopengl0 (see 3D Printing Export)

conservation_view

network access to an MMseqs2 server (ColabFold's public API by default). The chain's sequence is sent to that server, so for an unpublished sequence point MCPYMOL_MMSEQS_URL at one you run

fetch_structure, structure_info

network access to the RCSB

Installation

There are two halves to wire up: the native plugin (runs inside PyMOL) and the MCP bridge (runs outside, and is what your AI assistant launches). Both come from the same package.

1. Install MCPymol

uv tool install mcpymol

pipx install mcpymol works the same way. There is no need to clone the repository unless you intend to work on MCPymol itself.

Check it landed somewhere your shell can see:

which mcpymol      # if this prints nothing, run: uv tool update-shell

Note the full path it prints — you will want it in step 3. uv and pipx install into ~/.local/bin, which is not on everyone's PATH, and an MCP client started by the OS rather than from your shell does not inherit your PATH at all. Wiring the assistant to a bare mcpymol when it is not on PATH fails at launch with spawn mcpymol ENOENT, not at install time.

Why not uvx mcpymol? uvx runs the bridge perfectly well, but it is the wrong tool for step 2: it unpacks the package into ~/.cache/uv, and the plugin has to be loaded by absolute path, so the line written into your PyMOL startup file would point into a cache that uv cache clean reclaims. uv tool install puts it somewhere permanent — and lets both halves come from one installation, so the bridge and the plugin cannot drift apart.

2. Start the native plugin

The plugin runs inside PyMOL, which has its own Python interpreter — it cannot import the installed package, so it is loaded from a file path. Let MCPymol find that path for you:

mcpymol --install-plugin

That adds a small managed block to ~/.pymolrc.py, so PyMOL loads the plugin on every launch. Restart PyMOL and you should see:

MCPymol Native Plugin listening on 127.0.0.1:9876

Re-run it after upgrading MCPymol — the block embeds a path into one installation and is rewritten, not duplicated. mcpymol --uninstall-plugin removes it and leaves the rest of your .pymolrc.py alone.

If you would rather wire it up yourself, mcpymol --plugin-path prints the path, and you can run it from the PyMOL command line or add your own line to ~/.pymolrc.py.

Changing the port. Set MCPYMOL_PORT before launching both PyMOL and the bridge — see Configuration.

3. Register the bridge with your AI assistant

Pick one. Use the full path from which mcpymol — it is the same installation the plugin came from, and a bare mcpymol only works if that directory is on the PATH of whatever launches the client.

Claude Code CLI

claude mcp add mcpymol -- "$(which mcpymol)"

Start a new Claude Code session.

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "mcpymol": {
      "command": "/absolute/path/to/mcpymol"
    }
  }
}

The absolute path is not optional here: Claude Desktop is launched by the OS rather than from your shell, so it never inherits your PATH. Restart Claude Desktop afterwards.

Gemini CLI

gemini mcp add mcpymol "$(which mcpymol)"
gemini mcp refresh

Without installing — uvx

To run the bridge without installing anything, point your assistant at uvx mcpymol:

claude mcp add mcpymol -- uvx mcpymol

You still need the plugin, and step 2's command is not available to you — nothing was installed. Run it through uvx instead:

uvx mcpymol --install-plugin

That writes a path into ~/.cache/uv (see the note in step 1), so uv cache clean or a uvx upgrade will break it and you will have to re-run it. uvx also resolves the newest release on each launch, so the bridge can drift ahead of the plugin. This path trades a permanent install for maintenance; if that sounds worse than installing, install.

Restricted environments — no uv

If uv is blocked by your org's security policy, use a standard venv with Python 3.11 or newer. On Debian/Ubuntu you may need sudo apt-get install python3-venv pymol first (on Ubuntu 22.04, where default python3 is 3.10, install a newer Python such as python3.11-venv and invoke python3.11 -m venv below).

python3 -m venv ~/.venvs/mcpymol
~/.venvs/mcpymol/bin/pip install --upgrade pip
~/.venvs/mcpymol/bin/pip install mcpymol
~/.venvs/mcpymol/bin/mcpymol --install-plugin

# Point the assistant directly at the venv binary
claude mcp add mcpymol ~/.venvs/mcpymol/bin/mcpymol
# or
gemini mcp add mcpymol ~/.venvs/mcpymol/bin/mcpymol

If your network blocks PyPI, install from your internal mirror with pip install --index-url ....

Upgrading

Upgrade the way you installed — uv tool upgrade mcpymol, pipx upgrade mcpymol, or <venv>/bin/pip install --upgrade mcpymol. Then restart PyMOL and reconnect the MCP server in your client (/mcp in Claude Code).

Both halves have to move together, and neither moves on its own. The plugin is loaded into PyMOL's memory at startup, and the bridge is a process your MCP client launched — upgrading the package on disk changes neither until each is restarted. PyMOL will happily keep running the plugin it loaded days ago against a freshly upgraded bridge.

You do not normally need to re-run --install-plugin: uv tool, pipx and a venv all upgrade the package in place, so the path in ~/.pymolrc.py still points at the right file. Re-run it if you move the installation — switching install method, rebuilding the venv, or using the uvx path, whose cache directory does change.

A mismatched pair fails in a way that reads like a bug in a tool rather than a stale process: calls that should work report unknown actions, or a tool fixed in the release you just installed keeps misbehaving.

Working on MCPymol itself

For development, clone the repo and run from the checkout — this is the only path that needs a clone:

git clone https://github.com/chemrich/MCPymol.git
cd MCPymol
uv sync
uv run mcpymol --install-plugin
claude mcp add mcpymol -- uv --directory /absolute/path/to/MCPymol run mcpymol

See CONTRIBUTING.md.

Configuration

Everything is optional; the defaults are what the tools are tuned for. Set them before launching PyMOL and the bridge.

Variable

Default

What it does

MCPYMOL_PORT

9876

Bridge ↔ plugin TCP port. Must match on both sides.

MCPYMOL_AUTOSTART

1

Plugin side: set to 0 before launching PyMOL to load the plugin without opening the port. Type start_mcp in PyMOL to start listening, stop_mcp to stop. Useful with a second MCP plugin loaded, or when PyMOL sits idle.

MCPYMOL_RECV_TIMEOUT

30 s

How long the plugin waits for one complete request before answering with an error. Bounds how long a stalled client can hold the single-threaded accept loop.

MCPYMOL_MAX_REQUEST_BYTES

8388608

Largest single request the plugin will accept.

MCPYMOL_MAX_OUTPUT_CHARS

8000

Plugin side: how much of what PyMOL printed one execute_pymol_command sends back. The head and tail are kept and the middle counted, so an iterate all, print(name) cannot flood the conversation.

MCPYMOL_DO_START_TIMEOUT

120 s

Plugin side: how long an execute_pymol_command waits for PyMOL's main thread to start it. Once started it is waited on to the end. A main thread held by an open dialog or a hung command gets an honest "nothing was run" instead of a request that never returns.

MCPYMOL_APP_NAP_IDLE_S

900 s

Plugin side, macOS GUI only: how long after its last request the plugin lets macOS App Nap PyMOL again. 0 turns the guard off. See Slow renders on a Mac below.

MCPYMOL_SLOW_OP_TIMEOUT

600 s

Socket budget for operations that legitimately take minutes — ray, png, save, mpng, draw, execute_pymol_command — and for the Poisson reconstruction in print_export.

MCPYMOL_MAX_IMAGE_BYTES

5000000

Above this, render returns the file path instead of inlining the image.

MCPYMOL_PB_TIMEOUT

600 s

Wall-clock ceiling on the external apbs / pdb2pqr processes.

MCPYMOL_MMSEQS_URL

ColabFold public API

MMseqs2 server for conservation_view. Point at an internal one to avoid the public queue.

MCPYMOL_WIGGLES_TIMEOUT

10 s

Socket budget for the standalone BridgePort adapter in mcpymol.wiggles. The tools themselves use MCPYMOL_SLOW_OP_TIMEOUT, since a map load moves tens of megabytes.

MCPYMOL_ALPHAFOLD_API_URL

AlphaFold DB prediction API

Where fetch_alphafold asks which model file is current.

MCPYMOL_ALPHAFOLD_URL

AlphaFold DB files

Legacy filename template, used only when you pin model_version explicitly.

MCPYMOL_RCSB_URL

RCSB data API

Base URL for the metadata structure_info reports.

MCPYMOL_PORT=9867 open -a PyMOL       # macOS
MCPYMOL_PORT=9867 mcpymol             # bridge

Troubleshooting

Symptom

Likely cause

Fix

Every tool returns "Socket connection failed: nothing is listening on 127.0.0.1:9876 … Is the PyMOL plugin running?"

Plugin not loaded in PyMOL

run /path/to/plugin.py inside PyMOL, or add it to ~/.pymolrc.py

"Address already in use" on plugin start

A previous PyMOL session left the port open, or another app uses 9876

Quit lingering PyMOL processes, or set MCPYMOL_PORT=9867 on both sides

Long get_fastastr / get_chains calls fail with a JSON parse error

You're on a pre-2026-05 version of MCPymol that capped recv() at 8 KB

Upgrade — the bridge now drains the response in full

conservation_view is slow

First call hits the ColabFold MMseqs2 API (30 s–few min); subsequent calls for the same sequence hit a local cache

If you have an internal MMseqs2 server, set MCPYMOL_MMSEQS_URL

poisson_boltzmann_view fails

apbs or pdb2pqr missing

brew install brewsci/bio/apbs and pip install pdb2pqr

A tool reports a file "did not appear"

PyMOL and the bridge are on different machines — they exchange files through the filesystem

Run both on the same host

render returns a size message instead of an image

The PNG exceeded the inline limit; base64 inflates it by a third

Ask for a smaller width/height, or raise MCPYMOL_MAX_IMAGE_BYTES

fetch_structure/fetch_alphafold says "No AlphaFold model"

The accession is valid but AlphaFold DB has no model at that version

Try another model_version, or check the accession

A view comes out blank

The selection matched no atoms

count_atoms on the selection before building the scene

A long operation returns "PyMOL accepted '…' but sent no reply within N s"

Something slower than its budget. The request was not cancelled, so PyMOL may still be working on it

Check what PyMOL has done before re-sending; raise MCPYMOL_SLOW_OP_TIMEOUT (renders, saves) or MCPYMOL_PB_TIMEOUT (APBS)

A render took many minutes and says "the computer was asleep for N s of it", or any tool's timeout ends "asleep for N s of this wait"

The Mac slept during the call. Nothing runs while it sleeps — PyMOL, the bridge or the client — and the wait resumes on wake, which makes it look like a stall

Keep the machine awake for long unattended runs, e.g. caffeinate -i -w <pid of your MCP client>

Slow renders on a Mac: a ray trace that normally takes seconds takes minutes while PyMOL's window is in the background

macOS App Nap drops a background app to the lowest priority, and under load a 1 s ray trace was measured at 74–349 s

The plugin holds off App Nap while it is serving requests (MCPYMOL_APP_NAP_IDLE_S). Restart PyMOL after upgrading so it loads the current plugin

execute_pymol_command ends with "The PyMOL plugin that is running predates error reporting"

PyMOL loaded an old plugin, which reports success for every command without running it first

Restart PyMOL so it loads the plugin from this install (mcpymol --plugin-path prints its path)

execute_pymol_command says "PyMOL was busy for N s", "PyMOL was still rendering a movie" or "PyMOL's main thread did not pick up the command" — each ending "nothing was run"

PyMOL's main thread was held (a long command, an open dialog, a movie being rendered, a hang) for MCPYMOL_DO_START_TIMEOUT

Look at the PyMOL window; nothing from that request was run

A tool reports an unknown action, or a bug you just upgraded past is still there

PyMOL is still running the plugin it loaded at startup, from before the upgrade

Restart PyMOL, then reconnect the server in your client (/mcp in Claude Code) — see Upgrading

New tools don't show up after an upgrade

The MCP client is still running the previous bridge process

Reconnect the server in your client, or start a new session

A fetch reports success but nothing is loaded

Pre-v1.4.0 behaviour: cmd.fetch doesn't raise on a failed download

Upgrade — fetches now verify atoms arrived and say so plainly, and no longer clear the session on failure

render says the image is "a single flat colour"

The camera is pointed at nothing, or the session is wedged after heavy use

zoom on the object, or restart PyMOL if zoom stops responding

Tests

uv run pytest

The tests that run by default mock the socket layer and PyMOL's cmd module, so they need neither PyMOL nor a network, and cover the socket payloads, the bridge framing, the conservation pipeline (A3M parsing, Shannon entropy, MMseqs2 mocking, MSA→B-factor mapping), the mesh-repair paths, and every view. tests/test_bridge_roundtrip.py additionally runs the real bridge against the real plugin listener over TCP on an ephemeral port, so the wire format is checked against itself rather than against a mock.

The two opt-in suites

The rest are deselected by default, because they need things CI does not have. Both are worth running before a release tag:

uv run pytest -m live      # needs a test PyMOL on its own port: see CONTRIBUTING.md
uv run pytest -m network   # hits real external APIs

-m live clears the PyMOL session it connects to. So it runs only against a port you name for testing; your everyday PyMOL's port, 9876 or an MCPYMOL_PORT in your shell, is never assumed to be disposable.

-m live exists because a mocked suite asserts the payload we send, which can never tell you whether PyMOL will accept it — and that gap is where every wiring bug has lived: tools calling cmd functions that don't exist, arguments bound in the wrong order, renders that come back blank. It calls every registered tool once and asserts only that each is wired (the action resolves, the arguments bind), not that it succeeds, since many tools error honestly without the right context. New tools are swept automatically. Asking for it and having no live test pass is a failure, not a green run of skips, and it detects a wedged session rather than reporting a hundred confusing failures.

Treat a green default run as necessary, not sufficient.

Layout

Module

Responsibility

mcpymol/app.py

the shared FastMCP application

mcpymol/bridge.py

socket protocol to the in-PyMOL plugin

mcpymol/structures.py

fetching/loading structures, sessions, introspection

mcpymol/primitives.py

one thin tool per pymol.cmd function

mcpymol/views.py

the *_view scene presets

mcpymol/style.py

scene conventions shared across the presets

mcpymol/rendering.py

render, turntable

mcpymol/comparison.py

superposition_view

mcpymol/conservation.py

MSA + Shannon entropy

mcpymol/analysis.py

contact_report, interface_report

mcpymol/wiggles/

cryo-EM occupancy, ensembles, maps and local resolution

mcpymol/pdbtext.py

parsing the PDB records PyMOL hands back as text

mcpymol/printing.py

watertight STL export

mcpymol/cli.py

--install-plugin, --plugin-path, --uninstall-plugin

mcpymol/plugin.py

the half that runs inside PyMOL

mcpymol/cli.py is the entry point (the mcpymol command). mcpymol/server.py imports every tool module and re-exports everything, so from mcpymol.server import ligand_view still works.

The view library

These are the high-level visualization tools. Each does its own setup — coloring, transparency, H-bonds, labels — in one prompt.

ligand_view — binding site

Pocket residues (within 5 Å of the ligand) as element-colored sticks with CA labels, ligand as yellow sticks, H-bonds as yellow dashes, protein as a translucent cartoon.

Show me the ATP binding site in 1ATP

Ligand view of ATP in cAMP-dependent kinase (1ATP)

interface_view — protein–protein interface

Chain A marine, chain B salmon. Interface residues (within 4 Å of the partner) as solid surface patches with sidechain sticks and CA labels. Cross-chain H-bonds as yellow dashes.

Show the interface between chain A and chain D in 1BRS

Interface view of barnase–barstar complex (1BRS)

putty_view — B-factor flexibility

Tube radius and color scale with B-factor: blue/thin = rigid, red/thick = flexible. A 70%-transparent surface adds shape context.

Show the B-factor flexibility of 1UBQ as a putty view

Putty view of ubiquitin (1UBQ)

bfactor_view — B-factor flexibility, plain cartoon

The same color story as putty_view (blue → red on B-factor) but on a plain cartoon. Cheaper, cleaner in figures where you don't want the putty distortion.

Color 1UBQ by B-factor

hydrophobic_surface_view — surface chemistry

Surface colored by amino-acid chemistry: orange = hydrophobic, white = polar, sky blue = positive, salmon = negative. Useful for spotting hydrophobic patches, membrane belts, and charge complementarity.

Show the hydrophobic surface of 1TCA

Hydrophobic surface view of Candida antarctica Lipase B (1TCA)

electrostatic_view — approximate electrostatics

Red→white→blue surface coloring driven by per-residue pKa-weighted partial charges. Two modes: atomic (charges on the actual charge-center atoms — localized, natural falloff) and residue (uniform across charged residues — saturated patches).

Show the electrostatic surface of 1LYZ

Electrostatic view of lysozyme (1LYZ)

poisson_boltzmann_view — true PB electrostatics

Full Poisson-Boltzmann potential via APBS and PDB2PQR, mapped onto the surface at ±20 kT/e. Physically correct, accounts for solvent screening and ionic strength.

Prerequisites (must be on PATH):

brew install brewsci/bio/apbs
pip install pdb2pqr

Run a Poisson-Boltzmann electrostatics calculation on 1LYZ

Poisson-Boltzmann electrostatic surface of lysozyme (1LYZ)

conservation_view — evolutionary conservation

Pipeline: extract the chain's sequence → submit to MMseqs2 (ColabFold public API by default, so the sequence leaves your machine; override with MCPYMOL_MMSEQS_URL) → parse the A3M alignment → compute per-position Shannon entropy → map onto B-factor and color via cyan_white_magenta spectrum.

Magenta = conserved, white = moderate, cyan = variable. First call takes 30 s – few minutes depending on sequence length; results are cached in memory by sequence, so re-running on the same protein (or changing only the color scale) is instant.

Color lysozyme (1LYZ) by conservation

Lysozyme (1LYZ) coloured by evolutionary conservation from a 5,507-sequence alignment

Lysozyme against 5,507 homologues. The variable surface loops go cyan while the core and the substrate-binding cleft stay magenta — conservation tracking function, which is the whole reason to compute it.

CYS sidechains and disulfide bonds in yellow, metal coordination bonds in orange, the rest of the protein as a thin grey cartoon.

Show the disulfide bonds in 1CEL

Crosslink view of cellulase (1CEL)

pocket_view — binding pocket surface

The pocket cavity (residues within 5 Å of the ligand) as a semi-transparent surface colored by chemistry. Sticks for the pocket sidechains, yellow sticks for the ligand, cyan dashes for H-bonds.

Show the binding pocket around MK1 in 1HSG

Pocket view of MK1 binding site in HIV-1 protease (1HSG)

pharmacophore_view — ligand pharmacophore features

The ligand colored by pharmacophore type: violet = aromatic ring carbon, yellow = aliphatic carbon, sky blue = N (donor/acceptor), salmon = O (acceptor), gold = S, pale green = halogen. Interacting residue sticks with CA labels, cyan dashes for H-bonds.

Show the pharmacophore features of MK1 in 1HSG

Pharmacophore view of MK1 in HIV-1 protease (1HSG)

mutation_view — mutation hotspots

Grey cartoon, mutated sidechains as magenta sticks with white CA labels, neighboring residues (within 4 Å) as thin element-colored sticks for packing context. Standard A123G notation; optional chain prefix A:A123G.

Highlight mutations E6V, K16E, and V67F in hemoglobin (4HHB)

Mutation view of hemoglobin (4HHB) showing E6V, K16E, V67F

textbook_view — cel-shaded illustration

White cartoon + surface with heavy ray-trace contours. The cel-shaded look kicks in after you run ray (or ask the model to render).

Make 4HHB look like a textbook illustration

Haemoglobin (4HHB) rendered in the cel-shaded textbook style

cinematic_view — fog and shadows

Depth-cueing + fog + soft shadows on a black background. Best on big assemblies — ribosomes, capsids, nucleosomes — where you want a sense of scale. Run ray for the full effect.

Give me a cinematic view of GroEL

GroEL (1GRL) down its seven-fold axis with depth cueing and shadows

Depth cueing needs scale to pay off — this is one GroEL ring down its seven-fold axis. On a small globular protein the effect is mostly lost.

pointillist_view — starfield surface

Replaces the surface with a dense dot cloud; ligands become bright yellow stars. More art than analysis.

plddt_view — AlphaFold confidence

Colors a predicted model by pLDDT in AlphaFold's official palette: dark blue >90 (very high), light blue 70–90 (confident), yellow 50–70 (low), orange <50 (very low). Reports the breakdown, e.g. "very high: 62%, confident: 21%, …".

pLDDT is stored in the B-factor column, which is why bfactor_view and putty_view render these models backwards — they read low B as rigid, whereas low pLDDT means the model doesn't know. plddt_view warns if the B-factors don't look like pLDDT at all.

Get the AlphaFold model for P0DTC2

pLDDT confidence of the AlphaFold SARS-CoV-2 spike model (P0DTC2)

Mean pLDDT 67.1 across 1273 residues — 7% very high, 49% confident, 20% low, 24% very low. The orange tails are the point: AlphaFold is telling you it does not know where they go, and no amount of rendering makes that a structure.

superposition_view — where two structures differ

Superposes mobile onto target, then colors the mobile structure by how far each residue's CA actually moved: blue = unchanged, red = most shifted. The target stays as a grey reference. Reports the RMSD, the mean and max shift, and names the worst-shifted residues.

An RMSD alone tells you a structure moved; this tells you where.

Superpose 4AKE onto 1AKE and show me where it moves

Adenylate kinase open (4AKE) superposed on closed (1AKE), coloured by per-residue shift

Adenylate kinase, open against closed: the core fits at 2.07 Å RMSD while residues 145–152 move up to 24 Å. That is the LID domain closing over the substrate, and it is the whole reason to colour by deviation rather than quote one number.

Both structures have to be loaded at once, and fetch_structure clears the session by default — fetch the second with replace=False. Compare single chains when the entries are multimers: superposing one dimer onto another fits the assembly rather than the fold, which reports 18.5 Å for this same pair.

Analysis — answers with numbers

The view presets draw interactions; these report them. Both matter, and they compose: run the report to get the numbers for your figure legend, run the view to make the figure.

contact_report — what touches what

Lists contacting residue pairs closest first, with the minimum heavy-atom distance, how many atoms are involved, and a classification: salt bridge, hydrogen bond, hydrophobic, polar contact, or π-stacking (parallel vs T-shaped from the interplanar angle).

contact_report("1hsg and resn MK1", "1hsg and polymer")

Criteria are heavy-atom distances — salt bridge ≤ 4.0 Å between charged sidechain tips, H-bond ≤ 3.5 Å between N/O pairs, hydrophobic ≤ 4.5 Å between C/S, ring centroids ≤ 5.5 Å — because crystal structures usually have no hydrogens. A reported hydrogen bond is therefore a donor–acceptor pair with plausible geometry, not one verified against a hydrogen position.

Ring perception needs bond orders, which a PDB dump doesn't carry, so aromatics are detected for the standard aromatic amino acids only; ligand rings show up as hydrophobic contacts rather than being mis-called as stacking.

What holds MK1 in the HIV protease pocket?

26 residue pairs in contact within 4.0 A between '1hsg and resn MK1' and '1hsg and polymer':

  B/MK1902     -- B/ASP25       2.63 A  hydrogen bond, polar contact, contact (8 atom contacts)
  B/MK1902     -- A/ASP25       2.77 A  hydrogen bond, contact (8 atom contacts)
  B/MK1902     -- B/GLY27       3.03 A  hydrogen bond, polar contact, contact (8 atom contacts)
  B/MK1902     -- B/ASP29       3.06 A  hydrogen bond, polar contact, contact (6 atom contacts)
  B/MK1902     -- A/GLY48       3.15 A  hydrophobic, contact (6 atom contacts)
  B/MK1902     -- B/VAL32       3.32 A  hydrophobic (2 atom contacts)
  ... and 20 more pairs (raise max_pairs to see).

Interaction types across all pairs: 20 hydrophobic, 14 contact, 5 hydrogen bond, 4 polar contact.

Both copies of the catalytic Asp25 — one from each chain of the protease dimer — hydrogen bond the inhibitor at 2.63 and 2.77 Å. That is the interaction the drug was designed to make, read straight off the structure. It is the same pocket the ligand_view image above shows; the picture and the numbers are two views of one question.

interface_report — how big is this interface

Buried surface area from ΔSASA (free minus bound), the per-side figure papers quote, a ranking of residues by how much surface each buries, and a breakdown by residue chemistry.

It also interprets the number: under ~400 Ų per side is usually crystal packing rather than a biological interface; over ~1000 Ų is a substantial, likely specific association. Guidance from PDB-wide surveys, not a verdict.

How big is the barnase–barstar interface in 1BRS?

Interface between chains A and D of 1brs:
  Buried surface area: 777 A^2 per side (1,553 A^2 total).
  That is a typical size for a specific but transient protein-protein interface.
  Interface residues: 22 in chain A, 19 in chain D.
  Composition by buried area: 41% charged, 32% polar, 28% hydrophobic.
  Chain A hot spots: ARG59 (154 A^2), HIS102 (107 A^2), ARG83 (78 A^2), GLU60 (69 A^2), ...
  Chain D hot spots: ASP35 (120 A^2), TYR29 (97 A^2), ASP39 (86 A^2), TRP44 (75 A^2), ...

Barnase–barstar is the textbook electrostatically-driven interface, and the numbers say so unprompted: 41% of the buried area is charged, and the hot spots it ranks — Arg59/His102 on barnase, Asp35/Asp39/Trp44 on barstar — are the residues the mutagenesis literature identifies.

structure_info and get_sequence — what am I looking at

structure_info combines what PyMOL knows (chains, counts, ligands, states, space group) with RCSB entry metadata (title, method, resolution, release date, source organism), and flags a probable AlphaFold model when the B-factor column looks like pLDDT.

1hsg — CRYSTAL STRUCTURE AT 1.9 ANGSTROMS RESOLUTION OF HUMAN IMMUNODEFICIENCY
VIRUS (HIV) II PROTEASE COMPLEXED WITH L-735,524, AN ORALLY BIOAVAILABLE
INHIBITOR OF THE HIV PROTEASES
  X-RAY DIFFRACTION, 2.00 A resolution, released 1996-04-03
  Source: Human immunodeficiency virus 1
  1,686 atoms, 198 residues, 127 waters
  Chains (2): A, B
  Ligands in '1hsg': MK1
  Space group P 21 21 2, cell 59.6 x 87.1 x 46.7 A

atom_properties reads properties that live on individual atoms rather than residues or objects — occupancy, alternate conformations, per-atom B-factor, formal charge. Nothing else reaches them: the PyMOL call that exposes them returns an object that cannot cross the bridge, so the plugin flattens it on the way out.

2 atoms in '1hsg and resi 25':

  chain  resi  resn  name  b      q
  A      25    ASP   OD1   18.42  1.00
  A      25    ASP   OD2   21.07  0.50

That 0.50 is the tool's reason to exist: a sidechain modelled in two conformations, invisible to every per-residue view.

get_sequence returns FASTA — plus the two things the sequence alone hides and that routinely cause mistakes: the numbering offset (PDB numbering rarely starts at 1, so "residue 50" in a paper and position 50 in the sequence are usually different residues) and chain breaks where loops went unmodelled.

Rendering and sessions

render — see what you made

Ray-traces the current scene and returns the image as MCP image content, so the model can actually look at it and iterate. This is the tool to use instead of ray + png, which only leave a file behind.

Defaults to 1000×750 — the image is inlined into the conversation, and base64 inflates it by a third. Above 5 MB (MCPYMOL_MAX_IMAGE_BYTES) it returns the path instead, and keeps the file there even if you did not pass a filename, so a render that took minutes is not thrown away for being too big to show.

Every render is ray-traced, and ray_trace=False does not change that: PyMOL's fast unshaded frame grab needs its GUI thread, which the plugin does not run on, so that path wrote blank images. The flag is accepted and ignored, with a note in the reply, rather than silently handing back a blank PNG. To make a render cheaper, ask for a smaller width/height. render also detects the two ways an image comes back empty — a single flat colour, or nothing written at all — and says so instead of returning a black square.

turntable — 360° animation

Writes a numbered PNG sequence spinning the camera a full turn, plus the ffmpeg command to assemble it. Defaults to 36 frames (10° apart) at 800×600.

Every frame is ray-traced, for the same reason render is — the unshaded OpenGL path silently produced blank frames over this bridge. That makes it slow: 36 frames of a large assembly can take an hour, so start with a low frames count and a small width/height before committing to a long run.

Make me a turntable animation of 1AOI

save_session / load_session — keep a scene

.pse round-trips the entire session: every object, selection, representation, color, scene and the camera. Save before experimenting with a scene that took effort to build. load_session(merge=True) adds a saved scene to the current one rather than replacing it.

🖨️ 3D Printing Export

The print_export tool turns a structure into watertight STL files ready for multi-colour 3D printing. PyMOL's open-source build can't write STL and its OBJ exporter dumps the whole visible scene as non-manifold surface soup — print_export works around all of that: it isolates each colour group, exports it, and rebuilds a watertight, manifold solid per group. Every STL is written in PyMOL's model coordinates, so a slicer can load the groups as aligned multi-material parts.

This tool needs the optional print extra (trimesh, pymeshlab, scipy, scikit-image, manifold3d, numpy):

Install it into the same environment MCPymol is already in — a bare pip install picks whatever pip is first on your PATH, which is usually a different interpreter entirely, and leaves print_export still reporting the dependencies missing:

uv tool install 'mcpymol[print]'                   # if you used uv tool
pipx install --force 'mcpymol[print]'              # if you used pipx
~/.venvs/mcpymol/bin/pip install 'mcpymol[print]'  # if you used a venv
uv sync --extra print                              # from a checkout

Re-running over an existing install is fine — it adds the extra in place.

On Linux, pymeshlab also needs the system OpenGL library, even headless. Without it the Poisson method fails (libOpenGL.so.0: cannot open shared object file) and auto falls back to voxel, saying why. On Debian and Ubuntu: sudo apt-get install libopengl0. macOS needs nothing extra.

Export T7 RNA polymerase (1MSW) for 3D printing with the protein and the
nucleic acid as separate colours

This produces one STL per group (e.g. 1MSW_protein.stl, 1MSW_nucleic.stl). method="auto" (default) picks the cheapest path that works: compact structures (e.g. a GFP barrel) often export already-watertight, so it does a light cleanup rather than Poisson, which can degrade an already-closed surface. Otherwise it falls back to Poisson, then voxel. method="poisson" forces detail-preserving reconstruction (best for bulky chains); it runs in a child process, because PoissonRecon ends the process it runs in when it gives up. method="voxel" is robust for thin cartoons and nucleic acids, and is the one to use for ribbons. In your slicer, load the first STL, then add the others as parts (don't re-centre) and assign a filament per part.

What gets exported (representation):

  • "surface" (default) — each group's molecular surface.

  • "cartoon" — the triangles the group's objects display: cartoon, plus any surface shown. Hidden loops and per-object cartoon types are kept. Sticks and spheres are left out, and the result names what was left out.

  • "displayed" — everything PyMOL draws for the group's objects: the triangles, plus sticks, spheres, lines, ribbon and distance dashes, merged with an exact boolean union. Dashes become one solid rod for the export only. Lines, dashes, ribbon, mesh and dots are sized in pixels unless their *_radius setting is set, so set it (e.g. dash_radius) for a definite size in Å.

In cartoon and displayed modes a group names whole objects; name distance and CGO objects in the group too, e.g. lig=(lig or hbonds).

Coordinates and size. STLs are in PyMOL model coordinates — the numbers get_coords reports — whatever the camera is doing, and your view is left as it was. Groups from one call, or from separate calls at the same scale, line up. mm_per_angstrom (default 1.0) sets the print scale: it is applied to every group about the origin after repair, so parts stay registered, while voxel_pitch stays in Å. The result gives each part's size in mm, the assembled size, and a warning when a part is small enough for a slicer to take it for inches and enlarge it 25.4× (under 9 mm³ in PrusaSlicer, 8 in Bambu Studio and OrcaSlicer; Bambu's 2.8.4 beta does it without asking), with the scale that avoids it.

Separate pieces (bodies). A group can legitimately come out as several pieces: chains whose cartoons don't touch (4hhb's two dimers), or four hemes. bodies="all" (default) keeps every piece and the result says "prints as N separate pieces"; bodies="largest" keeps one and warns when that drops more than 1% of the volume. Enclosed cavities are filled and stray fragments removed either way, and the result counts both.

Voxel growth (undo_voxel_growth, default on). Voxelising grows every surface by about 0.62 voxel; this moves it back, never past half a thin part's thickness. Gaps narrower than about 2.5 × voxel_pitch fuse while voxelising and can't be reopened, so for a designed clearance use voxel_pitch ≤ gap / 2.5, and measure clearances on the exported STLs.

Warnings in the result need action before printing: a cartoon feature thinner than 3 voxels (naming the setting and object), rods or spheres thinner than 0.8 mm at the chosen scale (naming what draws them, e.g. set valence, 0 for double bonds), a dropped piece, a part a slicer would read as inches, and shown residues whose Cα lies outside the printed mesh — typically next to a hidden residue, where loop smoothing pulls the tube away and a part meant to attach there will not touch.

print_ribbon_view — print-ready chunky ribbons

A preset that solves the classic problem of printing cartoons: PyMOL builds each β-strand and loop as a separate mesh segment, so the strand→loop junctions have no connecting geometry and slice into fragile, disconnected pieces. print_ribbon_view configures chunky β-strand arrows and a fat helix, hides the loop cartoon, and adds a continuous backbone spine (<obj>_spine, a cartoon tube that ignores secondary structure and runs unbroken through the whole chain). Exported together the voxel step fuses them into one watertight solid with no junction discontinuity — and the spine doubles as internal rebar for print rigidity. Tune spine_radius for more or less reinforcement.

The style is set on the object and its spine only; other objects and PyMOL's global settings are left alone. Residues that are peptide-linked but have no CA atom, such as GFP's chromophore (CRO), used to break the spine; it is now carried through them on the spine copy, without renaming or renumbering anything in your object (bridge_modified, default on). The result names each residue it bridged, or says why it could not.

print_ribbon_view(obj_name="1ema")
print_export(obj_name="1ema", groups="1ema=(1ema or 1ema_spine)",
             representation="cartoon", method="voxel", voxel_pitch=0.2)

GFP (1EMA) as chunky print-ready ribbons with the reinforcing backbone spine

GFP's β-barrel with the chunky arrows applied. The bulges running along each strand are the spine tube passing through — the internal rebar, visible before it gets fused into one solid on export.

strand_width and strand_thickness (defaults 2.8 and 2.0) are PyMOL's cartoon_rect_length and cartoon_rect_width; PyMOL draws a strand √2 times both, so the defaults give strands about 4.0 × 2.8 Å and a β-barrel's wall closes up. To see into a barrel, thin the strands and take the spine out of their interiors:

print_ribbon_view(obj_name="2b3p", strand_width=2.0, strand_thickness=1.0,
                  spine_in_strands=False)

Measured on GFP (2b3p): the see-through share of the barrel wall goes from 8% to 29%, the spine no longer bulges out of the thin strands (399 ų of it did; 1 ų does now), and the model still exports as one piece. strand_overlap (default 2, at least 2) is how many residues of spine stay at each strand end, where the loops fuse to the strands.

Cryo-EM: occupancy, ensembles and maps

Ten tools for the things a viewer usually throws away. Every one of them exists because a render that looked fine was hiding something, so they share a rule: say what is being shown, and refuse when the picture would be meaningful-looking and wrong.

occupancy_view and altloc_view — is this atom really there

occupancy_view colours and scales by per-atom occupancy q, de-emphasising alternates at q<1 in proportion, so a half-occupied conformer looks half-there. altloc_view shows every alternate location at once, one colour per group, occupancies labelled — PyMOL shows one by default, which quietly turns a statement about heterogeneity into a single structure.

"Occupancy" names two incompatible quantities: the crystallographic q above, and the fraction of imaged particles containing a subunit. A model can be q = 1.0 everywhere while its subunit is present in half the particles. Both are true, they are different questions, and occupancy_view reports only the first — the legend says which.

occupancy_view(obj_name="1ejg")
altloc_view(obj_name="1ejg")

ensemble_spread_view and morph_states — how much do the states disagree

ensemble_spread_view computes per-residue RMS deviation across the states of a multi-model object, pushes it into the B-factor column and putty-scales it, so spread reads as tube width as well as colour. Spread is a description of how much the deposited members differ — not a calibrated uncertainty and not an error bar.

morph_states interpolates between states, and the value in it is the refusal. A morph is only meaningful when every state shares a topology; across independently reconstructed volumes it animates a correspondence nobody established, so the tool checks and declines. (cmd.morph is Incentive-only — on open-source PyMOL the check still runs and reports, and only the interpolation is unavailable.)

restore_bfactors puts back what these views overwrote.

ensemble_spread_view(obj_name="1l2y")
morph_states(obj_name="1l2y", validate_only=True)

qscore_view — per-residue model quality, already published

Colours a model by Q-score parsed straight out of its wwPDB validation report. No network, no map, no computation — the numbers exist, nothing surfaces them. Two things to expect from real data: entries deposited before the September 2023 rollout carry no Q-scores at all, and real Q-scores go negative, so the published 0–1 framing is the intended range rather than the observed one.

qscore_view(obj_name="9c0k", validation_path="9c0k_validation.xml.gz")

map_info — the number nothing displays

Reads an MRC/CCP4 header and reports the geometry, above all voxel size. Only the 1024-byte header is read: the data is never loaded, PyMOL is never touched, nothing goes over the network.

Voxel size is not stored, it is derived, and the derivation has a trap — it is cella/m (the grid sampling), not cella/n (the stored extent). Those differ on any boxed or cropped map, and dividing by n gives a wrong answer of the right order of magnitude. The nominal value is itself only expected to be accurate to ±5–15%, which at 1.2 Å is a systematic stretch of every distance in the model that looks like a slightly strained structure rather than an error. Anisotropy, cropping and axis permutation are all flagged loudly.

load_map and density_view — contouring honestly

load_map parses the header before touching PyMOL, so a malformed file fails without leaving a half-loaded object, confirms the object arrived rather than assuming it, and records provenance — which defaults to unknown and is never inferred. A measured reconstruction, a sharpened map, a network-enhanced map and a decoder output are the same isosurface once drawn, so defaulting to "measured" would assert that somebody observed a generated volume.

density_view draws an isomesh around a selection and states the contour level in both σ and absolute units. PyMOL normalises maps on load, so its levels are in σ; EMDB's author-recommended contour is an absolute map value. They are not interchangeable and the difference is not subtle — EMD-30913 publishes 0.05, which is 3.16 σ; used directly it contours noise.

load_map(path="emd_30913.map.gz", name="emd30913", provenance="measured")
density_view(map_obj="emd30913", selection="chain A", level=0.05, units="absolute")

local_resolution_view — where the map is actually good

Colours a map's isosurface by a local-resolution volume instead of by chain. A single global resolution number misrepresents almost every map: a rigid core at 2.5 Å and a flexible periphery at 5 Å live in the same volume.

Two things make this harder than it looks. The volumes must share a voxel grid — colouring one map by another samples it at the first map's coordinates, so a mismatch in extent, spacing, origin or axis order draws colour from the wrong place and renders smooth, plausible and wrong. The tool refuses and names what differs. And because PyMOL normalises on load, ramp breakpoints given in Å are converted to σ against the resolution map's own header — a different σ scale from the contour level, which comes from the density map's. Every breakpoint is reported in both units.

Local resolution is an estimate: estimators disagree with each other on the same map, and the value at a voxel depends on the window and the mask as much as on the data.

local_resolution_view(map_obj="emd30913", res_obj="emd30913_locres",
                      level=0.05, units="absolute")

Ensembles — motion, and what not to claim from it

Four tools for heterogeneity job output, and one result governs all of them. The Flatiron Institute blind challenge put 41 submissions on the same thyroglobulin data: the motions they recovered resembled both each other and the ground truth, but the simulated truth had three population modes, most submissions found two, and only three of 41 found all three. The one they missed was the middle. So: motion is recoverable, populations are not, and these tools draw the first and decline to draw the second.

load_ensemble reads a job directory — cryoDRGN, 3DVA, RECOVAR, 3DFlex, DynaMight — as ordered frames. They all write the same shape to disk: a directory of maps plus a table of latent coordinates. Frames are sorted naturally, so frame 10 does not land between 1 and 2 and silently reorder the motion. The method is identified from documented markers and never guessed; an unrecognised directory still loads, and simply stays unidentified.

latent_traverse_view contours those frames into a steppable trajectory. It refuses when the method was never identified — that is invariant I2, and the refusal is the point: cryoDRGN's latent density can bear no relation to the truth while 3DVA's frames are linear interpolations no particle occupied, so drawing them identically asserts something for one that holds only for the other. It draws no latent scatter and estimates no density, because the rendering users most want from latent space is the one the evidence says is most often wrong.

It also closes a trap specific to trajectories. PyMOL normalises every map independently on load, so contouring each frame at "1.5 σ" contours each at its own σ — and a traversal is exactly the case where density genuinely changes between frames. That is the signal, and per-frame normalisation rescales it away, leaving frames that look reassuringly alike whatever the ensemble does. So the level is held in absolute terms and converted per frame, and the spread of the resulting σ values is reported, because that spread is the change.

deformation_view is the confident one — per-residue displacement between two states, as colour and as arrows. It refuses states with differing atom counts, since atoms cannot be paired across them. Where a method estimates deformation on independent half-sets, pass that table and the arrows are coloured by the disagreement; without it, every arrow is drawn with identical confidence and they do not have identical confidence, which the report says out loud.

composition_view is occupancy in sense 2 — the fraction of imaged particles containing a part, which is a different quantity from the per-atom q that occupancy_view shows. A model can be q = 1.0 at every atom while the subunit it belongs to is present in half the particles; both are true and they answer different questions. So the fractions come from an explicit table and are never derived from q. The two tools stay separately named forever.

load_ensemble(directory="job042_cryodrgn", name="drgn", method="cryodrgn")
latent_traverse_view(ensemble_name="drgn")
deformation_view(obj_name="1l2y", arrows=True)
composition_view(obj_name="complex", table="chain A=1.0, chain B=0.38")

The name

My best friend in high school once shared an apartment with MC Chris, who voiced MC Pee Pants in Aqua Teen Hunger Force. I'm not saying that was the inspiration for the name of this project, but I'm not denying it either.

Provenance

Built on macOS using the open-source PyMOL available via Homebrew. Started with Antigravity, then Gemini Pro 3.1 until I ran out of tokens, then Claude Code (Sonnet 4.6 thinking). Tested with Claude Code and Gemini CLI. Conservation analysis uses the ColabFold public MMseqs2 API (please don't hammer it).

License

MIT.

Available Tools

135 tools
alignC
DestructiveIdempotent

Aligns one selection to another

Inputs: mobile (required), target, options. Returns: result

alterC
Destructive

Alters atomic properties in a selection

Inputs: selection (required), expression (required). Returns: result

alter_stateC
Destructive

Alters atomic coordinates in a state

Inputs: state (required), selection (required), expression (required). Returns: result

altloc_viewA
Idempotent

Show every altloc group at once, one colour per group, occupancies labelled.

A multiconformer model says "at this site, these discrete alternatives, in these proportions". PyMOL shows one of them by default, which quietly turns a statement about heterogeneity into a single structure.

Inputs: obj_name (required), label. Returns: result

angleB
Idempotent

Measures the angle between three selections and returns it in degrees.

Also draws the measurement as a named angle object.

Inputs: name, selection1, selection2, selection3. Returns: result

asA
Idempotent

Shows one representation while hiding all others for the specified selection

Inputs: representation (required), selection. Returns: result

atom_propertiesA
Destructive

Reads per-atom properties, which nothing else in the tool set can reach.

Object-level facts come back through structure_info and list_chains, and per-residue values through get_sequence or the view presets. But properties that live on individual atoms — occupancy, alternate conformations, per-atom B-factor, formal charge — have no other route: the PyMOL call that exposes them returns an object that cannot cross the bridge.

Use it to check what you are actually looking at: partial occupancy where a sidechain has two conformations, per-atom pLDDT inside a predicted model, or which atoms carry a formal charge before reasoning about electrostatics.

properties is evaluated by PyMOL once per atom, so it accepts any expression valid in iterate — the names above are the useful subset.

Inputs: selection (required), max_atoms, properties. Returns: result

backwardB

Goes back one frame

Inputs: no named parameters. Returns: result

bfactor_viewA
Idempotent

Colors the structure by crystallographic B-factor (temperature factor).

Blue = rigid/ordered (low B), white = intermediate, red = flexible/disordered (high B). Useful for identifying dynamic loops, disordered termini, and rigid structural cores. Shown as cartoon on black background.

Inputs: obj_name (required). Returns: result

bondC
DestructiveIdempotent

Creates a bond between two atoms

Inputs: atom1 (required), atom2 (required), order. Returns: result

cartoonC
Idempotent

Sets the cartoon type for the specified selection

Inputs: item_type (required), selection. Returns: result

cdB
Idempotent

Changes the current directory

Inputs: path (required). Returns: result

centerB
Idempotent

Centers the view on a selection

Inputs: selection. Returns: result

cinematic_viewB
Idempotent

Configures PyMOL for a depth-cued, cinematic look with dramatic lighting.

This view emphasizes volume and scale using deep shadows, fog, and depth-cueing. The core of the structure emerges from a dark background, making massive complexes (like ribosomes or viral capsids) look dramatic and imposing. Protein uses standard coloring but with altered material properties.

Inputs: obj_name (required). Returns: result

clipC
Idempotent

Adjusts the clipping planes

Inputs: mode (required), distance. Returns: result

colorC
Idempotent

Sets the color for a selection.

Inputs: color_name (required), selection. Returns: result

composition_viewA
Idempotent

Colour parts of a structure by the fraction of particles containing them.

This is occupancy in SENSE 2 — compositional. A ligand at 40% here means 40% of imaged complexes had it bound. It is not the per-atom crystallographic occupancy q, and it is never derived from q: a model can be q=1.0 at every atom while the subunit it belongs to is present in half the particles. Both statements are true and they answer different questions, so the table must be supplied and this tool never reads an atom property at all. For sense 1, use occupancy_view.

A selection matching no atoms is refused rather than skipped — PyMOL would accept it silently, colour nothing, and leave a render that looks like a fully-present structure.

Inputs: table (required), obj_name (required), label, transparency. Returns: result

conservation_viewA
Idempotent

Colors the structure by evolutionary conservation using Shannon entropy.

Runs a full pipeline: extracts the protein sequence from the loaded structure, submits it to an MMseqs2 server (ColabFold public API by default) for multiple sequence alignment, computes per-residue Shannon entropy, and maps the conservation scores onto the structure via the B-factor column and spectrum coloring.

Entropy scores are cached in memory by sequence, so changing the scale or re-running on the same protein does not require a repeat API call.

Magenta/blue = highly conserved (low entropy), white = moderate, cyan/green = highly variable (high entropy).

NOTE: The first call makes an external API call and may take 30 seconds to several minutes depending on the server and sequence length. Subsequent calls for the same sequence are instant.

Inputs: obj_name (required), chain, scale, use_env, +3 more. Returns: result

contact_reportA
Read-onlyIdempotent

Lists the residues in contact across two selections, with distances and types.

This is the numeric counterpart to ligand_view and interface_view: instead of drawing the interactions, it reports them — which residue pairs touch, how close they get, and whether the contact is a salt bridge, hydrogen bond, hydrophobic packing or pi-stacking. Use it to answer "what holds this ligand in the pocket" or "which residues form this interface".

Classification uses heavy-atom distance criteria, since crystal structures usually have no hydrogens: salt bridge <= 4.0 A between formally charged sidechain tips, hydrogen bond <= 3.5 A between N/O pairs, hydrophobic <= 4.5 A between C/S pairs, pi-stacking <= 5.5 A between aromatic ring centroids (classified parallel or T-shaped by interplanar angle). A reported hydrogen bond is therefore a donor-acceptor pair with plausible geometry, not one verified against a hydrogen position.

Inputs: selection1 (required), selection2 (required), cutoff, max_pairs, +1 more. Returns: result

count_atomsA
Read-onlyIdempotent

Counts the atoms matching a selection.

Handy for checking a selection expression does what you think before building a scene on top of it — an empty count means the expression is wrong, which is otherwise invisible until the picture comes out blank.

Inputs: selection. Returns: result

createC
Idempotent

Creates a new object from a selection

Inputs: name (required), selection, source_state. Returns: result

deformation_viewA
Idempotent

Colour and arrow a model by how far each residue moved between two states.

This is the well-supported tool in the tier. A 41-submission blind challenge found the molecular motions these methods recover resemble both each other and the ground truth; it was relative populations that fell apart. So the arrows mean: density moved this way. They do not mean: this fraction of particles moved this way, and no population can be read out of them.

Refuses when the two states differ in atom count — atoms cannot be paired across them, so a displacement field would be meaningless rather than approximate.

Where a method estimates deformation on independent half-sets, pass that table and the arrows are coloured by the disagreement. Without it every arrow is drawn with identical confidence and they do not have identical confidence, which the report says rather than leaving the picture to imply otherwise.

Inputs: obj_name (required), arrows, as_putty, end_state, +5 more. Returns: result

deleteC
DestructiveIdempotent

Deletes objects or selections

Inputs: name (required). Returns: result

density_viewA
Idempotent

Draw an isomesh around a selection, stating the contour level in both units.

PyMOL normalises MRC/CCP4 maps on load, so an isomesh level is in sigma. EMDB's author-recommended contour is an absolute map value. They are not interchangeable and the difference is not subtle: EMD-30913 publishes 0.05, which is 3.16 sigma — used directly as a sigma level it contours noise.

So the level is reported in sigma AND absolute units every time, an absolute level is converted before it reaches PyMOL, and EMDB depositions get a pointer to their published contour with the units named. Requires the map to have been loaded through load_map, because the conversion needs the header's mean and RMS.

Inputs: map_obj (required), selection (required), name, carve, +2 more. Returns: result

deselectA
Idempotent

Clears the current selection

Inputs: no named parameters. Returns: result

dihedralA
Idempotent

Measures the dihedral (torsion) angle between four selections, in degrees.

Also draws the measurement as a named dihedral object. Useful for backbone phi/psi angles and ligand torsions.

Inputs: name, selection1, selection2, selection3, +1 more. Returns: result

distanceA
Idempotent

Measures the distance between two selections and returns it in Angstrom.

Also draws the measurement in the viewport as a named distance object. With multi-atom selections PyMOL reports the average over the pairs it found within its default cutoff.

Inputs: name (required), selection1 (required), selection2 (required). Returns: result

drawB
Idempotent

Uses OpenGL renderer (faster but lower quality)

Inputs: width, height. Returns: result

electrostatic_viewA
Idempotent

Colors the molecular surface by approximate residue-based electrostatics.

Surface is colored red→white→blue via a B-factor spectrum. A white cartoon is shown beneath a semi-transparent surface. Organic ligands shown as sticks with yellow carbons.

For a more accurate Poisson-Boltzmann electrostatic surface, use poisson_boltzmann_view (requires APBS and PDB2PQR to be installed).

Inputs: obj_name (required), mode. Returns: result

ensemble_spread_viewA
Idempotent

Colour and thicken a multi-state object by how much its states disagree.

Per-residue RMS deviation across states, pushed into the B-factor column and spectrum-coloured blue (rigid) to red (variable).

Spread is a description of how much the deposited members differ. It is NOT a calibrated uncertainty and NOT an error bar: the number of members and the refinement protocol both shape it, so a wider tube means these models disagree more, not that the true position is less well determined.

Inputs: obj_name (required), as_putty. Returns: result

execute_pymol_commandA
Destructive

Executes a raw PyMOL command string (PyMOL CLI syntax). PREFER the dedicated tools when one exists — show, color, select, distance, ligand_view, interface_view, etc. They have better defaults, do compound setup in one call, and produce cleaner results. Reach for this tool only when no other tool covers what you need (e.g. set ray_shadow, 0, bg_color grey20, multi-statement scripts). It takes PyMOL's command language, as typed at the PyMOL prompt. That language includes Python: a line starting with / and a python ... python end block run as Python inside PyMOL, with full access to the machine, so treat a command from untrusted text (a file, a web page) accordingly.

Returns once the command has finished, with what PyMOL printed (get_view, iterate output, ...). If PyMOL rejects a line — a bad selection, a typo, a Python error — the result is an error naming that line, in PyMOL's words; warnings from lines that still ran are listed. Put each command on its own line: alter, iterate and label take the rest of the line literally, so ; does not start a new command after them.

Inputs: command (required). Returns: result

extractC
Idempotent

Extracts a selection to a new object

Inputs: name (required), selection. Returns: result

fabC

Creates a peptide chain from a sequence

Inputs: sequence (required), options. Returns: result

fetch_alphafoldA
DestructiveIdempotent

Fetches a predicted structure from AlphaFold DB by UniProt accession.

These are predictions, not experimental structures, so the model is coloured by pLDDT confidence rather than the usual style — dark blue is reliable, orange is essentially unmodelled. Read the orange and yellow regions as "probably disordered or wrong", not as flexible loops.

Note that pLDDT rides in the B-factor column, so bfactor_view and putty_view will mis-colour these models (they assume low = rigid, which is backwards for confidence). Use plddt_view instead.

Inputs: uniprot_id (required), replace, fragment, obj_name, +1 more. Returns: result

fetch_structureA
DestructiveIdempotent

Fetches a protein structure from the PDB, or a predicted model from AlphaFold DB.

By default, it attempts to fetch the first biological assembly (multimer), and removes any unrelated chains/states that are not part of the primary multimer.

A UniProt accession or an AF- prefixed identifier routes to AlphaFold DB instead and is coloured by pLDDT confidence — see :func:fetch_alphafold.

Inputs: pdb_code (required), replace, obj_name, multimer_cutoff. Returns: result

forwardB

Advances one frame

Inputs: no named parameters. Returns: result

fragmentC

Loads a molecular fragment

Inputs: name (required). Returns: result

frameC
Idempotent

Sets or queries the current frame

Inputs: frame_number. Returns: result

full_screenB
Idempotent

Toggles fullscreen mode

Inputs: no named parameters. Returns: result

get_sequenceA
Read-onlyIdempotent

Returns the amino-acid sequence of a loaded structure, in FASTA.

Also reports how the sequence positions line up with the residue numbers in the file, and where the chain is broken. Both matter: PDB numbering rarely starts at 1, so "residue 50" in a paper and position 50 in the sequence are usually different residues — and unmodelled loops leave gaps in the structure that the sequence alone does not reveal.

Inputs: obj_name (required), chain. Returns: result

h_addC
DestructiveIdempotent

Adds hydrogens to a selection

Inputs: selection. Returns: result

helpC
Read-onlyIdempotent

Shows help for a command

Inputs: command. Returns: result

h_fillA
DestructiveIdempotent

Fills open valences on the currently picked atom with hydrogens.

Takes no selection: cmd.h_fill operates on PyMOL's editor pick, so it needs an atom picked in the GUI and cannot be aimed from here. Passing it a selection used to land the string in its quiet argument and fail with an integer conversion error. For adding hydrogens to a selection over the bridge, use h_add.

Inputs: no named parameters. Returns: result

hideB
Idempotent

Hides a graphical representation for a given selection.

Inputs: representation (required), selection. Returns: result

hydrophobic_surface_viewB
Idempotent

Colors the molecular surface by amino acid hydrophobicity.

Orange = hydrophobic (ILE, VAL, LEU, PHE, MET, ALA, TRP, PRO), white = polar (SER, THR, CYS, TYR, ASN, GLN, GLY), sky blue = positively charged (ARG, LYS, HIS), salmon = negatively charged (ASP, GLU). A white cartoon is shown beneath a semi-transparent surface. Organic ligands shown as sticks with yellow carbons.

Inputs: obj_name (required). Returns: result

interface_reportA
Idempotent

Measures how large a protein-protein interface is, and which residues form it.

Reports buried surface area — the standard measure of how much of a complex is actually complex — by comparing each chain's solvent-accessible area free and bound. Also ranks the residues by how much surface each buries, and breaks the interface down by residue chemistry.

Interpretation: a per-side area under ~400 A^2 is usually a crystal packing contact rather than a biological interface, while over ~1000 A^2 indicates a substantial, likely specific association. These are guides from PDB-wide surveys, not a verdict — small biological interfaces exist.

For the interactions themselves — which pairs hydrogen bond, which form salt bridges — use contact_report on the same two chains.

Inputs: chain_a (required), chain_b (required), obj_name (required), max_residues. Returns: result

interface_viewA
Idempotent

Highlights the protein-protein binding interface between two chains.

Chain A shown in marine blue, chain B in salmon. Interface residues (within 4Å of the partner chain) shown as a solid surface patch with sticks. H-bonds across the interface drawn as yellow dashes.

Inputs: chain_a (required), chain_b (required), obj_name (required). Returns: result

intra_fitB
DestructiveIdempotent

Fits all states within an object

Inputs: selection (required). Returns: result

intra_rmsB
Read-onlyIdempotent

Calculates RMSD between states within an object

Inputs: selection (required). Returns: result

isomeshC
Idempotent

Creates a mesh isosurface

Inputs: name (required), level (required), map_object (required), selection. Returns: result

isosurfaceC
Idempotent

Creates a solid isosurface

Inputs: name (required), level (required), map_object (required), selection. Returns: result

labelC
Idempotent

Adds labels to atoms in the selection

Inputs: selection (required), expression. Returns: result

latent_traverse_viewA
Idempotent

Step through an ensemble's conformations as a contoured trajectory.

Refuses when the generating method was never identified. That is SPEC invariant I2 working, not a failure: cryoDRGN's latent density can bear no relation to the truth while 3DVA's frames are linear interpolations no particle occupied, and rendering both the same way asserts something for one that holds only for the other.

The contour is held at a constant ABSOLUTE value and converted to each frame's own sigma. PyMOL normalises every map independently on load, so a fixed sigma level would contour each frame at its own scale and flatten away the density change the traversal exists to show.

No latent scatter and no density estimate are drawn, deliberately. In a 41-submission blind challenge most methods missed a genuinely present middle state, so an empty region of latent space is a region of unknown occupancy — never evidence that a conformation does not occur.

Inputs: ensemble_name (required), name, color, level, +2 more. Returns: result

ligand_viewA
Idempotent

Shows a binding-site view focused on a ligand.

Protein rendered as a semi-transparent cartoon. Pocket residues (within 5Å of the ligand) shown as sticks with element coloring and lightblue carbons. Ligand shown as thick sticks with yellow carbons. H-bonds drawn as yellow dashes. Pocket residues labeled. View zooms to the ligand.

Inputs: obj_name (required), ligand_resn (required). Returns: result

list_chainsA
Read-onlyIdempotent

Lists the chain IDs present in an object (or in all objects).

Useful before calling :func:interface_view, :func:conservation_view or any tool that needs a specific chain ID.

Inputs: obj_name. Returns: result

list_ligandsA
Read-onlyIdempotent

Lists the small-molecule (organic) ligand residue names in an object.

Call this before :func:ligand_view, :func:pocket_view, or :func:pharmacophore_view when you don't already know the ligand's residue name (three characters, or five for newer CCD codes).

Inputs: obj_name (required). Returns: result

list_objectsA
Read-onlyIdempotent

Lists all loaded PyMOL objects.

Call this when you don't know what's currently in the session — for example before composing a selection or running a view tool that needs an obj_name.

Inputs: no named parameters. Returns: result

load_ensembleA
DestructiveIdempotent

Load a cryo-EM heterogeneity job's volumes in trajectory order.

Every method in this space writes the same thing: a directory of maps plus a table of latent coordinates. This reads them in trajectory order — naturally, so frame 10 does not sort between 1 and 2 and silently reorder the motion.

The generating method is identified from documented on-disk markers and is never guessed. A directory that matches nothing loads its volumes fine and stays unidentified, which makes latent views refuse to render: an unlabelled latent plot is what SPEC invariant I2 forbids, because each method's caveat is different and they are not interchangeable. Pass method= if you know.

Provenance defaults to "generated" rather than "unknown" — nothing observed a decoder's output — and the report says it declared that and on what evidence.

Inputs: directory (required), name, method, provenance, +2 more. Returns: result

load_mapA
DestructiveIdempotent

Load a volume into PyMOL, recording where it came from and reporting its geometry.

The header is parsed before PyMOL is touched, so a malformed file fails without leaving a half-loaded object in the session, and the load is confirmed rather than assumed.

Provenance defaults to unknown and is never guessed. A measured reconstruction, a sharpened map, a network-enhanced map and a decoder output all render identically once they are an isosurface, so defaulting to "measured" would quietly assert that somebody observed a generated volume. The report shows what the file says about itself — MRC labels, filename tokens — so the caller can declare it.

Inputs: path (required), name, provenance. Returns: result

load_sessionA
DestructiveIdempotent

Restores a PyMOL session from a .pse file.

By default this replaces everything currently loaded, exactly as opening the file in PyMOL would. Set merge=True to add its objects to the current session instead, which is how you get two saved scenes side by side — though note that objects with the same name will collide.

Inputs: filename (required), merge. Returns: result

load_structureA
DestructiveIdempotent

Loads a structure from a local file path and applies the BFS multimer heuristic.

Inputs: obj_name (required), file_path (required), replace, multimer_cutoff. Returns: result

local_resolution_viewA
Idempotent

Colour a map's isosurface by a local-resolution volume instead of by chain.

A single global resolution number misrepresents almost every map: a rigid core at 2.5 Å and a flexible periphery at 5 Å live in the same volume, and one isosurface invites the reader to believe all of it is equally real.

Two things make this harder than it looks, and both are handled. The volumes must share a voxel grid — colouring one map by another samples it at the first map's coordinates, so a mismatch in extent, spacing, origin or axis order draws colour from the wrong place and renders smooth, plausible and wrong. This tool refuses and names what differs. And PyMOL normalises maps on load, so ramp breakpoints given in Ångström must be converted to sigma against the RESOLUTION map's own header — a different sigma scale from the contour level, which comes from the density map's. Every breakpoint is reported in both units.

Local resolution is an estimate. Estimators disagree with each other on the same map, and the value at a voxel depends on the window and the mask as much as on the data.

Inputs: map_obj (required), res_obj (required), name, carve, +7 more. Returns: result

lsC
Read-onlyIdempotent

Lists files in the current directory

Inputs: path. Returns: result

map_infoA
Read-onlyIdempotent

Report an MRC/CCP4 map's geometry, above all its voxel size.

Reads only the 1024-byte header — the map data is never loaded, PyMOL is never touched, and nothing goes over the network.

Voxel size is not stored in the header, it is derived, and the derivation has a trap: it is cella/m (the grid sampling), not cella/n (the stored extent). Those differ on any boxed or cropped map, and dividing by n gives a wrong answer of the right order of magnitude. The nominal value is only expected to be accurate to ±5–15% in the first place, which at 1.2 Å is a systematic stretch of every distance in the model. Anisotropy, cropping and axis permutation are all flagged loudly.

Inputs: path (required). Returns: result

morph_statesA
DestructiveIdempotent

Interpolate between states, refusing when interpolation is ill-posed.

The value here is the refusal, not the interpolation — PyMOL morphs natively. A morph is only meaningful when every state shares a topology, so that atom i in state 1 is the same atom as atom i in state 2. That holds for a deformation-model ensemble (3DFlex, DynaMight). It does not hold for volumes reconstructed and modelled independently, and a morph across those animates a correspondence nobody established.

Note that cmd.morph is Incentive-only. On open-source PyMOL the topology check still runs and reports; only the interpolation is unavailable.

Inputs: obj_name (required), name, steps, validate_only. Returns: result

moveB
Destructive

Moves the camera along an axis

Inputs: axis (required), distance. Returns: result

mplayB
Idempotent

Starts playing the movie

Inputs: no named parameters. Returns: result

mpngB
DestructiveIdempotent

Saves a series of PNG images for movie frames

Inputs: prefix (required). Returns: result

msetC
Idempotent

Defines a sequence of states for movie playback

Inputs: specification (required). Returns: result

mstopB
Idempotent

Stops the movie

Inputs: no named parameters. Returns: result

mutation_viewA
Idempotent

Highlights mutated residues on the protein structure.

Given a comma-separated list of mutations in standard notation (e.g. "A123G,V45L,T200S"), the mutated residues are shown as magenta sticks and labeled. Nearby residues (within 4 Å) are shown as thin grey sticks for packing context. The protein backbone is shown as a grey cartoon. Organic ligands are shown as yellow sticks.

Mutation format: <wildtype_aa><mutant_aa>, e.g. "A123G" (Ala→Gly at position 123). Chain can optionally be prefixed: "A:A123G".

Inputs: obj_name (required), mutations (required). Returns: result

occupancy_viewA
Idempotent

Colour and scale a structure by per-atom crystallographic occupancy (q).

Alternates at q<1 are visually de-emphasised in proportion, so a half-occupied conformer looks half-there instead of looking like a confident model.

This is occupancy in the crystallographic sense — the fraction of unit cells in which an atom sits at this position. It is NOT the fraction of imaged particles containing a subunit; a model can be q=1.0 everywhere while the subunit is present in half the particles. Both are true and they are different questions, so this tool never reports the other sense.

Inputs: obj_name (required), preserve_bfactors. Returns: result

orientC
Idempotent

Orients the view to align with principal axes of the selection

Inputs: selection. Returns: result

pharmacophore_viewA
Idempotent

Colors a ligand by pharmacophore feature type.

The ligand is shown as sticks color-coded by pharmacophore property: violet=ring/aromatic carbon, yellow=aliphatic carbon, skyblue=nitrogen (H-bond donor/acceptor), salmon=oxygen (H-bond acceptor), gold=sulfur, palegreen=halogen (F/Cl/Br/I). H-bonds to protein are shown as cyan dashes. Interacting residue sidechains are shown as element-colored sticks with CA labels. The pocket is shown as a semi-transparent grey surface for cavity context. The protein backbone is shown as a thin grey cartoon.

Inputs: resn (required), obj_name (required). Returns: result

plddt_viewA
Idempotent

Colors an AlphaFold model by pLDDT confidence, using the official palette.

Dark blue = very high (>90), light blue = confident (70-90), yellow = low (50-70), orange = very low (<50). Regions below 70 are usually intrinsically disordered or simply unreliable — read them as "the model does not know", not as a flexible loop.

AlphaFold stores pLDDT in the B-factor column, which is why bfactor_view and putty_view get these models backwards: they assume low = rigid, whereas low pLDDT = low confidence. Use this instead for predicted models.

Inputs: obj_name (required). Returns: result

pngC
DestructiveIdempotent

Saves a PNG image

Inputs: filename (required), options. Returns: result

pocket_viewA
Idempotent

Visualizes the binding pocket cavity around a ligand as a colored surface.

The pocket (all residues within 5 Å of the ligand) is shown as a semi-transparent surface colored by chemical character: orange=hydrophobic, white=polar, skyblue=positive, salmon=negative. Pocket residue sidechains are shown as sticks. The ligand is shown as yellow sticks. H-bonds between the ligand and pocket are drawn as cyan dashes. The protein backbone is shown as a thin grey cartoon for context.

Inputs: resn (required), obj_name (required). Returns: result

pointillist_viewA
Idempotent

Renders the structure as an artistic, abstract pointillist/starfield cloud.

The continuous surface is replaced by thousands of individual dots representing the solvent-accessible surface, resembling a galaxy or pointillist painting. The protein backbone is hidden to emphasize the scattered volume. Ligands are shown as bright yellow spheres (stars) embedded in the cloud.

Inputs: obj_name (required). Returns: result

poisson_boltzmann_viewA
Idempotent

Colors the molecular surface by true Poisson-Boltzmann electrostatic potential.

Runs PDB2PQR (AMBER force field, pH 7.0) then APBS to compute the full electrostatic potential map. Surface is colored red→white→blue over the range ±20 kT/e. A white cartoon is shown beneath a semi-transparent surface. Organic ligands shown as sticks with yellow carbons.

Requires APBS and PDB2PQR to be installed on the system: brew install brewsci/bio/apbs pip install pdb2pqr

Inputs: obj_name (required). Returns: result

putty_viewA
Idempotent

Visualizes protein flexibility using a putty (tube-width) representation.

The cartoon tube radius scales linearly with crystallographic B-factor: thin/blue = rigid/ordered regions, thick/red = flexible/disordered regions. A 70%-transparent surface is shown, also colored by B-factor. Organic ligands are shown as sticks with yellow carbons. Black background.

Inputs: obj_name (required). Returns: result

pwdA
Read-onlyIdempotent

Prints the current directory

Inputs: no named parameters. Returns: result

qscore_viewA
Idempotent

Colour a model by per-residue Q-score parsed from its wwPDB validation report.

No network, no map, and no computation — Q-scores are already published, and this reads the numbers rather than re-deriving them.

Two things to expect from real data: entries deposited before the September 2023 validation rollout carry no Q-scores at all, which is the common case for older EM structures; and real Q-scores go negative, so the published 0–1 framing is the intended range and not the observed one.

Inputs: obj_name (required), validation_path (required), preserve_bfactors. Returns: result

rayC
Idempotent

Performs ray-tracing

Inputs: width, height. Returns: result

rebuildC
Idempotent

Regenerates all displayed geometry

Inputs: selection. Returns: result

refreshC
Idempotent

Refreshes the display

Inputs: no named parameters. Returns: result

removeA
DestructiveIdempotent

Permanently removes the atoms matching the selection. This deletes atoms; it does not just hide them. To hide instead, use :func:hide.

Inputs: selection (required). Returns: result

renderA
DestructiveIdempotent

Renders the current scene and returns the image, so you can see it.

Use this instead of calling ray and png separately — those leave you holding a filename you cannot look at. Call this after setting up a view to check what it actually looks like, and iterate.

Every render is ray-traced, which takes seconds to minutes on a large assembly. ray_trace=False is accepted but ignored: PyMOL's fast unshaded frame grab needs its GUI thread, which this plugin does not run on, so that path wrote blank images. Render smaller to render faster.

Inputs: width, height, filename, ray_trace.

resetC
DestructiveIdempotent

Resets the view, optionally resetting an object's matrix

Inputs: obj. Returns: result

restore_bfactorsA
DestructiveIdempotent

Restore the B-factors a Wiggles view overwrote.

occupancy_view, ensemble_spread_view and qscore_view all push their values into the B-factor column so PyMOL can spectrum-colour by them. The originals are stashed first; this puts them back in one pass.

Inputs: obj_name (required). Returns: result

rms_curA
Read-onlyIdempotent

Measures RMSD between two selections without moving anything.

Use this when the structures are already superposed, or when you want to know how far apart they are as currently positioned. Compare with align and super, which move the mobile structure to minimise RMSD before reporting it, and with superposition_view, which shows where the difference is rather than summarising it as one number.

Requires the two selections to have matching atom counts.

Inputs: mobile (required), target (required). Returns: result

rockC
Idempotent

Toggles a rocking animation

Inputs: no named parameters. Returns: result

sasaA
Read-onlyIdempotent

Measures solvent-accessible surface area, in square Angstrom.

Reports the SASA of selection in the context of the object it belongs to — so a chain measured inside a complex is already partly occluded by its partner. To get the free (unbound) area, copy the chain to its own object first with create, or use interface_report, which does the bound/free bookkeeping for you.

Accuracy depends on PyMOL's dot_solvent (0 = molecular surface, 1 = solvent-accessible) and dot_density settings.

Inputs: state, selection. Returns: result

saveC
DestructiveIdempotent

Saves data to a file

Inputs: filename (required), state, selection. Returns: result

save_sessionA
DestructiveIdempotent

Saves the entire PyMOL session to a .pse file.

A session captures everything — every object, selection, representation, colour, scene and the camera — so the work can be reopened exactly as it was. Use this before experimenting with a scene you would not want to rebuild, and to hand a finished figure to a colleague.

Unlike save, which writes bare coordinates, this preserves the whole visual state.

Inputs: filename (required). Returns: result

sceneC
Idempotent

Manages scenes for later recall

Inputs: key (required), action. Returns: result

scene_orderC
Idempotent

Sets the order of scenes

Inputs: scene_list (required). Returns: result

sculpt_activateC
Idempotent

Activates sculpting mode for an object

Inputs: obj (required). Returns: result

sculpt_deactivateB
Idempotent

Deactivates sculpting mode for an object

Inputs: obj (required). Returns: result

sculpt_iterateC
Destructive

Performs sculpting iterations

Inputs: obj (required), state, iterations. Returns: result

selectA
Idempotent

Creates (or replaces) a named selection for later reuse.

Inputs: name (required), selection (required). Returns: result

setA
Idempotent

Sets a PyMOL setting to a specified value.

Settings live at a level — global, object, object-state, atom or bond — and PyMOL ignores a value stored below its setting's level. cartoon_tube_radius on a residue range is stored per atom and never drawn; ray_shadow on an object is never read. PyMOL only warns about that, so this reports it as an error, with what to do instead.

Inputs: value (required), setting (required), selection. Returns: result

set_symmetryC
DestructiveIdempotent

Sets symmetry parameters for an object

Inputs: a (required), b (required), c (required), beta (required), +3 more. Returns: result

showC
Idempotent

Shows a graphical representation for a given selection.

Inputs: representation (required), selection. Returns: result

spectrumC
Idempotent

Colors selection in a spectrum

Inputs: expression (required), palette, selection. Returns: result

spheroidC
Idempotent

Displays atoms as smooth spheres

Inputs: obj. Returns: result

structure_infoA
Read-onlyIdempotent

Summarises what a loaded structure actually is, in one call.

Answers the question you ask before any analysis: what protein is this, how was it determined, at what resolution, what is in the file. Combines what PyMOL knows (chains, residue and atom counts, ligands, symmetry) with entry metadata from the RCSB (title, method, resolution, release date, source organism).

Metadata lookup is best-effort — it is skipped silently if the object is not named after a PDB entry, or the API is unreachable.

Inputs: obj_name (required), pdb_id. Returns: result

superC
DestructiveIdempotent

Superimposes one selection onto another

Inputs: mobile (required), target, options. Returns: result

superposition_viewA
Idempotent

Superposes two structures and colors the mobile one by per-residue shift.

An RMSD alone tells you that something moved, not where. This superposes mobile onto target, measures how far each residue's CA ended up from its counterpart, and colors the mobile structure blue (unchanged) through white to red (most shifted). The target is left as a grey reference cartoon.

Best on two states of the same protein — apo vs holo, open vs closed, a mutant against wild type. Residues are paired by chain and residue number, falling back to residue number alone when the two use different chain IDs.

Both structures have to be loaded first, and fetch_structure clears the session by default — so fetch the second one with replace=False or it will replace the first. If either entry is a multimer, compare single chains (create one object per chain): superposing one dimer onto another fits the assembly rather than the fold, which inflates the RMSD dramatically. 4AKE against 1AKE gives 18.5 A as deposited dimers and 2.1 A chain-to-chain.

Inputs: mobile (required), target (required), method, max_deviation. Returns: result

symexpC

Generates symmetry-related copies

Inputs: prefix (required), obj_name (required), selection (required), segi, +1 more. Returns: result

systemC
Destructive

Executes a system command

Inputs: command (required). Returns: result

textbook_viewA
Idempotent

Configures PyMOL for a crisp, cel-shaded illustrative look ("Textbook Illustration").

This view transforms the structure into a bold, 2D illustrative style with sharp black outlines, ideal for presentations or textbook-style diagrams. It hides the interior complexities, showing a solid white cartoon and surface with heavy black edge contours. Ligands are styled similarly as opaque white sticks with outlines.

Inputs: obj_name (required). Returns: result

turnB

Rotates the camera around an axis

Inputs: axis (required), angle. Returns: result

turntableA
DestructiveIdempotent

Renders a full 360° rotation as a numbered PNG sequence.

Spins the camera around the vertical axis in equal steps and writes one frame per step, ready to assemble into a GIF or MP4 (e.g. ffmpeg -i turntable_0000.png out.mp4).

Every frame is ray-traced, which is slow — 36 frames of a large assembly can take an hour, so start with few frames and a small width/height. The unshaded OpenGL renderer would be far faster but does not work over this bridge (it needs PyMOL's GUI thread), and silently produced blank frames until this was found.

Inputs: width, frames, height, prefix, +3 more. Returns: result

unbondB
DestructiveIdempotent

Removes a bond between two atoms

Inputs: atom1 (required), atom2 (required). Returns: result

util_cbabC
Idempotent

Colors by atom, slate carbons (Color By Atom, slateBLue)

Inputs: selection. Returns: result

util_cbacC
Idempotent

Colors by atom, cyan carbons (Color By Atom, Cyan)

Inputs: selection. Returns: result

util_cbagC
Idempotent

Colors by atom, green carbons (Color By Atom, Green)

Inputs: selection. Returns: result

util_cbakC
Idempotent

Colors by atom, pink carbons (Color By Atom, pinK)

Inputs: selection. Returns: result

util_cbamC
Idempotent

Colors by atom, magenta carbons (Color By Atom, Magenta)

Inputs: selection. Returns: result

util_cbaoB
Idempotent

Colors by atom, orange carbons (Color By Atom, Orange)

Inputs: selection. Returns: result

util_cbapB
Idempotent

Colors by atom, purple carbons (Color By Atom, Purple)

Inputs: selection. Returns: result

util_cbasC
Idempotent

Colors by atom, salmon carbons (Color By Atom, Salmon)

Inputs: selection. Returns: result

util_cbawC
Idempotent

Colors by atom, white carbons (Color By Atom, White)

Inputs: selection. Returns: result

util_cbayB
Idempotent

Colors by atom, yellow carbons (Color By Atom, Yellow)

Inputs: selection. Returns: result

util_cbcC
Idempotent

Colors by chain (Color By Chain)

Inputs: selection. Returns: result

util_chainbowC
Idempotent

Colors chains in rainbow gradient (CHAINs in rainBOW)

Inputs: selection. Returns: result

util_color_by_elementC
Idempotent

Colors atoms by their element

Inputs: selection. Returns: result

util_color_secondaryC
Idempotent

Colors secondary structure elements

Inputs: selection. Returns: result

util_rainbowC
Idempotent

Colors residues in rainbow from N to C terminus

Inputs: selection. Returns: result

util_ssC
Idempotent

Colors by secondary structure

Inputs: selection. Returns: result

viewportC
Idempotent

Sets the viewport size

Inputs: width (required), height (required). Returns: result

zoomC
Idempotent

Zooms the view on a selection

Inputs: buffer, selection. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 135 tools

    Disambiguation2/5

    There are several near-duplicate clusters: ten `util_cb*` tools all do "color by atom with a different carbon color," and `util_rainbow`/`util_chainbow`/`util_ss`/`util_color_by_element`/`util_color_secondary`/`spectrum`/`color` all recolor structures. Rendering/export tools (`ray`, `render`, `draw`, `png`, `mpng`, `turntable`, `print_export`, `print_ribbon_view`) and representation tools (`show`, `as`, `spheroid`, `isomesh`, `isosurface`, `cartoon`) overlap enough that an agent must read long descriptions to choose. Individual descriptions are excellent and often explicitly cross-reference siblings, which rescues some but not all of the boundaries.

    Naming Consistency2/5

    At least four conventions coexist: bare PyMOL command names (`as`, `set`, `show`, `hide`, `color`, `turn`, `scene`, `frame`, `clip`), an `util_` prefix group with ad-hoc suffixes (`util_cbam`, `util_cbak`, `util_cbc`, `util_chainbow`), a `_view` suffix group (`ligand_view`, `putty_view`, `qscore_view`), and a `*_report`/`*_info` group. Several names are single vague words (`as`, `set`, `do`-like `draw`, `fab`, `mset`, `mpng`) that give no hint of scope.

    Tool Count1/5

    135 tools is an order of magnitude beyond what an agent can hold in context for a single server, and many are trivially redundant (ten carbon-color variants, three isosurface/mesh tools, four render paths). The surface should be compressed into parameterized tools (e.g. one `color_by_atom(carbon=...)`, one `render(kind=...)`).

    Completeness4/5

    The domain (scripting PyMOL) is covered practically end to end: loading/session, selections, representations, measurements, analysis reports, views/presets, movies, scenes, ray-tracing, and 3D-print export. `execute_pymol_command` provides an explicit escape hatch for whatever the curated set misses. Minor gaps (e.g. no dedicated undo/history, some settings only reachable via `set`/`execute_pymol_command`) are workable.

    Maintenance

    ActivityMaintained
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      A Model Context Protocol server that enhances language models with protein structure analysis capabilities, enabling detailed active site analysis and disease-related protein searches through established protein databases.
      2
      20
      ISC
    • A
      license
      B
      quality
      D
      maintenance
      A comprehensive Model Context Protocol server that enables advanced PubMed literature search, citation formatting, and research analysis through natural language interactions.
      12
      10
      MIT
    • A
      license
      Not graded
      quality
      F
      maintenance
      A Model Context Protocol server that enables AI assistants to interact with LAMMPS for molecular dynamics simulations through natural language commands.
      13
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      A Model Context Protocol server providing programmatic access to 3D protein structural data from RCSB PDB, PDBe, and UniProt, enabling search, retrieval, comparison, and analysis of protein structures.
      466 npm
      6
      Apache 2.0