MCP server + CLI · for cob-rag-engine · MIT

Your business's knowledge, in every agent.

cob-rag-mcp is an MCP server and a full CLI for cob-rag-engine, the self-hosted knowledge layer for AI assistants and agents. Plug a business's own knowledge base into Claude, Cursor, VS Code, n8n or any MCP client, or work with it straight from the shell. One set of 52 tools, two ways in.

# run the MCP server, nothing to install
npx -y cob-rag-mcp start

# or install both commands, then sign in
npm i -g cob-rag-mcp
cob-rag-engine login --url http://127.0.0.1:8000 --key ck_...
  • Node.js 22+
  • stdio and streamable HTTP
  • Scoped by the key you hand it
  • You host the engine
# a first search: passages with sources, no model needed
cob-rag-engine search "How long should I fast before a cholesterol test?" --final-k 3
[1] Fasting before a lipid profile [faq-fasting-lipid]  (score 0.066)
    For a lipid profile (cholesterol test) fast for 10 to 12 hours
    before your sample is taken. ...
Who it's for

Agents over MCP. People in the shell.

An agent is only as useful as what it knows about the business it works for: the returns policy, the price list, which tests need fasting. cob-rag-engine holds that knowledge, one isolated knowledge base (a corpus) per business. This package puts it where agents and people work.

MCP server · cob-rag-mcp start

In any MCP client

Claude, Cursor, VS Code, n8n, any client that speaks MCP.

  • The agent calls search to pull the right passages, with sources, and answers from them with its own model.
  • Or it calls ask for a complete cited answer written by the model configured in your engine.
  • Destructive tools are hidden unless you allow them with COB_RAG_ALLOW_DESTRUCTIVE=true.
Shell CLI · cob-rag-engine

In the shell

You, scripts, CI, an agent's own terminal.

  • search "...", ingest records, corpora create, usage: every tool is also a command.
  • Readable tables by default, --json for scripts.
  • Destructive commands ask first, or need --yes.
CLI (cob-rag-engine)MCP server (cob-rag-mcp start)
Who it is forYou, scripts, CI, an agent's own terminalClaude, Cursor, VS Code, n8n, any MCP client
OutputTables; --json for machinesJSON tool results
Destructive actionsAsks first, or --yesHidden unless COB_RAG_ALLOW_DESTRUCTIVE=true
Transportsn/astdio (default) and streamable HTTP
Setup

You host the engine. No hosted service, ever.

