← Blog
April 14, 2026

Integrating MentisDB with Claude Desktop, OpenCode, and any MCP Client

MentisDB supports multiple integration paths depending on your setup. The recommended path is Model Context Protocol (MCP) — a stdio-based protocol that works with Claude Desktop, OpenCode, Cursor, and any other MCP-compatible tool. For non-MCP clients, the REST API works with any HTTP library.

Table of Contents

Integration Paths Overview

IntegrationProtocolBest ForSetup Effort
Claude DesktopMCP via mcp-remoteClaude Desktop users on macOS/Linux~2 minutes with wizard
OpenCodeMCPTerminal-based coding agents~2 minutes with wizard
pymentisdb + LangChainRESTPython agents, chatbotspip install + 10 lines of code
Custom MCP clientMCP stdioBuilding MCP-native integrationsDepends on complexity
REST APIHTTP/JSONAny language, any platformRead the OpenAPI spec

One-Command Setup with the Wizard

The fastest path to any integration is mentisdbd setup:

# Interactive wizard — picks the right config for your platform
mentisdbd setup claude-desktop

# Dry run to see what would be written
mentisdbd setup claude-desktop --dry-run

# Auto-accept everything (CI/CD friendly)
mentisdbd setup claude-desktop --assume-yes

The wizard detects your platform, checks for prerequisites (Node.js, mcp-remote, etc.), writes the config file, and tells you what to do next. Run it and follow the prompts.

Homebrew-installed mcp-remote: If you installed mcp-remote via brew install mcp-remote, the wizard detects this and writes the correct mcp-remote as the command directly (no Node.js wrapper needed). The generated config looks like:

{
  "mcpServers": {
    "mentisdb": {
      "command": "/opt/homebrew/bin/mcp-remote",
      "args": ["https://my.mentisdb.com:9473"],
      "env": { "NODE_TLS_REJECT_UNAUTHORIZED": "0" }
    }
  }
}

Claude Desktop

Claude Desktop uses MCP over stdio. Since MCP servers run locally and can't handle self-signed HTTPS certificates, MentisDB ships an mcp-remote bridge that tunnels MCP stdio over HTTPS to your mentisdbd instance.

Prerequisites

Homebrew users: brew install mcp-remote installs mcp-remote with a proper shebang pointing to the correct Node version. The wizard detects this automatically and writes the minimal config.

Manual Config (optional — wizard does this for you)

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "mentisdb": {
      "command": "/opt/homebrew/bin/mcp-remote",
      "args": ["https://my.mentisdb.com:9473"],
      "env": {
        "NODE_TLS_REJECT_UNAUTHORIZED": "0"
      }
    }
  }
}

The NODE_TLS_REJECT_UNAUTHORIZED=0 flag tells mcp-remote to accept self-signed certificates. This is required for private servers with self-signed certs. Omit it when using a public HTTPS endpoint with valid certificates.

Starting Up

After saving the config, restart Claude Desktop. The mentisdb MCP server will be available — verify by asking Claude directly:

What tools do you have from mentisdb?

Or use the MCP info command in any MCP client to confirm the mentisdb server is connected and responding.

Available Tools in Claude Desktop

ToolDescription
mentisdb_appendAppend a structured memory thought
mentisdb_ranked_searchSemantic search with multi-signal ranking
mentisdb_context_bundlesGet seed thoughts with supporting evidence
mentisdb_list_chainsList all memory chains
mentisdb_register_webhookRegister HTTP callbacks on thought appends

OpenCode

OpenCode is a terminal-based coding agent. It uses MCP for tool integration. The wizard handles the setup:

mentisdbd setup opencode

This writes the OpenCode MCP config to the standard location. OpenCode's MCP block uses a slightly different format:

{
  "mcp": {
    "mentisdb": {
      "type": "remote",
      "url": "https://my.mentisdb.com:9473",
      "enabled": true
    }
  }
}

REST API — Any HTTP Client

If there's no MCP integration available for your tool, the REST API works from any language with HTTP support. mentisdbd exposes a full REST API on port 9472 (HTTP) or 9473 (HTTPS).

Quick HTTP Examples

# Append a thought to a specific chain (bash + curl)
curl -X POST http://127.0.0.1:9472/v1/thoughts \
  -H "Content-Type: application/json" \
  -d '{
    "chain_key": "my-project",
    "thought_type": "Insight",
    "content": "The cache invalidation strategy needs rethinking.",
    "role": "Memory",
    "importance": 0.8,
    "tags": ["architecture", "cache"],
    "concepts": ["invalidation", "consistency"]
  }'

