Skip to content

Latest commit

 

History

134 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Local Vector Search for Jira, Confluence & Files (with MCP support)

Overview

Index documents from Jira, Confluence, or local files into a local vector database and search them. All data stays on your machine.

Key features:

  • Jira & Confluence (Server/Data Center and Cloud). Jira ticket = document, Confluence page = document
  • Local files (.pdf, .pptx, .docx, etc.) via Unstructured
  • No data sent to third parties (except when used as MCP with a remote AI agent)
  • Hybrid search: vector search + BM25 keyword search, merged by Reciprocal Rank Fusion
  • Incremental updates: no need to rebuild the full index each time
  • Filter results by metafields (space, project, date, etc.)
  • Ability to extend: add more data sources, search engines, embeddings, etc.

Technologies: SQLite (sqlite-vec and BM25), ChromaDB, sentence-transformers, Unstructured, LangChain

More context: Medium article

Contacts:

  • Like it? Please star the repo
  • Found a bug? Open an issue
  • Want to contribute? - feel free to do it via fork and sending a pull request
  • Want to chat? LinkedIn

Updates

  • Check UPDATES.md for major updates.
  • Some minor updates can be not added the file, so they can be found only in git history.

How it works

flowchart TD
    A[1. Create collection] -->|loads & indexes documents| B["Collection stored in ./data/collections/${name}"]
    B --> C{What next?}
    C --> D[2. Update collection]
    C --> E[3. Search via CLI]
    C --> F[4. Search via MCP]
    D -->|indexes only new/changed docs| B
    E -->|search| B
    F -->|search| B
Loading
  1. Create a collection — load and index documents from Jira, Confluence, or local files. Stored in ./data/collections/{name}
  2. Update — re-index only new or changed documents (much faster than full creation)
  3. Search — find documents by text query via CLI
  4. MCP — expose search as a tool for AI agents

Collection structure

graph TD
    A["./data/collections/${name}/"] --> B["documents/"]
    A --> C["indexes/"]
    A --> D["manifest.json"]
    B --- B1["Loaded and converted documents"]
    C --- C1["Vector and keyword index files"]
    D --- D1["Collection metadata: name, last update time, reader config, index list"]
Loading

See ./main/core/documents_collection_creator.py for creation/update details and ./main/core/documents_collection_searcher.py for search details.

Indexers configuration

