freeplane-mcp
by metacoma
README.md
# freeplane-mcp
An MCP server that allows AI agents such as Claude Desktop, Cursor, and opencode to read and modify a running Freeplane mind map through the [`freeplane_plugin_grpc`](https://github.com/metacoma/freeplane_plugin_grpc) gRPC plugin.
Unlike one-shot “Markdown → image” MCP servers, changes are applied live to the currently opened Freeplane map.
## Architecture
```text
MCP client (Claude / Cursor / opencode)
│
│ stdio or Streamable HTTP (MCP SDK)
▼
freeplane-mcp (Python, FastMCP)
│
│ gRPC (grpcio)
▼
Freeplane + org.freeplane.plugin.grpc
(port 50051)
```
## Requirements
- Python 3.10+
- Freeplane running with the gRPC plugin installed
- Default Freeplane gRPC port: `50051`
## Installation
```bash
cd ~/spaces/freeplane-mcp
python -m venv .venv
.venv/bin/pip install -e .
```
## Running
### stdio
Default transport for Claude Desktop, Cursor, opencode, etc.:
```bash
.venv/bin/freeplane-mcp
```
### Streamable HTTP
```bash
.venv/bin/freeplane-mcp --transport http --port 8000
```
## Configuration
| Environment variable | CLI option | Default |
|---|---|---|
| `FREEPLANE_GRPC_HOST` | `--grpc-host` | `127.0.0.1` |
| `FREEPLANE_GRPC_PORT` | `--grpc-port` | `50051` |
| `FREEPLANE_GRPC_TIMEOUT` | — | `10` |
| `FREEPLANE_MCP_TRANSPORT` | `--transport` | `stdio` |
| `FREEPLANE_MCP_HOST` | `--host` | `127.0.0.1` |
| `FREEPLANE_MCP_PORT` | `--port` | `8000` |
## MCP Tools
### `export_map`
Exports the current map to canonical JSON.
Supported fields include:
`text`, `id`, `children`, `note`, `detail`, `link`, `tags`, `icons`, `attributes`, `background_color`, `folded`, and `relationships`.
### `import_map`
Imports a mind map from canonical JSON.
Supported `insert_mode` values:
- `root` — insert below the map root; default
- `node` — insert below `insert_node_id`
- `selected` — insert below the currently selected node
## Testing
Export the current map:
```bash
.venv/bin/python -c "
import sys; sys.path.insert(0, '.')
from freeplane_mcp.freeplane_grpc import FreeplaneGrpcClient
c = FreeplaneGrpcClient()
print(c.export_map())
"
```
Import a map and export it again:
```bash
.venv/bin/python -c "
import sys; sys.path.insert(0, '.')
from freeplane_mcp.freeplane_grpc import FreeplaneGrpcClient
c = FreeplaneGrpcClient()
c.import_map('{\"text\": \"Hello from MCP\", \"children\": [{\"text\": \"child 1\"}]}')
print(c.export_map())
"
```
## MCP Client Configuration
Example stdio configuration:
```json
{
"mcpServers": {
"freeplane": {
"command": "/home/bebebeka/spaces/freeplane-mcp/.venv/bin/freeplane-mcp"
}
}
}
```
HTTP configuration:
```json
{
"mcpServers": {
"freeplane": {
"url": "http://127.0.0.1:8000/mcp"
}
}
}
```
## JSON Format Notes
The canonical JSON format is defined by the plugin's `JsonHelper.java`.
Import supports `_fp_import_root_node`:
```json
{"_fp_import_root_node": "root", "mindmap": {...}}
```
inserts below the map root.
```json
{"_fp_import_root_node": "ID_...", "mindmap": {...}}
```
inserts below a specific node.
Without the wrapper, the map is inserted below the currently selected node.
The legacy format is also supported:
```json
{"node text": {"child node": "note"}}
```
## License
MIT
TDQS
A4.1/5.0
Scored across 2 tools
Disambiguation5/5
export_map and import_map have clearly opposite purposes and there is no overlap. An agent can unambiguously determine which to call based on the direction of data transfer.
Naming Consistency5/5
Both tool names follow the same verb_noun pattern: export_map and import_map. The naming is simple, predictable, and perfectly matches the server's purpose.
Tool Count3/5
Two tools is a very minimal set, but each covers one half of the map exchange workflow. It feels slightly thin for a general MCP server, though the scope is focused.
Completeness5/5
The two tools provide a complete round-trip: export the map as JSON and import it back. For this server's apparent purpose of whole-map synchronization, there are no obvious gaps.
Maintenance
ActivityMaintained
ResponsivenessNo issues