# Ranked search on a specific chain
curl -X POST http://127.0.0.1:9472/v1/ranked-search \
  -H "Content-Type: application/json" \
  -d '{
    "chain_key": "my-project",
    "text": "cache invalidation strategy",
    "limit": 5,
    "min_importance": 0.5
  }'

# Search across a branch chain AND its ancestor chains (federated)
curl -X POST http://127.0.0.1:9472/v1/ranked-search \
  -H "Content-Type: application/json" \
  -d '{
    "chain_key": "project-x",
    "text": "what is our company's position on cache consistency?",
    "limit": 5
  }'

# List chains
curl http://127.0.0.1:9472/v1/chains

Python with requests

import requests

base = "http://127.0.0.1:9472"

# Append to a specific chain
r = requests.post(f"{base}/v1/thoughts", json={
    "chain_key": "my-project",
    "thought_type": "Finding",
    "content": "Query latency spiked after the last deploy.",
    "role": "Memory",
    "importance": 0.8,
    "tags": ["performance", "database"],
})
thought = r.json()["thought"]
print(f"Appended to {thought['chain_key']}: {thought['id']}")

# Search within a specific chain
r = requests.post(f"{base}/v1/ranked-search", json={
    "chain_key": "my-project",
    "text": "database performance",
    "limit": 5,
    "thought_types": ["Finding", "Insight"],
})
results = r.json()
for hit in results["results"]:
    print(f"[{hit['score']['total']:.3f}] {hit['thought']['content']}")

Complete Python REST Examples

import requests

base = "http://127.0.0.1:9472"

# ==================== THOUGHTS ====================

# Append a thought to a specific chain
r = requests.post(f"{base}/v1/thoughts", json={
    "chain_key": "my-project",        # specify chain — omit to use default chain
    "thought_type": "Insight",
    "content": "The cache invalidation strategy needs rethinking.",
    "role": "Memory",
    "importance": 0.8,
    "confidence": 0.9,
    "tags": ["architecture", "cache"],
    "concepts": ["invalidation", "consistency"],
})
thought = r.json()["thought"]
print(f"Appended: {thought['id']}")

# Get a thought by ID
r = requests.get(f"{base}/v1/thoughts/{thought['id']}")
print(r.json())

# Get genesis (first) thought
r = requests.post(f"{base}/v1/thoughts/genesis")
print(r.json())

# Traverse thoughts from anchor
r = requests.post(f"{base}/v1/thoughts/traverse", json={
    "anchor_index": 1,
    "direction": "forward",
    "chunk_size": 10
})
print(r.json())

# ==================== SEARCH ====================

# Ranked search within a specific chain
r = requests.post(f"{base}/v1/ranked-search", json={
    "chain_key": "my-project",
    "text": "cache invalidation",
    "limit": 5,
    "min_importance": 0.5
})
print(r.json())

# Lexical search
r = requests.post(f"{base}/v1/lexical-search", json={
    "chain_key": "my-project",
    "text": "database performance",
    "limit": 10
})
print(r.json())

# Semantic search
r = requests.post(f"{base}/v1/search", json={
    "chain_key": "my-project",
    "text": "architecture decisions",
    "thought_types": ["Insight", "Finding"]
})
print(r.json())

# Context bundles
r = requests.post(f"{base}/v1/context-bundles", json={
    "chain_key": "my-project",
    "text": "cache consistency",
    "limit": 3,
    "graph": {"max_depth": 2, "include_seeds": True}
})
print(r.json())

# ==================== CHAINS ====================

# List all chains
r = requests.get(f"{base}/v1/chains")
print(r.json())

# Branch from a thought
r = requests.post(f"{base}/v1/chains/branch", json={
    "source_chain_key": "default",
    "branch_chain_key": "experiment-1",
    "branch_thought_id": thought["id"]
})
print(r.json())

# Merge chains
r = requests.post(f"{base}/v1/chains/merge", json={
    "source_chain_key": "experiment-1",
    "target_chain_key": "default"
})
print(r.json())

# ==================== AGENTS ====================

# Upsert agent
r = requests.post(f"{base}/v1/agents/upsert", json={
    "agent_id": "my-agent-001",
    "display_name": "My Agent",
    "description": "Primary coding agent"
})
print(r.json())

# List agents
r = requests.get(f"{base}/v1/agents")
print(r.json())

# ==================== WEBHOOKS ====================

# Register webhook
r = requests.post(f"{base}/v1/webhooks", json={
    "url": "https://myapp.com/webhook/mentisdb",
    "chain_key_filter": "default",
    "thought_type_filter": ["Insight", "Finding"]
})
webhook = r.json()["webhook"]
print(f"Registered: {webhook['id']}")

# List webhooks
r = requests.get(f"{base}/v1/webhooks")
print(r.json())

# Delete webhook
r = requests.delete(f"{base}/v1/webhooks/{webhook['id']}")
print(r.json())

# ==================== HEAD & HEALTH ====================

# Get head metadata
r = requests.post(f"{base}/v1/head")
print(r.json())

# Health check
r = requests.get(f"{base}/health")
print(r.json())

# ==================== SKILLS ====================

# List skills
r = requests.get(f"{base}/v1/skills")
print(r.json())

# Upload skill
r = requests.post(f"{base}/v1/skills/upload", json={
    "agent_id": "my-agent-001",
    "skill_id": "my-skill",
    "content": "# My Skill\n\nA custom skill for...",
    "format": "markdown"
})
print(r.json())

# Search skills
r = requests.post(f"{base}/v1/skills/search", json={
    "text": "coding assistance"
})
print(r.json())

# Read skill
r = requests.post(f"{base}/v1/skills/read", json={
    "skill_id": "my-skill"
})
print(r.json())

# List skill versions
r = requests.post(f"{base}/v1/skills/versions", json={
    "skill_id": "my-skill"
})
print(r.json())

# Deprecate skill
r = requests.post(f"{base}/v1/skills/deprecate", json={
    "skill_id": "my-skill",
    "reason": "Superseded by new version"
})
print(r.json())

# Revoke skill
r = requests.post(f"{base}/v1/skills/revoke", json={
    "skill_id": "my-skill",
    "reason": "Security concern"
})
print(r.json())

# ==================== MEMORY MARKDOWN ====================

# Export chain as MEMORY.md
r = requests.post(f"{base}/v1/memory-markdown", json={
    "chain_key": "my-project",       // optional — omit to export the default chain
    "limit": 100
})
print(r.json())  # Returns { "markdown": "# MEMORY.md\n\n..." }

# Import from MEMORY.md into a specific chain
r = requests.post(f"{base}/v1/import-markdown", json={
    "markdown": "# MEMORY.md\n\n## Thought\nContent here...",
    "chain_key": "my-project"
})
print(r.json())

# ==================== RECENT CONTEXT & BOOTSTRAP ====================

# Get recent context for prompts from a specific chain
r = requests.post(f"{base}/v1/recent-context", json={
    "chain_key": "my-project",      // optional — omit to use the default chain
    "last_n": 10
})
print(r.json())

# Bootstrap a chain if empty
r = requests.post(f"{base}/v1/bootstrap", json={
    "chain_key": "my-project",       // optional — omit to bootstrap the default chain
    "agent_id": "my-agent-001",
    "content": "Initial bootstrap thought"
})
print(r.json())

# ==================== RETROSPECTIVES ====================

# Append retrospective to a specific chain
r = requests.post(f"{base}/v1/retrospectives", json={
    "chain_key": "my-project",      // optional — omit to use the default chain
    "content": "Lesson learned: always verify TLS certs in development.",
    "agent_id": "my-agent-001",
    "refs": [thought["id"]]
})
print(r.json())

Full REST API Reference

Generate a Swagger client for any language at Swagger Editor using the OpenAPI spec, or check the interactive docs at http://127.0.0.1:9472/docs (if running with --enable-http-docs).

MethodPathDescription
POST/v1/thoughtsAppend a thought
GET/v1/thoughts/{id}Get a thought by ID, index, or hash
POST/v1/thoughts/genesisGet the first thought in the chain
POST/v1/thoughts/traverseTraverse chain forward/backward from anchor
POST/v1/ranked-searchRanked semantic search
POST/v1/context-bundlesSeed + supporting context bundles
POST/v1/lexical-searchFlat ranked lexical search
POST/v1/searchSemantic search with filters
GET/v1/chainsList all chains
POST/v1/chains/branchCreate a new chain from a thought
POST/v1/chains/mergeMerge source chain into target
POST/v1/agents/upsertCreate or update an agent registry record
GET/v1/agentsList all registered agents
POST/v1/webhooksRegister a webhook
GET/v1/webhooksList all registered webhooks
DELETE/v1/webhooks/{id}Delete a webhook by UUID
POST/v1/headGet head metadata and latest thought
GET/healthHealth check
POST/v1/skills/uploadUpload a new skill version
POST/v1/skills/readRead a stored skill
GET/v1/skillsList skill summaries
POST/v1/skills/searchSearch skills by metadata
POST/v1/skills/versionsList versions for one skill
POST/v1/skills/deprecateMark a skill as deprecated
POST/v1/skills/revokeMark a skill as revoked
POST/v1/memory-markdownExport chain as MEMORY.md
POST/v1/import-markdownImport MEMORY.md into chain
POST/v1/recent-contextGet recent context for prompts
POST/v1/bootstrapBootstrap a chain if empty
POST/v1/retrospectivesAppend a retrospective thought

