Metadata-Version: 2.4
Name: ckanext-mcp
Version: 0.1.0
Summary: CKAN extension that exposes all available CKAN API actions as MCP tools via a Flask blueprint
Author-email: Thomas Hanke <thomas.hanke@iwm.fraunhofer.de>
License: AGPL
Project-URL: Homepage, https://github.com/Mat-O-Lab/ckanext-mcp
Project-URL: Repository, https://github.com/Mat-O-Lab/ckanext-mcp
Keywords: CKAN,MCP,Model Context Protocol,AI,LLM,API bridge
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# ckanext-mcp

MCP bridge for CKAN — exposes all API actions from CKAN core and installed extensions as MCP tools. LLMs act as the authenticated user, inheriting all CKAN permissions.

## How it works

CKAN installations have ~200 API actions depending on installed extensions. Exposing all of them as flat MCP tools would overwhelm any LLM. Instead, ckanext-mcp builds **~25 synthetic entity tools** at startup:

- **`ckan_package`** — show, list, create, update, delete, patch, search
- **`ckan_resource`** — show, create, update, delete, patch, search
- **`ckan_organization`** — show, list, create, update, delete, patch
- **`ckan_tag`** — show, list, create, delete, search
- **`ckan_search_tools`** — discover any of the ~200 actions by keyword, entity, or source
- ... and more, derived automatically from installed plugins

Each entity tool bundles CRUD operations. The LLM passes an `operation` parameter to select the action:

```json
{
  "name": "ckan_package",
  "arguments": {
    "operation": "show",
    "id": "my-dataset"
  }
}
```

**Zero hardcoding** — entity grouping derived from CKAN's naming convention (`package_show` → entity `package`), source from `IActions` plugin registry, read/write from `side_effect_free` attribute.

## Installation

```bash
pip install ckanext-mcp
```

Add `mcp` to `ckan.plugins` in your ckan.ini or `.env`:

```
ckan.plugins = ... mcp
```

## Configuration

| Option | Default | Description |
|--------|---------|-------------|
| `ckanext.mcp.categories` | *(empty)* | Comma-separated entity or source filter (e.g. `package,resource,harvest`) |

The MCP endpoint is always available at `/mcp`.

## Client Setup

Generate a `.mcp.json` config for your MCP client:

```bash
ckan -c ckan.ini mcp init
```

This creates `.mcp.json`:

```json
{
  "mcpServers": {
    "ckan": {
      "type": "http",
      "url": "https://your-ckan.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_API_KEY>"
      }
    }
  }
}
```

Replace `<YOUR_API_KEY>` with your CKAN API key, then point your MCP client (Claude Code, Cursor, etc.) at this file.

## Authentication

The bridge piggybacks on CKAN's existing auth:

- **API token**: pass in `Authorization` header — CKAN middleware resolves the user before the MCP endpoint runs
- **Session**: browser-based MCP clients use the existing CKAN session

CKAN's action-level auth enforces all permissions. The LLM can only do what the authenticated user can do.

## Search & Discovery

The `ckan_search_tools` tool lets the LLM discover actions beyond the default entity tools:

```json
{
  "name": "ckan_search_tools",
  "arguments": {"entity": "harvest_source"}
}
```

Returns full MCP definitions (name, description, inputSchema) for all matching actions — the LLM can then call them through their entity tool.

## MCP Protocol

- **Spec**: 2025-11-25
- **Transport**: Streamable HTTP (JSON-RPC 2.0 over POST)
- **Methods**: `initialize`, `notifications/initialized`, `tools/list`, `tools/call`
- **No external MCP dependencies** — manual JSON-RPC implementation

## Development

```bash
git clone https://github.com/Mat-O-Lab/ckanext-mcp.git
cd ckanext-mcp
pip install -e .
pip install -r dev-requirements.txt
```

Run tests:

```bash
pytest --ckan-ini=test.ini ckanext/mcp
```

## License

AGPL-3.0
