Data analyst on Slack

Wire your warehouse into an agent so anyone on the team can ask plain-English questions in Slack and get tables, analysis, and recommended actions back.

Outcome

A Slack agent for ad-hoc data requests. Ask a question in plain English; it writes the SQL, runs it against your warehouse, and posts the result back in the thread.

Prerequisites

  • A warehouse with read-only credentials scoped to the schemas you want the agent to see. Postgres, Snowflake, BigQuery, or anything else that has an MCP server.
  • A Slack workspace connected to Nairi. If you haven't done this yet, see Connecting Nairi to Slack.
  • An LLM provider connected. Claude Sonnet via the Anthropic integration is what we recommend for this playbook. See Connecting your LLM provider.
  • (Optional) A Gmail or Drive MCP if you want the agent to email or export reports.

Step 1 — Add the warehouse MCP

Warehouses live behind your own credentials, so you'll configure them as a custom MCP (paste JSON), not from the OAuth marketplace.

Open Settings → Artifacts → MCP ConfigsNew, mark the config as sensitive, and paste the JSON for your warehouse. The credentials sit inside the MCP config; the agent only sees the MCP's tool surface, never the config itself.

Postgres

Postgres MCP Pro (Crystal DBA, MIT) is the actively-maintained option. It runs over stdio, supports configurable read/write modes, and works against any Postgres-compatible warehouse (Redshift, Aurora, etc.). Pass --access-mode=restricted to lock it to read-only and safe meta queries:

{
  "mcpServers": {
    "postgres": {
      "command": "uvx",
      "args": ["postgres-mcp", "--access-mode=restricted"],
      "env": {
        "DATABASE_URI": "postgresql://analyst:YOUR_PASSWORD@db.your-company.com:5432/analytics?sslmode=require"
      }
    }
  }
}

Snowflake

isaacwasserman/mcp-snowflake-server (community, GPL-3) is the simplest stdio option and works with username/password or key-pair auth. The PyPI package name uses underscores (mcp_snowflake_server):

{
  "mcpServers": {
    "snowflake": {
      "command": "uvx",
      "args": ["--python=3.12", "mcp_snowflake_server"],
      "env": {
        "SNOWFLAKE_ACCOUNT": "xy12345.us-east-1",
        "SNOWFLAKE_USER": "analyst",
        "SNOWFLAKE_PASSWORD": "YOUR_PASSWORD",
        "SNOWFLAKE_ROLE": "ANALYST_RO",
        "SNOWFLAKE_WAREHOUSE": "ANALYTICS_WH",
        "SNOWFLAKE_DATABASE": "PROD",
        "SNOWFLAKE_SCHEMA": "PUBLIC"
      }
    }
  }
}

If you want a Snowflake-managed MCP instead of a community one, Snowflake exposes an official remote MCP over HTTP with OAuth — heavier setup but supported by Snowflake.

BigQuery

LucasHild/mcp-server-bigquery (MIT) supports the standard BigQuery client auth. The cleanest path is to mount a service-account key file into the agent container and point BIGQUERY_KEY_FILE at it; alternatively the MCP falls back to Application Default Credentials if the env var is omitted.

{
  "mcpServers": {
    "bigquery": {
      "command": "uvx",
      "args": ["mcp-server-bigquery"],
      "env": {
        "BIGQUERY_PROJECT": "your-gcp-project",
        "BIGQUERY_LOCATION": "us-central1",
        "BIGQUERY_KEY_FILE": "/etc/gcp/analyst-sa.json"
      }
    }
  }
}

Whichever MCP you pick, give the underlying database user the minimum permissions needed: SELECT on the schemas you care about, no write grants anywhere. The MCP layer is one safety net; the database grant is the real one.

See the MCP Tools overview for the full custom-config reference. If you want to rotate a credential across multiple MCPs or agents from one place, store it in a vault instead and reference it from the env block with $CCASECRET_NAME.

Step 2 — Create the agent

Open Fleet → New agent and fill in:

  • Nameanalyst works well. Slack mentions go to the Nairi bot (@Nairi); this name is what shows up in the agent picker and Nairi's dashboard.
  • LLM integration — Anthropic (Claude Sonnet). Reasoning-heavy SQL benefits from Sonnet over smaller models.
  • MCPs — attach the warehouse config from Step 1. Optionally also attach Gmail or Drive if you want the agent to email or export reports.
  • Channel — bind to your analyst Slack channel now, or leave it and let the channel self-bind on the first @-mention.