Request/Response Schema Examples

POST /v1/thoughts — Append a Thought

Request:

{
  "chain_key": "my-project",          // optional — defaults to server's default chain
  "thought_type": "Insight",
  "content": "The cache invalidation strategy needs rethinking.",
  "role": "Memory",
  "importance": 0.8,
  "confidence": 0.9,
  "tags": ["architecture", "cache"],
  "concepts": ["invalidation", "consistency"],
  "agent_id": "my-agent-001"
}

Response:

{
  "thought": {
    "id": "01AR3WZFV3Q5MZ8...",
    "thought_type": "Insight",
    "content": "The cache invalidation strategy needs rethinking.",
    "role": "Memory",
    "importance": 0.8,
    "confidence": 0.9,
    "tags": ["architecture", "cache"],
    "concepts": ["invalidation", "consistency"],
    "created_at": "2026-04-14T10:30:00Z",
    "chain_index": 42,
    "content_hash": "sha256:abc123..."
  }
}

POST /v1/ranked-search — Ranked Semantic Search

Request:

{
  "chain_key": "my-project",          // optional — omit to search the default chain
  "text": "cache invalidation strategy",
  "limit": 5,
  "min_importance": 0.5,
  "thought_types": ["Insight", "Finding"],
  "tags_any": ["architecture"],
  "concepts_any": ["consistency"],
  "since": "2026-01-01T00:00:00Z"
}

Response:

{
  "results": [
    {
      "score": {
        "total": 0.94,
        "lexical": 0.42,
        "semantic": 0.52
      },
      "thought": {
        "id": "01AR3WZFV3Q5MZ8...",
        "thought_type": "Insight",
        "content": "The cache invalidation strategy needs rethinking.",
        "importance": 0.8,
        "tags": ["architecture", "cache"]
      }
    }
  ],
  "total_hits": 1,
  "query_time_ms": 12
}

POST /v1/context-bundles — Context Bundles

Request:

{
  "chain_key": "my-project",          // optional — omit to use the default chain
  "text": "cache consistency",
  "limit": 3,
  "thought_types": ["Insight", "Finding", "LessonLearned"],
  "graph": {
    "max_depth": 2,
    "max_visited": 20,
    "include_seeds": true
  }
}

Response:

{
  "bundles": [
    {
      "seed": {
        "id": "01AR3WZFV3Q5MZ8...",
        "thought_type": "Insight",
        "content": "The cache invalidation strategy needs rethinking."
      },
      "supporting": [
        {
          "id": "01AR3WZFV3Q5MZ9...",
          "thought_type": "Finding",
          "content": "Cache coherence protocol was causing 200ms delays.",
          "relation": "related"
        }
      ]
    }
  ]
}

Troubleshooting

MCP Connection Issues

ProblemSolution
"Certificate verify failed" errorsSet NODE_TLS_REJECT_UNAUTHORIZED=0 in your mcp-remote config env, or use a valid TLS certificate.
"Connection refused" on localhost:9473Ensure mentisdbd is running with --https --port 9473. Check with curl https://127.0.0.1:9473/health.
mcp-remote not foundInstall via Homebrew: brew install mcp-remote, or npm: npm install -g mcp-remote. Requires Node.js >= 20 for npm.
Claude Desktop doesn't see mentisdb toolsRestart Claude Desktop after config changes. Verify config at ~/Library/Application Support/Claude/claude_desktop_config.json.
Wrong mcp-remote path in configUse which mcp-remote or brew --prefix mcp-remote to find the correct absolute path.
MCP server starts but tools return errorsCheck mentisdbd logs. Ensure the chain exists and is accessible. Try mentisdbd status.

REST API Issues

ProblemSolution
404 on all endpointsEnsure mentisdbd is running with --enable-http (default port 9472 for HTTP, 9473 for HTTPS).
400 Bad Request on POSTVerify Content-Type is application/json and body is valid JSON.
401/403 auth errorsMentisDB currently does not require auth for local access. If using a reverse proxy, check its auth config.

Building Custom MCP Clients

mentisdbd ships a built-in MCP server — any MCP-compatible client can connect directly via stdio. To use the MCP server, start mentisdbd and point your MCP client at it:

