# wso2-docs-mcp-server [Health: Active]

**Category:** 🧠 Knowledge & Memory  
**Repository:** https://github.com/iamvirul/wso2-docs-mcp-server  
**GitHub Stars:** 3  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/wso2-docs-mcp-server

## Description
Semantic search over WSO2 docs (APIM, MI, Choreo, Ballerina) via RAG and pgvector.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "wso2-docs-mcp-server": {
    "command": "npx",
    "args": ["-y","wso2-docs-mcp-server"]
  }
}
```

## Documentation & README

# WSO2 Docs MCP Server

[![npm version](https://img.shields.io/npm/v/wso2-docs-mcp-server.svg)](https://www.npmjs.com/package/wso2-docs-mcp-server)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)

>"This is an unofficial community project. Not affiliated with or endorsed by WSO2."

A production-ready **Model Context Protocol (MCP)** server that provides AI assistants (Claude Desktop, Claude Code, Cursor, VS Code) with semantic search over WSO2 documentation via Retrieval-Augmented Generation (RAG).

Under the hood, it uses a blazing-fast dual-ingestion engine:
- **GitHub Native:** Fetches raw Markdown directly from WSO2's public GitHub repositories via the Git Trees API (avoids web-scraping noise and rate limits)
- **Web Crawl Fallback:** For products without dedicated GitHub docs repos (like the WSO2 Library)

## Architecture

![System Architecture](https://raw.githubusercontent.com/iamvirul/wso2-docs-mcp-server/main/docs/architecture.svg)

## Documentation Sources

| Product | ID | URL |
|---|---|---|
| API Manager | `apim` | https://apim.docs.wso2.com |
| Micro Integrator | `mi` | https://mi.docs.wso2.com/en/4.4.0 |
| Ballerina Integrator | `bi` | https://bi.docs.wso2.com |
| Choreo | `choreo` | https://wso2.com/choreo/docs |
| Identity Server | `is` | https://is.docs.wso2.com/en/latest |
| Ballerina | `ballerina` | https://ballerina.io/learn |
| WSO2 Library | `library` | https://wso2.com/library |

## Prerequisites

- **Node.js** ≥ 20
- **Docker** (for pgvector)
- **Embeddings** - no API key required by default:
  - **[Ollama](https://ollama.com)** (recommended) - runs locally, model auto-downloaded on first run
  - If Ollama is not running, the server automatically falls back to **HuggingFace ONNX** (in-process, also downloads automatically)
  - Cloud providers are also supported: OpenAI, Google Gemini, Voyage AI

---

## Quick Start

Choose the setup path that fits your use case:

- **[Install from npm](#install-from-npm)** - simplest, no cloning required
- **[Clone and build](#clone-and-build)** - for development or contributions

---

### Install from npm

Install the package globally to get the `wso2-docs-mcp-server`, `wso2-docs-crawl`, and `wso2-docs-migrate` commands available system-wide:

```bash
npm install -g wso2-docs-mcp-server
```

> **Prefer no global install?** You can use `npx wso2-docs-mcp-server`, `npx wso2-docs-crawl`, and `npx wso2-docs-migrate` in every step below - just replace the bare command with its `npx` equivalent.

#### 1. Start pgvector

Download the `docker-compose.yml` and start the database:

```bash
curl -O https://raw.githubusercontent.com/iamvirul/wso2-docs-mcp-server/main/docker-compose.yml
docker compose up -d
```

#### 2. Start Ollama (optional but recommended)

[Install Ollama](https://ollama.com) and pull the default embedding model:

```bash
ollama pull nomic-embed-text
ollama serve
```

> **No Ollama?** Skip this step. The server automatically falls back to HuggingFace ONNX - model downloads on first use with no extra setup.

#### 3. Run database migration

```bash
DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  wso2-docs-migrate
```

> Run migration again whenever you change `EMBEDDING_DIMENSIONS` (i.e. switch embedding provider). The script detects and handles dimension changes automatically.

#### 4. Index WSO2 documentation

```bash
# Index all products (first run downloads the embedding model automatically)
DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  wso2-docs-crawl

