Metadata-Version: 2.4
Name: mad-mcp-qdrant
Version: 1.7.0
Summary: MCP server for retrieving context from a Qdrant vector database
License-Expression: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: fastembed>=0.6.0
Requires-Dist: fastmcp==2.7.0
Requires-Dist: openai>=1.40.0
Requires-Dist: pdf2image>=1.17.0
Requires-Dist: pydantic<2.12.0,>=2.10.6
Requires-Dist: pypdf>=4.2.0
Requires-Dist: pytesseract>=0.3.10
Requires-Dist: python-docx>=1.1.0
Requires-Dist: qdrant-client>=1.12.0
Description-Content-Type: text/markdown

<p align="center">
  <img src="./assets/brand/header.jpg" alt="MADPANDA3D QDRANT MCP header" />
</p>

<p align="center">
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="Apache 2.0 License" /></a>
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" alt="Python 3.10+" /></a>
  <a href="https://modelcontextprotocol.io/"><img src="https://img.shields.io/badge/MCP-Server-000000" alt="MCP Server" /></a>
  <a href="https://qdrant.tech/"><img src="https://img.shields.io/badge/Qdrant-Connected-ff6f00" alt="Qdrant" /></a>
  <a href="https://github.com/MADPANDA3D/QDRANT-MCP/releases"><img src="https://img.shields.io/github/v/release/MADPANDA3D/QDRANT-MCP?display_name=tag&color=0e8a16" alt="release" /></a>
  <a href="https://github.com/MADPANDA3D/QDRANT-MCP/issues"><img src="https://img.shields.io/github/issues/MADPANDA3D/QDRANT-MCP?color=ff8c00" alt="open issues" /></a>
  <a href="https://github.com/MADPANDA3D/QDRANT-MCP"><img src="https://img.shields.io/github/stars/MADPANDA3D/QDRANT-MCP?color=f1c40f" alt="stars" /></a>
</p>

<h1 align="center"><strong>MADPANDA3D QDRANT MCP</strong></h1>
<p align="center"><strong>Manage your Vector Database how you see fit</strong></p>
<p align="center">
  MADPANDA3D QDRANT MCP is a production-ready Model Context Protocol server for Qdrant.
  It turns your vector store into a managed memory layer with structured controls for
  ingest, retrieval, validation, and ongoing cleanup.
</p>
<p align="center">
  Use it to keep memories clean, deduped, and relevance-tuned over time. The toolkit
  includes safe dry-run previews, bulk maintenance jobs with progress reporting, and
  operational guardrails so agents can manage your database at scale without chaos.
</p>

## Overview

This server is designed for production workloads and supports hosted header-auth access for clients like n8n, Claude Desktop, and other MCP-capable agents.

## Hosted MCP (Header Auth)

Use the MADPANDA3D hosted endpoint:

```
https://qdrant-mcp.madpanda3d.com/mcp
```

Note: `https://qdrant-mcp.madpanda3d.com/mcp/` is deprecated and returns `410 Gone` with a migration message.

n8n setup:

1. Add **MCP tool node** to your agent.
2. Add the MCP endpoint URL.
3. Set **Server transport** to **HTTP streamable**.
4. Set **Auth** to **Multiple Headers Auth**.
5. Add headers:
   - `X-MADPANDA-PORTAL-GRANT`
   - `X-Qdrant-Url`
   - `X-Qdrant-Api-Key`
   - `X-Collection-Name` (optional)
   - `X-Embedding-Provider` (optional; required for semantic search + write tools)
   - `X-Embedding-Model` (optional; required with `X-Embedding-Provider`)
   - `X-OpenAI-Api-Key` (required when `X-Embedding-Provider=openai`)
6. Save the auth credentials.
7. Set **Tools to include** → **All**.

## n8n Setup

Screenshots below show the MCP node configuration in n8n.

<p align="center">
  <img src="./assets/n8n/n8n-qdrant-mcp-setup-step1.jpg" alt="n8n MCP setup step 1" width="900" />
