# @faqai/mcp-server

Official [Model Context Protocol](https://modelcontextprotocol.io) server for [FAQai.app](https://faqai.app) — turn any document into a production-ready RAG dataset directly from Claude Desktop, Cursor, VS Code, Windsurf, Zed, JetBrains, Claude Code, the OpenAI Agents SDK, or any MCP host.

> MCP is model-agnostic — it is supported by *host apps*, not by a specific LLM. This server works with any MCP-compatible desktop app or agent framework regardless of whether it runs Claude, GPT, Gemini, or another model.

## Requirements

- Node.js 18+
- A FAQai API key (`faq_...`) — create one at [faqai.app/settings/api-keys](https://faqai.app/settings/api-keys). API access requires a paid plan (Basic or higher).

## Setup

### Standard config (Cursor, Claude Desktop, Windsurf, Cline/Roo, JetBrains AI)

Add this block to your host's MCP configuration — only the file location differs:

```json
{
  "mcpServers": {
    "faqai": {
      "command": "npx",
      "args": ["-y", "@faqai/mcp-server"],
      "env": {
        "FAQAI_API_KEY": "faq_your_key_here"
      }
    }
  }
}
```

| Host | Where it goes |
|---|---|
| Cursor | `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per-project) |
| Claude Desktop | `claude_desktop_config.json` |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
| Cline / Roo Code | the extension's `cline_mcp_settings.json` |
| JetBrains AI Assistant | Settings → Tools → AI Assistant → MCP |

### VS Code (Copilot agent mode)

VS Code uses a top-level `servers` key. Save as `.vscode/mcp.json` in your workspace:

```json
{
  "servers": {
    "faqai": {
      "command": "npx",
      "args": ["-y", "@faqai/mcp-server"],
      "env": { "FAQAI_API_KEY": "faq_your_key_here" }
    }
  }
}
```

### Zed

Zed uses `context_servers` in its `settings.json`:

```json
{
  "context_servers": {
    "faqai": {
      "source": "custom",
      "command": "npx",
      "args": ["-y", "@faqai/mcp-server"],
      "env": { "FAQAI_API_KEY": "faq_your_key_here" }
    }
  }
}
```

### Claude Code (CLI)

```bash
claude mcp add faqai -e FAQAI_API_KEY=faq_your_key_here -- npx -y @faqai/mcp-server
```

### OpenAI Agents SDK (Python)

Drive the stdio server from your own GPT-powered agent:

```python
from agents import Agent
from agents.mcp import MCPServerStdio

faqai = MCPServerStdio(
    params={
        "command": "npx",
        "args": ["-y", "@faqai/mcp-server"],
        "env": {"FAQAI_API_KEY": "faq_your_api_key"},
    }
)

agent = Agent(
    name="RAG dataset builder",
    instructions="Use FAQai to turn documents into production-ready RAG datasets.",
    mcp_servers=[faqai],
)
```

### Web-based hosts (ChatGPT, Claude.ai web, Grok / xAI)

These connect to MCP servers over a **remote HTTPS URL** rather than launching a
local process, so this stdio package cannot be used directly. FAQai hosts a
**remote MCP endpoint** (Streamable HTTP) for them:

```
https://faqai.app/api/mcp
```

Authenticate either way:

- **One-click OAuth (recommended):** hosts with OAuth connectors show a
  *Connect* / *Sign in* button. You approve access on FAQai (and pick a grant
  level), then get bounced straight back — no key to copy. Manage or revoke these
  grants under **Developers → Connected apps**.
- **Manual key:** developer-mode custom servers can instead send an
  `Authorization: Bearer faq_...` header.

In each app's connector / custom-MCP settings, add a server with that URL. The
endpoint implements OAuth 2.1 discovery (`/.well-known/oauth-protected-resource`
and `/.well-known/oauth-authorization-server`), PKCE (S256), and Dynamic Client
Registration. Per-host snippets (OpenAI Agents SDK, OpenAI Responses API,
Cursor, VS Code) are in the dashboard under **Developers → SDKs & MCP**.

> Uploading a *local* file is only available through this stdio package (remote
> hosts have no local filesystem); all other tools work over the remote
> endpoint and are metered exactly like the REST API.

### Environment variables

| Variable | Required | Default | Description |
|---|---|---|---|
| `FAQAI_API_KEY` | Yes | — | Your FAQai API key. Never hardcode it in shared files. |
| `FAQAI_BASE_URL` | No | `https://faqai.app` | Override for testing against a different environment. |

## Tools

| Tool | Type | Description |
|---|---|---|
| `list_documents` | Read-only | List your documents with status, page count, and dataset counts |
| `get_document` | Read-only | Full details for one document |
| `get_processing_status` | Read-only | Poll a document's processing state |
| `list_export_formats` | Read-only | The 16 supported dataset export formats |
| `get_usage_stats` | Read-only | Current plan, page/API-call quota, and limits |
| `list_datasets` | Read-only | Datasets generated for a document, with IDs for export |
| `export_dataset` | Read-only | Export a dataset in any of 16 formats, inline or to a local file |
| `search_datasets` | Read-only | Full-text search across all generated Q&A items |
| `get_dataset_coverage` | Read-only | Chunk-level coverage report for a dataset |
| `get_rag_config` | Read-only | Tuned system prompt, embedding config, and code snippets |
| `upload_document` | Write | Upload a local PDF/DOCX/TXT/MD (presigned flow, quota pre-check); supports optional `generation_context` (audience steering) and `chunking` (profile presets or custom sizes) |
| `ingest_url` | Write | Ingest a public web page or crawl a same-domain site (sitemap/BFS, robots.txt-aware, per-plan page caps) into a new document; supports the same optional `generation_context` and `chunking` fields |
| `process_document` | Write | Start dataset generation — consumes page quota; supports the same optional `generation_context` and `chunking` fields |
| `cancel_processing` | Write | Cancel an in-flight processing run and release reserved pages |
| `delete_document` | Destructive | Permanently delete a document; requires explicit `confirm: true` |
| `list_webhooks` | Read-only | List webhook subscriptions (Pro plan) |
| `create_webhook` | Write | Subscribe an HTTPS endpoint to FAQai events (Pro plan) |
| `delete_webhook` | Destructive | Remove a webhook subscription (Pro plan) |

## Resources & Prompts

Besides tools, the server exposes MCP **resources** — `faqai://documents` (recent documents) and `faqai://usage` (plan quota) — that hosts can attach to a conversation as context, and two **prompts** (slash commands in most hosts):

- `generate-rag-dataset` — upload a local file, wait for processing, and report the generated datasets with coverage.
- `export-to-vector-db` — export a document's dataset in the right format for Pinecone, Qdrant, pgvector, Chroma, Weaviate, Milvus, LanceDB, or Upstash.

### Typical agent workflow

1. `upload_document` with a local file path, or `ingest_url` with a web page / site URL (starts processing by default)
2. `get_processing_status` — poll every 10–15 s until `completed`
3. `list_datasets` — get the generated dataset IDs
4. `export_dataset` with `save_path` — write the dataset to disk in the format your stack needs

## Security

- The server communicates exclusively with the public FAQai REST API over HTTPS using your API key. It has no other credentials and no database access. All plan limits, rate limits, quotas, and row-level security apply exactly as they do for direct API usage.
- Your API key is read from the environment and is never logged or echoed.
- **Use a scoped key.** If you only need the agent to read documents and export datasets, create a key with the `read` scope only — write tools (`upload_document`, `ingest_url`, `process_document`, `cancel_processing`, `delete_document`) will then be rejected by the API with a 403 even if the agent calls them.
- `delete_document` is guarded twice: the tool refuses to run without `confirm: true`, and it is annotated `destructiveHint` so well-behaved MCP hosts ask the user before invoking it.
- Every tool invocation is logged to stderr with a timestamp, outcome, and duration, giving you a local audit trail of what the agent did with your account. Most MCP hosts surface these logs (Cursor: Output panel → MCP; Claude Desktop: `~/Library/Logs/Claude/mcp*.log`).
- Quota protection: `upload_document` checks your remaining page quota *before* uploading and refuses when it is exhausted, and every response carries a plan-usage note so the agent can warn you before starting expensive jobs.

## Troubleshooting

| Symptom | Cause / fix |
|---|---|
| `FAQAI_API_KEY environment variable is required` | The key is missing from the MCP config `env` block. |
| `Authentication failed` (401) | The key is invalid or revoked — create a new one at [faqai.app/settings/api-keys](https://faqai.app/settings/api-keys). |
| `Access denied` (403) on every tool | API access requires a paid plan (Basic or higher). |
| 403 only on write tools | Your key is scoped `read` — intended behavior; create a `write` scoped key if you want uploads. |
| `Rate limited` (429) | Wait the indicated seconds. Plans allow 10–30 requests/minute. |
| `page_limit_exceeded` | Monthly page quota exhausted — upgrade or buy an overage pack. |
| Export "too large to return inline" | Call `export_dataset` again with `save_path` set to an absolute file path. |
| Server exits immediately | Run `node dist/index.js` manually; startup errors are printed to stderr. |

When reporting an issue, include the server version — it is printed on startup (`[faqai-mcp] vX.Y.Z ready`) and embedded in unexpected-error messages.

## Development

```bash
npm install
npm run build
npm test
```

Live smoke test against the real API (read-only by default):

```bash
FAQAI_PRO_API_KEY=faq_... node tests/live-smoke.mjs
# full write-path E2E (uploads + processes + deletes a tiny test doc, ~1 page of quota):
FAQAI_PRO_API_KEY=faq_... LIVE_E2E=1 node tests/live-smoke.mjs
# target a dev server:
FAQAI_PRO_API_KEY=faq_... FAQAI_BASE_URL=http://localhost:3000 LIVE_E2E=1 node tests/live-smoke.mjs
```

## License

MIT
