Skip to main content
Glama
README.md
<div align="center">
  <img src="image/logo_axomind.png" alt="Axomind Logo" width="150"/>
  <h1>axomind-mcp</h1>
  <p><strong>MCP server (Model Context Protocol) for Axomind — a harmless proxy to the Bot API.</strong></p>
</div>

---

## Principle

The MCP lives on the **consumer side**, not on the Axomind server. It contains no business logic — it makes HTTP POST requests to `bot_api.php` and returns the JSON. All security (auth, rate limiting, IP bans, `bots @>` checks) stays on the PHP side.

```
AI (any MCP client — Hermes, Claude, Cursor, etc.)
  → MCP server Python (FastMCP)
    → HTTP POST → bot_api.php
      → PHP does the work (auth, DB, WS notify)
    ← JSON response
  ← MCP tool result → AI
```

## What this MCP does

This server exposes **26 bot tools** that let an AI interact with Axomind resources where a bot is assigned:

- **Mindmap** (10 tools) — read, create, update, delete nodes; manage styles
- **Messenger** (4 tools) — send, read, update, delete bot messages
- **Planning** (9 tools) — list activities, manage assignments, read time slots
- **Tree** (3 tools) — scan local directories and inject them as mindmap structures

## Installation

```bash
uv pip install -e .
```

Dependencies: `mcp` (official SDK), `httpx` (HTTP client).

## Configuration

Copy `.env.example` to `.env` and fill in your bot credentials:

```bash
cp .env.example .env
```

### Required variables

| Variable | Description |
|---|---|
| `AXOMIND_BASE_URL` | URL to `bot_api.php` on the Axomind server (e.g. `https://quantive-studio.fr/app/bot_api.php`) |
| `AXOMIND_BOT_ID` | Bot ID (from Axomind UI → bot management) |
| `AXOMIND_BOT_KEY` | Bot access key (generated when creating the bot in the UI) |

### Optional

| Variable | Default | Description |
|---|---|---|
| `AXOMIND_TIMEOUT` | `30` | HTTP timeout in seconds |
| `AXOMIND_ENV_FILE` | — | Explicit path to `.env` file (recommended for production) |

## How to get bot credentials

1. Open Axomind desktop app
2. Go to bot management
3. Create a new bot → you get a **Bot ID** and a **Bot access key**
4. Assign the bot to the resources you want it to access (mindmaps, activities, conversations)
5. Put the credentials in your `.env` file

The bot can only access resources where its ID is listed in the `bots` JSONB column — this is enforced server-side by Axomind.

## Available tools (26)

### Mindmap (10) — bot API

| Tool | Description | Destructive? |
|---|---|---|
| `list_mindmaps` | List mindmaps where the bot is assigned (metadata only) | No |
| `get_mindmap` | Read a mindmap (metadata + all nodes). ⚠️ Response can exceed 2 MB for 60+ nodes with descriptions | No |
| `get_mindmap_summary` | **Compact summary** — node count, titles, structure, has_description. Context-safe, no descriptions or styles | No |
| `get_node_description` | Read a single node's description by order_index (capped at ~4 KB). Use after `get_mindmap_summary` | No |
| `sync_nodes` | Replace ALL nodes (full JSON, ~25 fields per node). ⚠️ DESTRUCTIVE — sends 1 node → deletes the other 98 | ⚠️ Yes |
| `add_nodes` | **Append nodes** to an existing mindmap (simplified format). Reads existing, appends, syncs | No |
| `replace_mindmap` | **Replace all nodes** (simplified format). Validates hierarchy before sending | ⚠️ Yes (validated) |
| `update_node` | **Update a single node** — all fields supported (title, descriptions, parent, style, positions, free_links). Reads full mindmap, patches one node, syncs back. The algorithm handles the JSON, not the AI | No (safe) |
| `delete_node` | **Delete a node + its subtree**. Cleans free_links pointing to deleted nodes. Root node (parent=0) cannot be deleted. The algorithm handles the JSON, not the AI | No (safe) |
| `update_nodes_style` | **Update style fields** on multiple nodes (color, bold, size_box, etc.). Reads, patches, syncs back | No (safe) |

#### Safe node modification — the algorithm handles the JSON

`update_node` and `delete_node` are the **safe** way to modify a mindmap. They read the full mindmap, apply targeted changes to specific nodes, and sync everything back. Other nodes (including their descriptions) are preserved untouched.

The AI never builds the full node JSON — it passes only the fields to modify, and the algorithm does the rest:

```json
// update_node: rename node 33
{"title": "messenger.md test"}

// update_node: change description (markdown → Quill Delta conversion is automatic)
{"descriptions": "# Module Messenger\n\nThis module handles..."}

// update_node: re-parent with cycle detection
{"parent": 2}

// update_node: change style + propagate to children
{"color": "0xFFFF6F91", "bold": true, "is_write_children": true}

// delete_node: just the order_index, no JSON at all
// delete_node(id_mindmap=100, order_index=33)
```

