Skip to the content.

API Reference

Reference for programmatic usage of Axiolex through the Python SDK, REST API, and MCP interface.

New to Axiolex? Start with the overview or the quick start guide.


Integration Surfaces

Axiolex exposes three integration surfaces. All hit the same backend — same Redis catalog, same retrieval engine, same execution dispatcher.

Surface Best for Package
Python SDK Python applications pip install axiolex (httpx + pydantic only)
REST API Non-Python applications, curl, any HTTP client Axiolex server on port 9700
MCP server AI clients (Claude Desktop, Cursor, custom LLM agents) Axiolex MCP endpoint at port 9700 /mcp

Operation mapping

Capability Python SDK REST endpoint MCP tool
Health check client.health() GET /status
List namespaces client.list_namespaces() GET /capabilities list_namespaces()
Discover tools client.discover(...) POST /discover axiolex_discover_tools(...)
Execute tool client.execute(...) POST /execute axiolex_execute_tool(...)
Retrieve documents client.retrieve(...) POST /retrieve

Quick Start

Python SDK

from axiolex import Axiolex

client = Axiolex("http://localhost:9700")

# Discover tools
tools = client.discover("get stock earnings", top_k=5, namespaces=["finance"])

# Execute the top-ranked tool
result = client.execute(tools["tools"][0]["tool_id"], {"symbol": "AAPL"})

# List available namespaces
namespaces = client.list_namespaces()

REST API

# Discover tools
curl -X POST http://localhost:9700/discover \
  -H "Content-Type: application/json" \
  -d '{"query": "get stock earnings", "top_k": 5, "namespaces": ["finance"]}'

# Execute a tool
curl -X POST http://localhost:9700/execute \
  -H "Content-Type: application/json" \
  -d '{"tool_id": "aina_markets:get_earnings_calendar", "arguments": {"symbol": "AAPL"}}'

# List namespaces
curl http://localhost:9700/capabilities

MCP server

// Claude Desktop config
"axiolex": { "url": "http://localhost:9700/mcp" }

The AI client sees axiolex_discover_tools, axiolex_execute_tool, and list_namespaces as callable tools.


Python SDK Reference

Axiolex class

from axiolex import Axiolex

client = Axiolex(base_url="http://localhost:9700", timeout=30.0)

Parameters:

Parameter Type Default Description
base_url str http://localhost:9700 Axiolex server URL
timeout float 30.0 Request timeout in seconds

The SDK is a thin HTTP client — only requires httpx and pydantic. No Redis, ColBERT, or server-side dependencies.

discover()

Discover tools relevant to a natural-language query.

client.discover(
    query: str,
    top_k: Optional[int] = None,
    hybrid_search: Optional[bool] = None,
    temperature: Optional[float] = None,
    min_hybrid_score: Optional[float] = None,
    bm25_weight: Optional[float] = None,
    colbert_weight: Optional[float] = None,
    candidate_limit: Optional[int] = None,
    namespaces: Optional[List[str]] = None,
    max_tools: Optional[int] = None,  # deprecated alias for top_k
) -> Dict[str, Any]

Parameters:

Parameter Type Default Description
query str required Natural-language request
top_k int deployment default Maximum number of tools to return
hybrid_search bool None (deployment default) True = force hybrid, False = force lexical, None = deployment default
temperature float from settings Softmax temperature for score fusion
min_hybrid_score float 0.0 Minimum fused hybrid score
bm25_weight float 0.4 BM25 blend weight (hybrid mode)
colbert_weight float 0.6 ColBERT blend weight (hybrid mode)
candidate_limit int 100 Per-model candidate count before fusion
namespaces List[str] None (all) Restrict discovery to these namespaces

Returns:

{
    "query": str,
    "tools": List[Dict],
    "count": int,
    "search_mode": str,  # "lexical" or "hybrid"
}

Each tool in the tools list contains:

Field Type Description
tool_id str Stable identifier ({provider_id}:{tool_name})
name str Tool name
description str Tool description
rank int Rank position (1-based)
relevance_score float Normalized score (0.0-1.0)
params Dict Input schema
inputSchema Dict JSON Schema for tool arguments
endpoint str or Dict Provider endpoint
transport str streamable-http, stdio, or a2a
provider str Provider ID
namespaces List[str] Namespaces this tool belongs to
bm25_score float Raw BM25 score (lexical mode)
softmax_score float Softmax probability (lexical mode)
colbert_score float ColBERT score (hybrid mode)
hybrid_score float Fused hybrid score (hybrid mode)