cob-rag-mcp is only a client. It talks to a cob-rag-engine that you run yourself, on your laptop, your server or your cloud, using the URL and key you give it. Nothing is sent anywhere else.

  1. Run the engine

    One docker compose up. Start with the engine's quick start, then come back. New to it? The engine's site has the overview.

  2. Get a key

    The admin key (RAG_ADMIN_API_KEY in the engine's .env), a tenant key (tk_...) or a corpus key (ck_...). Which one?

  3. Install

    npx -y cob-rag-mcp start with nothing installed, or npm i -g cob-rag-mcp for both commands. Needs Node.js 22 or newer.

  4. Point it at the engine

    Set COB_RAG_URL and COB_RAG_API_KEY, or save them once with cob-rag-engine login.

For ask, a model must be configured in the engine (engine default, per corpus, or per request with your own key). search needs no model at all.

SettingEnvironment variableFlagDefault
Engine URLCOB_RAG_URL--urlhttp://127.0.0.1:8000
Engine key (admin, tk_ or ck_)COB_RAG_API_KEY--keynone
Default corpus for tenant and admin keysCOB_RAG_CORPUS_ID--corpus-id per commandnone
Offer destructive tools over MCPCOB_RAG_ALLOW_DESTRUCTIVE--allow-destructivefalse
Hide or refuse every writeCOB_RAG_READ_ONLY--read-onlyfalse
The only directory MCP upload_file may readCOB_RAG_UPLOAD_DIRnone (upload off)
HTTP mode: let keyless requests use the server keyCOB_RAG_HTTP_USE_SERVER_KEYfalse
Config file locationCOB_RAG_CONFIG--configsee the README

Priority: command-line flags, then environment variables, then your config file, then defaults. Bring your own model key with COB_RAG_LLM_PROVIDER, COB_RAG_LLM_MODEL, COB_RAG_LLM_API_KEY and COB_RAG_LLM_BASE_URL; they are sent as X-LLM-* headers on search and ask only. The README has the full list.

Install and connect

Every snippet runs stdio with a corpus key.

Swap in a tenant or admin key to manage corpora; the tool list follows the key. Already ran cob-rag-engine login? Then the env block is optional: the server reads the saved config.

Claude Code

terminal
claude mcp add cob-rag \
  -e COB_RAG_URL=http://127.0.0.1:8000 \
  -e COB_RAG_API_KEY=ck_your_corpus_key \
  -- npx -y cob-rag-mcp start

Already logged in? claude mcp add cob-rag -- npx -y cob-rag-mcp start is enough.

Claude Desktop

claude_desktop_config.json
{
  "mcpServers": {
    "cob-rag": {
      "command": "npx",
      "args": ["-y", "cob-rag-mcp", "start"],
      "env": {
        "COB_RAG_URL": "http://127.0.0.1:8000",
        "COB_RAG_API_KEY": "ck_your_corpus_key"
      }
    }
  }
}

macOS: ~/Library/Application Support/Claude/. Windows: %APPDATA%\Claude\. Restart Claude Desktop afterwards.

Claude Desktop on Windows

when npx is not found
{
  "mcpServers": {
    "cob-rag": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "cob-rag-mcp", "start"],
      "env": {
        "COB_RAG_URL": "http://127.0.0.1:8000",
        "COB_RAG_API_KEY": "ck_your_corpus_key"
      }
    }
  }
}

The cmd /c variant. Or install globally and use cob-rag-mcp as the command. Use 127.0.0.1, not localhost: on Windows it can resolve to IPv6 ::1, which Docker Desktop may not forward.

Cursor

~/.cursor/mcp.json or .cursor/mcp.json
{
  "mcpServers": {
    "cob-rag": {
      "command": "npx",
      "args": ["-y", "cob-rag-mcp", "start"],
      "env": {
        "COB_RAG_URL": "http://127.0.0.1:8000",
        "COB_RAG_API_KEY": "ck_your_corpus_key"
      }
    }
  }
}

The first path covers all projects, the second one project.

VS Code

.vscode/mcp.json
{
  "inputs": [
    { "type": "promptString", "id": "cob-rag-key", "description": "cob-rag-engine key", "password": true }
  ],
  "servers": {
    "cob-rag": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "cob-rag-mcp", "start"],
      "env": {
        "COB_RAG_URL": "http://127.0.0.1:8000",
        "COB_RAG_API_KEY": "${input:cob-rag-key}"
      }
    }
  }
}

The inputs block makes VS Code ask for the key once and store it securely, so it never sits in the file.

n8n and anything that speaks HTTP

streamable HTTP
cob-rag-mcp start --transport http --host 127.0.0.1 --port 3333
# MCP over HTTP at http://127.0.0.1:3333/mcp

# Claude Code over HTTP
claude mcp add --transport http cob-rag http://127.0.0.1:3333/mcp \
  --header "Authorization: Bearer ck_..."

n8n: add an MCP Client Tool node, endpoint http://127.0.0.1:3333/mcp, transport HTTP Streamable, authentication Bearer, token = the corpus key. Health check: GET /health answers {"status":"ok"} without a key.

HTTP mode, the rules

Every request

Carries the caller's own engine key, as Authorization: Bearer <key> or X-API-Key: <key>. A request without a key gets 401, unless you set COB_RAG_HTTP_USE_SERVER_KEY=true on purpose.

Stateless

One fresh MCP server per request, so it scales horizontally and needs no sticky sessions. Callers may send their own X-LLM-* headers; the server's model key is never spent on a caller's behalf.

Bind

Binds 127.0.0.1 by default and, on loopback, refuses requests whose Host or Origin is not local. Bind wider and put TLS in front: keys travel in headers.

Docker

HTTP mode
docker build -t cob-rag-mcp .
docker run --rm -p 127.0.0.1:3333:3333 \
  -e COB_RAG_URL=http://host.docker.internal:8000 \
  cob-rag-mcp

The engine URL must be reachable from the container: host.docker.internal for an engine on the host, or the engine's service name on a shared Docker network.

Any other stdio client

Command npx, arguments -y cob-rag-mcp start, plus the COB_RAG_* environment variables. With a global install, the command is simply cob-rag-mcp start.

If a client shows the server as failed, run npx -y cob-rag-mcp start in a terminal with the same environment: the reason is printed on stderr.

The tools

52 tools, only the ones your key can use.

Each tool is one definition that is both an MCP tool and a CLI command. The server registers only the tools the key can use, and hides destructive ones unless allowed. With a tenant or admin key, tools that act on one corpus need a corpus_id (or a COB_RAG_CORPUS_ID default); a corpus key never sees that field.

Identity

identity.ts

Who the key is, and what the engine offers.

  • whoami

    Which kind of key this is and what it reaches

    CLI: whoami · keys: any key
  • get_engine_info

    Engine version, features, embedding and LLM models, limits (no secrets)

    CLI: info · keys: any key

Search and answer

query.ts

Passages with sources, or a cited answer.

  • search

    Relevant passages with sources, no generation

    CLI: search · keys: any key
  • ask

    A cited answer from the engine's model

    CLI: ask · keys: any key

Documents

documents.ts
  • list_documents

    Documents, with record ids and metadata; search by file name or record id; paged

    CLI: documents list · keys: any key
  • get_document

    One document, its versions and its indexed chunks, paged

    CLI: documents get · keys: any key
  • list_document_versions

    Versions of one document

    CLI: documents versions · keys: any key
  • delete_documentdestructive

    Delete a document, its versions and vectors

    CLI: documents delete · keys: any key

Ingest

ingest.ts
  • add_recordswrite

    Add or update up to 1000 text records

    CLI: ingest records · keys: any key
  • upload_filewrite

    Upload a local file; MCP: stdio only, inside COB_RAG_UPLOAD_DIR

    CLI: ingest upload · keys: any key
  • get_ingest_job

    One ingest job: status, corpus, file, mode, and the documents a held upload resembles

    CLI: ingest job · keys: any key
  • list_ingest_jobs

    Ingest jobs in scope; filter by status and corpus_id; paged

    CLI: ingest jobs · keys: any key

Usage and feedback

usage.ts, feedback.ts
  • get_usage

    Requests, tokens and estimated cost, by day, corpus, tenant or source

    CLI: usage · keys: any key
  • list_feedback

    Ratings of answers with their questions; filter by corpus, rating, time; paged

    CLI: feedback list · keys: any key

Settings

settings.ts

A corpus's settings, and the engine's own.

  • get_corpus_settings

    A corpus's model, prompt and retrieval settings

    CLI: settings get · keys: any key
  • update_corpus_settingswrite

    Change prompt and retrieval settings; null clears one

    CLI: settings update · keys: any key
  • get_assistant

    The knowledge base's assistant: on or off, the published configuration and the draft

    CLI: assistant get · keys: any key
  • update_assistant_draftwrite

    Change the assistant's draft with a JSON merge patch; nothing goes live until it is published

    CLI: assistant draft · keys: any key
  • publish_assistantwrite

    Make the draft live on every channel; earlier versions stay restorable

    CLI: assistant publish · keys: any key
  • get_settings

    Sign-up mode (open, approval, closed) and white-label branding, with who changed them last

    CLI: engine settings · keys: admin only
  • update_settingswrite

    Change the sign-up mode and/or branding; null resets a field

    CLI: engine update-settings · keys: admin only

