> ## Documentation Index
> Fetch the complete documentation index at: https://docs.biohub.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Biohub MCP mutation scoring tools

> Score named amino-acid substitutions or scan a protein for mutation tolerance with ESMC through Biohub MCP.

The [ESMC](https://docs.biohub.ai/learn/tutorials/esmc) model learns protein structure and function from sequence, so it can estimate how likely each amino acid is at every position and predict which mutations a protein is likely to tolerate. To find out how a protein responds to mutations or amino-acid substitutions, prompt your AI agent, and the Biohub MCP scores them with ESMC to return predicted scores.

> [!NOTE]
>
> Calls are billed to the Biohub account you are signed in with.

## What you can ask

Ask in your own words, and your AI agent picks the tool for your task.
For example:

Use ESMC to score the S65T and Y66H substitutions in GFP and explain what the scores mean.

Use ESMC to score the S65T and Y66H substitutions in GFP and explain what the scores mean.

Scan PETase from Ideonella sakaiensis for mutation tolerance with ESMC and list the most constrained and most tolerant positions.

Scan PETase from Ideonella sakaiensis for mutation tolerance with ESMC and list the most constrained and most tolerant positions.

You can paste a sequence instead of a name in either prompt.

> [!TIP]
>
> Positions count from 1 along the sequence that is scored.
> When you name a protein, that is its UniProt sequence, which can number residues differently from a paper, for example when the paper leaves out a signal peptide.
> If the numbering doesn't match, `expected_wild_type` makes the call fail instead of scoring the wrong residue.

## Which tools your AI agent uses

| When you ask to | Your assistant uses |
| - | - |
| Score a protein you named | [`esm_atlas_search_uniprot`](https://docs.biohub.ai/biohub-mcp/esm-atlas-tools#search-uniprot) first, to get its sequence. Free. |
| Score substitutions you already have, such as S65T or a list from a paper | [`esmc_score_mutations`](#score-substitutions), which scores each one. For a 300-residue protein, each position costs 0.03 credits, and one call covers up to 8 positions. |
| Find where a protein tolerates change, before you have picked substitutions | [`esmc_scan_mutation_tolerance`](#scan-mutation-tolerance), which ranks the positions. For a 300-residue protein, scanning every position costs 9 credits. |

## How scoring works

ESMC hides the residue at one position and predicts how likely each amino acid is there.
A substitution's score is ln P(new residue) - ln P(original residue) at that hidden position:

* A positive score means ESMC finds the new residue more likely than the original.
* A negative score means ESMC prefers the original.
* Each substitution is scored on its own on the original sequence, not combined with the others.

A scan scores all 20 amino acids at every position it covers, then ranks the positions by how constrained they are:

* `entropy_bits`, the default, measures how spread out ESMC's prediction is at the position.
  Low entropy means few residues fit, so the position is constrained.
* `negative_substitution_fraction` is the share of the 19 other amino acids that score below the original.
  A high fraction means the position is constrained.

These scores are predictions, not measured fitness, stability, or activity.
To run the same scoring using, see the [mutation scoring tutorial](https://docs.biohub.ai/learn/tutorials/esmc/mutation-scoring.md).

## Costs

Each position costs the protein's length divided by 10,000 credits, whichever ESMC model you choose.

| | 56 residues, such as GB1 | 300 residues | 1,000 residues |
| - | - | - | - |
| Score substitutions at 1 position | 0.0056 | 0.03 | 0.1 |
| Score substitutions at 8 positions, the most per call | 0.045 | 0.24 | 0.8 |
| Largest scan | 0.31 for all 56 positions | 9 for all 300 positions | 20 for 200 positions |

Scoring several substitutions at the same position costs the same as scoring one.
A scan never costs more than 20 credits.

> [!WARNING]
>
> Every call starts new work and bills again, even for the same input.
> If a call returns `indeterminate`, it may have been billed already, so don't retry it automatically.

## Score substitutions

`esmc_score_mutations` takes your protein sequence and any desired amino-acid substitutes and returns a score for each substitution.

### Inputs

| Input | Description |
| - | - |
| `sequence` (required) | One protein chain of 1 to 2,046 residues in one-letter codes. Whitespace is removed, and `\|` and `:` are refused. |
| `mutations` (required) | 1 to 64 substitutions at up to 8 different positions, as described below. |
| `model_id` | `esmc-300m-2024-12`, `esmc-600m-2024-12`, or `esmc-6b-2024-12`, with about 300 million, 600 million, and 6 billion parameters. Defaults to `esmc-600m-2024-12`. |

Each entry in `mutations` names one substitution:

| Field | Description |
| - | - |
| `position` | Position in the sequence, counting from 1. |
| `expected_wild_type` | The residue you expect at that position. If the sequence has a different one, the call fails, which catches numbering mistakes. |
| `alternate` | The new residue. |

Residues are one of the 20 standard amino acids, as uppercase one-letter codes.
This example scores W43F and W43A in GB1:

```json theme={null}
{
  "sequence": "MTYKLILNGKTLKGETTTEAVDAATAEKVFKQYANDNGVDGEWTYDDATKTFTVTE",
  "mutations": [
    { "position": 43, "expected_wild_type": "W", "alternate": "F" },
    { "position": 43, "expected_wild_type": "W", "alternate": "A" }
  ]
}
```

### Results

| Field | Description |
| - | - |
| `scores` | One row per substitution, in the order you gave them: `position`, `expected_wild_type`, `alternate`, `score`, and `wild_type_log_probability`. |
| `usage` | `logits_calls`, the ESMC calls made, and the `credits` Biohub billed. |
| `model_id` | The ESMC model that scored. |

Both substitutions in the example share one position, so they took one ESMC call:

```json theme={null}
{
  "model_id": "esmc-600m-2024-12",
  "scores": [
    { "position": 43, "expected_wild_type": "W", "alternate": "F", "score": 0.25, "wild_type_log_probability": -3.1464 },
    { "position": 43, "expected_wild_type": "W", "alternate": "A", "score": 0.75, "wild_type_log_probability": -3.1464 }
  ],
  "usage": { "credits": 0.0056, "logits_calls": 1 }
}
```

## Scan mutation tolerance

`esmc_scan_mutation_tolerance` finds the positions where a protein is most and least tolerant to change.
It returns the top positions of each kind with their strongest substitutions, not the full matrix of scores.

### Inputs

| Input | Description |
| - | - |
| `sequence` (required) | One protein chain of 1 to 2,046 residues, as for `esmc_score_mutations`. |
| `positions` | `"all"`, the default, a list of positions such as `[12, 43, 51]`, or a window such as `{ "start": 10, "end": 40 }` that includes both ends. |
| `model_id` | `esmc-300m-2024-12`, `esmc-600m-2024-12`, or `esmc-6b-2024-12`. Unlike scoring, the scan defaults to the largest model, `esmc-6b-2024-12`. |
| `ranking_metric` | `entropy_bits`, the default, or `negative_substitution_fraction`, as [How scoring works](#how-scoring-works) describes. |

One scan covers at most 400 positions, and at most 200,000 divided by the protein's length.
For a longer request, the tool returns `invalid_input` with a window that fits; it never shortens the scan for you.

### Results

| Field | Description |
| - | - |
| `execution_status` | `done`, or `partial` when the time limit or a rate limit stopped the scan early. |
| `most_constrained` | Up to 10 positions, most constrained first. |
| `most_tolerant` | Up to 10 positions, most tolerant first. When fewer than 20 positions are scanned, the two lists can share positions. |
| `coverage` | How many positions were `requested` and `scanned`, the `skipped` positions whose residue isn't one of the 20 standard amino acids, and the `unscanned` positions a partial scan didn't reach. |
| `usage` | `logits_calls` and the `credits` Biohub billed, for finished positions only. |
| `model_id` | The ESMC model that scanned. |
| `warnings` | Why positions were skipped or the scan stopped early. |

Each position in `most_constrained` and `most_tolerant` has:

| Field | Description |
| - | - |
| `position` | Position in the sequence, counting from 1. |
| `wild_type` | The residue the sequence has there. |
| `entropy_bits` | Entropy of ESMC's prediction at the position. Low means constrained. |
| `negative_substitution_fraction` | Share of the 19 other amino acids that score below the original. High means constrained. |
| `top_substitutions` | The three highest-scoring substitutions, each with its `alternate` and `score`. |

For example, a full scan of GB1 with the default model ranked Asp46 as most constrained, with every substitution scoring below the original, and Gly38 as most tolerant.
It made 56 ESMC calls for 0.31 credits.

### Partial scans

A scan that reaches the time limit, or a rate limit after some positions finished, returns `partial` and bills only the finished positions. To finish it, scan again with `coverage.unscanned` as `positions`. Each scan ranks only the positions it covers, so compare the two results to get the full picture.

## Limits

| Limit | Value | When exceeded |
| - | - | - |
| Protein length | 1 to 2,046 residues | `invalid_input` |
| Substitutions per call | 64, at up to 8 positions | `invalid_input` |
| Positions per scan | 400, and at most 200,000 divided by the length | `invalid_input`, with a window that fits |
| Cost of one scan | 20 credits | Can't be exceeded, because of the position limit |

## Errors

| Code | What to do |
| - | - |
| `invalid_input` | Fix the sequence, positions, or substitutions the message names. A wrong `expected_wild_type` usually means the numbering is off by one. Nothing was billed. |
| `rate_limited` | Your account reached a Biohub limit or ran out of credits. Wait at least `retry_after_seconds` when it is given. |
| `restricted` | Biohub refused the request for your account. Don't try to work around it. |
| `indeterminate` | The call may have been billed. Don't retry automatically. |
| `dependency_unavailable` | Biohub is temporarily unavailable. Wait and try again. |
| `internal_error` | Try once more later, and [tell us](https://info.biohub.org/product-feedback) if it continues. |

When an error includes `credits` or `billed_calls`, it describes the work Biohub confirmed before the failure. A later failure doesn't refund earlier ESMC calls in the same request. See [Troubleshooting](https://docs.biohub.ai/biohub-mcp/troubleshooting.md#error-codes) for details about codes.


## Related topics

- [Biohub MCP server](https://docs.biohub.ai/biohub-mcp/overview.md)
- [Biohub MCP ESM Atlas tools](https://docs.biohub.ai/biohub-mcp/esm-atlas-tools.md)
- [Troubleshoot Biohub MCP connections and tool errors](https://docs.biohub.ai/biohub-mcp/troubleshooting.md)
- [Biohub MCP folding tools](https://docs.biohub.ai/biohub-mcp/folding-tools.md)
- [Biohub MCP resource tools reference](https://docs.biohub.ai/biohub-mcp/resource-tools.md)
