MCP

Your datasets, callable by Claude.

Every Quorel dataset ships with a native MCP server. Claude — or any MCP-compatible agent — can list, query, filter, clean, and edit your data without you writing a script. Included on every plan.

How it connects

Quorel uses the MCP SSE transport. Your agent connects to a token-scoped SSE endpoint and receives tool definitions it can call in any order.

# SSE endpoint
https://quorel.vercel.app/mcp/{your_mcp_token}/

# Token in URL (recommended for Claude Desktop)
https://quorel.vercel.app/mcp/abc123def456.../

# Token as Bearer header (for programmatic clients)
GET https://quorel.vercel.app/mcp/{token}/
Authorization: Bearer abc123def456...

The token is scoped to your account. All nine tools operate on datasets you own — they cannot access other users' private datasets.

Getting a token

Generate your MCP token from the dashboard under Settings → MCP, or via the API below. Each account has one active token at a time. Generating a new one immediately invalidates the old one.

POST/mcp/token

Generate a new MCP token for the authenticated user. If a token already exists, it is replaced.

Auth: Session cookie (dashboard auth)

{ "ok": true, "token": "abc123...", "created_at": "2026-01-01T00:00:00Z" }
DELETE/mcp/token/revoke

Revoke the current MCP token. The SSE connection will reject any further requests using the old token.

Auth: Session cookie (dashboard auth)

{ "ok": true }
GET/mcp/token/view

Check whether a token exists and whether it is active.

Auth: Session cookie (dashboard auth)

{ "has_token": true, "token": "abc123...", "is_active": true, "last_used_at": "...", "created_at": "..." }

Connecting Claude Desktop

Add the following to your claude_desktop_config.json. Replace the token with the one from your dashboard.

{
  "mcpServers": {
    "vexaro": {
      "url": "https://quorel.vercel.app/mcp/your_mcp_token/"
    }
  }
}

Restart Claude Desktop after saving. The nine Quorel tools will appear in Claude's tool list automatically.

Tools

Nine tools are exposed. All require a valid MCP token. All are scoped to datasets you own.

list_datasets

List all datasets owned by the authenticated user.

returns An array of datasets with dataset_id, name, dataset_type, active_version, entity_count, and last_refresh.

get_dataset_schema

Get the field schema of a dataset. Call this before query_dataset to understand what fields are available for filtering and sorting.

Arguments

dataset_idnumberrequired

The dataset ID to inspect.

returns The dataset name, type, field list, field details with types and descriptions, entity count, versions, and include flags for links, images, and files.

query_dataset

Query a dataset with filters, keywords, sorting, and pagination. Supports all output formats. Each entity includes a _idx field (0-based position in the version file) for use with get_entity, update_entity, and delete_entity.

Arguments

dataset_idnumberrequired

The dataset ID to query.

versionstring

active (default), latest, or v1, v2 etc.

use_altboolean

Set true to query the alt version instead of the original.

formatstring

json (default), jsonl, csv, tsv, xml, parquet.

keywordsstring

Comma-separated keywords. Searched across all fields at every depth.

keywords_modestring

or (default) matches any keyword. and requires all.

filterstring

One or more exact field matches (AND logic). Comma-separated, dot-notation supported. Example: country:Germany or country:Germany,job_type:Remote.

filter_containsstring

One or more partial field matches (AND logic). Comma-separated, dot-notation supported. Example: title:engineer or title:engineer,location:berlin.

filter_rangestring

One or more range filters (AND logic). Comma-separated, format: field:op:value. Ops: gt, gte, lt, lte. Works on numbers and dates. Example: salary:gte:50000 or salary:gte:50000,salary:lte:100000.

keep_fieldstring

Comma-separated fields to keep. Dot-notation supported.

drop_fieldstring

Comma-separated fields to remove. Dot-notation supported.

sortstring

Sort by top-level field. Format: field:asc or field:desc.

limitnumber

Max number of results to return.

offsetnumber

Number of results to skip.

samplenumber

Return N randomly sampled results using cryptographically secure shuffling.

dedupboolean

Remove duplicate entities.

dedup_keystring

Comma-separated fields to use as the dedup key. Only meaningful when dedup is true.

denullboolean

Recursively strip null values and empty strings at all depths.

flattenboolean

Flatten nested objects and arrays into top-level dot-notation keys.

include_sourceboolean

Include the _source field. Default true.