# Index a single product (faster, great for testing)
DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  wso2-docs-crawl --product ballerina --limit 20

# Force re-index even unchanged pages
DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  wso2-docs-crawl --force
```

Available product IDs: `apim`, `mi`, `bi`, `choreo`, `is`, `ballerina`, `library`

#### 5. Configure your AI client

The MCP server is launched on demand by your AI client - no background process needed.

**Claude Desktop** - edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "wso2-docs": {
      "command": "wso2-docs-mcp-server",
      "env": {
        "DATABASE_URL": "postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs",
        "EMBEDDING_PROVIDER": "ollama"
      }
    }
  }
}
```

**Claude Code** - run once in your terminal:

```bash
claude mcp add wso2-docs \
  --transport stdio \
  -e DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  -e EMBEDDING_PROVIDER="ollama" \
  -- wso2-docs-mcp-server

# Verify
claude mcp list
```

**Cursor** - create `.cursor/mcp.json` in your project root:

```json
{
  "mcpServers": {
    "wso2-docs": {
      "command": "wso2-docs-mcp-server",
      "env": {
        "DATABASE_URL": "postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs",
        "EMBEDDING_PROVIDER": "ollama"
      }
    }
  }
}
```

**VS Code** - create `.vscode/mcp.json`:

```json
{
  "servers": {
    "wso2-docs": {
      "type": "stdio",
      "command": "wso2-docs-mcp-server",
      "env": {
        "DATABASE_URL": "postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs",
        "EMBEDDING_PROVIDER": "ollama"
      }
    }
  }
}
```

> **Using `npx` instead of global install?** Replace `"command": "wso2-docs-mcp-server"` with `"command": "npx"` and add `"args": ["-y", "wso2-docs-mcp-server"]`.

> **Cloud embedding provider?** Add the key to `env`, e.g. `"EMBEDDING_PROVIDER": "openai", "OPENAI_API_KEY": "sk-..."`.

---

### Clone and build

#### 1. Clone and install

```bash
git clone https://github.com/iamvirul/wso2-docs-mcp-server.git
cd wso2-docs-mcp-server
npm install
```

#### 2. Start Ollama (optional but recommended)

