eqanun-api
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., "@eqanun-apisearch for Civil Code"
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.
eqanun-api
Dependency-free Python client, CLI and MCP server for Azerbaijan's official legal-acts database (e-qanun.az, Ministry of Justice). Usable as a research tool by any MCP-capable assistant or Copilot Studio agent, or directly from Python and the shell.
Last verified against the live API: 2026-07-30. The full search → metadata → full-text chain works; the core client uses only the Python standard library and runs on a stock Python 3.9+.
What it does
Search acts by title or full text, filter by status (in force / cancelled / all) and by act type, paginated —
GET /getDetailSearch.Count matches without pulling the result list —
GET /detailNameCount(the count comes back in theidfield).Metadata for any act by id (title, dates, type, status,
htmlUrl) —GET /framework/{id}.Full text of any act as clean plain text — fetches the static HTML with the same-site
Refererthe host's hotlink guard requires, decodes the MS-Word legacy-codepage export correctly (the declared charset varies per document — windows-1251, -1252 and -1254 all occur, so it is read from each document rather than assumed), and strips it to text. Raw HTML is also available from the Python client (as_text=False) and the CLI (--html).Taxonomy — act-type tree and top-level sections, whose ids are the values the type filter accepts.
The search endpoint is GET /getDetailSearch; the parameter set (name,
title, text, exact, statusId, array, start, length, …) was
determined by observing the official frontend's own requests. See
API.md for the full reconstructed API reference. The separate
e-qanun.ai portal is Cloudflare-challenged with no public API and is not an
integration target.
Related MCP server: fr-eli-mcp
Scope — what the corpus actually contains
e-qanun.az holds ~59,500 documents (59,482 by the sum of the /all-type
top-level counts, checked 2026-07-30), split across four sections: Normativ
hüquqi aktlar, Normativ xarakterli aktlar, Qeyri-normativ hüquqi aktlar, Digər.
The corpus is overwhelmingly legislative and executive material. The largest categories are presidential orders (Sərəncamlar, 16,786), Cabinet decisions (9,593), presidential decrees (Fərmanlar, 9,495), laws (7,148, including 27 codes), normative acts of central executive bodies (4,099), Central Election Commission acts (3,894), Cabinet orders (3,665), Milli Məclis decisions (1,853), local self-government acts (1,522), financial-regulator decisions (451), constitutional laws (55) and the Constitution and referendum acts (9) — plus a long tail of smaller categories (Tariff Council 170, local executive authorities 75, Judicial-Legal Council 36, international treaties 4, UN Security Council acts 4, and others).
It also carries a set of judicial documents as act types in the same id space, so they are retrievable through the ordinary act chain and can be isolated with the type filter:
Act type | id | Count |
Constitutional Court decisions | 73 | 464 |
Supreme Court Plenum decisions | 87 | 114 |
ECtHR judgments concerning Azerbaijan | 89 | 25 |
That is 603 documents, about 1.0% of the corpus. Confirm the current ids with
list_types — they are the values types / --types / array accept.
This is not a case-law database. There is no ordinary, appellate or cassation court coverage, no docket / party / judge search, no citator or citation graph, and no headnotes. What you get is the officially published text of those specific decision types, retrieved the same way any other act is.
In-force status is reported from the publisher's own fields: statusName
(Qüvvədədir = in force, Ləğv olunmuşdur = repealed — that exact string is
what the API returns) plus the statusId search
filter, with acceptDate and effectDate where present. effectDate is often
null — notably on court decisions. The client surfaces these fields as published;
it performs no independent verification, reconstructs no amendment history, and
offers no point-in-time ("in force as of date X") retrieval. The full text
returned is whatever consolidated HTML the site currently serves, with no version
stamp.
Requirements
Python 3.9+ and no third-party dependencies — the client, the CLI, and the
MCP server are all pure standard library. (The MCP protocol is implemented
directly in stdlib, so you do not need the mcp SDK or Python 3.10+.)
Get it
git clone https://github.com/beerbottle90/eqanun-api
cd eqanun-apiThere is no pip install — run everything from the repo root. On Windows use
python or py -3 wherever these examples say python3.
Quick start — Python
from eqanun import EqanunClient
c = EqanunClient()
hits = c.search("mülki məcəllə", scope="title", status="in_force", length=5)
print(hits["total"], "results") # -> ~615 (live count; grows as acts are published)
act = c.get_act(46944) # Civil Code metadata
print(act["title"], act["statusName"]) # Azərbaycan Respublikasının Mülki Məcəlləsi Qüvvədədir
text = c.get_act_fulltext(46944) # ~2M chars of clean text
html = c.get_act_fulltext(46944, as_text=False) # raw MS-Word HTML, if you need the markup
# Restrict a search to Constitutional Court decisions (type id 73):
decisions = c.search("mülkiyyət", scope="text", status="all", types=[73], length=10)scope is "title" or "text"; status is "in_force", "cancelled", or
"all"; types is a list of act-type ids from list_types() (omit for no type
filter).
Quick start — CLI (no install, no deps)
python3 -m eqanun search "mülki məcəllə" --scope title --status in_force -n 10
python3 -m eqanun search "mülkiyyət" --scope text --status all --types 73 -n 10
python3 -m eqanun count "əmək məcəlləsi"
python3 -m eqanun get 46944
python3 -m eqanun fulltext 46944 --out civil-code.txt
python3 -m eqanun fulltext 46944 --html --out civil-code.html
python3 -m eqanun types
python3 -m eqanun sectionscount has no type filter — the upstream count endpoint ignores it. For a
type-filtered count, run search --types … -n 1 and read total.
MCP server (no auth, no dependencies)
MCP (JSON-RPC 2.0) is implemented directly in the standard library
(eqanun/mcp_server.py) — it runs on stock Python 3.9
with no mcp SDK and no pip install. Exposes search_acts (with the types
filter), count_acts, get_act, get_act_fulltext (paginated by characters —
offset / max_chars, default 20,000, with total_chars and next_offset in
every response), list_types, list_sections.
Full text is cached for up to 8 acts (LRU) for the process lifetime, so paging
through a long act costs one upstream fetch rather than one per page. The MCP
get_act_fulltext tool always returns plain text; the raw-HTML option exists
only in the Python client and the CLI.
No authentication. The upstream e-qanun.az API is public and this server adds no auth of its own — connect it straight from a client UI ("No authentication").
Local stdio — the usual desktop MCP client config:
{
"mcpServers": {
"eqanun": {
"command": "python3",
"args": ["/absolute/path/to/eqanun-api/server.py"]
}
}
}Or run it directly: python3 server.py.
Streamable HTTP, bound to loopback by default:
python3 server.py --transport http --port 8000
# -> http://127.0.0.1:8000/mcpEnv fallbacks: EQANUN_MCP_TRANSPORT, EQANUN_MCP_HOST, EQANUN_MCP_PORT,
EQANUN_USER_AGENT.
Exposure note: the HTTP transport has no authentication, and it issues an
Mcp-Session-Idoninitializewithout enforcing it on later requests. It binds127.0.0.1by default;--host 0.0.0.0is an explicit opt-in that lets anyone who can reach the port call the tools. Put it behind a reverse proxy with your own access control if it needs to be reachable from the internet.Browser requests are rejected by default: a request carrying an
Originheader gets 403 unless that origin is listed inEQANUN_MCP_ALLOWED_ORIGINS(comma-separated, or*to allow all). This is the MCP spec's DNS-rebinding protection — without it, any web page you visit could drive a loopback-bound server through your browser. Non-browser MCP clients send noOriginand are unaffected. Request bodies are capped at 1 MB.
To connect from a cloud UI (Claude connectors / Copilot Studio custom MCP
connector) the server must be reachable from the internet — a cloud UI cannot
reach localhost. Use your own reverse proxy or tunnel, or the convenience
scripts below, then paste the /mcp URL into the connector and select No
authentication.
run-public.sh (macOS/Linux) and run-public.ps1 (Windows) do this in one
command. They use a cloudflared already on your PATH if there is one. If there
is not, they will download and run a third-party binary, and they refuse to
do that unless you opt in with EQANUN_ALLOW_DOWNLOAD=1 — because Cloudflare
publishes no checksum file for its releases, so an automatic download cannot be
integrity-verified. Installing cloudflared through your package manager
(brew install cloudflared, winget install Cloudflare.cloudflared,
pkg.cloudflare.com) is the safer path, and then
the scripts just use it.
While a tunnel is up, anyone with the URL can call this unauthenticated server, which means they can make your IP pull multi-megabyte documents from the Ministry of Justice host in your name. Stop the script when you are done.
For Copilot Studio / Power Platform there are ready-made connector specs and a
step-by-step runbook in copilot-studio/ — an MCP connector
(x-ms-agentic-protocol: mcp-streamable-1.0) and a hosting-free direct REST
connector over api.e-qanun.az. The MCP connector ships with a placeholder host
(REPLACE-ME.example.com); set it to your own deployment URL before importing.
Note that the direct REST connector talks to the JSON API only and therefore
cannot return act full text — full text requires this server (or the Python
client), because it comes from the header-guarded static host.
Verify the server locally with a raw JSON-RPC call:
python3 server.py --transport http --host 127.0.0.1 --port 8000 &
curl -s -X POST http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Verify
Offline unit tests — no network, safe to run in CI:
python3 -m unittest discover -s tests -vLive end-to-end check against the real API (opt-in, because it fetches from the official host):
python3 examples/smoke_test.pyExercises search → count → get_act → get_act_fulltext → taxonomy and prints PASS/FAIL.
Layout
.
├── README.md
├── API.md # reconstructed e-qanun.az API reference
├── LICENSE # MIT
├── requirements.txt
├── eqanun/ # dependency-free core (Python 3.9+)
│ ├── __init__.py
│ ├── client.py # EqanunClient: search, get_act, get_act_fulltext, ...
│ ├── _html.py # charset-aware HTML → clean text
│ ├── mcp_server.py # MCP (stdio + Streamable HTTP), pure stdlib, no auth
│ └── __main__.py # `python3 -m eqanun` CLI
├── server.py # MCP server entry point (python3 server.py [--transport http])
├── run-public.sh # one-command: expose MCP over a free HTTPS tunnel (macOS/Linux)
├── run-public.ps1 # same, for Windows PowerShell
├── copilot-studio/ # Power Platform / Copilot Studio custom connectors
│ ├── mcp-connector.swagger.json # MCP connector (x-ms-agentic-protocol)
│ ├── rest-connector.swagger.json # direct REST connector (no hosting)
│ └── RUNBOOK.md # import + no-auth setup steps
├── tests/
│ └── test_offline.py # unit tests, no network
└── examples/
└── smoke_test.py # live end-to-end checkGovernance / legal note
e-qanun.az is the official Ministry of Justice database and its content is public legal acts. Read-only metadata and full-text retrieval for legal research is low-risk. If you intend to run this at scale or in production, prefer an official arrangement (a Swagger endpoint exists but is IP/referer-gated — request access and terms from justice.gov.az), and review e-qanun.az's own terms of use for yourself.
Be a polite client: acts change rarely, so cache aggressively and keep a low crawl rate. This client identifies itself as
eqanun-api/<version>rather than impersonating a browser; setEQANUN_USER_AGENTto name your own deployment and give the operator a way to reach you.On the
Refererheader, plainly: the static full-text host runs a hotlink guard, and this client sends a same-siteRefererthat steps past it. That is a deliberate choice, not an accident of implementation. The reasoning: the content is public law, no authentication or paywall is being defeated, the client identifies itself honestly and fetches single acts at a low rate, and the project ships no bulk harvester. If the operator objects, stop.Azerbaijani legislation via e-qanun is a primary source: cite with the status (
statusName) and dates as returned by the API — remembering that these are the publisher's own labels and thateffectDateis frequently absent.Always link or quote from the canonical
htmlUrlreturned byGET /framework/{id}rather than constructing URLs yourself.No warranty, and nothing here is legal advice. The software is provided as-is under the MIT License; the risk assessment above is not a substitute for your own review of the source's terms.
License
MIT — this covers the software in this repository only.
The legal acts it retrieves are published by the Ministry of Justice of the Republic of Azerbaijan on e-qanun.az. They are subject to that publisher's own terms; this project neither owns nor relicenses them, and redistributing the corpus is out of scope (see the governance note above).
This server cannot be installed
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 Servers
- Alicense-qualityFmaintenanceMCP server providing indexed access to 45,899 Czech statutes from e-sbirka.cz, enabling agents to retrieve real legal text and citations.Last updated572Apache 2.0
- AlicenseAqualityAmaintenanceMCP server for querying French legislation and case law via the Legifrance API, enabling search and retrieval of laws, codes, and court decisions with verifiable citations.Last updated71Apache 2.0
- Alicense-qualityBmaintenanceMCP server for real-time access to Mozambican legislation, enabling search, status checks, article retrieval, historical versions, and citation resolution via the Mozaia platform.Last updatedMIT
- Alicense-qualityAmaintenanceAn MCP server for accessing Turkish legislation (laws, regulations, decrees) via the Adalet Bakanligi API, providing search, full-text retrieval, and structured citations.Last updatedApache 2.0
Related MCP Connectors
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Task-oriented MCP for Indonesian law: search, resolve citations, read laws, and MK decisions.
MCP for CourtListener: US federal and state opinions, dockets, judges, plus eCFR regulations.
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/beerbottle90/eqanun-api'
If you have feedback or need assistance with the MCP directory API, please join our Discord server