Example:

result = client.discover("stock earnings calendar", top_k=3, namespaces=["finance"])

for tool in result["tools"]:
    print(f"#{tool['rank']} {tool['name']} (score={tool['relevance_score']:.3f})")
    print(f"  tool_id: {tool['tool_id']}")
    print(f"  transport: {tool['transport']}")

execute()

Execute a discovered tool by tool_id.

client.execute(
    tool_id: str,
    arguments: Dict[str, Any],
    idempotency_key: Optional[str] = None,
    timeout_ms: Optional[int] = None,
) -> Dict[str, Any]

Parameters:

Parameter Type Default Description
tool_id str required Stable identifier from discover()
arguments Dict required Arguments matching the tool’s input schema
idempotency_key str None Optional de-duplication key (logged, not enforced in Phase 1)
timeout_ms int None Optional execution timeout in milliseconds

Returns (success):

{
    "status": "success",
    "tool_id": str,
    "execution_id": str,
    "result": Dict,
}

Returns (error):

{
    "status": "error",
    "tool_id": str,
    "execution_id": str,
    "error": {
        "code": str,       # TOOL_NOT_FOUND, TOOL_UNAVAILABLE, INVALID_ARGUMENTS, UPSTREAM_TIMEOUT, UPSTREAM_ERROR, RATE_LIMITED, INTERNAL_ERROR
        "message": str,
        "retryable": bool,
    }
}

Example:

result = client.execute("aina_markets:get_earnings_calendar", {"symbol": "AAPL"})

if result["status"] == "success":
    print(result["result"])
else:
    print(f"Error: {result['error']['code']} - {result['error']['message']}")

list_namespaces()

Return the enterprise capability map — enabled namespaces with id, name, and description.

client.list_namespaces() -> List[Dict[str, Any]]

Returns:

[
    {"id": "finance.market_data", "name": "Market Data", "description": "..."},
    {"id": "finance.trading", "name": "Trading", "description": "..."},
]

retrieve()

Retrieve ranked documents (lower-level than discover() — returns raw documents, not execution-ready tools).

client.retrieve(
    query: str,
    top_k: Optional[int] = None,
    hybrid_search: Optional[bool] = None,
    temperature: Optional[float] = None,
    ignore_zero: Optional[bool] = None,
    llm_tools_cutoff: Optional[float] = None,
    bm25_weight: Optional[float] = None,
    colbert_weight: Optional[float] = None,
    candidate_limit: Optional[int] = None,
    min_hybrid_score: Optional[float] = None,
    namespaces: Optional[List[str]] = None,
    max_results: Optional[int] = None,  # deprecated alias for top_k
) -> Dict[str, Any]

Returns:

{
    "success": bool,
    "message": str,
    "documents": List[Dict],
    "total_retrieved": int,
    "cutoff_percentage": float,
    "settings": Dict,
    "search_mode": str,
}

health()

Check server health and retrieval status.

client.health() -> Dict[str, Any]

Returns:

{
    "status": "healthy",
    "document_count": int,
    "retriever_initialized": bool,
    "version": str,
    "hybrid_search": {
        "enabled": bool,
        "model": str,
        "available": bool,
        "index_ready": bool,
        "error": Optional[str],
    },
    "default_top_k": int,
}

Error handling

The SDK raises AxiolexError on any non-2xx response from the server. The exception includes the server’s error message and HTTP status code.

from axiolex import Axiolex, AxiolexError

client = Axiolex("http://localhost:9700")

try:
    result = client.discover("test query", namespaces=["bad_namespace"])
except AxiolexError as e:
    print(f"Error: {e.message}")        # "Unknown namespace(s): bad_namespace"
    print(f"Status code: {e.status_code}")  # 400

AxiolexError attributes:

Attribute Type Description
message str Human-readable error detail from the server
status_code int HTTP status code (400, 422, 500, etc.)

Common error scenarios:

Scenario Status code Example message
Unknown namespace 400 Unknown namespace(s): bad_ns
Invalid parameter value 422 body > top_k: Input should be greater than or equal to 1
Tool not found 400 TOOL_NOT_FOUND: Tool 'bad:tool' not found in the current catalog
Server error 500 Internal server error

Context manager

The SDK supports use as a context manager to ensure the HTTP client is properly closed:

with Axiolex("http://localhost:9700") as client:
    tools = client.discover("stock earnings")
    result = client.execute(tools["tools"][0]["tool_id"], {"symbol": "AAPL"})

REST API Reference

Base URL

http://localhost:9700