Validations enforced by the algorithm (not by the AI):
- Self-reference: `parent == order_index` → rejected
- Cycle detection: `new_parent` is a descendant of `order_index` → rejected
- Parent must exist in the mindmap
- Root node (parent=0) cannot be deleted
- `free_links` cannot target self, all targets must exist
- `size_box` must be 0–11

#### Simplified format for `replace_mindmap` / `add_nodes`

The AI provides a compact JSON — the MCP auto-expands ~25 default fields:

```json
[
  {"title": "Root", "parent": 0, "color": "0xFFF0BA6D", "size_box": 2, "bold": true},
  {"title": "Category A", "parent": 1, "color": "0xFF7A8FF5", "size_box": 1, "line_style": 1},
  {"title": "Item 1", "parent": 2},
  {"title": "Item 2", "parent": 2, "color": "0xFFFF6F91", "free_links": [3]}
]
```

Fields:
- `title` (required) — node title
- `parent` (required) — order_index of the parent node (0 = root, 1 = first node)
- `color` (optional) — hex color (default: `0xFF7A8FF5`)
- `pos_x`, `pos_y` (optional) — canvas position (default: 0)
- `size_box` (optional) — 0=normal, 1=category, 2=root (default: 0)
- `bold`, `italic`, `underline` (optional) — text style
- `line_type` (optional) — 0=curve, 1=rounded, 2=square
- `line_style` (optional) — 0=solid, 1=dashed
- `stroke_width`, `dot_radius`, `radius`, `border_size`, `label_size` (optional)
- `icon_id` (optional) — icon ID
- `active_bg_colors` (optional) — active background colors
- `descriptions` (optional) — descriptive text (markdown → Quill Delta)
- `free_links` (optional) — list of order_index for free links between nodes
- `spacing_h`, `spacing_v` (optional) — spacing multipliers (0-10)
- `is_write_children` (optional) — propagate style to children (one-shot)

UID and order_index are assigned automatically. `add_nodes` reads the existing mindmap and appends after existing nodes.

### Tree / Directory scanning (3) — local + bot API

These tools scan the local filesystem to build mindmap structures from directory trees.

| Tool | Description | HTTP? |
|---|---|---|
| `tree_scope` | **Compact telemetry** of a directory (title, type, size, hierarchy). Does NOT read file content. Use before injection to get a reference node count | No (local) |
| `inject_directory_to_mindmap` | **One-shot scan + read + inject** — scans the directory, reads `.md`/`.markdown`/`.txt` files, converts to Quill Delta, and syncs everything into the mindmap. Returns a compact summary for validation | Yes (sync_nodes) |
| `tree_to_mindmap` | **Scan → JSON nodes** (simplified format, no file content). Ready for `replace_mindmap` or `add_nodes` | No (local) |

#### Workflow: inject a directory into a mindmap

```
1. tree_scope(root_path, root_title) → reference count (1 root + N dirs + M files)
2. inject_directory_to_mindmap(root_path, root_title, id_mindmap) → scan + read + Quill Delta + sync
3. Compare the returned summary (total_nodes, descriptions_filled, errors) with tree_scope count
4. If they match and errors is empty → injection validated. DONE.
```

- Only `.md`, `.markdown`, `.txt` files are read and converted to Quill Delta
- Files > 500 KB and non-text formats (`.docx`, `.pdf`, images) get nodes with empty descriptions
- Hidden files and VCS directories (`.git`, `node_modules`, `__pycache__`) are skipped automatically
- **Never** call `get_mindmap` to verify an injection — the summary + `tree_scope` count are sufficient

### Messenger (4) — bot API

| Tool | Description |
|---|---|
| `send_message` | Send a message (targeted or broadcast to all conversations) |
| `get_messages` | Read bot messages in a conversation |
| `update_message` | Update a bot message |
| `delete_message` | Delete a bot message |

### Activity / Planning (9) — bot API

All planning tools use the bot API (`bot_api.php` → `api_activity` route). The bot operates as the bot owner's user_id — the same authentication chain as `add_assignment` / `update_assignment` / `delete_assignment`.

#### High-level tools (prefer these)

| Tool | Description |
|---|---|
| `create_assignment` | Create an assignment (single-day or recursive) with human-friendly params (dates, hours, weekday names). Builds the JSON internally |
| `modify_assignment` | Modify an existing assignment group. Server marks tombstone, removes old slots, creates new ones |
| `verify_assignment` | Read an activity and return a telemetry report (groups, slots, consistency checks) |
| `read_planning` | Read all planning slots for a given year via the bot API. Returns actual time slot data (start/end times, day of year, user assignments) and group controls. Uses `PlanningsUsers::getList()` + `GstGroupControlPlanning::getList()` with the bot owner's user_id |

#### Low-level tools (raw JSON)

| Tool | Description |
|---|---|
| `list_activities` | List activities where the bot is assigned |
| `get_activity` | Read a specific activity (full metadata) |
| `add_assignment` | Assign time slots (raw `planning_list` + `recursive_group` JSON) |
| `update_assignment` | Update an assignment group (raw JSON) |
| `delete_assignment` | Delete an assignment group |