Knowledge bases

corpora.ts, migrations.ts

A knowledge base is a corpus.

  • list_corpora

    Corpora in scope with owner, document and chunk counts, last activity; paged, or all

    CLI: corpora list · keys: tenant or admin
  • get_corpus

    One corpus with its settings

    CLI: corpora get · keys: tenant or admin
  • create_corpuswrite

    New corpus, optionally with its embedding model; returns its ck_ key once

    CLI: corpora create · keys: tenant or admin
  • update_corpuswrite

    Name, model, prompt, retrieval, embedding settings; admin can move it to another tenant

    CLI: corpora update · keys: tenant or admin
  • rotate_corpus_keydestructive

    New ck_ key; the old one stops working

    CLI: corpora rotate-key · keys: tenant or admin
  • delete_corpusdestructive

    Delete a corpus and everything in it

    CLI: corpora delete · keys: tenant or admin
  • list_migrations

    Embedding migrations across corpora (pending_approval ones included); paged

    CLI: migrations list · keys: tenant or admin

Widget keys

widget-keys.ts

Publishable keys for a corpus's website widget.

  • list_widget_keys

    Website widget keys (pk_)

    CLI: widget-keys list · keys: any key
  • create_widget_keywrite

    New widget key and embed snippet

    CLI: widget-keys create · keys: any key
  • revoke_widget_keydestructive

    Delete a widget key

    CLI: widget-keys revoke · keys: any key

Tenants and plans

tenants.ts, plans.ts

Who the customers are, and what they may use.

  • get_my_tenant

    This tenant key's own tenant: name, status, corpus count and limit

    CLI: tenants me · keys: tenant only
  • rotate_my_tenant_keydestructive

    New tk_ key for the key making the call; it stops working at once

    CLI: tenants rotate-my-key · keys: tenant only
  • list_tenants

    Tenants with status (pending sign-ups, active, suspended) and owners; paged

    CLI: tenants list · keys: admin only
  • create_tenantwrite

    New active tenant, optionally on a plan with its own knowledge-base limit; returns its tk_ key once

    CLI: tenants create · keys: admin only
  • rotate_tenant_keydestructive

    New tk_ key; the old one stops working

    CLI: tenants rotate-key · keys: admin only
  • activate_tenantwrite

    Activate a pending sign-up (optional plan_id and note)

    CLI: tenants activate · keys: admin only
  • suspend_tenantdestructive

    Every key, widget and sign-in of the tenant stops (data kept); needs confirm_name

    CLI: tenants suspend · keys: admin only
  • reactivate_tenantwrite

    Undo a suspension

    CLI: tenants reactivate · keys: admin only
  • decline_tenantdestructive

    Remove a pending sign-up and its account; the owner gets a polite e-mail

    CLI: tenants decline · keys: admin only
  • delete_tenantdestructive

    Delete a tenant and everything it owns; needs confirm_name

    CLI: tenants delete · keys: admin only
  • list_plans

    Plans with their four limits and how many tenants use each

    CLI: plans list · keys: admin only
  • set_tenant_planwrite

    Move a tenant to another active plan

    CLI: plans set · keys: admin only
  • get_my_plan

    A tenant's plan, limits and usage: questions this month (and when they reset), knowledge bases, documents, widget keys

    CLI: plans usage · keys: tenant or admin

Team

team.ts

A tenant's owners and members.

  • list_team

    A tenant's owners and members (last sign-in) and open invitations

    CLI: team list · keys: tenant or admin
  • invite_memberwrite

    Invite someone as owner or member; the engine e-mails the link (never returned)

    CLI: team invite · keys: tenant only
  • admin_invitewrite

    Invite someone to any tenant, typically its first owner; returns accept_url, the link to send them

    CLI: team admin-invite · keys: admin only

