{"id":"797c9af3-05fb-46bb-946a-c22bc4691d6d","slug":"phylokit-mcp","kind":"mcp","name":"phylokit-mcp","summary":"MCP server for phylogenetic inference over IQ-TREE 3 (through piqtree) — never returns a topology without its bootstrap support","owner":"musharna","repoUrl":"https://github.com/musharna/phylokit-mcp","license":"GPL-2.0","licenseTier":"strong-copyleft","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-07-30T05:05:30.000Z","addedAt":"2026-10-14T05:50:09.640Z","logoUrl":"https://avatars.githubusercontent.com/u/96366172?u=ed39bf0a3be4c523b5c31f05a1388623aed31930&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","memory-knowledge"],"tags":["bioinformatics","bootstrap","iqtree","phylogenetics","python"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T17:29:31.743Z","sample":false,"url":"https://conduits.dev/tools/phylokit-mcp","language":"Python","transports":["stdio"],"install":{"pypi":"phylokit-mcp"},"requirements":{"env":[{"name":"OMP_NUM_THREADS","secret":false,"required":false,"description":"Pinned so inference is reproducible; overriding it makes IQ-TREE runs non-deterministic."},{"name":"MKL_NUM_THREADS","secret":false,"required":false,"description":"Pinned alongside OMP_NUM_THREADS for the same reproducibility reason."}],"upstreamMayCharge":false},"tools":null,"readme":"# phylokit-mcp\n\n[![ci](https://github.com/musharna/phylokit-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/musharna/phylokit-mcp/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/phylokit-mcp)](https://pypi.org/project/phylokit-mcp/)\n[![python](https://img.shields.io/pypi/pyversions/phylokit-mcp)](https://pypi.org/project/phylokit-mcp/)\n[![license](https://img.shields.io/pypi/l/phylokit-mcp)](LICENSE)\n[![Glama](https://glama.ai/mcp/servers/musharna/phylokit-mcp/badges/score.svg)](https://glama.ai/mcp/servers/musharna/phylokit-mcp)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21713870.svg)](https://doi.org/10.5281/zenodo.21713870)\n\n<!-- mcp-name: io.github.musharna/phylokit-mcp -->\n\nPhylogenetic inference over MCP, driving IQ-TREE 3 through\n[piqtree](https://github.com/cogent3/piqtree) 0.8, which builds IQ-TREE 3 into\nits wheel.\n\n**A topology without support is not a result.** `infer_tree` always runs a\nbootstrap and always returns per-clade support. There is no flag to skip it.\n\n6 tools. The test suite runs real IQ-TREE and real MAFFT (no mocked engine),\nand includes 23 mutation checks and a real-process JSON-RPC handshake test.\n\n## Why the rule\n\nA maximum-likelihood tree looks identical whether or not the data support it.\nMeasured here, on alignments simulated from a _known_ 7-taxon tree so the right\nanswer is not in doubt:\n\n| sites | informative sites | recovered the true tree? | lowest clade support |\n| ----: | ----------------: | ------------------------ | -------------------: |\n|   300 |                51 | yes, exactly             |                 1.00 |\n|    60 |                11 | **no — RF 2**            |                 0.57 |\n\nAt 60 sites the tree contains a clade (`C,D,G`) that does not exist and omits\none that does (`E,F,G`). Both runs return a fully resolved Newick string of the\nsame shape; nothing about the topology itself distinguishes them. The support\nvalues do — and the false clade is the _lowest-supported_ one in the tree.\n\nThat is the entire argument for this server. Returning a bare tree returns a\nresult the caller cannot evaluate.\n\n## What it reports that a Newick string cannot\n\n- **Conflicting clades** — groupings the data support at ≥0.70 that are _absent_\n  from the reported tree. A support-annotated Newick string has nowhere to\n  attach these, so the standard format silently drops them.\n- **`fraction_resolved`** — the share of clades clearing 0.70. The headline\n  number, before any individual grouping is repeated as fact.\n- **Model runners-up with ΔAIC** — not just a winner. On the 300-site alignment\n  above, simulated under **JC**, the AIC winner is **not JC** (TPM2u and TPM2\n  tie at the top), and several other models, JC among them at ΔAIC 0.7, sit\n  inside the conventional ±2 indistinguishability margin (`seed=1`, piqtree\n  0.8.3). A winner without its margin is a claim the numbers do not support.\n- **Length versus evidence** — `n_parsimony_informative` alongside `n_sites`.\n  A 10,000-site alignment of near-identical sequences supports nothing.\n\n## Tools\n\n| tool                        | what it does                                                                       |\n| --------------------------- | ---------------------------------------------------------------------------------- |\n| `infer_tree`                | ML tree **plus** bootstrap support, per clade. Never one without the other.        |\n| `select_substitution_model` | Ranks 100+ models with ΔAIC/AICc/BIC, and says when the criteria disagree.         |\n| `compare_trees`             | Robinson–Foulds distance and the clades that differ. Compares splits, not strings. |\n| `simulate_alignment`        | Generates sequences along a tree you specify — the positive control.               |\n| `align_sequences`           | Aligns unaligned FASTA with MAFFT; the output goes straight into `infer_tree`.     |\n| `capabilities`              | piqtree and IQ-TREE versions, 215 substitution models, MAFFT version, limits.      |\n\n## Install\n\n```bash\npip install phylokit-mcp\n```\n\npiqtree ships prebuilt wheels, so there is no compiler, no R and no conda step —\nbut it requires **Python 3.12+**, and so does this package.\n\n`align_sequences` is the one tool that needs something pip cannot install: the\n[MAFFT](https://mafft.cbrc.jp/alignment/software/) binary on `PATH`\n(`apt install mafft`, `brew install mafft`, or `conda install -c bioconda mafft`).\nThe other five tools work without it, `capabilities` reports\n`aligner_version: null`, and calling `align_sequences` returns a refusal that\nnames the install rather than a crash. A MAFFT that is installed but does not\nanswer `--version` is a different state: `aligner_version` is still `null` and\n`aligner_error` says what happened.\n\n## Configure your MCP client\n\n```json\n{\n  \"mcpServers\": {\n    \"phylokit\": {\n      \"command\": \"uvx\",\n      \"args\": [\"phylokit-mcp\"]\n    }\n  }\n}\n```\n\n`uvx` fetches the released package on demand, so this needs no prior install — but\nit must resolve a **Python 3.12+** interpreter, since that is piqtree's wheel floor.\nIf `uvx` picks an older one, pin it with `\"args\": [\"--python\", \"3.12\", \"phylokit-mcp\"]`.\n\nIf you installed it yourself instead, `\"command\": \"phylokit-mcp\"` works when the\nexecutable is on your `PATH`; give the absolute path to the entry point in the\nenvironment you installed into if it is not.\n\nThe same file ships as [`.mcp.json`](.mcp.json) in this repo, which Claude Code\npicks up automatically when the repo is your working directory.\n\n## Reproducibility, stated precisely\n\nMeasured, not assumed:\n\n- **Not bit-exact, in any setting.** The same request with the same seed — on\n  repeat in one process, or in a fresh process — can return branch lengths and a\n  log-likelihood that differ in the trailing digits (eight fresh processes gave\n  five distinct log-likelihoods, spread ~2e-6). IQ-TREE reads the wall clock\n  during its search: freezing `gettimeofday()` alone made every run\n  bit-identical. piqtree exposes no option to take the clock out, so the server\n  reports `deterministic_across_processes: false` rather than promise it.\n- **Support can move by a replicate flipping.** Over six repeated 50-replicate\n  calls, three of four clades were bit-identical and one moved **0.02**, well\n  inside the bootstrap's own sampling error (~0.07 at 50 replicates). The\n  topology and every conclusion were unchanged. The column resampling itself is\n  numpy-seeded and exact.\n\nCompare trees with `compare_trees`, and numbers with a tolerance — never by\nstring equality.\n\nThreads are pinned to 1 before piqtree is imported: likelihood sums accumulate in\nthread-completion order, floating-point addition is not associative, and\nnear-tied topologies can flip on the last bits. Pinning is necessary, not\nsufficient.\n\n## Limitations\n\n- **Nucleotide and protein alignments.** Pass `sequence_type=\"protein\"` and a\n  protein model (`LG`, `WAG`, …). Codon models are still not exposed.\n  The molecule type is **declared, never sniffed**: an alignment of only A/C/G/T\n  is a valid protein alignment too (Ala/Cys/Gly/Thr), so guessing would fit a\n  nucleotide model to protein data and return a tree, a likelihood and support\n  values that are all wrong and none of which complain.\n- **Bootstrap only** — no aLRT, no approximate Bayes, no UFBoot. Support is the\n  nonparametric bootstrap (Felsenstein 1985), computed here rather than read back\n  from IQ-TREE, because piqtree 0.8.3 runs `bootstrap_replicates` but does not\n  expose the resulting values.\n- **Cost is linear in replicates.** Each replicate is a full maximum-likelihood\n  search on a resampled alignment, so it grows with taxon count, alignment\n  length and model complexity. Capped at 200 taxa and 1000 replicates.\n- **Alignment is MAFFT `--auto`, single-threaded, and nothing else.** No choice\n  of strategy, no profile alignment, no trimming, at most 200 sequences of\n  100,000 residues, and a 600 s wall-clock cap. Input that already contains gaps\n  is refused rather than silently degapped. The tree tools still refuse ragged\n  input; they do not align it for you.\n- **Unrooted trees.** No rooting, no dating, no ancestral reconstruction.\n\n## Licence\n\n**GPL-2.0-only.** The \"only\" is load-bearing: piqtree declares `GPL-2.0-only`,\nwhich is _incompatible_ with GPL-3.0, so the distributed combination cannot be\nGPL-3. cogent3 is BSD and imposes nothing.\n\nUnofficial. Not affiliated with, endorsed by, or sponsored by the IQ-TREE authors\nor the cogent3 project. **IQ-TREE is academic software and expects to be cited**\n— if results from this server appear in published work, cite IQ-TREE 3 as\ndirected at [iqtree.org](http://www.iqtree.org/) (currently Wong et al. 2026,\n[doi:10.1093/molbev/msag117](https://doi.org/10.1093/molbev/msag117), plus the\npaper for any method used, such as ModelFinder), and piqtree, McArthur et al.\n2026, [doi:10.1093/molbev/msag061](https://doi.org/10.1093/molbev/msag061) —\nnot this wrapper. The same holds for MAFFT when `align_sequences` produced the\nalignment: Katoh & Standley 2013,\n[doi:10.1093/molbev/mst010](https://doi.org/10.1093/molbev/mst010). MAFFT is\nBSD-licensed and is run as a separate program, not linked. See [NOTICE](NOTICE).\n"}