[Install Ollama](https://ollama.com) and start it:

```bash
ollama serve
```

> **No Ollama?** Skip this step. The server detects Ollama is not running and automatically falls back to HuggingFace ONNX inference - the model downloads on first use with no extra setup.

#### 3. Configure environment

```bash
cp .env.example .env
# Defaults work out of the box with Ollama.
# Only edit if using a cloud provider (OpenAI / Gemini / Voyage).
```

#### 4. Start pgvector

```bash
docker compose up -d
# pgAdmin available at http://localhost:5050 (admin@wso2mcp.local / admin)
```

#### 5. Run database migration

```bash
npm run db:migrate
```

> **Note:** Run migration again whenever you change `EMBEDDING_DIMENSIONS` (i.e. switch embedding provider). The script detects and handles dimension changes automatically.

#### 6. Index documentation

```bash
# Index all products
# On first run the embedding model is downloaded automatically (Ollama or HuggingFace)
npm run crawl

# Index a single product (faster, great for testing)
npm run crawl -- --product ballerina --limit 20

# Force re-index even unchanged pages
npm run crawl -- --force
```

#### 7. Build and start the MCP server

```bash
npm run build
npm start
```

For development (no build step):
```bash
npm run dev
```

#### 8. Configure your AI client

> Replace `/ABSOLUTE/PATH/TO/wso2-docs-mcp-server` with your actual clone path.

**Claude Desktop** - edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "wso2-docs": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/wso2-docs-mcp-server/dist/src/index.js"],
      "env": {
        "DATABASE_URL": "postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs",
        "EMBEDDING_PROVIDER": "ollama"
      }
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add wso2-docs \
  --transport stdio \
  -e DATABASE_URL="postgresql://wso2mcp:wso2mcp@localhost:5432/wso2docs" \
  -e EMBEDDING_PROVIDER="ollama" \
  -- node "/ABSOLUTE/PATH/TO/wso2-docs-mcp-server/dist/src/index.js"

# Verify
claude mcp list
```

See `config-examples/claude_code.sh` for a convenience script.

**Cursor** - create `.cursor/mcp.json` - see `config-examples/cursor_mcp.json`.

**VS Code** - create `.vscode/mcp.json` - see `config-examples/vscode_mcp.json`.

---

## MCP Tools

| Tool | Description |
|---|---|
| `search_wso2_docs` | Semantic search across all products. Optional `product` and `limit` filters. |
| `get_wso2_guide` | Search within a specific product (`apim`, `mi`, `bi`, `choreo`, `is`, `ballerina`, `library`). |
| `explain_wso2_concept` | Broad concept search across all products, returns 8 top results. |
| `list_wso2_products` | Returns all supported products with IDs and base URLs. |

### Example response

```json
[
  {
    "title": "Deploying WSO2 API Manager",
    "snippet": "WSO2 API Manager can be deployed in various topologies…",
    "source_url": "https://apim.docs.wso2.com/en/latest/install-and-setup/...",
    "product": "apim",
    "section": "Deployment Patterns",
    "score": 0.8712
  }
]
```

---

## Local Embeddings

The default `EMBEDDING_PROVIDER=ollama` runs entirely on your machine with no API key. The startup sequence is:

```
Is Ollama running?
├── Yes → Is model present?
│         ├── Yes → Ready (instant)
│         └── No  → Pull via Ollama (streamed, runs once)
└── No  → Download ONNX model from HuggingFace Hub (~250 MB, cached after first run)
           and run inference in-process via @huggingface/transformers
```

Both paths use `nomic-embed-text` / `Xenova/nomic-embed-text-v1` by default and produce identical 768-dim vectors, so you can switch between them without re-indexing.

### Hardware acceleration (HuggingFace ONNX fallback)

When Ollama is not available, the server auto-detects the best compute backend:

| Machine | Detection | ONNX dtype | Batch size | Throughput |
|---|---|---|---|---|
| Apple Silicon (M1/M2/M3/M4) | `process.arch === 'arm64'` | `q8` INT8 | 32 | ~9 ms/chunk |
| NVIDIA GPU | `nvidia-smi` probe | `fp32` | 64 | GPU-dependent |
| All others | fallback | `q8` INT8 | 16 | ~10 ms/chunk |

**Why `q8` on Apple Silicon instead of CoreML/Metal?**
CoreML compiles Metal shaders on first use (~20 min cold-start). For the typical chunk sizes produced by this server (6–20 chunks per page), the CPU↔GPU transfer overhead eliminates any inference gain. INT8 quantized inference on ARM NEON SIMD is consistently **~100× faster than fp32 CPU** with zero cold-start cost.

**Benchmark (Apple M-chip, `Xenova/nomic-embed-text-v1`):**
```
fp32 CPU (before): ~1,000 ms/chunk   (68 chunks ≈ 68 s of embedding)
q8  ARM NEON:          ~9 ms/chunk   (68 chunks ≈  0.6 s of embedding)  ← ~100× speedup
```

> **Note:** For small crawls (≤ 10 pages) total wall-clock time is dominated by network I/O
> (HTTPS fetches to docs sites), so the end-to-end improvement is modest. The embedding
> speedup becomes significant at scale - crawling 500+ pages where embedding previously
> accounted for hours of runtime. For best crawl performance, run Ollama (`ollama serve`)
> which parallelises inference natively and has no per-chunk overhead.

---

## Environment Variables

### Core

| Variable | Default | Description |
|---|---|---|
| `DATABASE_URL` | - | PostgreSQL connection string (required) |
| `EMBEDDING_PROVIDER` | `ollama` | `ollama` \| `openai` \| `gemini` \| `voyage` |
| `EMBEDDING_DIMENSIONS` | `768` | Must match model output dimensions |
| `CRAWL_CONCURRENCY` | `5` | Concurrent HTTP requests during crawl |
| `CHUNK_SIZE` | `800` | Approximate tokens per chunk |
| `CHUNK_OVERLAP` | `100` | Overlap tokens between chunks |
| `CACHE_TTL_SECONDS` | `3600` | In-memory query cache TTL |
| `TOP_K_RESULTS` | `10` | Default search result count |

### Ollama (default)

| Variable | Default | Description |
|---|---|---|
| `OLLAMA_BASE_URL` | `http://localhost:11434` | Ollama server URL |
| `OLLAMA_EMBEDDING_MODEL` | `nomic-embed-text` | Model pulled and used via Ollama |
| `HUGGINGFACE_EMBEDDING_MODEL` | `Xenova/nomic-embed-text-v1` | ONNX fallback when Ollama is not running |

### Cloud providers

| Variable | Default | Description |
|---|---|---|
| `OPENAI_API_KEY` | - | Required if `EMBEDDING_PROVIDER=openai` |
| `OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | OpenAI model |
| `GEMINI_API_KEY` | - | Required if `EMBEDDING_PROVIDER=gemini` |
| `GEMINI_EMBEDDING_MODEL` | `text-embedding-004` | Gemini model |
| `VOYAGE_API_KEY` | - | Required if `EMBEDDING_PROVIDER=voyage` |
| `VOYAGE_EMBEDDING_MODEL` | `voyage-3` | Voyage model |

### Embedding dimension reference

| Provider | Model | Dimensions |
|---|---|---|
| Ollama / HuggingFace | `nomic-embed-text` / `Xenova/nomic-embed-text-v1` | **768** (default) |
| Ollama / HuggingFace | `mxbai-embed-large` / `Xenova/mxbai-embed-large-v1` | 1024 |
| Ollama / HuggingFace | `all-minilm` / `Xenova/all-MiniLM-L6-v2` | 384 |
| OpenAI | `text-embedding-3-small` | 1536 |
| OpenAI | `text-embedding-3-large` | 3072 |
| Gemini | `text-embedding-004` | 768 |
| Voyage | `voyage-3` | 1024 |
| Voyage | `voyage-3-lite` | 512 |

---

## Scheduled Re-indexing

```bash
# Run a one-off re-index (checks hashes, skips unchanged pages)
npm run reindex

# Or from the project directory using node-cron (runs daily at 2 AM)
DATABASE_URL=... node -e "
  const { ReindexJob } = require('./dist/jobs/reindexDocs');
  const job = new ReindexJob();
  job.initialize().then(() => job.scheduleDaily());
"
```

---

## Project Structure

```
src/
  config/          env.ts · constants.ts
  vectorstore/     pgvector.ts · schema.sql
  ingestion/       crawler.ts · parser.ts · githubFetcher.ts · markdownParser.ts · chunker.ts · embedder.ts
  server/          mcpServer.ts · toolRegistry.ts
  jobs/            reindexDocs.ts
  index.ts
scripts/
  crawl.ts         CLI ingestion pipeline
  migrate.ts       Dynamic schema migration
config-examples/   claude_desktop.json · claude_code.sh · cursor_mcp.json · vscode_mcp.json
docker-compose.yml
.env.example
```

---

## Development

```bash
# Type-check
npx tsc --noEmit

# Run crawl with tsx (no build needed)
npm run crawl -- --product ballerina --limit 5

# Run server in dev mode
npm run dev
```

