liberrex-mcp-server (Python)
Publish a platform's tools on the Liberrex MCP mesh, so that Liberrex AI, Animatoria, the ERP and any other
platform of the ecosystem can call them. It follows the shared mesh conventions: peer keys,
per-call user identity, permissions, write control and [code] errors. The package also ships the Liberrex AI
platform server (liberrex-mcp-server): agents, copilot and sales intelligence (next best action, next best
product…) as tools.
- Python ≥ 3.10, built on the official
mcpSDK v2. Stateless Streamable HTTP (any instance answers any call) or stdio. - Pair it with
liberrex-mcp-clienton the calling side. - TypeScript equivalent:
@liberrex/mcp-server.
pip install liberrex-mcp-server
Publish your platform's tools
from typing import Optional
from liberrex_mcp_server import PeerRegistry, PlatformError, PlatformServer, ToolContext
server = PlatformServer("erp", title="Acme ERP", peers=PeerRegistry.from_env())
@server.tool(permission="invoices.read", category="finance")
def overdue_invoices(ctx: ToolContext, customer: Optional[str] = None, limit: int = 20) -> dict:
"""Overdue invoices the user can see, oldest first."""
user = ctx.require_identity() # who the call acts for: user_id, tenant_id, roles, locale
rows = invoices.overdue(tenant=user.tenant_id, user=user.user_id, customer=customer, limit=limit)
if rows is None:
raise PlatformError("not_found", "Unknown customer") # → "[not_found] Unknown customer"
return {"items": rows}
@server.tool(permission="invoices.write", write=True)
async def send_reminder(ctx: ToolContext, invoice_id: str) -> dict:
"""Send a payment reminder."""
...
Then serve it:
app.mount("/mcp", server.asgi()) # FastAPI / Starlette; the endpoint answers at /mcp/
server.run_http(port=8765) # standalone, at /mcp
server.run_stdio() # local desktop clients
The SDK checks these before your function runs:
| check | refusal |
|---|---|
The Authorization: Bearer key is a valid (not expired) key of a configured peer |
HTTP 401 [unauthorized] |
At most rate_per_minute × 10 HTTP requests per minute from that peer (flood guard) |
HTTP 429 + Retry-After |
At most rate_per_minute tool calls per minute from that peer |
[rate_limited] |
| The identity's tenant is one the peer may act in | [tenant_not_allowed] |
The identity's roles, capped by the peer's roles, include the tool's permission |
[forbidden] / [identity_required] |
write=True tools only for peers with writes |
[writes_disabled] |
| At most 4 platform hops | [too_many_hops] |
| Any other exception: logged, and not leaked to the caller | [internal_error] <tool> failed |
Sync functions run in a worker thread, so they may block, for example on a database call. Use
ctx.forward_meta() when a tool calls another platform: the same person and trace go along, with hops + 1.
Already integrated with the Liberrex copilot?
Publish every tool you declared with liberrex_copilot in one line. The schemas, permission checks and error codes stay
the same:
from liberrex_mcp_server.copilot import publish_copilot
publish_copilot(server, copilot, user=lambda identity: load_user_with_roles(identity))
This is how Animatoria publishes its 43 tools at /mcp. The user callback lets your platform compute the user's
roles itself, rather than trust the roles the caller sends.
Tools that already have a JSON Schema
server.raw_tool("lookup", description="…", input_schema={"type": "object", "properties": {...}},
handler=lambda ctx, arguments: ...)
Peers (who may call)
liberrex-mcp-server new-key liberrex-ai # prints a key for the caller and the sha256 entry for you
LIBERREX_MCP_PEERS='{"liberrex-ai": {"keys": [{"key": "sha256:…", "expires": "2027-01-31"}, "sha256:…"],
"tenants": "*", "writes": false, "rate_per_minute": 300},
"erp": {"key": "sha256:…", "tenants": ["acme"], "roles": ["invoices.read"]}}'
LIBERREX_MCP_PEERS_FILE=/etc/erp/mcp-peers.json # or: the same JSON in a file, re-read when it changes
| field | meaning | default |
|---|---|---|
key / keys |
sha256:<64 hex> (preferred) or the raw key (24 characters at least); or {"key", "expires": "YYYY-MM-DD"}: valid until the end of that UTC day |
required |
tenants |
"*" or the tenant ids the peer may act in |
"*" |
writes |
may call write=True tools |
false |
roles |
ceiling: the identity's roles are intersected with it | none |
rate_per_minute |
tool calls per minute (1 to 10,000), per process; HTTP requests are capped at 10× that | 120 |
Keep only hashes on the server, give each caller its own key, and grant writes only where needed. Rotate with an
overlap: add the new hash to keys, give the caller the new key, then remove the old hash (or let its expires pass).
python -m liberrex_mcp_server.keys <peer> also prints a key and its hash.
With LIBERREX_MCP_PEERS_FILE (FilePeerRegistry), the file is re-read when its mtime changes (checked at most every
2 s): revoke a caller without a restart. Invalid at startup → PeerConfigError; invalid later → logged, the previous
peers stay; missing → no caller is accepted.
Audit
Every tool call (ok / refused / error) and every refused HTTP request (unauthorized, rate_limited) produces one
event for PlatformServer(..., audit=fn) (default: a JSON line on the liberrex_mcp_server.audit logger; None: off):
at, platform, event, tool, write, peer, user, tenant, trace_id, origin, hops, status, code,
duration_ms (and client for HTTP events). Tool arguments are never included. The fields are the same in the
TypeScript server; see MCP_MESH.md §6.
The Liberrex AI platform server
liberrex-mcp-server --check # credentials, peers, tools
liberrex-mcp-server --transport http --port 8765 # the mesh endpoint at /mcp (needs LIBERREX_MCP_PEERS)
liberrex-mcp-server # stdio for Claude Desktop / Cursor (acts as LIBERREX_USER_ID)
| Variable | Meaning |
|---|---|
LIBERREX_API_URL |
Liberrex API (default https://ai-api.liberrex.com) |
LIBERREX_API_KEY |
Developer API key key_id:secret: agents, conversations, usage (company-wide tools) |
LIBERREX_SECRET_KEY |
Embedded copilot key lxsk_…: copilot and surfaces, for the identity of each call |
LIBERREX_SURFACES |
next_best_action=nba-queue,next_best_product=nbp-queue: modes of sales_recommendations |
LIBERREX_MCP_PEERS / LIBERREX_MCP_PEERS_FILE |
Platforms allowed to call (see above) |
LIBERREX_USER_ID, LIBERREX_TENANT_ID, LIBERREX_USER_ROLES, LIBERREX_LOCALE |
stdio only: the user a desktop client acts as |
LIBERREX_MCP_READ_ONLY |
1 leaves out confirm_action, create_action_batch and end_conversation |
The 20 tools are:
| Group | Tools |
|---|---|
| Agents | whoami, list_agents, get_agent, ask_agent, list_copilot_agents, start_agent_group, ask_agent_group, get_agent_group, list_conversations, get_conversation, end_conversation, get_usage |
| Copilot | copilot_ask, copilot_list_threads, copilot_get_thread |
| Sales intelligence | sales_recommendations, render_surface, suggest_field, run_surface_action, create_action_batch, confirm_action, cancel_action, record_feedback |
| Billing | get_copilot_usage |
Each calling user gets their own copilot session, minted for the user.id and tenant.id the calling platform sends.
Recommendations are therefore computed from that user's own data, under their own roles.
Development
python3.12 -m venv .venv && .venv/bin/pip install -e ".[dev]" -e ../../mcp-client/python -e ../../python
.venv/bin/pytest # 39 tests, including server ↔ client end to end over HTTP
Metadata
Release files for liberrex-mcp-server 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| liberrex_mcp_server-0.1.0.tar.gz | 44.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| liberrex_mcp_server-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 82.1 kB
Release files / liberrex_mcp_server-0.1.0.tar.gz
| Download URL | liberrex_mcp_server-0.1.0.tar.gz |
|---|---|
| Size | 44.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37ce874f0877631e6d00e35f09dea4f8990ec8bec1201428d20eee73766dde51
|
|
BLAKE2b-256 checksum How to use checksums |
3366003a127a88ac0799f26d5d9a155929a67e693eec4d4bc02d14894fa4b6e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|
Release files / liberrex_mcp_server-0.1.0-py3-none-any.whl
| Download URL | liberrex_mcp_server-0.1.0-py3-none-any.whl |
|---|---|
| Size | 37.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
058a375acef8f69b430ea896da404f547762841b820f1971996e4cb555032518
|
|
BLAKE2b-256 checksum How to use checksums |
d0aa732b189452877f77aa10c883e41f1b865f6f8a443aa080209b61f1ad7f12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.12
|