POST /discover

Discover execution-ready tools for a natural-language query.

Request body:

{
    "query": "stock earnings calendar",
    "top_k": 5,
    "namespaces": ["finance"],
    "hybrid_search": null,
    "temperature": null,
    "bm25_weight": null,
    "colbert_weight": null,
    "candidate_limit": null,
    "min_hybrid_score": null
}

Only query is required. All other fields are optional.

Response (200):

{
    "query": "stock earnings calendar",
    "tools": [...],
    "count": 3,
    "search_mode": "hybrid"
}

Error responses:

Status Body Cause
400 {"detail": "Unknown namespace(s): bad_ns"} Invalid namespace
422 {"detail": [{...validation errors...}]} Invalid parameter values
500 {"detail": "..."} Server error

POST /execute

Execute a tool by tool_id.

Request body:

{
    "tool_id": "aina_markets:get_earnings_calendar",
    "arguments": {"symbol": "AAPL"},
    "idempotency_key": null,
    "timeout_ms": null
}

Response (200):

{
    "status": "success",
    "tool_id": "aina_markets:get_earnings_calendar",
    "execution_id": "abc123...",
    "result": {...}
}

GET /capabilities

List enabled namespaces (consumer-facing capability map).

Response (200):

[
    {"id": "finance.market_data", "name": "Market Data", "description": "..."},
    {"id": "finance.trading", "name": "Trading", "description": "..."}
]

GET /namespaces

List all registered namespaces (management endpoint — includes disabled).

POST /retrieve

Retrieve ranked documents (lower-level than /discover).

Request body: Same as /discover plus ignore_zero and llm_tools_cutoff.

GET /status

Server health and retrieval status.

Response (200):

{
    "status": "healthy",
    "document_count": 62,
    "retriever_initialized": true,
    "version": "1.0.11",
    "hybrid_search": {
        "enabled": true,
        "model": "colbert-ir/colbertv2.0",
        "available": true,
        "index_ready": true,
        "error": null
    },
    "default_top_k": 7
}

Management endpoints

Method Path Purpose
GET /mcp-providers List providers (MCP and A2A)
POST /mcp-providers Add a provider
PUT /mcp-providers/{id} Update a provider
DELETE /mcp-providers/{id} Remove a provider
GET /mcp-providers/{id}/discover Discover tools from a provider
DELETE /mcp-providers/{id}/tools Delete cached tools for a provider
POST /mcp-providers/{id}/secret Store an encrypted provider secret
GET /mcp-providers/{id}/secret Check whether a secret exists
DELETE /mcp-providers/{id}/secret Delete a provider secret
POST /namespaces Add a namespace
PUT /namespaces/{id} Update a namespace
DELETE /namespaces/{id} Delete a namespace
POST /index Build or rebuild the index
GET /settings Get current settings
POST /settings Update settings
POST /reload Reload catalog from Redis

MCP Interface Reference

The MCP endpoint (port 9700 at /mcp) exposes three tools to AI clients:

axiolex_discover_tools(query, top_k?, hybrid_search?, namespaces?, ...)

Find tools relevant to a natural-language request. Returns tool_id, name, parameter schema, endpoint, and transport.

Key parameters:

Parameter Type Required Description
query str yes Natural-language request
top_k int no Maximum tools to return
namespaces List[str] no Restrict to these namespaces
hybrid_search bool no Force hybrid or lexical mode

Returns: DiscoverToolsResult with query, tools, count, search_mode.

axiolex_execute_tool(tool_id, arguments, idempotency_key?, timeout_ms?)

Execute a tool by tool_id. The client selects a tool_id from discovery and passes arguments. Axiolex resolves the provider, transport, endpoint, and credentials server-side and returns a normalized result. The client never needs to know whether the tool is backed by MCP, A2A, an adapter, or an internal service.

Returns: ExecuteToolResult with status, tool_id, execution_id, result (on success) or error (on failure).

list_namespaces()

List enabled namespaces with id, name, and description. Call this first to discover available capability areas.

Returns: ListNamespacesResult with namespaces list and count.


A2A (Agent-to-Agent) Providers

Axiolex supports A2A agents alongside MCP providers. A2A agents expose their capabilities as skills via an agent card, and Axiolex maps each skill to a tool in the catalog. The caller never needs to know whether a tool is backed by MCP or A2A — both are discovered, ranked, and executed through the same axiolex_execute_tool(tool_id, arguments) contract.

How A2A differs from MCP