When you create a collection, you can specify a list of indexers like: --indexers "indexer_SqlLiteVector__embeddings_sentence-transformers_slash_all-MiniLM-L6-v2", "indexer_SqlLiteBM25" (it's also the default value). The indexers define what vector/keyword databases and embedding models are used. Database and embedding model are separated by __. For example:

  • indexer_SqlLiteVector__embeddings_sentence-transformers_slash_all-MiniLM-L6-v2 means that SqlLite with sqlite-vec extension is used as vector database and sentence-transformers/all-MiniLM-L6-v2 is used as the embedding model. You can use any embedding model from next list, you only need to add prefix embeddings_ and replace slash symbols with _slash_. For example, if you want to use it with BAAI/bge-m3 embedder model, indexer name should be: indexer_SqlLiteVector__embeddings_BAAI_slash_bge-m3;
  • indexer_SqlLiteBM25 means that SqlLite BM25 is used as search engine.
  • indexer_ChromaDb__embeddings_sentence-transformers_slash_all-MiniLM-L6-v2 means that ChromaDb is used as vector database and sentence-transformers/all-MiniLM-L6-v2 is used as the embedding model. Embedding model names follow the same rules as for indexer_SqlLiteVector.

You can define as many indexers as you want, their search results will be combined by Reciprocal Rank Fusion.

Setup

Env setup

Either uv or docker can be used to run the project.

Local setup

  1. Clone the repository
  2. Install uv
  3. Run uv sync in the project root

Docker setup

A Dockerfile is included for running the tool without installing Python or uv locally.

Build the image:

docker build -t documents-vector-search .

Run any command by passing it as arguments and mounting a local data/ folder:

docker run --rm \
  -v $(pwd)/data:/app/data \
  -e CONF_TOKEN="${yourToken}" \
  documents-vector-search \
  uv run dvs.py create-confluence \
    --collection "confluence" \
    --url "${baseConfluenceUrl}" \
    --cql "${confluenceQuery}"
  • Mount -v $(pwd)/data:/app/data so collections and caches are persisted on your host machine
  • Pass credentials as -e ENV_VAR=value (see Authentication)
  • The data/ folder structure (collections/, caches/, local_file_input/) is created automatically inside the container

Run the unified MCP HTTP server with Docker:

docker run --rm \
  -p 8000:8000 \
  -v $(pwd)/data:/app/data \
  documents-vector-search \
  uv run dvs.py mcp --http --httpPort 8000

Then configure your MCP client to connect to http://localhost:8000/mcp.

Commands

All functionality is available through a single script:

uv run dvs.py <operation> [arguments]
Operation Description
create-confluence Create a collection from Confluence pages
create-jira Create a collection from Jira tickets
create-files Create a collection from local files
update Re-index new and changed documents of an existing collection
search Search in a collection from the command line
fetch Fetch a document content from a collection by its id
mcp Run unified MCP server (all collections, stdio or HTTP)
mcp-single Run MCP stdio server for a single collection

Every operation has its own arguments, each with a short and a long form (e.g. -c / --collection). Run uv run dvs.py <operation> --help to see all of them.

Authentication

Set environment variables before creating or updating Jira/Confluence collections (not needed for local files):

Platform Type Environment Variables
Confluence Server/DC Bearer token (recommended) CONF_TOKEN
Confluence Server/DC Login/Password CONF_LOGIN, CONF_PASSWORD
Confluence Cloud Email/API token ATLASSIAN_EMAIL, ATLASSIAN_TOKEN (get token)
Jira Server/DC Bearer token (recommended) JIRA_TOKEN
Jira Server/DC Login/Password JIRA_LOGIN, JIRA_PASSWORD
Jira Cloud Email/API token ATLASSIAN_EMAIL, ATLASSIAN_TOKEN (get token)

Cloud vs Server is auto-detected: URLs ending with .atlassian.net are treated as Cloud.

Create collection for Confluence

uv run dvs.py create-confluence \
  --collection "confluence" \
  --url "${baseConfluenceUrl}" \
  --cql "${confluenceQuery}"
  • --collection — name of the collection (used later for update/search). Data stored in ./data/collections/{name}
  • --url — Confluence base URL (e.g., https://confluence.example.com or https://your-domain.atlassian.net)
  • --cql — Confluence query, e.g., "(space = 'MySpace') AND (lastModified >= '2025-01-01')"

Create collection for Jira

uv run dvs.py create-jira \
  --collection "jira" \
  --url "${baseJiraUrl}" \
  --jql "${jiraQuery}"
  • --url — Jira base URL (e.g., https://jira.example.com or https://your-domain.atlassian.net)
  • --jql — Jira query, e.g., "project = MyProject AND created >= -183d"

Create collection for local files

uv run dvs.py create-files --basePath "${pathToFolder}"
  • Collection name defaults to the last folder name. Override with --collection {name}
  • Unreadable files are skipped by default. Use --failFast to stop on first error
  • Filter files with --includePatterns "regex1" "regex2" and --excludePatterns "regex1" "regex2"
  • Uses Unstructured for parsing. Some formats may need extra software

Update collection

uv run dvs.py update --collection "${collectionName}"

Search

uv run dvs.py search \
  --collection "${collectionName}" \
  --query "How to set up react project locally"
  • --includeMatchedChunksText — include matched text chunks in results
  • --filter — filter by metafields (see below)
  • --rrfK — RRF constant for multi-index fusion (default: 60)

Filtering by metafields

Works with ChromaDB, SQLite BM25 and SQLite Vector indexes.

Syntax:

field operator "value" and/or field operator "value"

Operators: =, !=, >, >=, <, <=. Use and / or to join conditions (mixing both is not supported).

Confluence metafields:

Field Description
space Space key
createdAt Page creation date
createdBy Creator email (lowercase)
lastModifiedAt Last update date

Examples:

--filter 'space = "SPACE_KEY"'
--filter 'space = "SPACE_KEY" and lastModifiedAt > "2026-01-01"'
--filter '(space = "SPACE_KEY1" or space = "SPACE_KEY2") and lastModifiedAt > "2026-01-01"'

Jira metafields:

Field Description
project Project key
type Issue type (Bug, Task, Story, ...)
status Status (Open, In Progress, Done, ...)
priority Priority (High, Medium, Low, ...)
epic Epic or parent issue key
assignee Assignee email (lowercase)
createdAt Issue creation date
createdBy Creator email (lowercase)
lastModifiedAt Last update date

Examples:

--filter 'project = "PROJ"'
--filter 'project = "PROJ" and lastModifiedAt > "2026-01-01"'
--filter '(project = "PROJ1" or project = "PROJ2") and lastModifiedAt > "2026-01-01"'

Files metafields:

Field Description
createdAt File creation date
lastModifiedAt Last modified date
folder1 First subfolder of the file path
folder2 Second subfolder of the file path
folderN Nth subfolder of the file path (only present if path has N or more subfolders)

Examples:

--filter 'folder1 = "docs"'
--filter 'folder1 = "docs" and folder2 = "api"'
--filter '(folder2 = "api" or folder2 = "presentations") and lastModifiedAt > "2026-01-01"'

Fetch

uv run dvs.py fetch \
  --collection "${collectionName}" \
  --id "${documentId}"
  • --id — document ID to fetch (required)
  • --startLine / --endLine — line range to return (default: 1–200)
  • --format — output format: json, json_with_indent (default), or toon

Set up MCP

There are two MCP server operations:

Operation Best for Key differences
dvs.py mcp Modern AI models All collections in one server. AI model chooses collection, filter and number of chunks. Supports stdio and HTTP transport.
dvs.py mcp-single Simpler AI models or restricted setups One collection per server. Collection, filter and other settings are hardcoded via CLI args. Stdio only.

Unified MCP (recommended)

Add to your MCP config (e.g., .vscode/mcp.json for VS Code + GitHub Copilot):

{
    "servers": {
        "dvs": {
            "type": "stdio",
            "command": "uv",
            "args": [
                "--directory", "${fullPathToRootProjectFolder}",
                "run", "dvs.py", "mcp"
            ]
        }
    }
}
  • All collections from ./data/collections/ are available automatically
  • Use --collections "name1" "name2" to limit which collections are exposed
  • Use --rrfK {number} to tune Reciprocal Rank Fusion behavior for multi-index search
  • Use --defaultNumberOfChunks {number} and --maxNumberOfChunks {number} to tune the number of text chunks returned by a single search

Or start as http server:

uv run dvs.py mcp --http --httpPort 8000

And setup mcp like:

{
    "servers": {
        "dvs": {
            "type": "http",
            "url": "http://localhost:8000/mcp",
        }
    }
}

Simple MCP

{
    "servers": {
        "search_${collectionName}": {
            "type": "stdio",
            "command": "uv",
            "args": [
                "--directory", "${fullPathToRootProjectFolder}",
                "run", "dvs.py", "mcp-single",
                "--collection", "${collectionName}"
            ]
        }
    }
}
  • Replace ${collectionName} and ${fullPathToRootProjectFolder} with real values
  • Use --maxNumberOfChunks {number} to control how many text chunks are returned (more = better search, but may exceed model context window)
  • Use --rrfK {number} to tune Reciprocal Rank Fusion behavior for multi-index search
  • Use --filter for metafield filtering (details)

Prompt examples:

  • "Find info about AI use cases, search on Confluence, include all used links"
  • "Find info about PDP carousel, search on Jira, include all used links"

Run unit tests

If you develop the tool, you can run unit tests:

uv run pytest

Good to know

  • Incremental updates — only new/changed documents are re-indexed. Uses lastModifiedDocumentTime from manifest.json (5 mins for Jira and Confluence buffer to avoid missing concurrent updates);
  • Caching — Jira/Confluence collection creation caches downloaded documents in ./data/caches/{hash}. Same parameters = same cache. If you need fresh data, either run an update after creation, or delete the cache folder manually;
  • there are more parameters in each operation, use uv run dvs.py <operation> --help to get more.

About

Project allows document indexing in a local vector database and then search (supports Jira, Confluence and local files, can be integrated via MCP)

Resources

Stars

41 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages