Give Claude (and any MCP client) instant federated search and RAG over 100+ enterprise sources β without moving your data.
β‘ Quickstart Β· π οΈ Tools Β· π Connectors Β· π€ Contribute
Contents: π€ Why Β· π‘ What can you build Β· π See it in action Β· β‘ Quickstart Β· π©Ί Troubleshooting Β· π οΈ Tools Β· π Resources & prompts Β· βοΈ Configuration Β· π§ͺ Development Β· π§ How it works Β· π€ Contributing Β· π Need help? Β· π License
swirl-mcp-server is a Model Context Protocol adapter for SWIRL. It exposes SWIRL's federated search and RAG capabilities as MCP tools, so Claude Desktop, Claude Code, Cursor, and other MCP clients can answer questions against your private data sources β SharePoint, Confluence, GitHub, Jira, Elastic, BigQuery, Snowflake, MongoDB, M365, and 100+ more β without any of it leaving your network.
flowchart LR
Clients["Claude Desktop<br/>Claude Code<br/>Cursor / other"]
MCP["swirl-mcp-server<br/>(this repo)"]
SWIRL["SWIRL server<br/>(your infra)"]
Sources["SharePoint Β· Confluence<br/>GitHub Β· Jira Β· Elastic<br/>M365 Β· BigQuery Β· 100+ more"]
Clients -->|"MCP / stdio"| MCP
MCP -->|"REST"| SWIRL
SWIRL --> Sources
classDef box fill:#f4faf9,stroke:#088395,stroke-width:1px,color:#00215E;
class Clients,MCP,SWIRL,Sources box;
- Search where your data lives. SWIRL queries each connector in parallel, federates the results, and re-ranks them with cosine relevancy β no vector DB, no ETL, no data movement.
- One tool call, one answer.
search(query="...", rag=true)returns a generated answer with sources. The model never has to orchestrate per-source plumbing. - Permission-aware. SWIRL enforces per-user ACLs on every search and result. The MCP server forwards the user's credentials and never widens that scope.
- Drop-in. No changes to your SWIRL deployment. The server speaks SWIRL's existing REST API.
Real workflows that snap into place once Claude can call search:
- Point Claude Desktop at SharePoint, Confluence, OneDrive, and Notion via SWIRL.
- Ask "what did we decide about the Q3 pricing change?" β get a synthesized answer with links back to the source docs.
- No data leaves your network; results respect each user's existing permissions.
- Wire Claude Code into GitHub, Jira, and your internal docs in one tool call.
- "Why does service X retry on 503?" pulls in code, tickets, and runbooks together.
- Stop alt-tabbing between Jira and your editor while debugging.
- Ground replies in your real support docs and past tickets β not the model's training data.
- Maintain consistent answers across the team.
- Cite sources in every response so reps can verify before sending.
- One MCP server fans out to 100+ connectors.
- Same SWIRL deployment serves the Galaxy UI, REST APIs, and every MCP client on every desk.
- Add a new source once, and every assistant can search it.
rag_answer running against a local SWIRL via the MCP Inspector β a federated query answered with sources, ready to be piped into any MCP client:
- Python 3.10+ on the machine that runs the MCP server.
- A running SWIRL instance β the upstream Docker quickstart gets you one in 60 seconds.
- For
rag=true(generated answers): SWIRL itself needs an OpenAI or Azure OpenAI key. SetOPENAI_API_KEYin the SWIRL environment beforedocker compose upβ not on the MCP server. Without it, RAG calls return a "check credentials" message. Plainsearchworks fine without a key.
| Component | Tested versions |
|---|---|
| Python | 3.10, 3.11, 3.12 |
| SWIRL Metasearch | 4.x (against main of swirlai/swirl-search) |
| MCP Python SDK | 1.x |
| OS | macOS, Linux, Windows (WSL2) |
curl https://raw.githubusercontent.com/swirlai/swirl-search/main/docker-compose.yaml -o docker-compose.yaml
export OPENAI_API_KEY=<your-openai-or-azure-openai-key> # optional, enables rag=true
docker compose pull && docker compose upSWIRL will be at http://localhost:8000. The Docker image ships with admin / password as default dev credentials β change them for anything beyond local experimentation.
Until v0.1 lands on PyPI, install from GitHub:
pipx install git+https://github.com/swirlai/swirl-mcp-serverThat puts swirl-mcp on your PATH. (Don't have pipx? python -m pip install --user pipx && pipx ensurepath.)
Once published to PyPI,
uvx swirl-mcp-serverwill be the zero-install one-liner.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"swirl": {
"command": "swirl-mcp",
"env": {
"SWIRL_BASE_URL": "http://localhost:8000",
"SWIRL_USERNAME": "<your-swirl-username>",
"SWIRL_PASSWORD": "<your-swirl-password>"
}
}
}
}Restart Claude Desktop. You should see "swirl" in the tools menu. Try:
Use the swirl search tool with rag=true to ask: what are the latest arxiv papers on retrieval-augmented generation?
claude mcp add swirl swirl-mcp \
-e SWIRL_BASE_URL=http://localhost:8000 \
-e SWIRL_USERNAME=<your-swirl-username> \
-e SWIRL_PASSWORD=<your-swirl-password>See examples/ for ready-to-paste configs.
| Symptom | Cause | Fix |
|---|---|---|
rag_answer returns "check the OpenAI or Azure/OpenAI credentials in your environment" |
SWIRL has no OPENAI_API_KEY set |
export OPENAI_API_KEY=β¦ before docker compose up. The MCP server itself doesn't need the key β SWIRL does. |
SWIRL denied access. The user lacks permission for this operation. on rag_answer or search(rag=true) |
Running an old build that used Basic auth for /sapi/ endpoints (SWIRL guards them with DRF Tokens). |
Upgrade to v0.1+; the client now obtains a token automatically. |
command not found: swirl-mcp after install |
pipx's bin dir isn't on PATH |
pipx ensurepath, then restart the shell or your MCP client. |
Connection refused / timeouts |
SWIRL isn't running, or SWIRL_BASE_URL points somewhere else |
curl http://localhost:8000/ should return a redirect (302). If not, docker compose up first. |
get_results returns {"status": "not_ready"} |
Search is still being mixed by SWIRL | Not an error β wait ~1s and call again. The model can loop on this. |
| TLS errors against a self-signed SWIRL cert | Default is to verify TLS | Set SWIRL_VERIFY_SSL=false in the env block. Only do this for trusted internal hosts. |
The server exposes six tools. The headline is search β the rest are escape hatches for async, discovery, and reuse.
| Tool | Purpose | Backend |
|---|---|---|
search |
One-shot federated search. Set rag=true for a generated answer with citations. |
GET /api/swirl/search/?qs=β¦ |
create_search |
Kick off a search asynchronously and get back a search_id. |
POST /api/swirl/search/ |
get_results |
Fetch (or re-mix) results for an existing search_id. Returns not_ready while running. |
GET /api/swirl/results/?search_id=β¦ |
rag_answer |
Generate a RAG answer over an existing search's results. | GET /api/swirl/sapi/detail-search-rag/ |
list_providers |
List the user's configured SearchProviders (credentials stripped). | GET /api/swirl/searchproviders/ |
list_searches |
List the user's recent searches. | GET /api/swirl/search/ |
Returning both structured and markdown is intentional: MCP clients that render rich content show the markdown; ones that pass tool output back to the model verbatim get the leaner structured form.
swirl://providersβ JSON catalog of active SearchProviders. Useful as pinned context in clients that support resource pinning.swirl_research(question)β a reusable prompt that instructs the model to callsearchwithrag=trueand cite each source.
All settings come from environment variables (prefixed SWIRL_). A .env file in the working directory is auto-loaded.
| Var | Required | Default | Notes |
|---|---|---|---|
SWIRL_BASE_URL |
yes | http://localhost:8000 |
Your SWIRL instance root. |
SWIRL_USERNAME |
yes | β | Basic auth user. |
SWIRL_PASSWORD |
yes | β | Basic auth password. |
SWIRL_VERIFY_SSL |
no | true |
Set to false for self-signed certs. |
SWIRL_TIMEOUT_SECONDS |
no | 30 |
HTTP timeout for normal calls. |
SWIRL_RAG_TIMEOUT_SECONDS |
no | 60 |
Separate, larger timeout for the RAG endpoint. |
SWIRL_MAX_RESULTS |
no | 50 |
Upper bound on result_count (caps LLM token cost). |
SWIRL_DEFAULT_PROVIDERS |
no | β | Comma-separated provider ids/names/tags applied when a caller omits providers. |
π Credentials are never logged or returned in tool output.
list_providersdeliberately stripscredentials,url, andquery_templatefrom its response.
# stdio (default β what desktop clients use)
swirl-mcp
# streamable HTTP β for shared / hosted deployments
swirl-mcp --transport http --host 0.0.0.0 --port 8765In HTTP mode, multi-tenant deployments should put an auth proxy in front and forward the per-user SWIRL credentials.
git clone https://github.com/swirlai/swirl-mcp-server
cd swirl-mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest # run tests (HTTP mocked, no SWIRL required)
ruff check src testsexport SWIRL_BASE_URL=http://localhost:8000
export SWIRL_USERNAME=<your-swirl-username>
export SWIRL_PASSWORD=<your-swirl-password>
swirl-mcp -vThen point any MCP client at the command, or use the MCP Inspector:
npx @modelcontextprotocol/inspector swirl-mcpswirl-mcp-server is a thin async adapter. There's no business logic on top of SWIRL β the server reshapes SWIRL's REST envelopes into a lean, LLM-friendly form and surfaces them as MCP tools.
src/swirl_mcp/
βββ config.py # pydantic-settings env loader
βββ client.py # async httpx wrapper around SWIRL's REST API
βββ formatting.py # SWIRL result envelopes β trimmed, normalized payloads
βββ models.py # pydantic schemas for tool inputs/outputs
βββ server.py # FastMCP entrypoint + tool/resource/prompt registrations
A few intentional design choices:
- Snippets are truncated to 600 chars per result. Stops a chatty connector from dumping a whole article into the model's context.
get_resultsreturns{status: "not_ready"}, not an error, when SWIRL is still running. Lets the model poll cleanly.- No admin tools. Creating/editing/deleting
SearchProviders, users, query transforms, etc. stays in the SWIRL UI. They're high blast radius and rarely what an assistant should be doing autonomously. searchis synchronous. SWIRL's?qs=endpoint blocks until results are mixed β fine for tool calls. Usecreate_search+get_resultswhen you need async (subscribe mode, slow connectors).
PRs welcome! Please:
- Run
pytestandruff checkbefore pushing. - Add a test for any new tool or behavior.
- Keep the dependency footprint small β this is a thin adapter, not a framework.
- Issues with this MCP server: open a GitHub issue β bug reports, feature ideas, and "this doc is confusing" all welcome.
- Questions about SWIRL itself, or requesting a new connector: email the SWIRL team at support@swirlaiconnect.com.
- Want SWIRL Enterprise (managed deployment, premium connectors, SSO, support SLAs)? Schedule a free 30-day demo.
Apache 2.0 β see LICENSE and NOTICE.
This project targets the open-source SWIRL Metasearch project, which is also Apache 2.0 licensed.