Tool annotations match: readOnlyHint on reads, destructiveHint on destructive tools, openWorldHint: false everywhere, because every call goes to your own engine. --read-only leaves only the read tools. One prompt is included, answer-with-citations: search first, answer only from the passages, cite each source. Request and response shapes are typed from the engine's OpenAPI spec, so the tools cannot drift from the API. cob-rag-engine tools prints every tool and which keys can use it.

The CLI

The same tools, from the shell.

cob-rag-engine <command> [options]. Global options: --url, --key, --config, --json, --yes, --read-only. Every command has --help. Exit codes: 0 success, 1 engine or configuration error, 2 invalid input.

Sign in, check the key

cob-rag-engine login --url http://127.0.0.1:8000 --key ck_...
# Logged in to http://127.0.0.1:8000 with ck_****a1b2
# kind         corpus
# corpus_name  acme-faq
cob-rag-engine whoami
cob-rag-engine config show          # every setting, its source, secrets masked
cob-rag-engine config get api_key   # ck_****a1b2
cob-rag-engine config set corpus_id 7b221003-...
cob-rag-engine config path

login checks the key with the engine's /api/v1/whoami before saving anything, and writes the config file owner-only (0600). Leave --key out at a terminal and it prompts without echoing.

Search and ask

cob-rag-engine search "How long should I fast before a cholesterol test?" --final-k 3
# [1] Fasting before a lipid profile [faq-fasting-lipid]  (score 0.066)

cob-rag-engine ask "Do I need to fast for a thyroid test?"
# No, you do not need to fast for a thyroid test. ... [1]
#
# Sources:
#   [1] Thyroid test (TSH, T3, T4) [faq-thyroid]

cob-rag-engine ask "..." --stream          # prints as it is generated
cob-rag-engine ask "..." --stream --json   # raw events, one JSON object per line

search returns passages with sources and needs no model. ask returns a cited answer from the engine's model. Streaming is a CLI feature: an MCP tool call returns one result.

Add knowledge

# FAQ entries, products or articles (JSON array or JSON lines), wait until indexed
cob-rag-engine ingest records --records @faq.json --wait
cob-rag-engine ingest upload ./price-list.pdf --wait
cob-rag-engine ingest jobs --status pending_review
cob-rag-engine ingest job <job id>

cob-rag-engine documents list --search price
cob-rag-engine documents get <document id> --chunk-limit 5

ingest records adds or updates up to 1000 text records. A held upload lists the documents it resembles.

Usage, feedback, settings

cob-rag-engine usage --group-by source --start 2026-09-01
cob-rag-engine feedback list --max-rating 2 --start 2026-09-01
cob-rag-engine settings update --retrieval-config '{"final_k": 8}'
cob-rag-engine settings update --retrieval-config '{"final_k": null}'  # back to the default
cob-rag-engine info                # engine version, features, models, limits
cob-rag-engine tools               # every tool and which keys can use it
cob-rag-engine documents list --json | jq '.items[].id'

Updates change only what you send. A field set to null is removed so the engine default applies again.

Tenant or admin key

cob-rag-engine corpora create "pune-path-lab" --description "Test prep FAQ"
cob-rag-engine corpora create "pune-path-lab" --tenant-id <tenant id>   # admin names the tenant
cob-rag-engine corpora list --all
cob-rag-engine widget-keys create "Lab website" --corpus-id <id> \
  --allowed-origins https://lab.example
cob-rag-engine migrations list --status pending_approval
cob-rag-engine corpora delete <id>     # asks first; --yes to skip

Lists are paged by the engine. Under each table the CLI says which items these are and the option that gets the next page.

The admin key