countboolean

Return only the count of matching entities, not the entities themselves.

returns The matching entities in the requested format, or a count object if count is true. Each entity includes a _idx field.

get_entity

Fetch a single entity by its 0-based index (_idx) within a specific dataset version. The _idx is returned by query_dataset and pull_for_edit and is stable for the lifetime of that version file.

Arguments

dataset_idnumberrequired

The dataset ID.

idxnumberrequired

0-based index of the entity as returned by query_dataset or pull_for_edit.

versionstring

Version to read from: active (default), latest, or v1, v2 etc.

use_altboolean

Set true to read from the alt version.

returns An object with dataset_id, version, is_alt, idx, entity_count, and the entity itself (with _idx injected).

pull_for_edit

Pull the full unfiltered entity list from a dataset version for AI processing. Each entity includes a _idx field (0-based position in the file) for use with get_entity, update_entity, and delete_entity. Use push_alt_version to save processed results back.

Arguments

dataset_idnumberrequired

The dataset ID to pull from.

versionstring

active (default), latest, or v1, v2 etc.

use_altboolean

Set true to pull the existing alt version instead of the original.

returns An object with dataset_id, version, is_alt, entity_count, and the full entities array.

push_alt_version

Push AI-processed entities back as the alt version of a dataset version. Always writes to alt — never overwrites the original. The dataset must not be frozen or currently processing. Any _idx fields in the entities array are stripped before saving.

Arguments

dataset_idnumberrequired

The dataset ID to push to.

versionnumberrequired

The version number to attach the alt to.

entitiesstringrequired

A JSON array of processed entities to save as the alt version.

returns Confirmation with ok, dataset_id, version, entity_count, and the alt file path.

append_alt_version

Append a batch of processed entities to an existing alt version. If no alt exists yet, it is created automatically. Use this for batch processing — e.g. process 20 entities at a time and append each batch. Returns the running total after each call.

Arguments

dataset_idnumberrequired

The dataset ID to append to.

versionnumberrequired

The version number the alt belongs to.

entitiesstringrequired

A JSON array of processed entities to append.

returns Confirmation with ok, dataset_id, version, appended count, total_entities, and was_created (true if this call created the alt).

update_entity

Patch a single entity in the alt version by its 0-based index (_idx). Only works on alt versions — use pull_for_edit with use_alt:true or query_dataset with use_alt:true to get valid _idx values. Performs a shallow merge: provided fields overwrite existing ones, unmentioned fields are preserved.

Arguments

dataset_idnumberrequired

The dataset ID.

versionnumberrequired

The version number the alt belongs to.

idxnumberrequired

0-based index of the entity to update.

fieldsstringrequired

JSON object of fields to merge into the entity. Example: {"status":"reviewed","score":9.5}.

returns Confirmation with ok, dataset_id, version, idx, and the full updated entity.

delete_entity

Delete one or more entities from the alt version. Supports three modes: single (idx), multiple (indexes array), or range (idx_from + idx_to). Deletions are processed back-to-front so indexes remain stable within the batch. Out-of-range indexes are skipped and reported. Only works on alt versions. WARNING: after deletion all entities after any removed one shift down — do not reuse _idx values from before this call.

Arguments

dataset_idnumberrequired

The dataset ID.

versionnumberrequired

The version number the alt belongs to.

idxnumber

0-based index of a single entity to delete.

indexesstring

JSON array of 0-based indexes to delete. Example: [2, 5, 11]. Takes priority over idx.

idx_fromnumber

Start of an index range to delete (inclusive). Must be used together with idx_to.

idx_tonumber

End of an index range to delete (inclusive). Must be used together with idx_from.

returns Confirmation with ok, dataset_id, version, deleted_count, deleted_indexes, remaining_entities, and a warning that indices have shifted. If any indexes were out of range, skipped_indexes and skipped_count are also returned.

Recommended workflow

The nine tools form a natural pipeline. You don't have to use all of them — query_dataset alone covers most use cases.

01

list_datasets

Start by listing your datasets to find the dataset_id you want to work with.

02

get_dataset_schema

Inspect the schema to understand which fields are available before writing filters or sort expressions.

03

query_dataset

Query with keywords, filters, range filters, and sorting to get the slice you need. Use count=true first to check how many entities match before fetching them all. Each result includes a _idx for targeted edits.

04

get_entity / update_entity / delete_entity

