Metadata-Version: 2.4
Name: knora-mcp
Version: 0.3.0
Summary: MCP server that exposes the Knora institutional-memory platform to AI agents
License: MIT
Keywords: ai,institutional-memory,knora,knowledge-management,mcp
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp>=1.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# Knora MCP Server

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that exposes the full Knora institutional-memory platform to AI agents. Once connected, Claude (or any MCP-compatible agent) can search, query, create, and manage your organisation's knowledge base directly from a conversation.

---

## What the server does

The Knora MCP server wraps the Knora REST API and exposes it as **~80 MCP tools** organised into these categories:

| Category | What agents can do |
|---|---|
| **Query & Search** | Ask natural-language questions (RAG), semantic search, view query history, find documentation gaps |
| **Knowledge Management** | Create/read/update/delete entries, verify, flag, relate, bulk import/export, manage tags and departments |
| **Capture** | Quick notes, voice upload (Whisper), document upload (PDF/Word/Excel/image), interviews, shift logs |
| **Admin** | Invite/manage members, update roles, org settings, API keys, webhooks, integrations |
| **Analytics** | Dashboard overview, bus factor risk, knowledge health score, staleness report, query analytics |

---

## Security boundaries

This MCP server is designed for **per-org customer access**, not platform administration. The following invariants are enforced:

1. **Org-isolated** — all operations are scoped to the authenticated user's organisation. Agents cannot see or modify data belonging to another org.
2. **No superadmin tools** — the admin endpoints (`/api/v1/admin/…`) are not exposed here and must not be added.
3. **No plan/billing changes through MCP** — subscription upgrades and cancellations must go through the Stripe checkout flow, which requires human-initiated payment.

---

## Installation

```bash
# From the repo root
pip install -e ./mcp

# Or install directly from the mcp/ directory
cd mcp
pip install -e .
```

Requirements: Python 3.11+, a running Knora backend.

---

## Configuration

All configuration is via environment variables. No config file is required.

### Required — API endpoint

| Variable | Default | Description |
|---|---|---|
| `KNORA_API_URL` | `http://localhost:5001/api/v1` | Base URL of the Knora REST API |

### Required — Authentication (one of the following)

Authentication is resolved in this priority order:

**Option 1 — API key (recommended for production)**

```bash
export KNORA_API_KEY=kn_xxxxxxxxxxxxxxxxxxxx
```

API keys are long-lived and org-scoped. Create one via `knora_create_api_key` or the Knora web app (Growth plan required).

**Option 2 — JWT token**

```bash
export KNORA_JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

Short-lived access token. The client refreshes it automatically when it expires.

**Option 3 — Email + password (development)**

```bash
export KNORA_EMAIL=admin@acme.com
export KNORA_PASSWORD=your-password
```

The server logs in on startup and acquires a JWT automatically.

### Optional — HTTP client tuning

| Variable | Default | Description |
|---|---|---|
| `KNORA_TIMEOUT` | `30` | Request timeout in seconds |
| `KNORA_MAX_RETRIES` | `3` | Max retries on 429 / 5xx |
| `KNORA_RETRY_BACKOFF` | `1.0` | Initial back-off delay in seconds |

### Rate limits

The two most frequently called endpoints enforce per-user rate limits:

| Tool | Limit |
|---|---|
| `knora_ask` | 20 requests / minute |
| `knora_search` | 40 requests / minute |

The client automatically retries on `429 Too Many Requests` with exponential back-off (controlled by `KNORA_MAX_RETRIES` and `KNORA_RETRY_BACKOFF`). Agents running in tight loops should add a small delay between calls to stay within these limits.

---

## Running the server

```bash
# Stdio transport — default for agent integrations
python -m knora_mcp

# Equivalent: run the server module directly
python -m knora_mcp.server

# Via the MCP CLI (after pip install)
mcp run knora-mcp

# Direct CLI entry point (after pip install)
knora-mcp
```

The server communicates over **stdio** (stdin/stdout), which is the standard transport for Claude Desktop and Claude Code integrations.

---

## Adding to Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "knora": {
      "command": "python",
      "args": ["-m", "knora_mcp"],
      "env": {
        "KNORA_API_URL": "https://api.knora.io/api/v1",
        "KNORA_API_KEY": "kn_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

If you installed into a virtual environment, use the full path to the Python interpreter:

```json
{
  "mcpServers": {
    "knora": {
      "command": "/path/to/venv/bin/python",
      "args": ["-m", "knora_mcp"],
      "env": {
        "KNORA_API_URL": "https://api.knora.io/api/v1",
        "KNORA_API_KEY": "kn_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

Restart Claude Desktop after saving the file.

---

## Adding to Claude Code

Add the server to `.claude/settings.json` in your project (or `~/.claude/settings.json` for global access):

```json
{
  "mcpServers": {
    "knora": {
      "command": "python",
      "args": ["-m", "knora_mcp"],
      "env": {
        "KNORA_API_URL": "https://api.knora.io/api/v1",
        "KNORA_API_KEY": "kn_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

Or use the Claude Code CLI:

```bash
claude mcp add knora -- python -m knora_mcp
```

Then set the env vars in your shell before starting Claude Code, or add them to the `env` block above.

---

## Tool Reference

### Query & Search

#### `knora_ask`
Ask a natural-language question and receive an AI-generated answer with source citations (RAG). If no relevant knowledge exists, the question is logged as a gap for managers to review. Rate-limited to **20 requests/minute**.

```json
{
  "question": "How do we handle supplier delays?"
}
```

Parameters: `question` (required, max 2000 characters). Supports Arabic and English automatically — no language selection needed.

Returns `{ answer, sources[], confidence, language, query_id }`.

---

#### `knora_search`
Semantic search — finds entries by meaning, not just keywords. Faster than `knora_ask`; returns raw entries without generating an answer. Cross-language: an Arabic query finds English entries and vice versa. Rate-limited to **40 requests/minute**.

```json
{
  "query": "onboarding process for new hires",
  "limit": 5,
  "department": "Engineering"
}
```

---

#### `knora_query_history`
Return the current user's recent query history.

```json
{ "limit": 50 }
```

---

#### `knora_list_gaps`
List questions that were asked but could not be answered — these are documentation gaps that should be filled. Requires manager or admin role.

```json
{ "department": "Operations", "limit": 20 }
```

---

#### `knora_resolve_gap`
Mark a documentation gap as resolved by linking it to a knowledge entry that answers it.

```json
{ "gap_id": "<uuid>", "entry_id": "<uuid>" }
```

---

#### `knora_query_analytics`
Aggregate query analytics: total queries, answer rate, trending topics, and unanswered questions. Requires admin role and Growth plan.

---

### Knowledge Management

#### `knora_list_knowledge`
List knowledge entries with optional filters and pagination.

```json
{
  "status": "active",
  "language": "en",
  "search": "maintenance",
  "per_page": 20
}
```

Filters: `page`, `per_page`, `department_id`, `tag_ids`, `status` (active|archived|needs_review|outdated), `visibility`, `language` (ar|en|mixed), `confidence` (high|medium|low), `search`.

---

#### `knora_get_entry`
Fetch a single knowledge entry by UUID with all metadata, tags, department, related entries, and version count.

```json
{ "entry_id": "550e8400-e29b-41d4-a716-446655440000" }
```

---

#### `knora_create_knowledge`
Create a new knowledge entry. Immediately stored — no async processing.

```json
{
  "title": "Supplier delay escalation process",
  "content": "When a supplier reports a delay of more than 48 hours...",
  "language": "en",
  "tag_ids": ["<tag-uuid>"],
  "department_id": "<dept-uuid>",
  "confidence": "high"
}
```

---

#### `knora_update_knowledge`
Update an existing entry. Only supply the fields to change — all others are preserved. A version record is created automatically.

```json
{
  "entry_id": "<uuid>",
  "content": "Updated content...",
  "status": "active"
}
```

---

#### `knora_delete_knowledge`
Soft-delete (archive) a knowledge entry. Not permanently removed.

```json
{ "entry_id": "<uuid>" }
```

---

#### `knora_verify_entry`
Mark an entry as verified. Verified entries have higher trust and appear first in query results. Requires manager or admin role.

```json
{ "entry_id": "<uuid>" }
```

---

#### `knora_flag_knowledge`
Flag an entry as needing review — useful when content may be stale, inaccurate, or incomplete.

```json
{ "entry_id": "<uuid>" }
```

---

#### `knora_get_versions`
List the full version history of a knowledge entry, newest first.

```json
{ "entry_id": "<uuid>" }
```

---

#### `knora_relate_entries`
Link two knowledge entries as "related". Related entries appear together in query results and the knowledge graph.

```json
{ "entry_id": "<uuid>", "related_entry_id": "<uuid>" }
```

---

#### `knora_unrelate_entries`
Remove the relationship link between two entries.

```json
{ "entry_id": "<uuid>", "related_id": "<uuid>" }
```

---

#### `knora_find_similar`
Find entries semantically similar to a given entry using vector embeddings. Results are ranked by cosine similarity.

```json
{ "entry_id": "<uuid>", "limit": 5 }
```

---

#### `knora_find_duplicates`
Find potential duplicate entries. Supply `entry_id` to check a specific entry, or omit to trigger an org-wide async scan.

```json
{ "entry_id": "<uuid>", "threshold": 0.92 }
```

---

#### `knora_bulk_import`
Import multiple entries at once from a JSON array. Requires Growth plan. Each entry must have `title` and `content`.

```json
{
  "entries": [
    { "title": "Entry A", "content": "..." },
    { "title": "Entry B", "content": "..." }
  ]
}
```

---

#### `knora_export_knowledge`
Export all knowledge entries as a JSON array. Requires Growth plan.

```json
{ "status": "active", "language": "en" }
```

---

#### `knora_list_tags`
List all tags in the organisation.

---

#### `knora_create_tag`
Create a new tag. Requires manager or admin role.

```json
{ "name": "safety", "color": "#FF5733" }
```

---

#### `knora_delete_tag`
Delete a tag and remove it from all entries. Requires manager or admin role.

```json
{ "tag_id": "<uuid>" }
```

---

#### `knora_list_departments`
List all departments in the organisation.

---

#### `knora_create_department`
Create a new department. Requires manager or admin role.

```json
{ "name": "Maintenance", "description": "Field maintenance teams" }
```

---

#### `knora_update_department`
Update a department. Requires manager or admin role.

```json
{ "dept_id": "<uuid>", "name": "Field Maintenance" }
```

---

### Capture

#### `knora_quick_note`
Fastest capture path — store a piece of knowledge immediately. Title is auto-generated if not supplied.

```json
{
  "content": "Discovered that the valve seal on unit 7 must be replaced every 6 months, not annually.",
  "tags": ["<tag-uuid>"]
}
```

---

#### `knora_upload_document`
Upload a PDF, Word, Excel, or image file. Knora extracts text and creates knowledge entries asynchronously. Poll with `knora_check_job`.

```json
{
  "file_path": "/tmp/maintenance_manual.pdf"
}
```

Returns `{ job_id, status }`.

---

#### `knora_check_job`
Poll a document or voice capture job for completion. Status: `pending` → `processing` → `completed` | `failed`. On completion, `result_entry_id` contains the created entry UUID.

```json
{ "job_id": "<uuid>", "job_type": "document" }
```

---

#### `knora_list_document_jobs` / `knora_get_document_job`
List or inspect document capture jobs.

---

#### `knora_upload_voice`
Upload an audio file for voice-to-knowledge processing. Transcribed via Whisper, then Claude extracts structured knowledge. Formats: mp3, mp4, m4a, wav, webm, ogg, flac (max 25 MB).

```json
{ "file_path": "/tmp/interview_recording.m4a" }
```

---

#### `knora_list_voice_jobs` / `knora_get_voice_job`
List or inspect voice capture jobs.

---

#### `knora_list_templates`
List structured interview templates. Requires Growth plan.

---

#### `knora_get_template`
Fetch a single interview template by UUID. Requires Growth plan.

```json
{ "template_id": "<uuid>" }
```

---

#### `knora_create_template`
Create an interview template with ordered questions. Requires manager or admin role and Growth plan.

```json
{
  "name": "Maintenance Supervisor Handover",
  "role_target": "maintenance_supervisor",
  "questions": [
    {"order": 1, "text": "What incidents occurred during your shift?"},
    {"order": 2, "text": "What equipment is currently out of service?"},
    {"order": 3, "text": "What tasks are pending for the next shift?"}
  ]
}
```

Each question object requires `order` (integer, 1-based) and `text`. Optional fields: `category`, `follow_up_prompt`.

---

#### `knora_update_template`
Update an interview template (name, description, questions, etc.). Requires manager or admin role.

```json
{
  "template_id": "<uuid>",
  "questions": [
    {"order": 1, "text": "What incidents occurred during your shift?"},
    {"order": 2, "text": "What handover items are critical for the next shift?"}
  ]
}
```

---

#### `knora_delete_template`
Deactivate (soft-delete) an interview template. Requires manager or admin role.

```json
{ "template_id": "<uuid>" }
```

---

#### `knora_start_interview`
Start a structured interview session. Returns `session_id` and the first question.

```json
{ "template_id": "<uuid>", "interviewee_id": "<uuid>" }
```

---

#### `knora_answer_question`
Submit an answer to the current interview question. Returns the next question or `status: complete` when done.

```json
{
  "session_id": "<uuid>",
  "answer_text": "Pump 3 was offline for 2 hours due to a seal failure.",
  "question_index": 0
}
```

---

#### `knora_list_sessions`
List interview sessions. Requires Growth plan. Non-admin/manager users only see their own sessions.

```json
{ "status": "completed", "template_id": "<uuid>", "per_page": 20 }
```

Filters: `status`, `interviewee_id`, `template_id`, `page`, `per_page`.

---

#### `knora_get_session`
Fetch a single interview session with all answers. Requires Growth plan.

```json
{ "session_id": "<uuid>" }
```

---

#### `knora_complete_session`
Complete an interview session and trigger asynchronous knowledge extraction. Claude processes all answers and creates knowledge entries.

```json
{ "session_id": "<uuid>" }
```

---

#### `knora_cancel_session`
Cancel an in-progress interview session.

```json
{ "session_id": "<uuid>" }
```

---

#### `knora_create_shift_log`
Create a supervisor shift-end log (saved as draft). Requires Growth plan.

```json
{
  "shift_date": "2026-06-01T08:00:00",
  "notes": "Replaced seal on unit 7. Pump 3 back online by 10:30.",
  "department_id": "<uuid>"
}
```

---

#### `knora_list_shift_logs`
List shift logs. Requires Growth plan. Non-admin/manager users see only their own.

```json
{ "status": "draft", "department_id": "<uuid>", "date_from": "2026-06-01" }
```

Filters: `user_id`, `department_id`, `date_from`, `date_to`, `status` (draft|submitted), `page`, `per_page`.

---

#### `knora_get_shift_log`
Fetch a single shift log by UUID. Requires Growth plan.

```json
{ "log_id": "<uuid>" }
```

---

#### `knora_update_shift_log`
Update a draft shift log. Cannot update already-submitted logs.

```json
{
  "log_id": "<uuid>",
  "notes": "Updated notes: also replaced filter on unit 9.",
  "location": "Site B"
}
```

---

#### `knora_submit_shift_log`
Submit a shift log and trigger asynchronous knowledge extraction. Cannot be edited after submission.

```json
{ "log_id": "<uuid>" }
```

---

### Admin

#### `knora_get_me`
Return the authenticated user's profile.

---

#### `knora_update_me`
Update the authenticated user's name or department.

```json
{ "name": "Baraa Al-Rashid", "department": "Engineering" }
```

---

#### `knora_invite_member`
Invite a new user to the organisation. Requires admin or manager role.

```json
{
  "email": "new.hire@acme.com",
  "name": "Jane Smith",
  "role": "member",
  "department": "Operations"
}
```

---

#### `knora_list_members`
List all active members of the organisation.

---

#### `knora_update_member_role`
Change a member's role. Requires admin role.

```json
{ "user_id": "<uuid>", "role": "manager" }
```

---

#### `knora_remove_member`
Deactivate a member (soft removal). Requires admin role.

```json
{ "user_id": "<uuid>" }
```

---

#### `knora_get_org` / `knora_update_org`
Get or update organisation settings (name, default language).

---

#### `knora_list_connectors`
List available integration connectors. Requires admin or manager role.

---

#### `knora_list_integrations`
List active integrations with sync status and last sync timestamp. An organisation may have multiple integrations of the same connector type (e.g. two Slack workspaces).

---

#### `knora_trigger_sync`
Trigger an immediate manual sync for a connected integration. Requires admin role.

```json
{ "integration_id": "<uuid>" }
```

---

#### `knora_list_api_keys` / `knora_create_api_key` / `knora_revoke_api_key`
Manage API keys. The full key value is returned once on creation — save it immediately. Requires Growth plan.

```json
{ "name": "Claude Code integration" }
```

---

#### `knora_api_key_usage`
Get aggregate request usage statistics for all API keys in the organisation. Requires admin or manager role and Growth plan.

---

#### `knora_list_webhooks` / `knora_create_webhook` / `knora_delete_webhook`
Manage webhook endpoints for real-time event notifications. Events: `knowledge.created`, `knowledge.updated`, `knowledge.deleted`, `member.invited`, `member.removed`, `query.asked`. Requires Growth plan.

```json
{
  "url": "https://your-service.com/hooks/knora",
  "events": ["knowledge.created", "query.asked"]
}
```

---

### Analytics

#### `knora_dashboard_overview`
Dashboard snapshot: `total_entries`, `total_users`, `health_score`, `recent_activity`, query counts, and all activity metrics. Requires admin or manager role and Growth plan.

---

#### `knora_dashboard_activity`
Recent activity feed: entry creates, verifications, queries, flags.

```json
{ "limit": 20 }
```

---

#### `knora_dashboard_departments`
Per-department statistics: entry count, coverage percentage, risk level.

---

#### `knora_dashboard_trending`
Most frequently asked questions in the last N days.

```json
{ "days": 7 }
```

---

#### `knora_bus_factor`
Organisation-wide bus factor risk analysis: risk overview, critical-risk people, and per-department scores. Requires admin or manager role and Growth plan.

---

#### `knora_bus_factor_person`
Bus factor risk score for a specific person, including what knowledge they exclusively own.

```json
{ "user_id": "<uuid>" }
```

---

#### `knora_bus_factor_department`
Bus factor risk breakdown for a specific department.

```json
{ "dept_id": "<uuid>" }
```

---

#### `knora_bus_factor_critical`
Only the people and departments at CRITICAL risk level — use for dashboard alerts.

---

#### `knora_staleness_report`
Knowledge staleness report: entries not reviewed within the threshold window, plus aggregate stats.

```json
{ "days": 30 }
```

Returns `{ stale_entries[], stats: { stale_count, total_entries, review_rate } }`.

---

#### `knora_health_score`
Knowledge health score (0–100) broken into: coverage, freshness, verification rate, gap rate. Requires admin or manager role and Growth plan.

---

#### `knora_get_graph`
Knowledge graph: nodes (entries), edges (relationships), and clusters (topic groupings). Optionally filter by department.

```json
{ "max_nodes": 100, "department": "<uuid>" }
```

---

#### `knora_auto_link`
Trigger automatic linking of semantically similar entries via a background task. Requires admin or manager role.

---

#### `knora_plan_info`
Current subscription plan, usage, limits, and trial days remaining.

---

#### `knora_health`
Check whether the Knora backend is reachable. No authentication required.

---

## Example workflows

### Research + capture loop

```
1. knora_ask("What is our current process for X?")
2. knora_search("X process", limit=5)          # find related entries
3. knora_quick_note("Learned today: ...")       # capture new insight
4. knora_relate_entries(new_id, related_id)     # link to existing entries
```

### Knowledge audit

```
1. knora_dashboard_overview()                   # health overview
2. knora_staleness_report(days=60)              # find stale content
3. knora_list_gaps()                            # find missing documentation
4. knora_bus_factor_critical()                  # find knowledge silos
```

### Document ingestion

```
1. knora_upload_document(file_path="~/documents/manual.pdf")
2. knora_check_job(job_id=..., job_type="document") until status=="completed"
3. knora_get_entry(entry_id=result_entry_id)
4. knora_verify_entry(entry_id=...)
```