## Token-efficient reading strategy

The MCP provides a 3-tier reading strategy to keep AI context small:

1. **`list_mindmaps()`** — metadata only (id, title, participants). No nodes.
2. **`get_mindmap_summary(id_mindmap)`** — compact summary: node count, titles, structure, `has_description` flag. No descriptions, no positions, no styles.
3. **`get_node_description(id_mindmap, order_index)`** — read a single node's description (capped at ~4 KB).

The AI should **never** call `get_mindmap` (full) unless it needs to inspect individual node fields before a modification. For understanding structure, use `get_mindmap_summary`. For reading content, use `get_node_description` on specific nodes.

## Integration with Hermes

To consume the Axomind Bot API from Hermes, add the MCP server to `~/.hermes/config.yaml`:

```yaml
mcp_servers:
  axomind:
    command: "python3"
    args: ["-m", "axomind_mcp.serveur.server"]
    env:
      # Bot API — URL to bot_api.php on the Axomind server
      AXOMIND_BASE_URL: "https://quantive-studio.fr/app/bot_api.php"
      # Bot credentials (from Axomind UI → bot management)
      AXOMIND_BOT_ID: "<your_bot_id>"
      AXOMIND_BOT_KEY: "<your_key_access>"
      # Python import path (required — workdir sets cwd but not the import path)
      PYTHONPATH: "/path/to/axomind-mcp/src"
    workdir: "/path/to/axomind-mcp"
```

⚠️ All `env` values must be strings (YAML parses `72` as int → pydantic rejects it).
⚠️ `PYTHONPATH` is required — `workdir` sets the cwd but not the Python import path.

After editing the config, restart Hermes or run `/reload-mcp` — the 26 tools are discovered automatically with the `mcp_axomind_` prefix (e.g. `mcp_axomind_list_mindmaps`, `mcp_axomind_send_message`, `mcp_axomind_read_planning`).

### Other MCP clients (Claude Desktop, Cursor, etc.)

Use the same env vars and command. The MCP server uses standard stdio transport.

## Tests

```bash
PYTHONPATH=src python -m pytest tests/ -v
```

149 tests — mock httpx, no network calls to the Axomind server.

## Architecture

```
src/axomind_mcp/
├── __init__.py
├── _common.py              — FastMCP instance, env config, _post() helper, node defaults
├── _planning.py            — 9 tools planning/activity (bot API)
├── imports.py              — Single import hub (registers all @mcp.tool() decorators)
├── messaging/              — Messaging tools
│   ├── __init__.py
│   └── _messenger.py       — 4 tools messenger (bot API)
├── serveur/
│   ├── __init__.py
│   └── server.py           — Entry point stdio, mcp.run()
├── mindmap/
│   ├── __init__.py
│   ├── _mindmap.py         — 10 tools mindmap (bot API)
│   ├── node_operations.py  — Shared algo: update/delete/patch nodes, cycle detection, style propagation
│   └── config_layout_mindmap.py — Node expansion, validation, auto-positioning
└── tools/
    ├── __init__.py
    ├── _file_reader.py     — File reading by extension → Quill Delta
    ├── md_to_quill_delta.py — Markdown → Quill Delta converter
    └── _tree.py            — 3 tools tree (local + bot API)
```

## Security

- The MCP does not touch the database or contain any business logic
- Credentials come from environment variables (never hardcoded)
- The Axomind server cannot tell it's a MCP — it sees normal bot_api requests
- Tree tools (local filesystem scan) only scan the local machine where the MCP runs
- The `.env` file path is set via `AXOMIND_ENV_FILE` — not discoverable from the public repo

## License

Proprietary — see [LICENSE](LICENSE). Copyright © 2025 VEZZANI Sébastien. All rights reserved.

---

<div align="center">
  <a href="https://sebastien-vezzani.xyz/" target="_blank"><img src="https://img.shields.io/badge/Portfolio-3423A6?style=for-the-badge&logo=firefox-browser&logoColor=white" alt="Link to Portfolio"/></a>
</div>

TDQS

A4/5.0

Scored across 26 tools

Disambiguation4/5

Tools are clearly grouped by domain (mindmap, planning, messaging) with distinct purposes. However, there is potential confusion between add_assignment and create_assignment (both create assignments with different parameter styles) and similarly update_assignment vs modify_assignment. The descriptions help differentiate but the overlap reduces clarity.

Naming Consistency4/5

Most tools follow a consistent snake_case verb_noun pattern. However, there are multiple verbs for similar operations (add/create, update/modify) which introduces minor inconsistency. Overall, the naming is predictable and readable.

Tool Count4/5

With 26 tools covering two main domains plus messaging, the count is slightly high but still reasonable. Some redundancy exists (duplicate raw and human-friendly versions), but each tool serves a specific use case. The scope fits the server's purpose.

Completeness5/5

The tool set provides full CRUD coverage for mindmaps, planning assignments, and bot messages. Mindmap tools include bulk import and scanning helpers; planning tools offer both raw and human-friendly operations; messaging covers send, read, update, delete. No obvious gaps in the featured workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues