joplin-mcp


Namejoplin-mcp JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummaryModel Context Protocol (MCP) server for Joplin note-taking application
upload_time2025-07-09 00:13:44
maintainerJoplin MCP Contributors
docs_urlNone
authorJoplin MCP Contributors
requires_python>=3.8
licenseMIT
keywords joplin mcp model-context-protocol notes ai assistant
VCS
bugtrack_url
requirements mcp joppy fastmcp pydantic httpx typing-extensions PyYAML pytest pytest-asyncio pytest-mock coverage black ruff mypy pre-commit
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Joplin MCP Server

A **FastMCP-based Model Context Protocol (MCP) server** for [Joplin](https://joplinapp.org/) note-taking application via its Python API [joppy](https://github.com/marph91/joppy), enabling AI assistants to interact with your Joplin notes, notebooks, and tags through a standardized interface.

## Table of Contents

- [What You Can Do](#what-you-can-do)
- [Quick Start](#quick-start)
- [Example Usage](#example-usage)
- [Tool Permissions](#tool-permissions)
- [Advanced Configuration](#advanced-configuration)
- [Project Structure](#project-structure)
- [Testing](#testing)
- [Complete Tool Reference](#complete-tool-reference)

## What You Can Do

This MCP server provides **18 optimized tools** for comprehensive Joplin integration:

### **Note Management**
- **Find & Search**: `find_notes`, `find_notes_with_tag`, `find_notes_in_notebook`, `get_all_notes`
- **CRUD Operations**: `get_note`, `create_note`, `update_note`, `delete_note`

### **Notebook Management** 
- **Organize**: `list_notebooks`, `create_notebook`, `update_notebook`, `delete_notebook`

### **Tag Management**
- **Categorize**: `list_tags`, `create_tag`, `delete_tag`, `get_tags_by_note`
- **Link**: `tag_note`, `untag_note`

### **System**
- **Health**: `ping_joplin`

## Quick Start

### 1. Install the Package

```bash
pip install joplin-mcp
```

### 2. Configure Joplin

1. Open **Joplin Desktop** → **Tools** → **Options** → **Web Clipper**
2. **Enable** the Web Clipper service
3. **Copy** the Authorization token

### 3. Run Setup Script

```bash
joplin-mcp-install
```

This interactive script will:
- Configure your Joplin API token
- Set tool permissions (Create/Update/Delete)
- Set up Claude Desktop automatically
- Test the connection

### 4. Choose Your AI Client

#### Option A: Claude Desktop
After running the setup script, restart Claude Desktop and you're ready to go!

```
"List my notebooks" or "Create a note about today's meeting"
```

#### Option B: OllMCP (Local AI Models)

If Claude Desktop was configured above, you can run the following to detect joplin-mcp automatically by OllMCP (Ollama served agents).

```bash
# Install ollmcp
pip install ollmcp

# Run with auto-discovery and your preferred Ollama model, such as:
ollmcp --auto-discovery --model qwen3:4b
```

## Example Usage

Once configured, you can ask your AI assistant:

- **"List all my notebooks"** - See your Joplin organization
- **"Find notes about Python programming"** - Search your knowledge base  
- **"Create a meeting note for today's standup"** - Quick note creation
- **"Tag my recent AI notes as 'important'"** - Organize with tags
- **"Show me my todos"** - Find task items with `find_notes(task=True)`

## Tool Permissions

The setup script offers **3 security levels**:

- **Read** (always enabled): Browse and search your notes safely
- **Write** (optional): Create new notes, notebooks, and tags  
- **Update** (optional): Modify existing content
- **Delete** (optional): Remove content permanently

Choose the level that matches your comfort and use case.

---

## Advanced Configuration

### Alternative Installation (Development)

For developers or users who want the latest features:

#### macOS/Linux:
```bash
git clone https://github.com/alondmnt/joplin-mcp.git
cd joplin-mcp
./install.sh
```

#### Windows:
```batch
git clone https://github.com/alondmnt/joplin-mcp.git
cd joplin-mcp
install.bat
```

### Manual Configuration

If you prefer manual setup or the script doesn't work:

#### 1. Create Configuration File

Create `joplin-mcp.json` in your project directory:

```json
{
  "token": "your_api_token_here",
  "host": "localhost", 
  "port": 41184,
  "timeout": 30,
  "verify_ssl": false
}
```

#### 2. Claude Desktop Configuration

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "joplin": {
      "command": "joplin-mcp-server",
      "env": {
        "JOPLIN_TOKEN": "your_token_here"
      }
    }
  }
}
```

#### 3. OllMCP Manual Configuration

```bash
# Set environment variable
export JOPLIN_TOKEN="your_token_here"

# Run with manual server configuration
ollmcp --server "joplin:joplin-mcp-server" --model qwen3:4b
```

### Tool Permission Configuration

Fine-tune which operations the AI can perform by editing your config:

```json
{
  "tools": {
    "create_note": true,
    "update_note": true, 
    "delete_note": false,
    "create_notebook": true,
    "delete_notebook": false,
    "create_tag": true,
    "delete_tag": false
  }
}
```

### Environment Variables

Alternative to JSON configuration:

```bash
export JOPLIN_TOKEN="your_api_token_here"
export JOPLIN_HOST="localhost"
export JOPLIN_PORT="41184"
export JOPLIN_TIMEOUT="30"
```

### HTTP Transport Support

The server supports both STDIO and HTTP transports:

```bash
# STDIO (default)
joplin-mcp-server

# HTTP transport 
python run_fastmcp_server.py --transport http --port 8000
```

# Claude Desktop HTTP config
```json
{
  "mcpServers": {
    "joplin": {
      "transport": "http",
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

### Configuration Reference

#### Basic Settings
| Option | Default | Description |
|--------|---------|-------------|
| `token` | *required* | Joplin API authentication token |
| `host` | `localhost` | Joplin server hostname |
| `port` | `41184` | Joplin Web Clipper port |
| `timeout` | `30` | Request timeout in seconds |
| `verify_ssl` | `false` | SSL certificate verification |

#### Tool Permissions
| Option | Default | Description |
|--------|---------|-------------|
| `tools.create_note` | `true` | Allow creating new notes |
| `tools.update_note` | `true` | Allow modifying existing notes |
| `tools.delete_note` | `true` | Allow deleting notes |
| `tools.create_notebook` | `true` | Allow creating new notebooks |
| `tools.update_notebook` | `false` | Allow modifying notebook titles |
| `tools.delete_notebook` | `true` | Allow deleting notebooks |
| `tools.create_tag` | `true` | Allow creating new tags |
| `tools.update_tag` | `false` | Allow modifying tag titles |
| `tools.delete_tag` | `true` | Allow deleting tags |
| `tools.tag_note` | `true` | Allow adding tags to notes |
| `tools.untag_note` | `true` | Allow removing tags from notes |
| `tools.find_notes` | `true` | Allow text search across notes (with task filtering) |
| `tools.find_notes_with_tag` | `true` | Allow finding notes by tag (with task filtering) |
| `tools.find_notes_in_notebook` | `true` | Allow finding notes by notebook (with task filtering) |
| `tools.get_all_notes` | `false` | Allow getting all notes (disabled by default - can fill context window) |
| `tools.get_note` | `true` | Allow getting specific notes |
| `tools.list_notebooks` | `true` | Allow listing all notebooks |
| `tools.list_tags` | `true` | Allow listing all tags |
| `tools.get_tags_by_note` | `true` | Allow getting tags for specific notes |
| `tools.ping_joplin` | `true` | Allow testing server connectivity |

#### Content Exposure (Privacy Settings)
| Option | Default | Description |
|--------|---------|-------------|
| `content_exposure.search_results` | `"preview"` | Content visibility in search results: `"none"`, `"preview"`, `"full"` |
| `content_exposure.individual_notes` | `"full"` | Content visibility for individual notes: `"none"`, `"preview"`, `"full"` |
| `content_exposure.listings` | `"none"` | Content visibility in note listings: `"none"`, `"preview"`, `"full"` |
| `content_exposure.max_preview_length` | `200` | Maximum length of content previews (characters) |

## Project Structure

- **`run_fastmcp_server.py`** - FastMCP server launcher
- **`src/joplin_mcp/`** - Main package directory
  - `fastmcp_server.py` - Server implementation with 17 tools (by default)
  - `models.py` - Data models and schemas
  - `config.py` - Configuration management
- **`docs/`** - API documentation
- **`tests/`** - Test suite

## Testing

Test your connection:

```bash
# For pip install
joplin-mcp-server

# For development  
python run_fastmcp_server.py
```

You should see:
```
Starting Joplin FastMCP Server...
Successfully connected to Joplin!
Found X notebooks, Y notes, Z tags
FastMCP server starting...
Available tools: 17 tools ready
```

## Complete Tool Reference

| Tool | Permission | Description |
|------|------------|-------------|
| **Finding Notes** | | |
| `find_notes` | Read | Full-text search across all notes (supports task filtering) |
| `find_notes_with_tag` | Read | Find notes with specific tag (supports task filtering) |
| `find_notes_in_notebook` | Read | Find notes in specific notebook (supports task filtering) |
| `get_all_notes` | Read | Get all notes, most recent first *(disabled by default)* |
| `get_note` | Read | Get specific note by ID |
| **Managing Notes** | | |
| `create_note` | Write | Create new notes |
| `update_note` | Update | Modify existing notes |
| `delete_note` | Delete | Remove notes |
| **Managing Notebooks** | | |
| `list_notebooks` | Read | Browse all notebooks |
| `create_notebook` | Write | Create new notebooks |
| `update_notebook` | Update | Modify notebook titles |
| `delete_notebook` | Delete | Remove notebooks |
| **Managing Tags** | | |
| `list_tags` | Read | View all available tags |
| `create_tag` | Write | Create new tags |
| `delete_tag` | Delete | Remove tags |
| `get_tags_by_note` | Read | List tags on specific note |
| **Tag-Note Relationships** | | |
| `tag_note` | Update | Add tags to notes |
| `untag_note` | Update | Remove tags from notes |
| **System Tools** | | |
| `ping_joplin` | Read | Test connectivity |

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "joplin-mcp",
    "maintainer": "Joplin MCP Contributors",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "joplin, mcp, model-context-protocol, notes, ai, assistant",
    "author": "Joplin MCP Contributors",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/f4/7d/b3ae1854682ef8103b173c6f6d2e4c3252caa50d25bc68e63f637f534d9e/joplin_mcp-0.1.1.tar.gz",
    "platform": null,
    "description": "# Joplin MCP Server\n\nA **FastMCP-based Model Context Protocol (MCP) server** for [Joplin](https://joplinapp.org/) note-taking application via its Python API [joppy](https://github.com/marph91/joppy), enabling AI assistants to interact with your Joplin notes, notebooks, and tags through a standardized interface.\n\n## Table of Contents\n\n- [What You Can Do](#what-you-can-do)\n- [Quick Start](#quick-start)\n- [Example Usage](#example-usage)\n- [Tool Permissions](#tool-permissions)\n- [Advanced Configuration](#advanced-configuration)\n- [Project Structure](#project-structure)\n- [Testing](#testing)\n- [Complete Tool Reference](#complete-tool-reference)\n\n## What You Can Do\n\nThis MCP server provides **18 optimized tools** for comprehensive Joplin integration:\n\n### **Note Management**\n- **Find & Search**: `find_notes`, `find_notes_with_tag`, `find_notes_in_notebook`, `get_all_notes`\n- **CRUD Operations**: `get_note`, `create_note`, `update_note`, `delete_note`\n\n### **Notebook Management** \n- **Organize**: `list_notebooks`, `create_notebook`, `update_notebook`, `delete_notebook`\n\n### **Tag Management**\n- **Categorize**: `list_tags`, `create_tag`, `delete_tag`, `get_tags_by_note`\n- **Link**: `tag_note`, `untag_note`\n\n### **System**\n- **Health**: `ping_joplin`\n\n## Quick Start\n\n### 1. Install the Package\n\n```bash\npip install joplin-mcp\n```\n\n### 2. Configure Joplin\n\n1. Open **Joplin Desktop** \u2192 **Tools** \u2192 **Options** \u2192 **Web Clipper**\n2. **Enable** the Web Clipper service\n3. **Copy** the Authorization token\n\n### 3. Run Setup Script\n\n```bash\njoplin-mcp-install\n```\n\nThis interactive script will:\n- Configure your Joplin API token\n- Set tool permissions (Create/Update/Delete)\n- Set up Claude Desktop automatically\n- Test the connection\n\n### 4. Choose Your AI Client\n\n#### Option A: Claude Desktop\nAfter running the setup script, restart Claude Desktop and you're ready to go!\n\n```\n\"List my notebooks\" or \"Create a note about today's meeting\"\n```\n\n#### Option B: OllMCP (Local AI Models)\n\nIf Claude Desktop was configured above, you can run the following to detect joplin-mcp automatically by OllMCP (Ollama served agents).\n\n```bash\n# Install ollmcp\npip install ollmcp\n\n# Run with auto-discovery and your preferred Ollama model, such as:\nollmcp --auto-discovery --model qwen3:4b\n```\n\n## Example Usage\n\nOnce configured, you can ask your AI assistant:\n\n- **\"List all my notebooks\"** - See your Joplin organization\n- **\"Find notes about Python programming\"** - Search your knowledge base  \n- **\"Create a meeting note for today's standup\"** - Quick note creation\n- **\"Tag my recent AI notes as 'important'\"** - Organize with tags\n- **\"Show me my todos\"** - Find task items with `find_notes(task=True)`\n\n## Tool Permissions\n\nThe setup script offers **3 security levels**:\n\n- **Read** (always enabled): Browse and search your notes safely\n- **Write** (optional): Create new notes, notebooks, and tags  \n- **Update** (optional): Modify existing content\n- **Delete** (optional): Remove content permanently\n\nChoose the level that matches your comfort and use case.\n\n---\n\n## Advanced Configuration\n\n### Alternative Installation (Development)\n\nFor developers or users who want the latest features:\n\n#### macOS/Linux:\n```bash\ngit clone https://github.com/alondmnt/joplin-mcp.git\ncd joplin-mcp\n./install.sh\n```\n\n#### Windows:\n```batch\ngit clone https://github.com/alondmnt/joplin-mcp.git\ncd joplin-mcp\ninstall.bat\n```\n\n### Manual Configuration\n\nIf you prefer manual setup or the script doesn't work:\n\n#### 1. Create Configuration File\n\nCreate `joplin-mcp.json` in your project directory:\n\n```json\n{\n  \"token\": \"your_api_token_here\",\n  \"host\": \"localhost\", \n  \"port\": 41184,\n  \"timeout\": 30,\n  \"verify_ssl\": false\n}\n```\n\n#### 2. Claude Desktop Configuration\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"joplin\": {\n      \"command\": \"joplin-mcp-server\",\n      \"env\": {\n        \"JOPLIN_TOKEN\": \"your_token_here\"\n      }\n    }\n  }\n}\n```\n\n#### 3. OllMCP Manual Configuration\n\n```bash\n# Set environment variable\nexport JOPLIN_TOKEN=\"your_token_here\"\n\n# Run with manual server configuration\nollmcp --server \"joplin:joplin-mcp-server\" --model qwen3:4b\n```\n\n### Tool Permission Configuration\n\nFine-tune which operations the AI can perform by editing your config:\n\n```json\n{\n  \"tools\": {\n    \"create_note\": true,\n    \"update_note\": true, \n    \"delete_note\": false,\n    \"create_notebook\": true,\n    \"delete_notebook\": false,\n    \"create_tag\": true,\n    \"delete_tag\": false\n  }\n}\n```\n\n### Environment Variables\n\nAlternative to JSON configuration:\n\n```bash\nexport JOPLIN_TOKEN=\"your_api_token_here\"\nexport JOPLIN_HOST=\"localhost\"\nexport JOPLIN_PORT=\"41184\"\nexport JOPLIN_TIMEOUT=\"30\"\n```\n\n### HTTP Transport Support\n\nThe server supports both STDIO and HTTP transports:\n\n```bash\n# STDIO (default)\njoplin-mcp-server\n\n# HTTP transport \npython run_fastmcp_server.py --transport http --port 8000\n```\n\n# Claude Desktop HTTP config\n```json\n{\n  \"mcpServers\": {\n    \"joplin\": {\n      \"transport\": \"http\",\n      \"url\": \"http://localhost:8000/mcp\"\n    }\n  }\n}\n```\n\n### Configuration Reference\n\n#### Basic Settings\n| Option | Default | Description |\n|--------|---------|-------------|\n| `token` | *required* | Joplin API authentication token |\n| `host` | `localhost` | Joplin server hostname |\n| `port` | `41184` | Joplin Web Clipper port |\n| `timeout` | `30` | Request timeout in seconds |\n| `verify_ssl` | `false` | SSL certificate verification |\n\n#### Tool Permissions\n| Option | Default | Description |\n|--------|---------|-------------|\n| `tools.create_note` | `true` | Allow creating new notes |\n| `tools.update_note` | `true` | Allow modifying existing notes |\n| `tools.delete_note` | `true` | Allow deleting notes |\n| `tools.create_notebook` | `true` | Allow creating new notebooks |\n| `tools.update_notebook` | `false` | Allow modifying notebook titles |\n| `tools.delete_notebook` | `true` | Allow deleting notebooks |\n| `tools.create_tag` | `true` | Allow creating new tags |\n| `tools.update_tag` | `false` | Allow modifying tag titles |\n| `tools.delete_tag` | `true` | Allow deleting tags |\n| `tools.tag_note` | `true` | Allow adding tags to notes |\n| `tools.untag_note` | `true` | Allow removing tags from notes |\n| `tools.find_notes` | `true` | Allow text search across notes (with task filtering) |\n| `tools.find_notes_with_tag` | `true` | Allow finding notes by tag (with task filtering) |\n| `tools.find_notes_in_notebook` | `true` | Allow finding notes by notebook (with task filtering) |\n| `tools.get_all_notes` | `false` | Allow getting all notes (disabled by default - can fill context window) |\n| `tools.get_note` | `true` | Allow getting specific notes |\n| `tools.list_notebooks` | `true` | Allow listing all notebooks |\n| `tools.list_tags` | `true` | Allow listing all tags |\n| `tools.get_tags_by_note` | `true` | Allow getting tags for specific notes |\n| `tools.ping_joplin` | `true` | Allow testing server connectivity |\n\n#### Content Exposure (Privacy Settings)\n| Option | Default | Description |\n|--------|---------|-------------|\n| `content_exposure.search_results` | `\"preview\"` | Content visibility in search results: `\"none\"`, `\"preview\"`, `\"full\"` |\n| `content_exposure.individual_notes` | `\"full\"` | Content visibility for individual notes: `\"none\"`, `\"preview\"`, `\"full\"` |\n| `content_exposure.listings` | `\"none\"` | Content visibility in note listings: `\"none\"`, `\"preview\"`, `\"full\"` |\n| `content_exposure.max_preview_length` | `200` | Maximum length of content previews (characters) |\n\n## Project Structure\n\n- **`run_fastmcp_server.py`** - FastMCP server launcher\n- **`src/joplin_mcp/`** - Main package directory\n  - `fastmcp_server.py` - Server implementation with 17 tools (by default)\n  - `models.py` - Data models and schemas\n  - `config.py` - Configuration management\n- **`docs/`** - API documentation\n- **`tests/`** - Test suite\n\n## Testing\n\nTest your connection:\n\n```bash\n# For pip install\njoplin-mcp-server\n\n# For development  \npython run_fastmcp_server.py\n```\n\nYou should see:\n```\nStarting Joplin FastMCP Server...\nSuccessfully connected to Joplin!\nFound X notebooks, Y notes, Z tags\nFastMCP server starting...\nAvailable tools: 17 tools ready\n```\n\n## Complete Tool Reference\n\n| Tool | Permission | Description |\n|------|------------|-------------|\n| **Finding Notes** | | |\n| `find_notes` | Read | Full-text search across all notes (supports task filtering) |\n| `find_notes_with_tag` | Read | Find notes with specific tag (supports task filtering) |\n| `find_notes_in_notebook` | Read | Find notes in specific notebook (supports task filtering) |\n| `get_all_notes` | Read | Get all notes, most recent first *(disabled by default)* |\n| `get_note` | Read | Get specific note by ID |\n| **Managing Notes** | | |\n| `create_note` | Write | Create new notes |\n| `update_note` | Update | Modify existing notes |\n| `delete_note` | Delete | Remove notes |\n| **Managing Notebooks** | | |\n| `list_notebooks` | Read | Browse all notebooks |\n| `create_notebook` | Write | Create new notebooks |\n| `update_notebook` | Update | Modify notebook titles |\n| `delete_notebook` | Delete | Remove notebooks |\n| **Managing Tags** | | |\n| `list_tags` | Read | View all available tags |\n| `create_tag` | Write | Create new tags |\n| `delete_tag` | Delete | Remove tags |\n| `get_tags_by_note` | Read | List tags on specific note |\n| **Tag-Note Relationships** | | |\n| `tag_note` | Update | Add tags to notes |\n| `untag_note` | Update | Remove tags from notes |\n| **System Tools** | | |\n| `ping_joplin` | Read | Test connectivity |\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Model Context Protocol (MCP) server for Joplin note-taking application",
    "version": "0.1.1",
    "project_urls": {
        "Documentation": "https://github.com/alondmnt/joplin-mcp/blob/main/README.md",
        "Homepage": "https://github.com/alondmnt/joplin-mcp",
        "Issues": "https://github.com/alondmnt/joplin-mcp/issues",
        "Repository": "https://github.com/alondmnt/joplin-mcp"
    },
    "split_keywords": [
        "joplin",
        " mcp",
        " model-context-protocol",
        " notes",
        " ai",
        " assistant"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b0a6286574b685f754c850c30ca79e694dd437c679b37c136d68e60171a727a6",
                "md5": "cc52676c41dbe713b592bd745460ce51",
                "sha256": "c98a08c4a8acce8c53ac963237f4f0805125a2a057abe7b87a32a29d68edde8e"
            },
            "downloads": -1,
            "filename": "joplin_mcp-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cc52676c41dbe713b592bd745460ce51",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 44005,
            "upload_time": "2025-07-09T00:13:43",
            "upload_time_iso_8601": "2025-07-09T00:13:43.715404Z",
            "url": "https://files.pythonhosted.org/packages/b0/a6/286574b685f754c850c30ca79e694dd437c679b37c136d68e60171a727a6/joplin_mcp-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f47db3ae1854682ef8103b173c6f6d2e4c3252caa50d25bc68e63f637f534d9e",
                "md5": "07e1d6dd1832d466f048ca7153304de5",
                "sha256": "0d549125ae85f67f7d95696dcd1460734a65ca63e51298d3df9d24c0e8535889"
            },
            "downloads": -1,
            "filename": "joplin_mcp-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "07e1d6dd1832d466f048ca7153304de5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 60841,
            "upload_time": "2025-07-09T00:13:44",
            "upload_time_iso_8601": "2025-07-09T00:13:44.939940Z",
            "url": "https://files.pythonhosted.org/packages/f4/7d/b3ae1854682ef8103b173c6f6d2e4c3252caa50d25bc68e63f637f534d9e/joplin_mcp-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-09 00:13:44",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "alondmnt",
    "github_project": "joplin-mcp",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "mcp",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "joppy",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "fastmcp",
            "specs": [
                [
                    ">=",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    ">=",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "httpx",
            "specs": [
                [
                    ">=",
                    "0.24.0"
                ]
            ]
        },
        {
            "name": "typing-extensions",
            "specs": [
                [
                    ">=",
                    "4.0.0"
                ]
            ]
        },
        {
            "name": "PyYAML",
            "specs": [
                [
                    ">=",
                    "6.0.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "pytest-asyncio",
            "specs": [
                [
                    ">=",
                    "0.21.0"
                ]
            ]
        },
        {
            "name": "pytest-mock",
            "specs": [
                [
                    ">=",
                    "3.10.0"
                ]
            ]
        },
        {
            "name": "coverage",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "black",
            "specs": [
                [
                    ">=",
                    "23.0.0"
                ]
            ]
        },
        {
            "name": "ruff",
            "specs": [
                [
                    ">=",
                    "0.1.0"
                ]
            ]
        },
        {
            "name": "mypy",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "pre-commit",
            "specs": [
                [
                    ">=",
                    "3.0.0"
                ]
            ]
        }
    ],
    "lcname": "joplin-mcp"
}
        
Elapsed time: 0.55636s