Make targeted changes to individual entities in the alt version using the _idx returned by query_dataset or pull_for_edit. update_entity does a shallow merge. delete_entity supports single (idx), multiple (indexes), or range (idx_from + idx_to) deletion — all processed back-to-front to keep indexes stable within the batch. Indices shift after any deletion, so re-query before reusing _idx values.

05

pull_for_edit

Pull the full unfiltered entity list when you want Claude to clean, deduplicate, enrich, or restructure the entire dataset in one pass.

06

push_alt_version / append_alt_version

Push the processed entities back as the alt version. Use push_alt_version to replace the alt wholesale, or append_alt_version to build it up in batches. The original is never touched.

Example session

A Claude session that queries a remote jobs dataset, makes targeted edits, then cleans and publishes an alt version.

> list_datasets()
→ 3 datasets found
  id=12  remote-jobs       847 entities  v14
  id=7   yc-companies      412 entities  v6
  id=3   arxiv-ai-papers   1,204 entities v22

> get_dataset_schema(dataset_id: 12)
→ fields: title, company, salary, stack, location, type, _source

> query_dataset(
    dataset_id: 12,
    keywords: "React,TypeScript",
    keywords_mode: "and",
    filter_range: "salary:gte:80000",
    sort: "salary:desc",
    limit: 10,
    drop_field: "_source"
  )
→ 10 entities returned, each with _idx

> get_entity(dataset_id: 12, idx: 4)
→ single entity at position 4

> update_entity(
    dataset_id: 12,
    version: 14,
    idx: 4,
    fields: "{"status":"reviewed","score":9.2}"
  )
→ entity 4 patched in alt

> delete_entity(dataset_id: 12, version: 14, idx: 7)
→ { "deleted_count": 1, "deleted_indexes": [7], "remaining_entities": 846 }
  warning: indices have shifted

> delete_entity(
    dataset_id: 12,
    version: 14,
    indexes: "[3, 9, 21]"
  )
→ { "deleted_count": 3, "deleted_indexes": [3, 9, 21], "remaining_entities": 843 }
  warning: indices have shifted

> delete_entity(
    dataset_id: 12,
    version: 14,
    idx_from: 20,
    idx_to: 35
  )
→ { "deleted_count": 16, "deleted_indexes": [20,21,...,35], "remaining_entities": 827 }
  warning: indices have shifted

> query_dataset(dataset_id: 12, count: true)
→ { "count": 827 }

> pull_for_edit(dataset_id: 12, version: "active")
→ 827 entities pulled

  Claude deduplicates on title+company,
  fills missing salary fields from context,
  removes 12 listings with no stack specified.
  Processes in batches of 50 using append_alt_version.

> append_alt_version(
    dataset_id: 12,
    version: 14,
    entities: "[...batch 1 of 50...]"
  )
→ { "ok": true, "appended": 50, "total_entities": 50, "was_created": true }

> append_alt_version(
    dataset_id: 12,
    version: 14,
    entities: "[...batch 2 of 50...]"
  )
→ { "ok": true, "appended": 50, "total_entities": 100, "was_created": false }

  ... repeat until done ...

> push_alt_version(
    dataset_id: 12,
    version: 14,
    entities: "[full final array]"
  )
→ { "ok": true, "entity_count": 791, "version": 14 }
  live at /api/12/remote-jobs/v14/?alt=true

Alt versions and safety

push_alt_version and append_alt_version never touch the original version. They write a separate file and record it as the alt path for that version in the database. Two things will block a push:

Dataset is frozen

Frozen datasets are permanently locked. Clone the dataset first if you want to push an alt.

Dataset is currently processing

If a refresh is in progress, the push is rejected. Wait for the refresh to complete, then retry.

Once pushed, the alt is accessible via the REST API at ?alt=true or /vN/alt/ and is versioned alongside the original.

Understanding _idx

Every entity returned by query_dataset and pull_for_edit includes a _idx field. This is the 0-based position of the entity in the raw version file — it is injected at read time and never stored. Three things to know:

Stable within a version

_idx is stable for the lifetime of a version file. It does not change between queries as long as no delete_entity call has been made.

Shifts after delete_entity

Deleting entities causes all entities after the removed positions to shift down. Re-query before using _idx values again after any deletion.

Stripped on save

_idx is never written to disk. push_alt_version, append_alt_version, and saveAltFile all strip it before persisting.

Next steps