mentisdbd exposes an MCP server on HTTP port 9471 (and HTTPS on 9473 when TLS is enabled). MCP clients like Claude Desktop connect over HTTP/HTTPS — not stdio. The mcp-remote bridge is used when your MCP client speaks stdio but mentisdbd speaks HTTP/HTTPS, or when you need TLS.

# mentisdbd starts with MCP on port 9471 (HTTP) and 9473 (HTTPS)
mentisdbd

# Your MCP client connects over HTTP/HTTPS to port 9471 or 9473

mcp-remote vs direct HTTP: If your MCP client (Claude Desktop, etc.) uses stdio-based MCP, use mcp-remote to bridge to mentisdbd's HTTP MCP endpoint. If you have a client that speaks HTTP MCP directly, you can connect to port 9471 (HTTP) or 9473 (HTTPS/TLS) without mcp-remote.

MCP Protocol Basics

MCP communicates over JSON-RPC 2.0 over stdio. Each request has this shape:

{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {
  "name": "mentisdb_append",
  "arguments": {
    "chain_key": "my-project",       // omit to use the default chain
    "thought_type": "Insight",
    "content": "...",
    "importance": 0.8
  }
}}

Responses come back on stdout as JSON-RPC results. Check the MCP specification for full details.

Available MCP Tools Reference

ToolDescription
mentisdb_bootstrapCreate a chain if needed and write one bootstrap checkpoint when it is empty.
mentisdb_appendAppend a durable semantic thought with optional tags, concepts, refs, scope, and signature metadata.
mentisdb_append_retrospectiveAppend a retrospective memory intended to prevent future agents from repeating a hard failure.
mentisdb_searchSearch thoughts by semantic filters, identity filters, time bounds, and scoring thresholds.
mentisdb_lexical_searchReturn flat ranked lexical matches with explainable term and field provenance.
mentisdb_ranked_searchReturn flat ranked lexical, graph-aware, or heuristic results with additive score breakdowns. Supports as_of for point-in-time queries and scope for memory scope filtering.
mentisdb_context_bundlesReturn seed-anchored grouped support context beneath the best lexical seeds.
mentisdb_list_chainsList known chains with version, storage adapter, counts, and storage location.
mentisdb_merge_chainsMerge all thoughts from a source chain into a target chain, then permanently delete the source.
mentisdb_branch_fromCreate a new chain that diverges from a thought on an existing chain.
mentisdb_list_agentsList the distinct agent identities participating in one chain.
mentisdb_get_agentReturn one full agent registry record.
mentisdb_list_agent_registryReturn the full per-chain agent registry.
mentisdb_upsert_agentCreate or update a registry record before or after an agent writes thoughts.
mentisdb_set_agent_descriptionSet or clear the description stored for one registered agent.
mentisdb_add_agent_aliasAdd a historical or alternate alias to a registered agent.
mentisdb_add_agent_keyAdd or replace one public verification key on a registered agent.
mentisdb_revoke_agent_keyRevoke one previously registered public key.
mentisdb_disable_agentDisable one agent by marking its registry status as revoked.
mentisdb_recent_contextRender recent thoughts into a prompt snippet for session resumption.
mentisdb_memory_markdownExport a MEMORY.md-style Markdown view of the full chain or a filtered subset.
mentisdb_import_memory_markdownImport a MEMORY.md-formatted Markdown document into a target chain.
mentisdb_get_thoughtReturn one stored thought by stable id, chain index, or content hash.
mentisdb_get_genesis_thoughtReturn the first thought ever recorded in the chain.
mentisdb_traverse_thoughtsTraverse the chain forward or backward in append order from a chosen anchor.
mentisdb_skill_mdReturn the official embedded MENTISDB_SKILL.md Markdown file.
mentisdb_list_skillsList versioned skill summaries from the skill registry.
mentisdb_skill_manifestReturn the versioned skill-registry manifest.
mentisdb_upload_skillUpload a new immutable skill version from Markdown or JSON.
mentisdb_search_skillSearch skills by indexed metadata.
mentisdb_read_skillRead one stored skill as Markdown or JSON.
mentisdb_skill_versionsList immutable uploaded versions for one skill.
mentisdb_deprecate_skillMark a skill as deprecated.
mentisdb_revoke_skillMark a skill as revoked.
mentisdb_headReturn head metadata, latest thought, and integrity state.
mentisdb_register_webhookRegister a webhook to receive HTTP POST notifications.
mentisdb_list_webhooksList all registered webhooks.
mentisdb_delete_webhookRemove a webhook registration by UUID.

Next Steps