Aspect MCP (streamable-http, stdio) A2A
Discovery tools/list over MCP session GET {endpoint}/.well-known/agent-card.json
Tool unit MCP tool with inputSchema A2A skill with id, name, description
Execution tools/call with name + arguments SendMessage with message.parts[].text
Required header Mcp-Session-Id A2A-Version: 1.0
Session Stateful (initialize handshake) Stateless (no handshake)
Response CallToolResult with content[] Task with artifacts[].parts[].text
Arguments Structured key-value matching inputSchema Natural-language prompt sent as text part

Provider configuration

providers:
  - id: veris_finance_a2a
    name: Veris Finance Research (A2A)
    transport: a2a
    endpoint: http://localhost:8100/agents/veris-finance-research-agent/
    auth:
      type: none
    enabled: true
    namespaces:
      - veris.research

Discovery

Axiolex fetches the agent card at {endpoint}/.well-known/agent-card.json and maps each skill to a tool:

agent card skill                     →  Axiolex catalog tool
────────────────────────────────────     ─────────────────────────────────────
id: "financial_research"               →  tool_id: veris_finance_a2a:financial_research
name: "Financial Research"             →  title: "Financial Research"
description: "Synthesizes sourced..."   →  description: "Synthesizes sourced..."
                                       →  params: {prompt: {type: string}}
                                       →  transport: a2a

Execution

When execute() is called on an A2A tool, the A2A adapter sends a SendMessage JSON-RPC request:

from axiolex import Axiolex

client = Axiolex("http://localhost:9700")

# Discover A2A agent skills
tools = client.discover("financial research on Nvidia", namespaces=["veris.research"])

# Execute — the A2A adapter sends SendMessage to the agent
result = client.execute(
    "veris_finance_a2a:financial_research",
    {"prompt": "What was Nvidia revenue in 2024?"}
)

# Result contains the agent's response in content[]
for item in result["result"]["content"]:
    print(item["text"])

If the tool’s schema has a single prompt field, its value is sent as a text part. Otherwise, the arguments dict is JSON-encoded as a text part.

A2A auth

A2A providers support the same auth options as MCP:

Auth type How it works
none No authentication
bearer Token sent in Authorization: Bearer header
api_key Key appended as query parameter (?api_key=...)

Execution Error Codes

Code Meaning Retryable
TOOL_NOT_FOUND tool_id not in the current catalog No
TOOL_UNAVAILABLE Tool exists but transport is not supported No
INVALID_ARGUMENTS Arguments don’t match the tool’s schema No
UPSTREAM_TIMEOUT Provider did not respond within the timeout Yes
UPSTREAM_ERROR Provider returned an error Depends
RATE_LIMITED Provider rate-limited the request Yes
INTERNAL_ERROR Unexpected dispatcher error No

Configuration

Environment variables

Variable Default Description
AXIOLEX_HYBRID_ENABLED false Enable hybrid search at startup
AXIOLEX_COLBERT_MODEL colbert-ir/colbertv2.0 HuggingFace model identifier
AXIOLEX_COLBERT_CACHE_DIR FastEmbed default Local cache directory for model weights
AXIOLEX_COLBERT_BATCH_SIZE 32 Encoding batch size
AXIOLEX_HYBRID_CANDIDATE_LIMIT 100 Per-model candidate count before fusion
AXIOLEX_RRF_K 60 Reciprocal Rank Fusion constant
AXIOLEX_HYBRID_BM25_WEIGHT 0.4 Default BM25 blend weight
AXIOLEX_HYBRID_COLBERT_WEIGHT 0.6 Default ColBERT blend weight
AXIOLEX_EXECUTE_TIMEOUT_MS 30000 Execution timeout ceiling
AXIOLEX_SECRET_MASTER_KEY Master key for encrypted secret store
BM25S_TEMPERATURE 0.5 Softmax temperature
BM25S_IGNORE_ZERO true Filter zero-score results
BM25S_CUTOFF 10.0 Minimum softmax percentage
BM25S_HOST 0.0.0.0 Server host
BM25S_PORT 9700 Server port
BM25S_LOG_LEVEL info Log level

Hybrid search tuning

For temperature, cutoff, hybrid weights, and ColBERT model configuration, see the Search Guide.

settings.yaml

bm25s:
  temperature: 0.5
  ignore_zero: true
  llm_tools_cutoff: 10.0

documents:
  source: "source_files/tools_list.yaml"
  auto_reload: true
  encoding: "utf-8"

server:
  host: "0.0.0.0"
  port: 9700
  reload: false
  log_level: "info"