hydra-mcp¶
hydra-mcp (source on GitHub) is an MCP server that lets an AI assistant turn a file into records for a Hydra archive. The assistant reads the file, writes the facts as Hydra's FollowTheMoney JSON, and the server checks them and saves them with the file as the evidence every entity cites.
It doesn't guess. Anything uncertain is left for a person: a name that might be someone already in the archive becomes a merge question in hydra-ctl review, and a role the hierarchy doesn't rank is reported, not rewritten.
How a session goes¶
labelling_guidelinestells the assistant how to model records for this archive.read_filereturns the file's text, exactly as it will be stored.describe_schemashows the properties and types of each kind of record, andfind_entitieslooks each name up, so records reuse the exact name of anyone already in the archive.check_recordsis a dry run: it reports errors, warnings and how each link and role resolves, and writes nothing.savechecks the records again, writes them and rebuilds. If anything breaks the modelling rules, nothing is written anderrorssays what to fix.get_recordsreads the saved collection back, with each property's type and what every link resolved to, so the assistant can check its work against the file.
You then answer whatever it left open with hydra-ctl todo and hydra-ctl review.
Tools¶
| Tool | Arguments | What it does |
|---|---|---|
labelling_guidelines |
archive |
The record format, which field each end of a relationship goes in, roles, dates, and this archive's relationship fields and position ladder |
read_file |
path, offset, archive |
The text of a .txt, .md, .html, .pdf or .docx file. Long files come in parts: call again with offset set to next_offset. Says whether the archive already holds the file |
describe_schema |
schema, archive |
With no schema, the record types and relationships. With one, every property it accepts: its type, whether it is required, and what a link takes |
find_entities |
query, schema, limit, archive |
Entities already in the archive closest to a name, best first |
check_records |
records, collection, archive |
A dry run of save: errors, warnings, how links and roles resolve, likely duplicates. Writes nothing |
save |
records, source, collection, replace, archive |
Checks and saves records as a new collection with their evidence, then rebuilds |
get_records |
collection, name, offset, limit, archive |
Reads a saved collection back with each property's type, what each link resolved to after the build, and the save checks repeated. With no collection, lists them |
link_image |
image, kind, schema, position, titled, name, confirm, archive |
Previews, then on confirm=true adds, a hints rule giving matching entities a portrait, an icon (thumb) or a logo |
create_archive |
path, name, prefix, confirm |
Previews, then on confirm=true creates, an empty archive in a new or empty folder (as hydra-ctl init). prefix defaults to one made from the name; none gives each collection its own |
path arguments must be full paths. A scanned PDF with no text layer is an error, never an empty source.
Records¶
Records use Hydra's dialect: links are written as the linked entity's name, not an id. See Links.
[
{
"schema": "Person",
"properties": {
"name": [
"Rob Kerr"
],
"weakAlias": [
"Kerr"
]
}
},
{
"schema": "PublicBody",
"properties": {
"name": [
"Port Authority"
]
}
},
{
"schema": "Employment",
"properties": {
"employee": [
"Rob Kerr"
],
"employer": [
"Port Authority"
],
"role": [
"deputy"
],
"startDate": [
"2019"
]
}
}
]
id is optional. Dates are YYYY, YYYY-MM or YYYY-MM-DD.
The source argument of save¶
{"file": "/full/path/report.pdf"} keeps the file as the evidence, {"text": "..."} keeps pasted text, and {"id": "..."} adds more records from evidence already saved. A file already saved in the archive is refused; save with its id instead.
Add title, url (which makes the source an Article), publisher, author, published or language when known.
Images¶
Records never carry images. link_image adds a rule to .hydra/rules/hints.yaml instead, the same rule hydra-ctl hints set writes. It only previews until it is called with confirm=true, which the assistant should do only after you agree. See Images and badges.
What a save writes¶
collections/<collection>.json the records
.hydra/sources/entries/<collection>.json the source, as one Document
.hydra/sources/files/<collection>/<file> a copy of the original file
Every entity cites the source in sources, so hydra-ctl claims and hydra-ctl sources trace each value back to the file. Relationships have no sources field in FtM; they trace back through their collection.
The collection is named from the file or title plus a timestamp unless you pass collection, and an existing one is never overwritten unless replace=true. If the rebuild fails, the files are put back as they were.
To undo a save, delete the files it lists in undo, then run hydra-ctl build.
Choosing the archive¶
The archive is, in order: the tool's archive argument, the HYDRA_ARCHIVE environment variable, an archive activated with hydra-ctl activate in or above the folder the server starts in, or that folder if it is an archive.
With no archive, nothing is written. labelling_guidelines, read_file, describe_schema and check_records still work on Hydra's defaults, find_entities returns nothing, and save, get_records and link_image refuse and tell the assistant to ask you for a folder or offer create_archive.
A path that is named but isn't an archive is an error, never a quiet fallback.
Setup¶
1. Install¶
hydra-mcp is a Python package with a hydra-mcp command, like hydra-ctl. It depends on open-hydra, the main open-hydra package. Neither is on PyPI, so install both from GitHub in one go:
uv tool install git+https://github.com/meridiangray/open-hydra-mcp --with git+https://github.com/meridiangray/open-hydra
Or with pip, into any environment:
pip install git+https://github.com/meridiangray/open-hydra git+https://github.com/meridiangray/open-hydra-mcp
Afterwards hydra-mcp is on your PATH. It speaks MCP over stdio, so running it by hand just waits for a client.
2. Add it to your client¶
Every MCP client needs the same two things: the command hydra-mcp, and optionally HYDRA_ARCHIVE set to the archive's folder. Leave HYDRA_ARCHIVE out to choose the archive per conversation.
Claude Code:
claude mcp add hydra --env HYDRA_ARCHIVE=/path/to/case -- hydra-mcp
Add --scope user to make it available in every project, or --scope project to write it to .mcp.json for everyone working in the repo.
Claude Desktop, Cursor, VS Code and other clients take the standard mcpServers JSON. For Claude Desktop it goes in claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"hydra": {
"command": "hydra-mcp",
"env": {"HYDRA_ARCHIVE": "/path/to/case"}
}
}
}
Restart the client, and the tools appear under hydra.
If the client can't find the command, give its full path instead. which hydra-mcp (macOS, Linux) or where hydra-mcp (Windows) prints it.
Windows: give the full path and double every backslash:
"command": "C:\\Users\\you\\.local\\bin\\hydra-mcp.exe",
"env": {"HYDRA_ARCHIVE": "C:\\cases\\case"}
Installed in WSL, client on Windows:
"command": "wsl",
"args": ["-d", "Debian", "--", "bash", "-lc", "HYDRA_ARCHIVE=/mnt/c/cases/case hydra-mcp"]
Updating¶
To update, run the install again with uv tool install --reinstall (or pip install --force-reinstall) and restart the client.