plans, a customer's first owner, settings
cob-rag-engine plans list
cob-rag-engine tenants activate <tenant id> --plan-id <plan id> --note "paid via UPI"
cob-rag-engine team admin-invite <tenant id> owner@shree.example
cob-rag-engine plans usage --tenant-id <tenant id>
cob-rag-engine engine update-settings --signup-mode approval \
  --branding '{"product_name": "Sahayak AI"}'

team admin-invite prints the link to send the customer's first owner.

A tenant key

its own record, plan and team, and a new key for itself
cob-rag-engine plans usage                 # questions this month, and when they reset
cob-rag-engine team list
cob-rag-engine team invite ravi@shree.example --role member
cob-rag-engine tenants me
cob-rag-engine tenants rotate-my-key      # warns, asks, then offers to save the new key
cob-rag-engine tenants rotate-my-key --yes --save-key   # scripts: rotate and save in one go

tenants rotate-my-key replaces the very key the CLI is using, and the old key fails on its next request. The CLI says so before asking.

Keys

The key decides the reach. Give an agent the narrowest one.

The server asks the engine who the key is and offers only the tools that key can use. The engine enforces scope on every request; this package also hides what a key cannot use, so an agent is not tempted to try.

KeyPrefixWhat it reachesGive it to an agent?
Corpus keyck_One knowledge base and nothing else: search, ask, documents, ingest, settings, usage, feedback, widget keys.Yes, this is the default. A corpus key for one knowledge base.
Tenant keytk_Manages that tenant's corpora, its team, its own plan and record. Can rotate its own key.Only when the agent must create or manage corpora.
Admin keyRAG_ADMIN_API_KEYRuns the engine: tenants, plans, sign-up mode and branding, every corpus.Almost never.
Rule of thumb

Start with ck_

Hand the agent the corpus key for the one knowledge base it works on, add --read-only if it should only look things up, and leave destructive tools off.

Shown once

Store keys when you see them

create_corpus, create_tenant and every rotate_* return the new key in the tool result, because that is the only time the engine reveals it.

Widget keys

pk_ is a different thing

Widget keys (list_widget_keys, create_widget_key, revoke_widget_key) are for a corpus's website widget, and come with an embed snippet.

Security

Safe defaults, so an agent can't do much harm.

From the README and SECURITY.md.

  • Keys stay on your machineThey go to your engine and nowhere else. The config file is owner-only; config show, login and every log line mask keys (ck_****a1b2).
  • Destructive tools are off over MCPDeleting documents or corpora, revoking widget keys, rotating keys and suspending, declining or deleting tenants appear only with COB_RAG_ALLOW_DESTRUCTIVE=true. The CLI asks before each one, and refuses when it cannot ask unless you pass --yes.
  • Read-only mode--read-only or COB_RAG_READ_ONLY=true hides every write tool from MCP clients and makes the CLI refuse every write.
  • Uploads over MCP are fencedupload_file exists over MCP only on stdio and only when COB_RAG_UPLOAD_DIR is set. Paths are resolved, symlinks included, and anything outside that directory is refused, so a prompt-injected agent cannot ship your SSH keys into a knowledge base. Use a dedicated folder, never your home directory.
  • HTTP mode never lends a keyEach request brings its own. Keep the default 127.0.0.1 bind, or put TLS and a firewall in front of it. Leave COB_RAG_HTTP_USE_SERVER_KEY off unless every client that can reach the port should act with that key.
  • rotate_my_tenant_key cuts off the key in useThe server's own key is dead the moment it succeeds; restart it with the new key. The CLI warns first and offers to save the new key.
  • Never commit keysPrefer cob-rag-engine login, which prompts without echo, or your MCP client's secret inputs, over pasting keys into files.
  • Report vulnerabilities privatelyDo not open a public issue. Use GitHub Private Vulnerability Reporting or callobuzz@gmail.com; expect a first response within 48 hours. Engine vulnerabilities go to cob-rag-engine.