Joplin Model Context Protocol (MCP) Server

repository·main·Indexed 40 days ago

https://github.com/alondmnt/joplin-mcp

An MCP server version 0.10.0 that enables AI assistants to interact with Joplin note-taking applications via the Joplin Web Clipper API. It provides 26 tools for managing notes, notebooks, tags, and imports, with support for access control via notebook allowlists and configurable content exposure for privacy and token optimization. Compatible with Claude Desktop, Claude Code, Jan AI, and Ollama via OllMCP.

Tokens
22.2K
Snippets
57
Records
93
Agent score
48%

What's inside Joplin MCP

  1. Overview of Joplin MCP Tools

    main

    The Joplin MCP server provides 26 tools categorized into several functional areas:

    • Note Management: Search (find_notes, find_notes_with_tag, find_notes_in_notebook, get_all_notes), CRUD (get_note, get_note_resources for OCR, get_links, create_note, update_note, edit_note, delete_note), and task finding.
    • Notebook Management: list_notebooks, create_notebook, update_notebook, delete_notebook.
    • Tag Management: list_tags, create_tag, update_tag, delete_tag, get_tags_by_note, tag_note, untag_note.
    • Trash Management: restore_from_trash to recover soft-deleted items.
    • Import: import_from_file (supports Markdown, HTML, CSV, TXT, JEX).
    • System: ping_joplin for health checks.
  2. Use edit_note vs update_note correctly

    main

    Choosing the right tool depends on whether you want to modify a portion of a note or replace it entirely:

    • edit_note: Use for partial changes such as find/replace, appending text, or prepending text. This is the preferred method for surgical edits (fixing typos, adding a paragraph).
    • update_note(body=...): This replaces the entire body of the note. Use this only when you intend to rewrite the whole note from scratch.
  3. Understand tool availability and configuration

    main

    The joplin-mcp server exposes approximately 26 tools, but only about 18 are enabled by default. Certain tools are disabled by default to prevent accidental data loss or heavy context usage.

    Disabled by default (destructive or context-heavy):

    • get_all_notes
    • delete_note
    • update_notebook
    • delete_notebook
    • update_tag
    • delete_tag
    • import_from_file

    To enable or disable specific tools, modify the tools block in your joplin-mcp.json configuration file.

  4. Restrict Notebook Access with an Allowlist

    main

    You can limit the AI's access to specific notebooks using the JOPLIN_NOTEBOOK_ALLOWLIST environment variable or the notebook_allowlist config option. It accepts a comma-separated list of gitignore-style patterns (e.g., Work,Projects/*,!Projects/Secret).

    • If not set: No restriction.
    • If set but empty: Denies access to every notebook.
    # Example pattern
    JOPLIN_NOTEBOOK_ALLOWLIST="Work,Projects/*,!Projects/Secret"
  5. Configure Content Exposure Levels

    main

    The Joplin MCP server allows you to control how much note content is exposed to AI assistants. You can set different exposure levels for different contexts to balance privacy and functionality.

    Exposure Levels

    • none: No content shown; only titles and metadata are visible. (Maximum privacy)
    • preview: Short snippets of note content are shown. (Balanced privacy)
    • full: The entire note content is accessible. (Full functionality)

    Configuration Contexts

    • search_results: Controls visibility in listing operations like find_notes, find_notes_with_tag, find_notes_in_notebook, and get_all_notes. (Default: preview)
    • individual_notes: Controls visibility when retrieving a specific note via get_note. (Default: full)
    {
      "content_exposure": {
        "search_results": "none",
        "individual_notes": "preview"
      }
    }
  6. Manage the test sandbox for allowlist testing

    main

    When testing allowlist gating, use a disposable sandbox structure within Joplin to avoid affecting real data. The sandbox should consist of a top-level notebook MCP-test with two children: MCP-test/allowed and MCP-test/denied, each containing one stub note.

    Provisioning

    • Automated: If the agent has create_notebook and create_note enabled, it can create the sandbox at the start of Scenario A.
    • Manual: If create_notebook is disabled, the operator must manually create the MCP-test hierarchy in the Joplin UI before starting Scenario A.

    Cleanup

    Cleaning up the sandbox is difficult in Scenario C (deny-all) because list_notebooks returns an empty list, leaving no IDs for delete_notebook to act upon.

    Recommended Cleanup Methods:

    1. Restore Access: After Scenario C, restore an unrestricted config (notebook_allowlist: null or omit the field), restart the server, and then run a cleanup pass or delete MCP-test manually in the Joplin UI.
    2. Early Cleanup: Perform the cleanup at the end of Scenario A or B, while the allowlist still permits access to the sandbox.
    3. Manual Sweep: If delete_notebook is unavailable, the operator must manually delete the MCP-test notebook and its contents in the Joplin UI.
  7. Install and Configure Joplin MCP for Claude Desktop

    main

    You can automatically install and configure the Joplin MCP server for Claude Desktop using the joplin-mcp-install script. This script handles the Joplin API token, sets tool permissions (Create/Update/Delete), and configures Claude Desktop automatically.

    Using pip

    pip install joplin-mcp
    joplin-mcp-install

    If you have uv installed, use uvx for a zero-install approach:

    uvx --from joplin-mcp joplin-mcp-install

    Pinning versions

    You can pin specific versions for stability:

    uvx --from joplin-mcp==0.4.1 joplin-mcp-install
    uvx --from 'joplin-mcp>=0.4,<0.5' joplin-mcp-install
    uvx --from joplin-mcp joplin-mcp-install
  8. Optimize Performance and Resource Usage

    main

    If the server experiences slow response times or high memory usage, apply these optimizations:

    1. Optimize Search Queries

    Reduce the scope of searches by using smaller limit values and specific notebook_id filters.

    2. Efficient Batching

    Avoid rapid-fire requests. When processing multiple notes, introduce a small delay between requests using asyncio.sleep().

    3. Resource Cleanup

    Use the async with context manager to ensure the server is properly cleaned up after use, which helps prevent memory leaks.

    # Example: Optimized search and batching
    # 1. Use limits and scope
    results = await server.handle_find_notes({
        "query": "specific terms",
        "limit": 20,
        "notebook_id": "specific_notebook"
    })
    
    # 2. Batch with delays
    for note_id in note_ids[:10]:
        await server.handle_get_note({"note_id": note_id})
        await asyncio.sleep(0.1)
    
    # 3. Proper cleanup with context manager
    async with JoplinMCPServer(token="your_token") as server:
        results = await server.handle_find_notes({"query": "test"})
  9. Configure Claude Desktop with Joplin MCP

    main

    You can integrate Joplin MCP with Claude Desktop using two primary methods.

    Option A: Using uvx (Zero-install) This is the recommended method if you have uv installed. It runs the server without a permanent installation.

    Option B: Using an installed package Use this if you have already installed the joplin-mcp-server package via pip.

    Note: Claude Desktop currently uses STDIO transport and does not support HTTP/SSE configurations directly.

    // Option A: Using uvx
    {
      "mcpServers": {
        "joplin": {
          "command": "uvx",
          "args": ["--from", "joplin-mcp", "joplin-mcp-server"],
          "env": {
            "JOPLIN_TOKEN": "your_token_here"
          }
        }
      }
    }
    
    // Option B: Using installed package
    {
      "mcpServers": {
        "joplin": {
          "command": "joplin-mcp-server",
          "env": {
            "JOPLIN_TOKEN": "your_token_here"
          }
        }
      }
    }
  10. Verify System Requirements

    main

    Before running the server, ensure your environment meets the following requirements:

    1. Python Version: Must be 3.8 or higher.
    2. Joplin Service: Ensure Joplin is running and the Web Clipper service is enabled.
    3. Package Installation: Verify joplin_mcp is installed in your Python environment.
    # Check Python version
    python --version  # Should be 3.8+
    
    # Check if Joplin is running
    curl -s http://localhost:41184/ping || echo "Joplin not responding"
    
    # Check if required packages are installed
    python -c "import joplin_mcp; print('✅ joplin_mcp installed')" 2>/dev/null || echo "❌ joplin_mcp not installed"
  11. Run tests for Joplin MCP Server

    main

    When developing or testing the server, use pytest to run specific test categories.

    Running Unit and Integration Tests

    # Run only unit tests
    pytest tests/test_server.py -v
    
    # Run only integration tests
    pytest tests/test_integration.py -v
    
    # Skip slow tests
    pytest -m "not slow"

    Test Environment Setup

    Ensure all development dependencies are installed:

    pip install -e ".[dev]"

    Mocking Joplin for Tests

    You can use a Mock object to simulate the Joplin client during testing:

    from unittest.mock import Mock
    
    mock_client = Mock()
    mock_client.ping.return_value = True
    server = JoplinMCPServer(client=mock_client)
  12. Install Joplin MCP for Jan AI

    main

    Manual Configuration

    1. Open Jan AI.
    2. Go to Settings → Extensions → Model Context Protocol.
    3. Click Add MCP Server.
    4. Use the following settings:
      • Name: joplin
      • Command: uvx --from joplin-mcp joplin-mcp-server (requires uv)
      • Environment Variables: JOPLIN_TOKEN = your_joplin_api_token_here
    5. Enable the server.

    Automated Setup

    If Jan AI is already installed, you can use the installer script to detect and configure it automatically:

    pip install joplin-mcp
    joplin-mcp-install
    uvx --from joplin-mcp joplin-mcp-server