Skip to main content
Glama
README.md
# gengomcp

An [MCP](https://modelcontextprotocol.io/) server (Python, stdio transport) that
lets an agent retrieve ACL conference papers about NLP from a [Qdrant](https://qdrant.tech/) vector
database. It combines **semantic search** (Sentence‑Transformers embeddings)
with **structured filtering** by bibliographic fields like publication year and
venue.

> **Qdrant access is currently limited.** This server queries a shared Qdrant
> collection of ACL NLP papers. If you'd like credentials to use it, please
> reach out to the project maintainer — access may be granted at a limited
> scale. You'll receive a `QDRANT_URL`, `QDRANT_KEY`, and
> `QDRANT_COLLECTION_NAME` to set in your MCP client's `env` field.

## Quick start

1. **Install** `gengomcp` from PyPI:

   ```bash
   pip install gengomcp
   ```

2. **Configure credentials** in your MCP client's `env` field. You'll need
   `QDRANT_URL`, `QDRANT_KEY`, and `QDRANT_COLLECTION_NAME` — see
   [Wiring it into an MCP client](#wiring-it-into-an-mcp-client) for full config
   examples.

3. **Use it.** Your agent can now call `search_papers`, `get_paper`,
   `list_papers`, and `get_collection_info` to find ACL NLP conference papers.

### Wiring it into an MCP client

Any MCP client over **stdio** works. When installed from PyPI (`pip install
gengomcp` or `uv tool install gengomcp`), the `gengomcp` command is on your
PATH and runs independently of your working directory, so it's safe to launch
from anywhere.

Example for Claude Desktop (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "gengomcp": {
      "command": "gengomcp",
      "args": []
    }
  }
}
```

#### Configuring credentials via the MCP client

Credentials (`QDRANT_URL`, `QDRANT_KEY`, `QDRANT_COLLECTION_NAME`) are read from
the process environment. Inject them **directly through your MCP client's `env`
field** — this is the recommended way to configure per-agent credentials:

```json
{
  "mcpServers": {
    "gengomcp": {
      "command": "gengomcp",
      "args": [],
      "env": {
        "QDRANT_URL": "https://<cluster>.cloud.qdrant.io",
        "QDRANT_KEY": "<your-api-key>",
        "QDRANT_COLLECTION_NAME": "papers_test"
      }
    }
  }
}
```

> Credentials come from the MCP client's `env` field and are **never logged or
> hard-coded**. They live only on your machine — they are not sent to any
> third-party service.

Required variables (no defaults):

| Variable | Description |
| --- | --- |
| `QDRANT_URL` | Qdrant cluster URL |
| `QDRANT_KEY` | Qdrant API key |
| `QDRANT_COLLECTION_NAME` | Collection to search (e.g. `papers_test`) |

Optional variables (have defaults; not needed for basic use):
`EMBEDDING_MODEL`, `AUTO_CREATE_INDEXES`, `LOG_LEVEL`.

If a required variable is missing at startup, the server exits with a clear error
explaining how to set it.

#### Poolside (`pool`)

The server is registered to use the PyPI-installed `gengomcp` command with
credentials injected via the `env` field. Verify with:

```bash
pool mcp list          # shows: gengomcp
pool mcp get gengomcp  # shows the stored command + args + env vars
```

The config is stored under `mcp_servers` in `~/.config/poolside/settings.yaml`
(personal config). Credentials are passed via the `env` field and live only on
your machine — they are never sent to Poolside's servers. To remove the server
later:

```bash
pool mcp remove gengomcp
```

## Tools

| Tool | Purpose |
| --- | --- |
| `search_papers` | **Semantic search for ACL NLP papers.** USE when the user has a topic/question. Embeds `query` and returns the most similar papers, optionally narrowed by structured filters. |
| `get_paper` | USE to inspect a single ACL NLP paper in full detail (abstract, summaries, entities) when you already have its `paper_uuid` from a search result. |
| `list_papers` | USE to **browse/filter ACL NLP papers with no query text** — pure structured filtering + pagination (e.g. "all ACL 2024 papers"). |
| `get_collection_info` | USE first to discover available venues, years, fields of study, and vector names before building filters. |

### `search_papers` parameters

```
query                 str   (required) search text
limit                 int   = 10   (clamped 1..100)
vector_name           str   = "overview"   one of overview/approach/challenge/outcome
year                  int            exact publication year (e.g. 2026)
year_min / year_max   int            year range (inclusive)
year_gt  / year_lt    int            year range (exclusive)
venue                 str            substring match on the booktitle (e.g. "Annual Meeting")
collection_acronym    str            exact venue acronym, e.g. "ACL" / "EMNLP" / "NAACL"
collection_id         str            e.g. "2026.acl"
field_of_study        list[str]      membership on `field_of_studies` (e.g. ["Reasoning"])
author                str            name contained in `author_names`
min_score             float          only return results with similarity >= this value
```

All filters are AND‑combined, so you can layer them, e.g.
`search_papers(query="...", year_min=2020, collection_acronym="ACL")`.

### Example tool calls

```
search_papers(query="stress testing large language models",
              vector_name="overview", year_min=2024, year_max=2026,
              collection_acronym="ACL", limit=5)

get_paper(paper_id="000036a6-e2be-523e-8b8d-0f2cbe2b39e7")

list_papers(collection_acronym="EMNLP", year=2024, limit=20)

list_papers(field_of_study=["Reasoning"], author="Pan", limit=20, offset=<prev_uuid>)
```

## How it works

* **Secrets & config** — credentials are set via your MCP client's `env` field
  (`QDRANT_URL`, `QDRANT_KEY`, `QDRANT_COLLECTION_NAME`). `QDRANT_KEY` is
  passed directly to the Qdrant client and is never printed or hard-coded.
* **Payload indexes** — Qdrant **requires** a payload index to filter on a
  field. This collection ships with no indexes, so the server creates the needed
  ones **idempotently at startup** (non-destructive — it only adds indexes).
  Disable with `AUTO_CREATE_INDEXES=0` if you manage indexes yourself.
* **Embeddings** — queries are embedded with Sentence‑Transformers using
  `Snowflake/snowflake-arctic-embed-s`, the **only** model that matches this
  collection's 384-dimensional index. The server can truncate+renormalise other
  model outputs to the index dimensionality (matryoshka‑style) as a safety net,
  but models in a different embedding space (e.g. the 768-dim `m-v1.5`) will
  still fail to retrieve — see [The embedding model](#the-embedding-model).
* **Named vectors** — the `overview`/`approach`/`challenge`/`outcome` named
  vectors in the collection are all **384-dimensional**.

### The embedding model

The collection's vectors are **384-dimensional** and were built with the
**Snowflake arctic-embed "s" model** (`Snowflake/snowflake-arctic-embed-s`).
This is the **only** model that produces embeddings in the correct space for
this index — it is the default and **should not be changed**.

Other models in the Snowflake family (e.g. `m-v1.5` at 768-dim or `l-v1.5` at
1024-dim) live in **different embedding spaces**. Even though the server can
truncate embeddings to the index dimensionality (matryoshka-style) as a safety
net, those models will **not** retrieve against this collection — keep
`EMBEDDING_MODEL` at its default unless you re-index with a different model.

## Project layout

```
gengomcp/
├── server.py        # the MCP server (tools + Qdrant/Embeddings glue)
├── main.py          # thin launcher
├── pyproject.toml   # deps + `gengomcp` console script
├── uv.lock          # pinned dependency versions
├── LICENSE          # MIT
├── .env.example     # template for all config vars (committed)
└── README.md
```

## Development / testing

```bash
uv run python -c "import server; print('ok')"
```

TDQS

A4.7/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct role: semantic search, ID-based retrieval, filter-based browsing, and schema discovery. There is no overlap in purpose; search_papers and list_papers differ meaningfully by query type.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with lowercase and underscores: search_papers, get_paper, list_papers, get_collection_info. This is predictable and easy to understand.

Tool Count5/5

Four tools is well-scoped for a read-only ACL paper search and retrieval server. Each tool covers a core capability without unnecessary bloat.

Completeness5/5

The tool surface covers the full read-only lifecycle: discover schema, search semantically, browse with filters, and retrieve a specific paper by ID. There are no obvious missing operations for the stated purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues