DEV Community

Sid Probstein
Sid Probstein

Posted on

Turning Slackbot into an Enterprise Research Agent with MCP

We connected a Slack agent to our federated search engine over the Model Context Protocol, then asked it a question only our OneDrive could answer. It searched, read the document, and replied in Slack with the coverage limits in a table and a citation that opens the exact sentence in SharePoint.

This post covers the architecture, the wiring, and two gotchas that cost us real debugging time.

The architecture

Three pieces, all standard:

  1. A Slack agent that speaks MCP as a client. Slack's agent platform lets a bot declare MCP servers in its manifest and connect to them at runtime.
  2. SWIRL's MCP server. SWIRL is a federated search + RAG engine; its MCP server exposes search, search_rag (grounded answers with citations), read_document, score_document, list_providers, and chat. It's a standalone process that calls a running SWIRL deployment over HTTP, so licensing, throttling, and per-user permissions are enforced by SWIRL exactly as for any API client.
  3. The sources. SharePoint, OneDrive, Box, databases, web APIs; SWIRL queries them where they live. Nothing is copied into the bot, the model, or a vector database.

The wiring

On the Slack side, the bot's manifest declares the MCP server and the bot connects with a slash command. On the SWIRL side, the server runs in HTTP transport mode:

SWIRL_MCP_TRANSPORT=http SWIRL_MCP_PORT=8675 \
SWIRL_MCP_TOKEN=<api-key> \
python -m swirl_mcp
Enter fullscreen mode Exit fullscreen mode

For the demo we exposed it through a tunnel with auth disabled; do not do that in production. The production path is the server's OAuth 2.1 resource-server mode (SWIRL_MCP_AUTH=oidc): the MCP host runs PKCE against your IdP, the server validates each bearer JWT (issuer, audience, JWKS signature), and SWIRL maps the token to the real calling user, so every search is permission-trimmed per caller.

What a query looks like

Asked "Search OneDrive for SWIRL's insurance policy", the bot:

  1. calls list_providers to find the OneDrive source id;
  2. calls search scoped to that provider;
  3. calls search_rag for a grounded answer over the results.

The reply carries the policy limits as a table, flags that professional services are excluded from that policy, and includes a text_fragment_url citation: a deep link that opens the source document scrolled to the exact quoted passage.

The bot listing SWIRL's MCP tools in Slack

The cited answer: coverage limits in a table, exclusions flagged, deep link to the source

Two gotchas worth knowing

Timeout mismatch. Slack gives an MCP tool call about 60 seconds; SWIRL's search_rag polls up to 90 seconds for the RAG answer, sized for a cold local model. On a slow model the Slack call dies first and the bot reports a failure while the answer lands seconds later. Fix: fast model for Slack-facing RAG, or lower SWIRL_MCP_RAG_POLL_TIMEOUT so failures are honest.

Tool descriptions are UX. The bot's first act in the demo is describing SWIRL's tools, in its own words, accurately. That's not the bot being clever; it's the MCP server's tool descriptions being written for an LLM audience. If your agent misuses a tool, fix the description before touching the agent.

The takeaway

Agents don't need your data ingested into them; they need a governed search layer. The bot never held our documents. It held a connection to a server that could search them, as us, with permissions enforced and citations attached.

The same MCP server works from Claude Desktop and Claude Code. There's a Claude Code plugin that stands up the whole stack: swirl-claude-plugin, and the 2-minute demo video is here: [LINK-TO-VIDEO].

Docs: docs.swirlaiconnect.com

Top comments (0)