liara-docs-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@liara-docs-mcpWhy does my database get wiped after every deploy on Liara?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
liara-docs-mcp
An MCP server over the official Liara cloud documentation. Four read-only tools — search, page read, deployment config and build-log diagnosis — over a corpus that ships inside the package: 3,502 chunks across 1,143 pages, mostly Persian, some English.
No ingest step, no database, no vector store, and no API key required. A fresh install answers immediately.
you ▸ my database gets wiped after every deploy on Liara. why?
⚙ search_docs("liara disk persistence deploy")
⚙ read_page("https://docs.liara.ir/paas/disks/getting-started/")The retrieval stack and the prompt-injection defenses are lifted from lia-helper, a Persian RAG assistant over the same corpus that won Best Solution for the Liara challenge at the StartCoach hackathon in August 2026. This repository is the part of it that is useful to any assistant, not just that one.
Install
The server needs no configuration. Point your host at it and restart.
Claude Code
claude mcp add liara-docs -- uvx --from git+https://github.com/SalehB1/Lira-mcp liara-docs-mcpClaude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json on macOS,
%APPDATA%\Claude\claude_desktop_config.json on Windows. Quit Claude fully and reopen it after
editing; the config is read at launch.
{
"mcpServers": {
"liara-docs": {
"command": "uvx",
"args": ["--from", "git+https://github.com/SalehB1/Lira-mcp", "liara-docs-mcp"]
}
}
}Cursor — .cursor/mcp.json
{
"mcpServers": {
"liara-docs": {
"command": "uvx",
"args": ["--from", "git+https://github.com/SalehB1/Lira-mcp", "liara-docs-mcp"]
}
}
}VS Code — .vscode/mcp.json. Note the different wrapper key and the type field.
{
"servers": {
"liara-docs": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "git+https://github.com/SalehB1/Lira-mcp", "liara-docs-mcp"]
}
}
}Then ask your assistant something it could not answer before:
دیتابیسم بعد از هر دیپلوی پاک میشه، چیکار کنم؟
Related MCP server: docs-scraper
The tools
Tool | Returns | Bounds |
| Numbered snippets with their source URLs. The tool to reach for on any factual claim. |
|
| One whole documentation page. No network fetch exists on this path — the URL must already be in the loaded corpus. | body ≤ 8,000 chars |
| Every canonical deployment page for one of 15 platforms, plus the complete |
|
| The error signature extracted from a failing build or runtime log, and the pages that explain that class of failure. | log ≤ 20,000 chars, last 300 lines, signature ≤ 200 chars |
There is also one resource, liara://corpus, reporting which documentation snapshot answered:
upstream commit, ingest date, chunk and page counts, and whether dense search is active.
Every tool is annotated read_only_hint. Nothing here writes anything.
How it searches
Three ranked lists, fused by reciprocal rank at equal weight. Word-level BM25 and dense cosine
over 50 candidates each, character-4-gram BM25 over 20, combined as 1/(60 + rank + 1) with ties
broken on raw cosine. No reranker, no cross-encoder: either one puts a model call on every query.
The n-gram list is deliberately the short one. Sub-word overlap is the weakest of the three signals, and a long tail of it outvotes the word index on literal questions. Measured on a 100-question set: at 18–22 candidates literal recall@5 holds its 51/55 baseline while paraphrase recall goes 14 → 18; at the full 50, paraphrase reaches 20 but literal drops to 49.
One Persian normalizer, hand-written, no NLP dependency. A 49-key str.translate table applied
after NFC: Arabic→Persian letter unifications, both Arabic-Indic digit ranges folded to ASCII, and
19 deletions covering tatweel, diacritics and invisible bidi marks. No target is itself a key, which
makes normalize idempotent by construction. ZWNJ is kept and ZWJ is deleted, because ZWNJ is
load-bearing orthography: پایگاهداده must stay one token while Node.js splits into two.
Stemming is four suffixes, additive — tokenize emits both the surface form and the stem, so a
wrong cut can only ever add a term the query side produces identically.
Character n-grams buy morphology and typos, not scripts. داکر and docker share no n-gram at
all. Bridging that is what the 73 bidirectional synonym groups are for, and synonym expansion is
BM25-only: the dense leg embeds the untouched query.
The dense list is optional and degrades silently by design. Set AVALAI_API_KEY and each query
is embedded through an OpenAI-compatible /embeddings endpoint, cached in process. Without it — or
on a timeout, a bad response, or a provenance mismatch between embeddings.npz and the corpus it
was built from — the query runs on the two lexical lists and nothing errors. Seven independent
conditions drop the dense leg, and none of them fails a request.
Grounding
The corpus is public third-party markdown and demonstrably contains instruction-shaped text: one page in it is a leftover content brief telling the reader to rewrite links. Four layers assume it is hostile, and all four are enforced in code rather than asked for in a prompt.
Layer | Where |
Every result carrying documents is wrapped in |
|
|
|
A URL allowlist at load: prefix |
|
Citation numbers are minted server-side by the registry, keyed by chunk id, at the moment a chunk is formatted. |
|
read_page reads only URLs already in the loaded index. There is no HTTP client on the tool path,
so it cannot be pointed at an internal host.
Two honest limits. A number can only be created here, but nothing resolves the markers back out
of a finished answer, because over MCP the answer is written by the client's model and this server
never sees it — the upstream project could check that and this one cannot. And the instruction that
the corpus is data rather than instructions travels in the server's instructions field, which a
client is free to drop; the four rows above are the part that does not depend on being read.
Runnable check: uv run pytest tests/test_untrusted_corpus.py -v drives a javascript: URL, a
plain-http URL and a URL carrying </docs> through the real loader, then feeds _neutralize a
forged envelope and two forged citation headers.
Run it as a shared service
--http serves Streamable HTTP instead of stdio, for one instance several people point at.
uvx --from git+https://github.com/SalehB1/Lira-mcp liara-docs-mcp --http --port 8000
# clients connect to http://127.0.0.1:8000/mcp
# GET /healthz answers {"status":"ok","chunks":3502,...}The Host allowlist is the one thing to get right. The MCP SDK defaults to DNS-rebinding
protection that accepts only localhost Host headers, which is correct on a laptop and returns
421 Misdirected Request to every request behind a real hostname. So:
Set
MCP_ALLOWED_HOSTS=mcp.example.com,mcp.example.com:*and the server allowlists exactly those. Entries are matched literally, so list the bare host and the:*port form both. There is no wildcard, andMCP_ALLOWED_ORIGINSon its own is refused at startup rather than left to 421 every request.Bind to loopback with nothing set, and the SDK default stands.
Bind to a public interface with nothing set, and the server assumes a reverse proxy already controls
Host, switches the check off, and says so in the log rather than silently refusing every caller.
Deploying to Liara, whose CLI reads the committed liara.json:
liara app:create --platform docker --name liara-docs-mcp
liara deployDo not set AVALAI_API_KEY on a public instance unless you accept paying for one embedding call
per distinct query from anyone who can reach it. There is no authentication on the HTTP transport;
this serves public documentation and nothing else.
Environment
Every key is optional and every default works.
Key | Default | What it does |
| (unset) | Turns on the dense retrieval list. The only outbound call this server makes. |
|
| Any OpenAI-compatible |
|
| Must match what |
|
| Same. A different-width model is caught here; a same-width one is caught by the provenance hash. |
| packaged | Where |
|
| Logs go to stderr; stdout is the stdio wire. |
|
| Hosts to keep away from a local proxy. |
| (unset) |
|
| (unset) |
|
Development
git clone https://github.com/SalehB1/Lira-mcp && cd Lira-mcp
uv sync
uv run pytest -q # 73 checks, no key and no network
uv run ruff check .
uv run mcp dev src/liara_docs_mcp/server.py # the MCP InspectorThe test suite runs the real corpus through the real tools and drives the server through an in-process MCP client, so what it asserts is what a host actually sees. It forces the keyless configuration, so a real key in your shell cannot turn a test run into a spend.
The corpus
A frozen snapshot of public/llms/**/*.md from
liara-cloud/docs, committed to this repository rather than
fetched at startup — so there is no crawler in the boot path and a cold start does no work.
Upstream commit |
|
Ingested | 2026-08-21 |
Contents | 3,502 chunks over 1,143 pages — 3,270 Persian, 232 English |
Embeddings | 3,502 × 1,536, |
corpus_meta.json carries that provenance, and embeddings.npz is stamped with the corpus hash it
was built from: a matrix that disagrees with the chunks actually on disk is refused rather than
multiplied. Ask the server itself by reading the liara://corpus resource.
Refreshing it means running lia-helper's ingest/ against
a newer docs commit and copying the three files back into src/liara_docs_mcp/data/.
Limitations
The corpus is frozen at one upstream commit. Nothing here schedules a refresh, so pages added to the documentation since August 2026 are not searchable.
Dense retrieval has one provider and no fallback. Without a key it is simply absent, which is a quality difference a caller cannot see —
/healthzreportsdense_searchfor exactly this reason.The whole corpus is scored on every query. A
matrix @ querydot product over 3,502 chunks with no approximate-nearest-neighbour index is right at this size and does not carry to a million.Persian-first. Queries work in both languages and 174 of the 375 synonym keys are Latin, but the documentation itself is overwhelmingly Persian and the answers a model composes from it will be too.
No authentication on the HTTP transport. It serves public documentation; see the spend note above before exposing an instance with a key set.
Retrieval quality is unmeasured against what actually ships. The numbers quoted above come from the original project's harness against raw user wording, not against queries an MCP client's model composes.
MIT — see LICENSE.
Available Tools
4 toolsdiagnose_logARead-only
Extract the error from a failing build or runtime log and fetch the docs for it.
Reduces the log to one error signature — the most specific failure line, not the last one — and returns the documentation pages explaining that class of failure.
Args: log: The raw log text. Only the last 300 lines are read.
| Name | Required | Description | Default |
|---|---|---|---|
| log | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as readOnlyHint=true and openWorldHint=false. The description adds meaningful behavioral context beyond that: it reduces the log to one error signature, chooses the most specific failure line rather than the last one, and returns documentation pages. This is useful, non-contradictory transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: a front-loaded purpose statement, a short behavioral clarification, and a one-line parameter specification. Every sentence adds value, and the most important constraint (300-line limit) is stated explicitly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema and read-only annotations, the description covers the key operational details an agent needs: input format, log truncation, and the error-reduction behavior. It does not specify what happens when no error signature is found, but the existing output schema reduces that burden.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the parameter meaning. It does: 'log: The raw log text. Only the last 300 lines are read.' This clarifies both the content and a critical truncation behavior for the single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Extract the error from a failing build or runtime log and fetch the docs for it.' It clearly conveys a diagnostic workflow distinct from a generic docs search, though it does not explicitly name sibling tools or state what makes it different from search_docs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool—when you have a failing build or runtime log—and includes the input constraint that only the last 300 lines are read. However, it does not explicitly contrast with alternatives like search_docs or read_page, nor does it state when those should be preferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
platform_docsARead-only
Collect the deployment documentation for one platform, ready to write a liara.json.
Returns the platform's quick start, deployment and environment-variable pages plus the complete liara.json reference, so every key you write can be cited.
Args: platform: The target platform, for example "django" or "nextjs". needs: Extra requirements to look up as well, such as "disk", "cron" or "websocket". At most 10 short items.
| Name | Required | Description | Default |
|---|---|---|---|
| needs | No | ||
| platform | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true and openWorldHint=false already covering the read-only and closed-world safety profile, the description adds the aggregation behavior: it collects multiple pages for one platform and includes the full liara.json reference. No side effects or failure modes are described, but none are required given the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is about 60 words: a one-sentence purpose, a one-sentence output description, and formatted Args. No sentence is wasted, and the key action is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has only two parameters, an output schema exists (so return values need not be described), and annotations cover the safety model. The description covers purpose, output contents, and both parameters, leaving no essential invocation detail missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% coverage, and the 'Args' section compensates by explaining that 'platform' is the target and 'needs' is an optional list of extra lookups, with examples ('disk', 'cron', 'websocket') and a maximum of 10 items. This is enough for an agent to construct valid calls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb ('collect'), a specific resource ('deployment documentation for one platform'), and the intended end-goal ('ready to write a liara.json'). It also enumerates the return contents (quick start, deployment, env-var pages, liara.json reference), which separates it from the generic search_docs/read_page siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'ready to write a liara.json' gives an explicit scenario for choosing this tool. It does not name sibling alternatives or exclusion conditions, but the context is unambiguous enough to route selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_pageARead-only
Read one whole documentation page from the local corpus.
The URL must be one a previous search returned. No other URL can be fetched: this server has no HTTP client on the tool path and reads only what is already indexed.
Args: url: A canonical docs.liara.ir URL taken from a search result.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the read-only nature is covered. The description adds meaningful behavioral context: the tool cannot fetch arbitrary URLs and reads only already-indexed pages, which is valuable beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: the purpose is front-loaded, the critical limitation is stated next, and the parameter explanation is brief and direct. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with annotations and an output schema, the description is complete. It covers the prerequisite (previous search), the constraint (no arbitrary URLs), and the exact parameter expected. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the burden for parameter meaning. It does so clearly by stating that 'url' must be a canonical docs.liara.ir URL taken from a search result, which is essential information the schema alone does not provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Read one whole documentation page') and a specific resource ('the local corpus'), which clearly distinguishes it from the sibling tools. The addition that only pages returned by a prior search can be fetched makes its scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: the URL must come from a previous search result, and no other URL can be fetched. It also explains the underlying reason (no HTTP client, only indexed content), leaving no ambiguity about when this tool applies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_docsARead-only
Search the Liara documentation and return numbered snippets with their source URLs.
Use this for every factual claim about Liara. Write the query in the user's own words plus the product name; Persian and English both work.
Args: query: What to search for. Longer than 300 characters is truncated. k: How many snippets to return, 1 to 8. Values outside that range are clamped.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, so no contradiction. The description adds useful behavioral detail by specifying that the result includes numbered snippets with source URLs, and the parameter descriptions disclose truncation and clamping behavior, going beyond the minimal annotation info.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: a purpose sentence, a usage directive, a language tip, and then concise parameter explanations. No redundant or filler content; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params, output schema present), the description covers all necessary aspects: what it does, how to use it, parameter semantics, and output format. The presence of an output schema means detailed return structure is not needed in the description, so completeness is high.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no descriptions for the parameters (0% coverage), but the description fully compensates by explaining query as 'What to search for' with a 300-character truncation limit, and k as 'How many snippets to return' with a 1–8 range and clamping. This adds complete meaning to both parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: searching the Li documentation and returning numbered snippets with source URLs. It also explicitly says to use it for every factual claim about Liara, which contrasts with the sibling tools (read_page, platform_docs, diagnose_log) that serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: 'Use this for every factual claim about Liara.' It also gives concrete query formulation instructions (use the user's own words plus the product name, both Persian and English work), making the usage context unmistakable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
diagnose_log - First observed
platform_docs - First observed
read_page - First observed
search_docs
TDQS
Each tool has a clearly distinct purpose: search, read a specific page, aggregate platform-specific docs, and diagnose logs. No overlap or ambiguity.
All tools use snake_case and mostly follow verb_noun (search_docs, read_page, diagnose_log), but platform_docs is a noun phrase rather than a verb, which is a minor deviation.
Four tools are well-scoped for a documentation server, covering search, retrieval, and specialized workflows without unnecessary bloat.
The core documentation lifecycle (search, read, platform-specific aggregation, and error diagnosis) is covered. Minor gaps like browsing an index or listing available platforms exist, but they are not critical.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Run AI customer support from your terminal: conversations, knowledge base, and chat widget.
Ingest, manage, and retrieve documents for RAG-powered AI applications
Search and read Vector Panda docs: API operations, pricing, storage tiers, measured benchmarks.
81Versioned documentation registry and semantic search for AI tools and coding assistants.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants like Claude to search and retrieve technical documentation from a local DevDocs instance for hundreds of programming languages and frameworks.1MIT
- FlicenseNot gradedqualityDmaintenanceEnables scraping and searching documentation websites using semantic or keyword search, with support for multiple deployment modes.-
- FlicenseBqualityDmaintenanceEnables AI assistants to query and search library documentation from GitHub repositories or web pages using RAG and web scraping.2-
- AlicenseNot gradedqualityDmaintenanceEnables LLMs to search and retrieve information from large technical documentation (OpenAPI specs, markdown) via intelligent chunking and semantic search.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/SalehB1/Lira-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server