# One MCP Server, Two AI Clients: Wiring Actian VectorAI DB Into Claude and Cursor

> Source: <https://dev.to/gerimate/one-mcp-server-two-ai-clients-wiring-actian-vectorai-db-into-claude-and-cursor-432j>
> Published: 2026-08-29 13:54:56+00:00

**MCP promises one server, any AI client. I put that to the test by wiring Actian VectorAI DB up to Claude and Cursor with a single ~230-line Python file, and verified every claim about it at the protocol layer rather than taking anything on faith. Build's public on GitHub.**

Every vector database has its own SDK. Every AI assistant has its own plugin format. Want Claude *and* Cursor to search your vector DB? That's normally two separate integrations, and a third tool next month makes three.

MCP removes that last part. It's an open protocol (originally from Anthropic) that lets any MCP-aware client (Claude Desktop, Claude Code, Cursor, whatever comes next) talk to the *same* server over a standard interface. Write the server once, every client gets it for free.

I built a small MCP server for **Actian VectorAI DB**, a portable, local-first vector database, to see if that promise holds up.

Six tools, ~230 lines of Python, one file:

| Tool | What it does |
|---|---|
`create_collection` |
Idempotently creates a 384-dim collection with a chosen distance metric |
`ingest_documents` |
Embeds text and upserts it, payload included |
`search` |
Embeds a query, returns top-k ranked hits |
`list_collections` |
Lists what's in the instance |
`get_collection_info` |
Point count, status, vector config |
`delete_collection` |
Deletes it, no confirmation step |

The one design decision I'd defend to the death: **the LLM never sees a vector.** Every tool's input and output is plain strings, lists, and JSON dicts. The embedding happens inside the server process (`sentence-transformers`

running `all-MiniLM-L6-v2`

locally on CPU), so Claude or Cursor only ever reasons about text and decides when to call `search`

. LLMs are bad at generating 384 floating point numbers that mean something; they're good at calling a function with a `query: str`

argument.

``` php
Claude / Cursor  <--stdio JSON-RPC-->  server.py (FastMCP)  <--gRPC-->  Actian VectorAI DB
                                              │
                                     sentence-transformers
                                     (local, 384-dim embeddings)
```

It's a reference implementation, sized for a stage: a single global DB, running locally, built around a demo-sized dataset (six sentences, for this build).

Before locking in `get_collection_info`

, I checked what the response looked like against the installed `actian-vectorai-client==1.0.2`

, rather than coding purely off memory. Point count and status come back directly from that call, but not vector config (size/distance), so `get_collection_info`

pulls those two things from two places: gRPC for point count and status, and the REST API (port 6573) for vector config.

First, `examples/demo.py`

running straight against the live DB, plain Python calling the SDK directly: created a collection, ingested 6 FAQ sentences, searched, and got the right result back.

Then `fastmcp.Client`

, to drive `server.py`

over stdio JSON-RPC, the same path Claude and Cursor use. This is what confirmed `get_collection_info`

was pulling the right data from both the gRPC and REST calls, something that only became visible once data flowed through the full protocol path.

I also pointed the server at a dead port on purpose, just to confirm every tool failed with a plain-English message instead of a stack trace.

At the OS process level, I confirmed Cursor itself had spawned the MCP server subprocess after reloading, proof the config was picked up and working.

And finally, calling `search`

through that MCP connection and getting back `{"text": "Submissions close Sunday at 9am."}`

for "submission deadline for the hackathon," score `0.4227`

.

Create a collection called `notes`

.

`Collection 'notes' is ready (distance=cosine, dim=384).`

Add these three facts to `notes`

: submissions close Sunday at 9am, first prize is $2,000, teams can have 2-5 members.

`Inserted 3 document(s) into collection 'notes'.`

What's the submission deadline?

`[{"score": 0.4777, "payload": {"text": "Submissions close Sunday at 9am."}}]`

, which the assistant turns into "the deadline is Sunday at 9am."

Then the point of the whole exercise: ask the same question in Cursor, switch windows, ask it again in Claude Desktop. Only the client-specific config block differs between the two.

I picked Actian VectorAI DB for being local-first, no cloud dependency, which mattered for a live demo on conference wifi. The Community Edition is free and was enough for this entire build. If you want to spin it up yourself, the [Docker setup instructions](https://docs.vectoraidb.actian.com/home/installation/instructions) cover both a plain `docker run`

and a `docker-compose.yml`

.

The bigger point, though: one small MCP server, any MCP client, natural language in, semantic search out, no vectors ever exposed to the model. If you've got an SDK and a thing worth calling from an LLM, this is basically the whole recipe. You can find the repo [here](https://github.com/gerimate/vectorai-mcp-server).