See How to deploy an agent for the full editor walkthrough.

Step 3 — Base prompt

Keep it short. The prompt sets identity and boundaries; the rules in Step 4 carry the schema and conventions.

You are an analyst with read-only access to our warehouse.
When asked a question:
- Write the SQL, run it, and reply in Slack with a 1-sentence
  answer, the query (collapsed in a code block), and a small
  table of the data.
- Round numbers to the precision the audience will actually use.
- If the question is about a change or anomaly, also explain the
  likely cause based on what's in the data.
- If a question is ambiguous, ask one clarifying question before
  running anything expensive.
- Refuse to run anything that mutates state.

Step 4 — Rules to direct the agent

The base prompt is identity. The rules are the institutional knowledge — the schema, the conventions, the gotchas. Put each topic in its own rule so you can iterate them independently.

Open Settings → Artifacts → Rules and create a few rules, then attach them to the agent. Suggested starting set:

Schema cheat-sheet

The most important rule. Without it the agent will guess table and column names and spend tool calls poking around. With it, the first SQL it writes is usually right.

# Warehouse schema reference

Use these tables for the questions below. Prefer the listed
canonical table when more than one exists.

## ride_requests
One row per requested ride.
- request_id (pk)
- user_id
- city                  ('austin', 'denver', ...)
- zone                  ('downtown', 'east_austin', 'south_lamar', ...)
- requested_at          (timestamp, UTC)
- accepted_at           (timestamp, nullable — null = no driver)
- wait_time_seconds     (accepted_at − requested_at; null if cancelled)
- status                ('completed', 'cancelled_by_user', ...)
- fare_usd

## drivers_daily
One row per (driver_id, day).
- driver_id
- day                   (date)
- trips_completed
- hours_online

## Conventions
- "this week" means Monday 00:00 local through now.
- All timestamps in the warehouse are UTC. Convert to America/Chicago
  for Austin-area questions.
- "Active driver" = at least one completed trip that day.

Query safety

# Query safety

- Always include a date filter on time-series tables
  (ride_requests, events, sessions). Default to last 7 days
  if the user doesn't specify.
- Cap any unbounded SELECT with LIMIT 1000.
- Never run cross-joins.
- For BigQuery, always use partition columns when available
  to avoid full-table scans.
- If a query would scan more than 100 GB, ask before running.

Definitions

# Metric definitions

- "Wait time" is accepted_at − requested_at, not pickup_at − requested_at.
- "Active driver" requires ≥1 completed trip in the day, not just
  hours_online > 0.
- "Revenue" is sum(fare_usd) on rows where status = 'completed'.
  Cancelled rides are not revenue, even if a cancellation fee was
  charged.
- When comparing "this week vs. last week", align days-of-week
  (Mon-Mon, not by-date).

Output format

# How to reply in Slack

- Lead with a one-sentence answer.
- Then the table, in markdown.
- Then the SQL, in a collapsed code block.
- If you found an anomaly, end with a one-paragraph diagnosis.
- Keep numbers human: no more than 3 significant figures for
  metrics, no scientific notation for revenue or volume.
- Never paste raw warehouse error messages. Translate them.

You don't need all four on day one. Start with the schema cheat-sheet and the safety rules, then add the others as you notice the agent doing things you wish it wouldn't.

See Adding rules for the full editor reference.

Step 5 — First run

In your analyst channel:

@Nairi how were sign-ups last week vs. the week before?

Watch the thread. The agent should:

  1. React with then 👀 (queued, then running).
  2. Reply with a one-sentence answer, a 2-row table (this week vs. last), and the collapsed SQL.
  3. Add a diagnosis if there's a clear movement.

If the SQL it writes is wrong, the schema cheat-sheet is almost always the lever to fix it. Add the missing column or convention and try again.

Customisation

  • Charts. Add the charts skill so the agent posts a PNG alongside the table. Useful when "is it up or down?" is the real question.
  • Recurring digests. Turn the same prompt into a scheduled job that posts a Monday-morning KPI summary. Same agent, no new wiring.
  • Email distribution. Attach the Gmail MCP from the marketplace so the agent can send a finished report to a stakeholder directly from the thread.
  • Multiple warehouses. Attach multiple MCP configs to the same agent. Add a rule explaining which warehouse holds what so the agent picks the right one.

Can't find what you're looking for? Email support@nairi.ai.

On this page