Search — MDDB API

Search and query operations

Search documents #

POST /v1/search

Search documents with metadata filtering, sorting, and pagination.

Filtering: AND logic between different metadata keys, OR logic between values of the same key.

Sorting: Sort by addedAt, updatedAt, or key.

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: SearchRequest

{
  "asc": false,
  "collection": "blog",
  "filter": {
    "kind": {
      "not": [
        "test"
      ]
    },
    "modified": {
      "gte": "2026-09-01"
    },
    "path": {
      "prefix": "internal/"
    },
    "size": {
      "lt": 10000
    },
    "summary": {
      "exists": true
    },
    "title": {
      "contains": "hnsw"
    }
  },
  "filterMeta": {
    "category": [
      "blog",
      "tutorial"
    ],
    "status": [
      "published"
    ]
  },
  "limit": 10,
  "offset": 0,
  "sort": "updatedAt"
}

Responses #

Status Description Body
200 Search results array of Document (application/json)
400 Invalid request ErrorResponse (application/json)

Extension to language table for source files #

GET /v1/code-languages

The table the server classifies code by (AGT-001, v2.18.8), so a client walking a directory — mddb-cli autoindex — marks files the way the server would.

Authorization: BearerAuth or APIKeyAuth or none

Responses #

Status Description Body
200 The table object (application/json)
405 Method not allowed

Where a symbol is defined, used, called and tested #

GET /v1/symbol

Definitions with their span, references with the definition each sits in, callers, callees, tests and siblings of one symbol, as passages (CODE-008, v2.18.8). Candidates come from the metadata index (defines/uses) and the full-text index; spans are computed from the documents at query time, so nothing is stored. Also the code_symbol MCP tool and the codeSymbol GraphQL query. POST takes the same fields as a JSON body.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string
name (required) query string
include query string Comma-separated relations; default all.
limit query integer Default 20. Maximum 200.
includeContent query boolean Default false.

Responses #

Status Description Body
200 The symbol's relations SymbolResult (application/json)
400 Missing collection or name, or an unreadable body
403 Forbidden
422 Unknown relation in include

Symbol lookup (JSON body) #

POST /v1/symbol

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: SymbolRequest

{
  "collection": "string",
  "include": [
    "definitions"
  ],
  "includeContent": false,
  "limit": 20,
  "name": "string"
}

Responses #

Status Description Body
200 The symbol's relations SymbolResult (application/json)
400 Missing collection or name, or an unreadable body
422 Unknown relation in include

Code connection graph for one document #

GET /v1/code-graph

Answers the relational questions full-text search cannot: what breaks if this selector changes, which pages load this script, which file defines a function this one calls, which manifest declares the ConfigMap a Deployment refers to, what does nothing reference any more. Edges are derived at query time from the defines/uses/imports metadata of code documents through the metadata index — nothing is stored, so a reindex reproduces the graph exactly. Resolution stays inside one collection.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string Collection name
key (required) query string Document key, e.g. theme/style.css
direction query string in = what depends on this document, out = what it depends on. One of "in", "out", "both". Default "both".
depth query integer Hops to follow. Values above the maximum are clamped, not rejected. Default 1. Minimum 1. Maximum 3.
maxDegree query integer Maximum neighbours per node. A selector such as .title appears in nearly every template, so an unbounded walk returns the whole theme. Default 100. Minimum 1. Maximum 100.
lines query boolean Include the first line each edge's symbol appears on, both sides. Off by default: it is the only part of a traversal that reads document content. Default false.

Responses #

Status Description Body
200 The graph around the requested document CodeGraphResponse (application/json)
400 Missing collection/key, or an unknown direction
404 No such document in the collection

Code connection graph for one document (JSON body) #

POST /v1/code-graph

Identical to the GET form. Accepts a JSON body for keys containing characters awkward in a query string.

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: object

Property Type Description
collection (required) string
key (required) string
direction string One of "in", "out", "both". Default "both".
depth integer Default 1. Minimum 1. Maximum 3.
maxDegree integer Default 100. Minimum 1. Maximum 100.
lines boolean Include first-occurrence line numbers for each edge. Default false.
{
  "collection": "theme",
  "depth": 2,
  "direction": "in",
  "key": "theme/style.css"
}

Responses #

Status Description Body
200 The graph around the requested document CodeGraphResponse (application/json)
400 Missing collection/key, or an unknown direction
404 No such document in the collection

List metadata keys and values for a collection #

GET /v1/meta-keys

Returns all unique metadata keys and their unique values for a given collection. Useful for building filter UIs.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string Collection name

Responses #

Status Description Body
200 Metadata keys with their unique values object (application/json)
400 Missing collection parameter

Is what was just written searchable yet? #

GET /v1/indexing-status

Queued embedding and metadata work for one collection, or for the whole server without collection (GO-042, v2.18.8). Counters come from the queues, never from a scan. A write returns once its full text and metadata are indexed; its embedding follows from a background worker, so a semantic search sees the document only when pendingEmbeddings reaches 0. To wait for that inside a search, pass waitForIndex / waitForKeys; to be told, listen for the SSE event collection.indexed.

Also available as the get_indexing_status MCP tool, the GetIndexingStatus gRPC call and the GraphQL indexingStatus query.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection query string

Responses #

Status Description Body
200 Indexing status IndexingStatus (application/json)
403 Forbidden ErrorResponse (application/json)
405 Method not allowed

What retrieval saved over a window of days #

GET /v1/gain

Server-wide counts over a window of days (AGT-004, v2.18.8). They cover searches by type, algorithm and hybrid fusion, tokens returned, and tokens avoided. Tokens avoided are whole documents minus the passages or chunks returned instead. Counts only: no query text, keys or collection names. Kept per day in the database, so restarts do not reset them. Definitions are in docs/TELEMETRY.md. Also the get_gain MCP tool.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
window query string Days, as 7d or 7, from 1 to 365. Default "30d".
daily query boolean Add a per-day breakdown. Default false.

Responses #

Status Description Body
200 The report GainReport (application/json)
400 Invalid window ErrorResponse (application/json)
403 Forbidden ErrorResponse (application/json)
405 Method not allowed

Measure retrieval on an evaluation set #

POST /v1/eval

Runs the collection's evaluation set, or the inline queries, under up to 8 search configurations. For each configuration it returns recall@k, nDCG@k, MRR, p50/p99 latency and estimated returned tokens (SRCH-019, v2.18.8). Read-only. A configuration that fails carries error and does not stop the others. Also the run_eval MCP tool.

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: EvalRequest

{
  "collection": "string",
  "configs": [
    {
      "algorithm": "string",
      "alpha": 0,
      "bm25B": 0,
      "bm25K1": 0,
      "name": "string",
      "queryDecomposition": "off",
      "retrievalMode": "string",
      "searchType": "fts",
      "strategy": "string",
      "summaryMode": "off",
      "vectorAlgorithm": "string"
    }
  ],
  "details": false,
  "k": 10,
  "queries": [
    {
      "expectedKeys": [
        "string"
      ],
      "id": "string",
      "query": "string"
    }
  ]
}

Responses #

Status Description Body
200 Scores per configuration EvalResult (application/json)
400 No evaluation queries, an invalid query, or too many queries or configs ErrorResponse (application/json)
403 Forbidden ErrorResponse (application/json)
405 Method not allowed

List a collection's evaluation set #

GET /v1/eval-queries

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string

Responses #

Status Description Body
200 The stored queries object (application/json)
403 Forbidden ErrorResponse (application/json)

Add a query to the evaluation set #

POST /v1/eval-queries

Stores one query. An existing id is replaced, and a missing one is generated. The set lives in the collection config as evalSet, but PUT /v1/collection-config keeps it, so this is the only way to change it. At most 200 queries. Also the add_eval_query MCP tool.

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: allOf EvalQuery & object

{
  "expectedKeys": [
    "string"
  ],
  "id": "string",
  "query": "string"
}

Responses #

Status Description Body
200 The stored query, with its id EvalQuery (application/json)
400 Invalid query, or the set is full ErrorResponse (application/json)
403 Forbidden, or read-only mode ErrorResponse (application/json)

Remove a query from the evaluation set #

DELETE /v1/eval-queries

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string
id (required) query string

Responses #

Status Description Body
200 Whether a query was removed object (application/json)
403 Forbidden, or read-only mode ErrorResponse (application/json)

How should I search this collection? #

GET /v1/search-advisor

Measures a collection and recommends the search type, ranking algorithm, vector index, fusion weights and result shape — with a plain-language reason for every choice (SRCH-010).

Read-only by default. apply=true additionally writes the recommendation into the collection's retrieval profile, which needs write permission.

Also available as the search_advisor MCP tool, annotated read-only, so an agent can ask before it searches instead of guessing from algorithm names.

Authorization: BearerAuth or APIKeyAuth or none

Parameters #

Name In Type Description
collection (required) query string
apply query boolean Store the recommendation as the collection's retrieval profile. Default false.

Responses #

Status Description Body
200 The recommendation SearchRecommendation (application/json)
403 Forbidden, or read-only mode when apply=true ErrorResponse (application/json)

How should I search this collection? (body form) #

POST /v1/search-advisor

Authorization: BearerAuth or APIKeyAuth or none

Request body #

Required.

Content type application/json: object

Property Type Description
collection (required) string
apply boolean Default false.
{
  "apply": false,
  "collection": "string"
}

Responses #

Status Description Body
200 The recommendation SearchRecommendation (application/json)
400 The request is malformed (a body that is not JSON, a missing or invalid field, an unreadable body) or names a subsystem that is not initialized. The message says which. ErrorResponse (application/json)
401 Auth is on (MDDB_AUTH_ENABLED=true) and the request carries no credentials, an invalid or expired JWT, or an unknown API key. ErrorResponse (application/json)
403 The caller lacks the permission the route needs (SEC-019 access gate, auth on: read, write or admin on the collections the request names), or a write meets read-only mode (MDDB_MODE=read or the protocol's own mode). ErrorResponse (application/json)
413 The body is over MDDB_MAX_BODY_BYTES (32 MiB by default). ErrorResponse (application/json)
429 The client is over the API rate limit (MDDB_RATE_LIMIT_ENABLED=true, MDDB_RATE_LIMIT_REQUESTS per MDDB_RATE_LIMIT_WINDOW seconds). A call that embeds can also be refused by the collection's daily embedding budget, with a QuotaExceeded body. RateLimitError (application/json)

400 example (application/json)

{
  "error": "missing collection"
}

401 example (application/json)

{
  "error": "missing authentication"
}

403 example (application/json)

{
  "error": "forbidden"
}

413 example (application/json)

{
  "error": "request body too large"
}