</p>
<p align="center">
  <img src="./assets/n8n/n8n-qdrant-mcp-setup-step2.jpg" alt="n8n MCP setup step 2" width="900" />
</p>
<p align="center">
  <img src="./assets/n8n/n8n-qdrant-mcp-setup-step3.jpg" alt="n8n MCP setup step 3" width="900" />
</p>

## Deploy

- [![Deploy to VPS](https://img.shields.io/badge/Deploy_to_VPS-Hostinger-blue?style=for-the-badge&logo=linux&logoColor=white)](https://www.hostinger.com/cart?product=vps%3Avps_kvm_4&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-531e-70d3-83f5-e28eb919466d)

## Quickstart

<details>
<summary>Install (pip)</summary>

```bash
pip install mad-mcp-qdrant
```

</details>

<details>
<summary>Run with Docker</summary>

```bash
docker build -t mcp-server-qdrant .
docker run -d --name mcp-qdrant \
  --restart unless-stopped \
  --network mcp-network \
  --env-file .env \
  mcp-server-qdrant
```

Or use the hosted-standard compose file:

```bash
cp .env.example .env
docker compose up -d --build
```

</details>

<details>
<summary>Auto-update with Watchtower (GHCR)</summary>

```bash
# Run from GHCR (make the package public or login to GHCR first).
docker run -d --name mcp-qdrant \
  --network mcp-network \
  --env-file .env \
  --label com.centurylinklabs.watchtower.enable=true \
  ghcr.io/<owner>/mad-mcp-qdrant:latest \
  mcp-server-qdrant --transport streamable-http

# Watchtower will pull new release images and restart the container.
docker run -d --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --cleanup --interval 1800 --label-enable
```

</details>

<details>
<summary>Run locally (uvx)</summary>

```bash
QDRANT_URL=... COLLECTION_NAME=... uvx mad-mcp-qdrant
```

Prefer `mad-mcp-qdrant`; `mcp-server-qdrant` remains as a compatible alias.

</details>

## Tools

Most mutating tools support `dry_run` + `confirm` and return a `dry_run_diff` preview for safer approvals.

Search tools are token-safe by default. `qdrant-find`,
`qdrant-find-short-term`, and `qdrant-recommend-memories` return compact
results unless `response_mode="payload"` is requested. Start with `top_k=3-5`,
add filters when possible, and increase detail only after selecting a specific
result. For large content, prefer `qdrant-ingest-document` or
`qdrant-ingest-textbook` instead of sending long text directly to store tools.
For school work, start with `qdrant-study-search`; it defaults to the
`MCP_STUDY_COLLECTION` collection and exposes course, subject, material type,
title, document, and chapter filters directly.

<details>
<summary>Core Memory Tools</summary>

- `qdrant-store`: store a single memory point with metadata.
- `qdrant-cache-memory`: store short-term memory with a TTL in a cache collection.
- `qdrant-promote-short-term`: promote short-term memories into the long-term collection.
- `qdrant-ingest-with-validation`: validate inputs, optionally quarantine, then store.
- `qdrant-ingest-document`: chunk a document and store as multiple points.
  - PDF ingestion runs native text extraction plus OCR by default (`ocr=true`).
  - OCR is local (Tesseract via `pytesseract` + `pdf2image`), not a third-party API.
- `qdrant-ingest-textbook`: submit an async textbook PDF ingestion job (source_url-only).
  - Returns immediately with `job_id` for large-file workflows.
  - Requires metadata: `class`, `material_type`, `title`, `author`, `edition`, `isbn`.
  - Uses streaming download + page-wise extraction to reduce memory pressure.
  - With `ocr=true`, applies OCR coverage-gating (blank/low-text pages first) and fails fast if target coverage cannot be met within budget.
  - Job status is persisted on disk so restart scenarios return structured failure instead of `Job not found`.
- `qdrant-study-search`: search school/study materials with compact output and direct course/subject/title filters.
- `qdrant-find`: query vectors with filters and return matches.
- `qdrant-find-short-term`: query the short-term memory cache collection.
- `qdrant-recommend-memories`: recommend memories using positive/negative examples.
- `qdrant-update-point`: update payload fields for a point id.
- `qdrant-patch-payload`: patch specific payload keys for a point id.
- `qdrant-tag-memories`: append or replace labels for a set of points.
- `qdrant-link-memories`: link memories via related ids and optional associations.
- `qdrant-list-points`: scroll point ids in a collection with filters.
- `qdrant-get-points`: fetch points by id list with payload/vectors.
- `qdrant-count-points`: count points that match optional filters.

</details>

<details>
<summary>Agent Navigation</summary>

- `qdrant-check-configuration`: check hosted readiness, accepted headers, cache settings, and missing configuration without returning secrets.
- `qdrant-list-capabilities`: list compact capability groups and common workflows.
- `qdrant-get-endpoint-coverage`: summarize Qdrant endpoint coverage and documented exclusions from `docs/endpoint-coverage.md`.
- `qdrant-get-tool-usage`: inspect a tool schema, annotations, and token-safe usage guidance.

</details>

<details>
<summary>Housekeeping + Quality</summary>

- `qdrant-audit-memories`: scan for missing fields, bad payloads, and duplicates.
- `qdrant-backfill-memory-contract`: populate missing metadata fields at scale.
- `qdrant-bulk-patch`: patch payloads in bulk by filter or ids (dry-run supported).
- `qdrant-dedupe-memories`: dedupe exact matches by hash.
- `qdrant-find-near-duplicates`: cluster semantic near-duplicates.
- `qdrant-merge-duplicates`: merge duplicate groups into a canonical point.
- `qdrant-reembed-points`: recompute embeddings for selected points.
- `qdrant-expire-memories`: delete/archive memories past `expires_at_ts`.
- `qdrant-expire-short-term`: delete expired memories from the short-term cache.
- `qdrant-delete-points`: delete points by id list.
- `qdrant-delete-by-filter`: delete points that match a filter.
- `qdrant-delete-document`: delete all chunks for a document id.

</details>

<details>
<summary>Jobs + Progress</summary>

- `qdrant-submit-job`: start a background maintenance job.
- `qdrant-get-ingest-status`: ingest-focused status/metrics for textbook jobs.
- `qdrant-cancel-ingest`: cancel a running textbook ingest job.
- `qdrant-job-status`: get job status and summary.
- `qdrant-job-progress`: read progress counters and phase.
- `qdrant-job-logs`: tail recent logs for a job.
- `qdrant-job-result`: fetch the final job result.
- `qdrant-cancel-job`: cancel a running job.

</details>

<details>
<summary>Collection + Admin</summary>

- `qdrant-health-check`: validate collection health and expected indexes.
- `qdrant-metrics-snapshot`: capture collection stats and index coverage.
- `qdrant-ensure-payload-indexes`: create missing payload indexes.
- `qdrant-optimizer-status`: report optimizer and segment status.
- `qdrant-update-optimizer-config`: update optimizer settings (admin).
- `qdrant-list-collections`: list all collections.
- `qdrant-create-collection`: create a collection with embedding-compatible vector settings and default payload indexes.
- `qdrant-collection-exists`: check if a collection exists.
- `qdrant-collection-info`: fetch collection config and metadata.
- `qdrant-collection-stats`: read collection stats (points, segments).
- `qdrant-collection-vectors`: show vector config for the collection.
- `qdrant-collection-payload-schema`: list payload schema + indexed fields.
- `qdrant-get-vector-name`: resolve the active vector name.
- `qdrant-list-aliases`: list all aliases.
- `qdrant-collection-aliases`: list aliases for a collection.
- `qdrant-collection-cluster-info`: cluster and shard info.
- `qdrant-list-snapshots`: list collection snapshots.
- `qdrant-list-full-snapshots`: list full snapshots on the server.
- `qdrant-list-shard-snapshots`: list shard snapshots for a collection.
- `qdrant-create-snapshot`: create a new collection snapshot.
- `qdrant-restore-snapshot`: restore a snapshot into a collection.

</details>

## Configuration

<details>
<summary>Environment Variables</summary>

| Name                          | Description                                                         | Default Value                                                     |
|-------------------------------|---------------------------------------------------------------------|-------------------------------------------------------------------|
| `MCP_PORTAL_GRANT_TOKEN`      | Required grant token for `/mcp` HTTP traffic from the MAD MCP Portal | unset                                                             |
| `QDRANT_URL`                  | URL of the Qdrant server                                            | None                                                              |
| `QDRANT_API_KEY`              | API key for the Qdrant server                                       | None                                                              |
| `COLLECTION_NAME`             | Name of the default collection to use.                              | None                                                              |
| `QDRANT_VECTOR_NAME`          | Override vector name used by the MCP server                         | None                                                              |
| `QDRANT_LOCAL_PATH`           | Path to the local Qdrant database (alternative to `QDRANT_URL`)     | None                                                              |
| `QDRANT_SEARCH_LIMIT`         | Default result limit when `top_k` is omitted                        | `10`                                                              |
| `QDRANT_READ_ONLY`            | Hide mutating tools when enabled                                    | `false`                                                           |
| `QDRANT_ALLOW_ARBITRARY_FILTER` | Allow raw Qdrant filter input                                      | `false`                                                           |
| `EMBEDDING_PROVIDER`          | Embedding provider to use (`fastembed` or `openai`)                  | `fastembed`                                                       |
| `EMBEDDING_MODEL`             | Name of the embedding model to use                                  | `sentence-transformers/all-MiniLM-L6-v2`                          |
| `EMBEDDING_VECTOR_SIZE`       | Vector size override (required for unknown OpenAI models)           | unset                                                             |
| `EMBEDDING_VERSION`           | Embedding version label stored with each memory                     | unset                                                             |
| `OPENAI_API_KEY`              | OpenAI API key (required for `openai` provider)                     | unset                                                             |
| `OPENAI_BASE_URL`             | OpenAI-compatible base URL (optional)                               | unset                                                             |
| `OPENAI_ORG`                  | OpenAI organization ID (optional)                                   | unset                                                             |
| `OPENAI_PROJECT`              | OpenAI project ID (optional)                                        | unset                                                             |
| `TOOL_STORE_DESCRIPTION`      | Custom description for the store tool                               | See default in `src/mcp_server_qdrant/settings.py`               |
| `TOOL_FIND_DESCRIPTION`       | Custom description for the find tool                                | See default in `src/mcp_server_qdrant/settings.py`               |
| `MCP_ADMIN_TOOLS_ENABLED`     | Enable admin-only tools (optimizer updates)                         | `false`                                                           |
| `MCP_MUTATIONS_REQUIRE_ADMIN` | Require admin access for mutating tools                             | `false`                                                           |
| `MCP_MAX_BATCH_SIZE`          | Max batch size for bulk operations                                  | `500`                                                             |
| `MCP_MAX_POINT_IDS`           | Max point id list size                                              | `500`                                                             |
| `MCP_STRICT_PARAMS`           | Reject unknown keys/filters and oversized text                      | `false`                                                           |
| `MCP_MAX_TEXT_LENGTH`         | Max text length before chunking                                     | `8000`                                                            |
| `MCP_TEXTBOOK_MAX_FILE_BYTES` | Max textbook file size (bytes) for async ingest                     | `104857600`                                                       |
| `MCP_TEXTBOOK_MAX_PAGES`      | Max textbook page count for async ingest                            | `1000`                                                            |
| `MCP_TEXTBOOK_MAX_EXTRACTED_CHARS` | Max extracted characters for async textbook ingest           | `3000000`                                                         |
| `MCP_TEXTBOOK_MAX_CHUNKS`     | Max chunk count for async textbook ingest                           | `20000`                                                           |
| `MCP_TEXTBOOK_OCR_LOW_TEXT_THRESHOLD_CHARS` | Chars/page threshold considered low-text during OCR gating | `120`                                                             |
| `MCP_TEXTBOOK_OCR_MIN_COVERAGE_RATIO` | Minimum acceptable text coverage ratio after OCR budget pass | `0.85`                                                            |
| `MCP_TEXTBOOK_OCR_MAX_PAGES`  | Max number of pages eligible for OCR in textbook ingest             | `120`                                                             |
| `MCP_TEXTBOOK_OCR_MAX_PAGE_RATIO` | Max OCR page budget as ratio of total pages                    | `0.30`                                                            |
| `MCP_TEXTBOOK_JOB_TIMEOUT_SECONDS` | Timeout for async textbook ingest jobs                          | `2700`                                                            |
| `MCP_TEXTBOOK_EMBED_BATCH_SIZE` | Embed batch size for textbook jobs                               | `32`                                                              |
| `MCP_TEXTBOOK_UPSERT_BATCH_SIZE` | Upsert batch size for textbook jobs                              | `64`                                                              |
| `MCP_TEXTBOOK_MAX_CONCURRENCY` | Max concurrent textbook embed/upsert workers                       | `2`                                                               |
| `MCP_TEXTBOOK_JOB_STATE_DIR`  | Local directory used to persist async textbook job state            | `/tmp/mcp-server-qdrant/jobs`                                    |
| `MCP_TEXTBOOK_JOB_STATE_RETENTION_HOURS` | Retention window for terminal persisted job state         | `168`                                                             |
| `MCP_QUERY_EMBEDDING_CACHE_SIZE` | Max cached query embeddings; set `0` to disable                  | `256`                                                             |
| `MCP_QUERY_EMBEDDING_CACHE_TTL_SECONDS` | Query embedding cache TTL seconds                         | `3600`                                                            |
| `MCP_DEDUPE_ACTION`           | Dedupe behavior (`update` or `skip`)                                | `update`                                                          |
| `MCP_INGEST_VALIDATION_MODE`  | Validation mode (`allow`, `reject`, `quarantine`)                   | `allow`                                                           |
| `MCP_QUARANTINE_COLLECTION`   | Collection name for quarantined memories                            | `jarvis-quarantine`                                               |
| `MCP_HEALTH_CHECK_COLLECTION` | Default collection for health check                                 | unset                                                             |
| `MCP_SHORT_TERM_COLLECTION`   | Collection name for short-term memory cache                          | `jarvis-short-term`                                               |
| `MCP_STUDY_COLLECTION`        | Default collection for `qdrant-study-search`                        | `school`                                                          |
| `MCP_SHORT_TERM_TTL_DAYS`     | Default TTL (days) for short-term memory cache                       | `7`                                                               |
| `MCP_SERVER_VERSION`          | Optional git SHA for telemetry                                      | unset                                                             |
| `MCP_ALLOW_REQUEST_OVERRIDES` | Allow per-request Qdrant headers                                    | `false`                                                           |
| `MCP_REQUIRE_REQUEST_QDRANT_URL` | Require `X-Qdrant-Url` when overrides enabled                    | `true`                                                            |
| `MCP_REQUIRE_REQUEST_QDRANT_API_KEY` | Require `X-Qdrant-Api-Key` when overrides enabled           | `false`                                                           |
| `MCP_REQUIRE_REQUEST_COLLECTION` | Require `X-Collection-Name` when overrides enabled              | `true`                                                            |
| `MCP_DISABLE_DEFAULT_QDRANT_FALLBACK` | Disable server-side Qdrant fallback defaults                 | `false`                                                           |
| `MCP_DISABLE_DEFAULT_EMBEDDING_FALLBACK` | Require embedding headers for all tools                     | `false`                                                           |
| `MCP_PORTAL_GRANT_HEADER`      | Header name for the MAD MCP Portal grant token                     | `x-madpanda-portal-grant`                                         |
| `MCP_QDRANT_URL_HEADER`        | Header name for Qdrant URL                                         | `x-qdrant-url`                                                    |
| `MCP_QDRANT_API_KEY_HEADER`    | Header name for Qdrant API key                                     | `x-qdrant-api-key`                                                |
| `MCP_COLLECTION_NAME_HEADER`   | Header name for collection name                                    | `x-collection-name`                                               |
| `MCP_QDRANT_VECTOR_NAME_HEADER` | Header name for vector name                                       | `x-qdrant-vector-name`                                            |
| `MCP_EMBEDDING_PROVIDER_HEADER` | Header name for embedding provider                                | `x-embedding-provider`                                            |
| `MCP_EMBEDDING_MODEL_HEADER`   | Header name for embedding model                                    | `x-embedding-model`                                               |
| `MCP_EMBEDDING_VECTOR_SIZE_HEADER` | Header name for embedding vector size                          | `x-embedding-vector-size`                                         |
| `MCP_OPENAI_API_KEY_HEADER`    | Header name for OpenAI API key                                     | `x-openai-api-key`                                                |
| `MCP_OPENAI_BASE_URL_HEADER`   | Header name for OpenAI-compatible base URL                         | `x-openai-base-url`                                               |
| `MCP_OPENAI_ORG_HEADER`        | Header name for OpenAI organization                                | `x-openai-org`                                                    |
| `MCP_OPENAI_PROJECT_HEADER`    | Header name for OpenAI project                                     | `x-openai-project`                                                |
| `MCP_QDRANT_HOST_ALLOWLIST`    | Comma/space-separated allowed Qdrant hostnames                     | unset                                                             |

Note: You cannot provide both `QDRANT_URL` and `QDRANT_LOCAL_PATH` at the same time.

</details>

### Example .env templates

Base (Qdrant + hosted overrides):

```bash
MCP_PORTAL_GRANT_TOKEN=replace-with-shared-portal-token
QDRANT_URL=https://your-qdrant-host:6333
QDRANT_API_KEY=your-qdrant-api-key
COLLECTION_NAME=

# Hosted MCP: require client headers (recommended for public endpoints)
MCP_ALLOW_REQUEST_OVERRIDES=true
MCP_REQUIRE_REQUEST_QDRANT_URL=true
MCP_REQUIRE_REQUEST_QDRANT_API_KEY=true
MCP_REQUIRE_REQUEST_COLLECTION=false
MCP_DISABLE_DEFAULT_QDRANT_FALLBACK=true
MCP_DISABLE_DEFAULT_EMBEDDING_FALLBACK=false
MCP_QDRANT_HOST_ALLOWLIST=*.qdrant.io
MCP_QUERY_EMBEDDING_CACHE_SIZE=256
MCP_QUERY_EMBEDDING_CACHE_TTL_SECONDS=3600
```

FastEmbed (local embeddings, no external API):

```bash
EMBEDDING_PROVIDER=fastembed
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
```

OpenAI embeddings:

```bash
EMBEDDING_PROVIDER=openai
EMBEDDING_MODEL=text-embedding-3-large
OPENAI_API_KEY=your-openai-key
```

OpenAI-compatible embeddings (custom base URL):

```bash
EMBEDDING_PROVIDER=openai
EMBEDDING_MODEL=your-model-id
OPENAI_API_KEY=your-openai-compatible-key
OPENAI_BASE_URL=https://your-openai-compatible-host/v1
# Optional:
OPENAI_ORG=
OPENAI_PROJECT=
```

### Hosted MCP (Bring Your Own Qdrant)

If you run a public MCP endpoint and want users to supply their own Qdrant
credentials (e.g., in n8n), enable per-request overrides and send headers.

Server env:

```bash
MCP_PORTAL_GRANT_TOKEN=replace-with-shared-portal-token
MCP_ALLOW_REQUEST_OVERRIDES=true
MCP_REQUIRE_REQUEST_QDRANT_URL=true
MCP_REQUIRE_REQUEST_QDRANT_API_KEY=true
MCP_REQUIRE_REQUEST_COLLECTION=false
MCP_DISABLE_DEFAULT_QDRANT_FALLBACK=true
MCP_DISABLE_DEFAULT_EMBEDDING_FALLBACK=false
# Optional hardening
MCP_QDRANT_HOST_ALLOWLIST=*.qdrant.io
```

Client headers (n8n MCP node):

- `X-MADPANDA-PORTAL-GRANT`: shared portal grant token (required for `/mcp`)
- `X-Qdrant-Url`: user Qdrant URL (required)
- `X-Qdrant-Api-Key`: user Qdrant API key (required in strict hosted mode)
- `X-Collection-Name`: user collection (optional; omit to work across collections)
- `X-Qdrant-Vector-Name`: optional vector name override
- `X-Embedding-Provider`: optional (`fastembed` or `openai`)
- `X-Embedding-Model`: optional; required when provider is set
- `X-Embedding-Vector-Size`: optional vector size override
- `X-OpenAI-Api-Key`: required when provider is `openai`
- `X-OpenAI-Base-Url`: optional OpenAI-compatible endpoint
- `X-OpenAI-Org`: optional OpenAI org
- `X-OpenAI-Project`: optional OpenAI project

Behavior in hosted mode:

- `/health` is public and secret-free.
- `/mcp` fails closed before request override, Qdrant, or embedding headers are processed when `MCP_PORTAL_GRANT_TOKEN` is missing or `X-MADPANDA-PORTAL-GRANT` is absent/invalid.
- Missing embedding headers puts the session into read-only mode.
- Write/mutation tools are blocked until embedding headers are provided.
- Semantic search tools (`qdrant-find`, `qdrant-find-short-term`) require embedding headers.
- Collection-scoped tools remain visible in `tools/list` and include the marker `[Requires collection name]`.
- You can create collections without `X-Collection-Name` by calling `qdrant-create-collection` with `collection_name` in tool args.
- Send headers on `initialize`, then reuse `mcp-session-id` for `tools/list` and `tools/call`.

Tip: If you enable request overrides for a public endpoint, do not rely on
server-side `QDRANT_*` defaults. Require user headers and keep your own
Qdrant instance network-restricted.

<details>
<summary>Memory Contract</summary>

Stored memories are normalized to include at least:
`text`, `type`, `entities`, `source`, `created_at`, `updated_at`, `scope`, `confidence`, and `text_hash`.

Optional fields include `expires_at` / `ttl_days`, `labels`, `related_ids`, `associations`,
validation metadata (`validation_status`, `validation_errors`), merge markers
(`merged_into`, `merged_from`), plus embedding metadata
(`embedding_model`, `embedding_dim`, `embedding_provider`, `embedding_version`).

Document ingestion stores additional fields such as `doc_id`, `doc_title`, `doc_hash`,
`source_url`, `file_name`, `file_type`, `page_start`, `page_end`, and `section_heading`.

When a duplicate `text_hash` is found in the same `scope`, the server updates
`last_seen_at` and `reinforcement_count` instead of inserting a duplicate.

</details>

<details>
<summary>Maintenance Playbooks</summary>

See `docs/MAINTENANCE_PLAYBOOKS.md` for recommended maintenance flows.

</details>

## Release & Versioning

This repo uses conventional commits and semantic-release. Every push to `main` runs the
release workflow, and a release is created only when commit messages warrant a version bump.

## License

Apache-2.0.

## Support

[![Donate to the Project](https://img.shields.io/badge/Donate_to_the_Project-Support_Development-ff69b4?style=for-the-badge&logo=heart&logoColor=white)](https://donate.stripe.com/cNidRbdkAbdP8iU7SD4ko0b)

## Affiliate Links

<details>
<summary>Services I use (affiliate)</summary>

Using these links helps support continued development.

### Hostinger VPS
- [KVM 1](https://www.hostinger.com/cart?product=vps%3Avps_kvm_1&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a491-d783-7057-85d2-27de6e01e2c5)
- [KVM 2](https://www.hostinger.com/cart?product=vps%3Avps_kvm_2&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-26cf-7333-b6d7-692e17bf8ce1)
- [KVM 4](https://www.hostinger.com/cart?product=vps%3Avps_kvm_4&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-531e-70d3-83f5-e28eb919466d)
- [KVM 8](https://www.hostinger.com/cart?product=vps%3Avps_kvm_8&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-7ce9-70fb-b96c-2184abc56764)

### Cloud Hosting
- [Cloud Economy](https://www.hostinger.com/cart?product=hosting%3Acloud_economy&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a48f-e7fa-7358-9ff0-f9ba2e8d6e36)
- [Cloud Professional](https://www.hostinger.com/cart?product=hosting%3Acloud_professional&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a490-20fd-70bc-959e-a1f2cd9a69a6)
- [Cloud Enterprise](https://www.hostinger.com/cart?product=hosting%3Acloud_enterprise&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a490-5972-72e4-850f-40d618988dc1)

### Web Hosting
- [Premium](https://www.hostinger.com/cart?product=hosting%3Ahostinger_premium&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a48f-4c21-7199-9918-8f31a3f6a0d9)
- [Business](https://www.hostinger.com/cart?product=hosting%3Ahostinger_business&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a48f-1135-72ba-acbb-13e0e7550db0)

### Website Builder
- [Premium](https://www.hostinger.com/cart?product=hosting%3Ahostinger_premium&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-f240-7309-b3fe-9f6909fbc769&product_type=website-builder)
- [Business](https://www.hostinger.com/cart?product=hosting%3Ahostinger_business&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a492-7ce9-70fb-b96c-2184abc56764)

### Agency Hosting
- [Startup](https://www.hostinger.com/cart?product=hosting%3Aagency_startup&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a490-d03c-71de-9acf-08fd4fa911de)
- [Growth](https://www.hostinger.com/cart?product=hosting%3Aagency_growth&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a491-6af4-731f-8947-f1458f07fa5b)
- [Professional](https://www.hostinger.com/cart?product=hosting%3Aagency_professional&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a491-03fb-73f8-9910-044a0a33393a)

### Email
- [Business Pro](https://www.hostinger.com/cart?product=hostinger_mail%3Apro&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a493-5c27-727b-b7f9-8747ffb4e5ee)
- [Business Premium](https://www.hostinger.com/cart?product=hostinger_mail%3Apremium&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a493-a3fc-72b8-a961-94ed6e1c70e6)

### Reach
- [Reach 500](https://www.hostinger.com/cart?product=reach%3A500&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a494-3ebf-7367-b409-9948de50a297)
- [Reach 1000](https://www.hostinger.com/cart?product=reach%3A1000&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a494-8bb9-726e-bb8d-9de9a72a3c21)
- [Reach 2500](https://www.hostinger.com/cart?product=reach%3A2500&period=12&referral_type=cart_link&REFERRALCODE=ZUWMADPANOFE&referral_id=0199a494-c9c1-7191-b600-cafa2e9adafc)

</details>

## Contact

Open an issue in `MADPANDA3D/QDRANT-MCP`.

<p align="center">
  <img src="https://assets.zyrosite.com/cdn-cgi/image/format=auto,w=316,fit=crop,q=95/dJo56xnDoJCnbgxg/official-logo-mxBMZGQ8Owc8p2M2.jpeg" width="160" alt="MADPANDA3D logo" />
  <br />
  <strong>MADPANDA3D</strong>
</p>
