Skip to main content
Glama
README.md
# nectr-mcp

An [MCP](https://modelcontextprotocol.io) server for [nectr](https://nectr.ch), the markdown library for your LLMs.

It lets a model **search** your library, **read** any saved page as clean markdown, **save** new pages, and **list** your projects. You don't need to paste links into the chat.

- **Search:** a model can't guess your permalinks, but it can call `search_library("pricing page")`.
- **Private pages:** pages you haven't shared have no working public link, but your key can still read them.
- **Saving:** "save these docs and keep them current" becomes one step, and nectr re-crawls them on your plan's schedule.
- **Freshness:** every read says when the page was last fetched.

## Setup

1. In nectr, open **Settings → API keys** and create a key. It starts with `nct_`.
2. Add the server to your MCP client's configuration. Most desktop and editor clients use an `mcpServers` block like this:

```json
{
  "mcpServers": {
    "nectr": {
      "command": "npx",
      "args": ["-y", "nectr-mcp"],
      "env": {
        "NECTR_API_KEY": "nct_your_key_here"
      }
    }
  }
}
```

3. Restart the client. The four tools below should appear.

Node.js 20 or newer is required.

| Variable | Required | Default | Purpose |
|---|---|---|---|
| `NECTR_API_KEY` | yes | — | Your `nct_` API key |
| `NECTR_URL` | no | `https://nectr.ch` | The nectr site to talk to, for a self-hosted instance |

## Tools

| Tool | What it does | Writes? |
|---|---|---|
| `search_library(query?, limit?)` | Finds saved pages by title or URL. Returns ids, URLs, freshness and a two-sentence summary per page, but **not** the bodies. Leave out `query` to list the most recently refreshed pages. | no |
| `get_page(id \| url, max_chars?)` | Returns the clean markdown of one page, with when it was last fetched. Long pages are cut off at 40,000 characters by default; ask for more with `max_chars`. | no |
| `convert_url(url, project_id?, force_refresh?)` | Saves a web page, PDF or DOCX to your library, optionally filed under a project. Counts against your monthly conversion quota unless the page is already saved. | yes |
| `list_projects()` | Lists your projects with page counts and each project's public `llms.txt` URL. | no |

There is deliberately **no delete**. A model that could delete your library by misreading a request isn't worth the convenience.

Search returns summaries rather than bodies so that looking around your library doesn't fill the model's context. It reads a full page only when it chooses to.

## Limits and errors

The server uses the same developer API as any other script, so your plan's limits apply unchanged. Errors are worded so a model knows whether to retry:

| nectr says | The model is told |
|---|---|
| 401: the key is invalid or revoked | Don't retry; you need a new key |
| 402: over the monthly quota | Don't retry until the quota resets |
| 422: the page can't be read (for example, it's behind a login) | nectr's reason, as given |
| 429: rate limited | How many seconds to wait |
| 503: the converter is busy | Retry in a few seconds |

## Security

**Your API key is stored in plain text in your MCP client's config file.** That's normal for MCP servers, but anyone who can read that file can use the key.

- Create a dedicated key for each client, so you can revoke one without breaking the others.
- If a key leaks, delete it under **Settings → API keys** in nectr. It stops working immediately.
- This server only ever reads and adds pages. **The key itself is broader:** it has the same access to the nectr API as your account, deletion included, so treat it like a password.

## Development

Running the server needs Node 20+, but **developing needs Node 22.12 or newer** (Vitest and the MCP Inspector require it). CI uses Node 24.

```bash
npm ci                 # not `npm install`: installs exactly the lockfile and never rewrites it
npm run typecheck
npm test
npm run build
NECTR_API_KEY=nct_... node dist/index.js   # speaks MCP over stdio
```

The tests run against a fake nectr API (`test/fake-api.ts`) and through a real MCP client over an in-memory transport (`test/server.test.ts`).

If `npm test` fails with **"Cannot find native binding"**, the `node_modules` folder was installed on another platform, for example inside a Linux container. `npm install` on top of it won't fix it. Delete `node_modules` and run `npm ci` again.

### Trying it by hand with the MCP Inspector

The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) calls the tools directly, without a model, and shows exactly what a model would receive. Build first (`npm run build`), then use its CLI mode. **Put the server command before the options.** With the options first, the Inspector reports "No servers found in config file".

```powershell
# PowerShell; in bash, use $NECTR_API_KEY instead of $k
$k = "nct_your_key"

npx @modelcontextprotocol/inspector --cli node dist/index.js -e NECTR_API_KEY=$k --method tools/list
npx @modelcontextprotocol/inspector --cli node dist/index.js -e NECTR_API_KEY=$k --method tools/call --tool-name search_library
npx @modelcontextprotocol/inspector --cli node dist/index.js -e NECTR_API_KEY=$k --method tools/call --tool-name search_library --tool-arg query=pricing
npx @modelcontextprotocol/inspector --cli node dist/index.js -e NECTR_API_KEY=$k --method tools/call --tool-name get_page --tool-arg id=PAGE-ID
```

Add `-e NECTR_URL=http://localhost:8000` to test against a local nectr backend. Leave out `--cli` for the web interface; the argument order is the same.

The Inspector's own dependencies need a newer Node than this server does. If it fails with **"Cannot find native binding"** after you upgrade Node, delete its cached copy from the npx cache (`%LocalAppData%\npm-cache\_npx` on Windows, `~/.npm/_npx` elsewhere) and run it again.

The quickest sanity check needs no key at all: `npx -y nectr-mcp` should print "NECTR_API_KEY is not set" and exit.

### Publishing

```bash
npm version patch      # or minor / major; also bump VERSION in src/server.ts and USER_AGENT in src/client.ts
npm publish            # prepublishOnly runs typecheck, tests and build first
```

npm refuses to publish from an account without two-factor authentication (error `E403`). Enable it under your npm account settings; `npm publish` then asks you to confirm in the browser or with `--otp=<code>`.

## License

MIT

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct role: search_library finds pages by metadata, get_page retrieves a page's body, convert_url adds/saves new content, and list_projects enumerates projects. The search-vs-get boundary is well explained (metadata vs. full markdown), so misselection is unlikely.

Naming Consistency5/5

All four names follow a strict verb_noun snake_case pattern (search_library, get_page, convert_url, list_projects). No mixing of conventions or vague verbs.

Tool Count4/5

Four tools is a tight, well-scoped set that maps cleanly to the core read/add/project workflows. It leans slightly thin for a library service, but each tool earns its place.

Completeness3/5

The read and create paths are covered (search, get, convert), but there is no delete/update for saved pages and projects can only be listed, not created or managed. These are notable lifecycle gaps an agent would hit.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive