Lettria Perseus
БесплатноНе проверенWraps Lettria's Perseus text-to-graph engine to ingest documents, run ontology-driven extraction, and build knowledge graphs exportable to Neo4j and FalkorDB.
Описание
Wraps Lettria's Perseus text-to-graph engine to ingest documents, run ontology-driven extraction, and build knowledge graphs exportable to Neo4j and FalkorDB.
README
License: MIT Python 3.11+ Model Context Protocol
An MCP server that exposes Lettria Perseus, Lettria's Text-to-Graph engine, to MCP-compatible clients (Claude Code, Claude Desktop, Cursor, Zed, etc.).
It wraps the official perseus-client Python SDK, so anything the SDK can do — ingest files, run ontology-driven extraction, build knowledge graphs, interlink them, and export to Neo4j / FalkorDB / TTL / Cypher — becomes a callable tool for an LLM agent.
Status: experimental scaffold. The upstream SDK is a
1.0.0rcpre-release; APIs may shift.
Table of contents
- Features
- Requirements
- Installation
- Configuration
- Running
- Tool reference
- Typical workflows
- Inline text vs. file paths
- Design notes
- Security
- Development
- License
- Related links
Features
- 29 MCP tools covering the full Perseus workflow:
- Graph building (
build_graph) and merging (interlink_graphs) - An in-memory registry so graphs can be referenced across tool calls
- Paginated inspection of entities and relations
- Exports to TTL, Cypher (CQL) files, Neo4j, and FalkorDB
- Remote file, ontology, and job management
- Inline-text variants (
build_graph_from_text,upload_ontology_from_text) for agents without filesystem access
- Graph building (
- Async throughout — uses the SDK's
*_asyncvariants, so long extraction jobs don't block the event loop. - Safe by default —
PERSEUS_API_KEYis required at startup; the server refuses to run without it. - Pagination for large graphs — entities and relations are returned in slices, keeping tool-call payloads manageable.
Requirements
- Python 3.11+
- uv (for dependency management & running)
- A Perseus API key (see docs.perseus.lettria.net)
- (Optional) Running Neo4j or FalkorDB instance if you want to use the database-export tools
Installation
git clone https://github.com/Lettria/perseus-mcp.git
cd perseus-mcp
uv sync # optional — uv run will do this on first launch
uv sync creates .venv/, resolves uv.lock, and installs:
mcp[cli]— the Model Context Protocol Python SDKperseus-client— Lettria's Perseus SDKpython-dotenv— loads.envbefore the SDK reads settings
Running it upfront is not required — the MCP client (or any later
uv run) will auto-sync on first use — but it's a faster way to surface
dependency resolution errors.
Configuration
The Perseus SDK reads its settings from environment variables (via pydantic-settings). You have two equivalent ways to supply them; pick whichever fits how you launch the server.
At minimum, PERSEUS_API_KEY must be set. All other variables are optional
— see sample.env for the full list (Neo4j, FalkorDB, inline-content
cap, log level).
Option A — in your MCP client's server config (recommended)
Every MCP client lets you set environment variables on the subprocess it spawns. This keeps the credential attached to the server registration, with no extra file to manage. Examples are in the Running section below.
Option B — in a local .env file
Useful during development when you uv run the server directly, or when
you don't want secrets inside a client config file:
cp sample.env .env
$EDITOR .env
Precedence
Process environment variables always win over .env values, so a key set
in the MCP client config will override one sitting in .env.
A note on secret hygiene
Both options write your API key to a local file (either .env or the
client's JSON config). Treat them the same: don't commit them, and don't
sync them through cloud-backed config directories you wouldn't trust with
a password.
Running
You do not need to start the server manually. MCP clients spawn the
subprocess themselves using the command you register below — the uv
invocation in the client config is what actually launches the server each
time the client connects.
uv will auto-sync the lockfile on first launch, so even uv sync is
optional; running it once upfront just surfaces dependency errors earlier.
Registering with Claude Code
Pass the API key (and any optional DB creds) with -e KEY=value:
claude mcp add lettria-perseus \
-e PERSEUS_API_KEY=sk-perseus-... \
-- uvx --from git+https://github.com/Lettria/perseus-mcp.git \
--with 'perseus-client[all]' \
lettria-perseus-mcp
Add more -e flags for Neo4j / FalkorDB if you plan to use those export
tools.
Why
--with 'perseus-client[all]'? Theneo4jandfalkordbPython drivers are declared as optional extras onperseus-client. Without[all](or the narrower[neo4j]/[falkordb]),save_graph_to_neo4jandsave_graph_to_falkordbfail at import time. Drop the--withflag if you only need TTL / Cypher exports.
Registering with Claude Desktop
Add an entry to claude_desktop_config.json and set credentials via the
env block:
{
"mcpServers": {
"lettria-perseus": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/Lettria/perseus-mcp.git",
"--with",
"perseus-client[all]",
"lettria-perseus-mcp"
],
"env": {
"PERSEUS_API_KEY": "sk-perseus-...",
// Optional: only if you use `save_graph_to_neo4j`. These vars alone
// are not enough — the `--with 'perseus-client[all]'` flag above is
// what installs the `neo4j` driver into the uvx environment.
"NEO4J_URI": "bolt://localhost:7687",
"NEO4J_USER": "neo4j",
"NEO4J_PASSWORD": "password",
// Optional: only if you use `save_graph_to_falkordb`. Same caveat —
// requires the `--with` flag above so the `falkordb` driver is
// installed alongside `perseus-client`.
"FALKORDB_HOST": "localhost",
"FALKORDB_PORT": "6379",
"FALKORDB_USERNAME": "",
"FALKORDB_PASSWORD": "",
"FALKORDB_GRAPH_NAME": "perseus_graph"
}
}
}
}
Any other MCP client that can spawn a stdio subprocess supports the same
pattern — consult its docs for the equivalent of env / -e.
Optional: smoke-test or Inspector
These are only useful for local debugging — not prerequisites for the MCP client registrations above.
Smoke-test that the server starts and auth succeeds:
PERSEUS_API_KEY=sk-perseus-... uv run lettria-perseus-mcp
# Ctrl-C once you see it waiting on stdio.
Interactively call each tool via the MCP Inspector:
PERSEUS_API_KEY=sk-perseus-... uv run mcp dev src/lettria_perseus_mcp/server.py
Tool reference
Tools are grouped below by concern. Every tool that returns graph data uses
graph_id — a short identifier minted when build_graph or
interlink_graphs succeeds and held in server memory for the lifetime of
the process.
Graph building
| Tool | Description |
|---|---|
build_graph(file_paths, ontology_path?, refresh_graph?, metadata?) |
Build one graph per input file. Returns a summary and graph_id for each. |
build_graph_from_text(content, name?, ontology_ttl?, refresh_graph?, metadata?) |
Inline variant — pass document text (and optional TTL ontology) as strings. Bounded by PERSEUS_INLINE_CONTENT_MAX_BYTES. |
interlink_graphs(graph_ids, interlinking_key_uris?, immutable_properties?, merge_properties_on_conflict?) |
Merge two or more in-memory graphs on shared entity keys. |
Local registry inspection
| Tool | Description |
|---|---|
list_local_graphs() |
List every graph currently held in memory. |
get_graph_summary(graph_id) |
Entity / relation / document counts for one graph. |
get_graph_entities(graph_id, offset=0, limit=50) |
Paginated entity dump. |
get_graph_relations(graph_id, offset=0, limit=50) |
Paginated relation dump. |
forget_graph(graph_id) |
Drop a graph from the registry. |
forget_all_graphs() |
Drop all graphs from the registry. |
Exports
| Tool | Description |
|---|---|
export_graph_ttl(graph_id, output_path) |
Write the graph as Turtle. |
export_graph_cql(graph_id, output_path, strip_prefixes=True) |
Write the graph as Cypher statements. |
save_graph_to_neo4j(graph_id, strip_prefixes=True) |
Push to Neo4j via NEO4J_* env vars. |
save_graph_to_falkordb(graph_id, strip_prefixes=True) |
Push to FalkorDB via FALKORDB_* env vars. |
Remote files
| Tool | Description |
|---|---|
upload_file(file_path, wait=True) |
Upload a source document; optionally block until processed. |
list_files(ids?, source_hashes?) |
List remote files. |
get_file(file_id) |
Fetch a single file record. |
delete_file(file_id) |
Delete a remote file. |
Remote ontologies
| Tool | Description |
|---|---|
upload_ontology(ontology_path, wait=True) |
Upload an ontology (TTL/OWL). |
upload_ontology_from_text(content, name?, wait=True) |
Inline variant — pass a TTL string directly. Bounded by PERSEUS_INLINE_CONTENT_MAX_BYTES. |
list_ontologies(ids?, source_hashes?) |
List remote ontologies. |
get_ontology(ontology_id) |
Fetch a single ontology record. |
delete_ontology(ontology_id) |
Delete a remote ontology. |
Remote jobs
| Tool | Description |
|---|---|
submit_job(file_id, ontology_id?) |
Kick off extraction for an uploaded file. |
get_job(job_id) |
Fetch a single job (includes status). |
list_jobs(job_ids) |
Fetch multiple jobs at once. |
find_latest_job(file_id, ontology_id?) |
Most recent job for a file. |
find_latest_succeeded_job(file_id, ontology_id?) |
Most recent successful job. |
run_job(job_id, polling_interval=5, timeout=3600) |
Block until a job reaches a terminal state. |
download_job_output(job_id, output_path?) |
Save a job's output JSON locally. |
Typical workflows
"Give me a knowledge graph of this directory"
An agent can chain:
build_graph(file_paths=[...])→ gathergraph_idsinterlink_graphs(graph_ids=[...])→ single merged graphexport_graph_ttl(graph_id, "output/merged.ttl")
"Push the graph into my local Neo4j"
- Ensure
NEO4J_URI/NEO4J_USER/NEO4J_PASSWORDare set in.env. build_graph(...)save_graph_to_neo4j(graph_id)
"Re-use a previous extraction"
list_files()/list_ontologies()find_latest_succeeded_job(file_id, ontology_id?)download_job_output(job_id, "output/job.json")
Inline text vs. file paths
Some MCP clients (notably Claude Desktop) cannot write files to disk on their own, which breaks workflows where the agent drafts an ontology or document in chat and then wants Perseus to ingest it. To avoid forcing users to install a separate filesystem MCP server for that common case, the server provides inline variants:
build_graph_from_text(content, ...)— document text as a string.upload_ontology_from_text(content, ...)— TTL ontology as a string.
Both write the payload to a temp file, call the SDK, and clean up before returning. No path management required from the agent.
Size cap
Inline payloads are capped at PERSEUS_INLINE_CONTENT_MAX_BYTES
(default 1 MiB / 1,048,576 bytes, measured as UTF-8). Anything larger
is rejected with an error message that lists the three alternatives:
- Save locally and use the path-based tool
(
build_graph/upload_ontology). - Register the official @modelcontextprotocol/server-filesystem server and let the agent write the file itself.
- Raise the cap via
PERSEUS_INLINE_CONTENT_MAX_BYTESif you accept the memory / MCP-transport overhead.
The cap is deliberately conservative because every byte of inline content crosses the MCP wire and sits in the model's context. For real-world corpora (PDFs, multi-megabyte exports), path-based ingestion is always the right answer.
Design notes
- Graph state is in-memory. Restarting the server discards the registry;
export anything you want to keep. This is deliberate —
KnowledgeGraphobjects are Pydantic models that aren't cheap to serialize, and MCP servers are meant to be short-lived helpers. - Large graphs use pagination.
get_graph_entities/get_graph_relationsdefault to slices of 50 and returntotalso an agent can loop. - Secrets stay in env vars. API keys and database credentials are never passed through tool arguments; the SDK reads them via pydantic-settings.
- Failures surface as tool errors.
PerseusExceptions and validation errors propagate up to the MCP client rather than being swallowed.
Security
Automated checks run on the repository so the published package stays auditable:
- Dependabot — security-vulnerability alerts and automated fix PRs, plus
weekly version-update PRs for the
uv-resolved Python dependencies and the GitHub Actions used in CI (.github/dependabot.yml). - Secret scanning — GitHub secret scanning with push protection, so credentials can't be committed. No secrets live in the repo: API keys and database passwords are read from the environment at runtime only (see Configuration).
- SAST — CodeQL static analysis on every
push/PR to
mainand weekly, using thesecurity-and-qualityquery suite (.github/workflows/codeql.yml). - License scan — a dependency-license inventory plus GitHub
dependency-review, which blocks PRs that introduce strong-copyleft or
vulnerable dependencies (
.github/workflows/license-scan.yml).
Found a vulnerability? Please report it privately via the repository's security advisories rather than opening a public issue.
Development
# Install + create virtualenv
uv sync
# Run the server
PERSEUS_API_KEY=... uv run lettria-perseus-mcp
# List registered tools without starting stdio
PERSEUS_API_KEY=test uv run python -c "
from lettria_perseus_mcp.server import mcp
for t in mcp._tool_manager.list_tools():
print(t.name)
"
Testing
Tests mock the perseus_client SDK so no API key or network is needed.
# Install dev dependencies (pytest + pytest-asyncio)
uv sync --group dev
# Run the full suite
uv run pytest tests/ -v
Test structure
tests/
├── fakes.py # Lightweight stand-ins for SDK models
│ (FakeOntology, FakeKnowledgeGraph, etc.)
├── conftest.py # mock_perseus fixture — patches all SDK calls
├── test_helpers.py # _safe_basename, _inline_max_bytes,
│ _check_inline_size, graph registry
├── test_ontology_upload.py # upload_ontology, upload_ontology_from_text,
│ list/get/delete ontologies
└── test_graph_tools.py # build_graph, build_graph_from_text,
interlink, local registry, exports
What's covered
| Area | Examples |
|---|---|
| Ontology upload (TTL) | Temp file content, filename sanitization, .ttl extension appending, size-limit enforcement, wait/no-wait, cleanup |
| Graph building | Path-based and inline-text variants, inline ontology pass-through, size limits |
| Helpers | Path traversal in _safe_basename, env-var validation, multibyte UTF-8 size checks |
| Graph registry | Register/require round-trip, unknown-ID errors, pagination, forget/forget-all |
| Exports | TTL and CQL file writing |
| DB saves | Neo4j / FalkorDB env-var preconditions, strip_prefixes forwarding, missing-driver hint in error |
| CRUD tools | list/get/delete for ontologies, files |
License
MIT — see LICENSE for details.
Related links
- Perseus docs: https://docs.perseus.lettria.net/
perseus-clienton PyPI: https://pypi.org/project/perseus-client/- Model Context Protocol: https://modelcontextprotocol.io/
Установка Lettria Perseus
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/lettria/perseus-mcpFAQ
Lettria Perseus MCP бесплатный?
Да, Lettria Perseus MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Lettria Perseus?
Нет, Lettria Perseus работает без API-ключей и переменных окружения.
Lettria Perseus — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Lettria Perseus в Claude Desktop, Claude Code или Cursor?
Открой Lettria Perseus на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Lettria Perseus with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
