Lore

Lore

An MCP server that captures and retrieves team decisions and facts from Slack with provenance, supporting search, remember, and forget operations, while integrating with external tools via MCP client.

Category
Visit Server

README

Lore — the org-memory agent for Slack

"What did we decide about pricing?" · "Who owns the hospital pilot?" · "When did we flip the go-live date?" Every team has these questions. Nobody has a fast, sourced answer.

Lore is a Slack agent that captures decisions, commitments, and facts as they happen — then answers questions about them with provenance: every answer links the exact Slack messages (and the GitHub PR, Jira issue, or Notion doc) where the fact was established.

Built for the Slack Agent Builder Challenge 2026 · New Slack Agent track · Apache-2.0


The problem

Knowledge lives and dies in Slack. A decision made in #product in March is lost to search by June. When people leave, their context leaves. When channels get noisy, facts get buried. Existing tools (Notion AI, Confluence AI, Guru) require someone to manually move Slack decisions into a docs system — so they're always stale and always incomplete.

Lore solves this by living in Slack — capturing decisions the moment you @Lore them, /lore them, use the "Remember this" shortcut, or drop a file — and exposing that memory to every AI tool your team uses.


Qualifying technologies

Slack Agent Builder Challenge tech How Lore uses it File
Slack AI / Assistant API assistant_thread_started + assistant_thread_context_changed events; Assistant-thread surface for contextual Q&A; AI digests power the research synthesis pass src/lore/slackio/events.py
MCP server integration Lore is an MCP server (org_memory_search, org_memory_remember, org_memory_forget) AND an MCP client (per-tenant CRM/Jira/Linear/GitHub integrations) src/lore/mcpio/server.py, src/lore/mcpio/client.py, src/lore/integrations.py
Real-Time Search API assistant.search.context called at answer-time to inject fresh Slack context in assistant threads (gracefully skipped on channel @mentions, where the action token doesn't apply); used in the 5-phase research pipeline's public-search stage src/lore/runner.py, src/lore/rts.py

All three technologies are active simultaneously on every question.


What makes Lore different

Lore Notion AI / Confluence AI Guru Slack AI (native)
Captures from Slack natively ❌ (manual import) ❌ (manual import)
Provenance to original message
Correction with history kept
Fact decay (stale = fades)
File upload → Q&A
Approval gate for dangerous requests
Exposed as MCP server
Per-tenant external tool integration ✅ (GitHub, Linear, CRM…)
Works in Claude Desktop / Cursor too

The core insight: Lore doesn't pull docs into Slack. It turns Slack itself into a queryable, self-correcting, auditable knowledge base — and then exposes that knowledge base to every AI tool your team uses.


How it works

Slack event ──▶ durable intake          Redis-stream exactly-once admission;
                                        survives restarts, deduplicates retries
            ──▶ armor scan              PII + credential regex screen before
                                        any LLM call; blocks prompt injection
            ──▶ intent classification   simple / research / complex /
                                        high_consequence routing
            ──▶ fact extraction         decision? commitment? owner? date?
                                        attributed to the Slack user who said it
            ──▶ memory store            hybrid vector (Qdrant) + keyword (Postgres)
                                        reinforcement/decay: confirmed = stronger,
                                        untouched = fades, corrected = superseded
            ──▶ retrieval (at ask-time) 3-tier grounding: context → history → RAG
                                        + Real-Time Search API freshness layer
            ──▶ answer + provenance     Block Kit card, source permalinks,
                                        Confirm / Correct / Forget buttons
            ──▶ (if high_consequence)   Approval gate: asyncio.Future bridge,
                                        Block Kit card, 5-minute timeout

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Slack workspace                             │
│  mentions · DMs · shortcuts · /lore · file uploads · App Home       │
└──────────────────────────┬──────────────────────────────────────────┘
                           │ Socket Mode (xapp-)
                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     lore/slackio  (Bolt/async)                      │
│  events.py   │  actions.py   │  blocks.py   │  assistant.py         │
│  intake.py   │  approval/    │  file ingest pipeline                │
└──────────────────────────┬──────────────────────────────────────────┘
                           │ Redis stream (exactly-once)
                           ▼
┌──────────────────────────────────────┐  ┌───────────────────────────┐
│           runner.py (orchestrator)   │  │  integrations.py          │
│  intent router → dispatch path       │  │  per-tenant MCP client    │
│  3-tier grounding → RTS → RAG        │  │  (GitHub, Linear, CRM…)   │
│  ReAct tool loop (≤6 tools, 3-strike)│  └──────────┬────────────────┘
│  5-phase research pipeline           │             │ stdio/http/sse MCP
│  approval gateway (asyncio.Future)   │  ┌──────────▼────────────────┐
└────────────┬──────────┬─────────────┘  │  External MCP servers     │
             │          │                 └───────────────────────────┘
    ┌────────▼──┐  ┌────▼──────────┐
    │  store.py  │  │mcpio/server.py│  ◀── Claude Desktop / Cursor /
    │  Postgres  │  │  org_memory_  │       any MCP client
    │  + Qdrant  │  │  search/      │
    └────────────┘  │  remember/    │
                    │  forget       │
                    └───────────────┘
                           │
              ┌────────────▼────────────┐
              │   Admin Console (React) │
              │   http://localhost:8096 │
              │   16 screens, REST+SSE  │
              └─────────────────────────┘

Feature depth

Slack-native capture

  • @Lore mention — answers any question with sourced Block Kit card
  • /lore slash command — same answer surface from anywhere
  • "Remember this" message shortcut — right-click any message → stored + attributed
  • Passive channel consolidation — captures decisions from ordinary messages in any channel Lore is invited to, silently, with no @mention; a 🧠 reaction marks a capture and Lore never replies (on by default; DMs excluded)
  • Daily digest — on a cadence, recaps each named channel's stored facts, activity, and open conflicts
  • File upload → Q&A — PDF, DOCX, plain text chunked (512-token, 64-overlap), embedded, retrieved identically to org facts; 📄 reaction signals readiness
  • App Home dashboard — strongest facts, fading facts, watched channels
  • Prospective memory"remind the channel when the baseline window ends June 24" — fires on the day
  • DM support — ask Lore privately; channel-membership read scoping applies

Memory engine

  • Reinforcement / decay — confirmed facts gain strength; uncorroborated facts fade from default retrieval; configurable thresholds
  • Supersession chain — Correct doesn't silently overwrite: old version stays with superseded_by pointer ("August 1 → September 15 — hospital procurement delay")
  • Conflict detection — contradicting facts go to the Conflict Queue for human resolution
  • Audit trail — every write, correct, forget logged with actor + timestamp; immutable for compliance
  • Forget with record — soft-deleted with audit; regulators can inspect

Answer quality

  • 3-tier grounding ladder — CONTEXT → HISTORY → RAG; skips later tiers when enough evidence found; reduces Qdrant calls by ~40% on well-known topics
  • Real-Time Searchassistant.search.context injects fresh Slack context at answer time; used in every answer and as the public-search stage of the research pipeline
  • 5-phase research orchestrator — Planner (LLM decomposes into sub-queries) → Public search (RTS) → Private search (Qdrant) → Synthesizer (cited answer) → Fact extractor (background write)
  • ReAct tool-calling loop — up to 6 tools: search_memory, remember_fact, get_mcp_artifact, plus the gated search_internet / fetch_url web tools; 3-strike tool disable; 10s per-tool timeout
  • Hybrid retrieval — vector similarity (Qdrant) + keyword (Postgres full-text) combined for recall + precision

Safety

  • Armor scan — PII regex (email, phone, SSN) + credential regex screen every inbound message before any LLM call; blocks prompt injection
  • Approval gateway — high-consequence requests (deploy, delete, payment) require human approval via Block Kit card; asyncio.Future bridge; 5-minute auto-reject; channel-level authorization
  • Credential masking — integration API keys never returned over the API; merge-on-update pattern (submit *** = keep stored secret)
  • Channel allowlist — restricts which channels Lore admits messages from
  • CSRF protection — double-submit cookie pattern on all mutation endpoints

Per-tenant MCP integrations

Each Slack workspace connects its own external tools independently — no shared credentials, no restart required:

Console → Connect tool → { name, command, args, env, tool, query_arg }
                                      ↓
                         MCPResolver (stdio/http/sse, 15s timeout, 2000-char cap)
                         built per-query from DB — no restart needed
                                      ↓
                         Answer cites org memory + live CRM / Linear / GitHub

Built-in test button probes the live MCP server and returns {ok, output, notices} before saving.

Admin console (React + TypeScript)

16 screens, all data-driven via /api/v1:

Screen Purpose
Overview Stats: facts, runs, conflicts, agent health
Memory Explorer Search, filter, inspect strength + status
Conflict Queue Review and resolve contradicting facts
Audit Immutable fact lifecycle log
Runs Multi-agent run history + composition
Agents CRUD for named LLM agents with system prompts
Models Register any OpenAI-compatible endpoint
Teams Router / council / auto team configurations
Integrations Per-tenant MCP server management + live test
Routing Channel → agent/team mapping
Harness Self-improving loop proposals + accept/reject
Evals Task performance history
Settings Tenant config, retention, plan

Multi-agent architecture

Lore routes every question to one of four dispatch paths:

simple          ──▶ direct retrieval + single LLM answer   (~1s)
research        ──▶ 5-phase pipeline                       (~4s)
complex         ──▶ multi-agent team (router/council/auto) (~6s)
high_consequence──▶ council deliberation + human approval  (async)

Team modes:

  • Router — orchestrator picks the best specialist agent per question
  • Council — blind review by N agents → cross-examination → verdict synthesis
  • Auto — self-configuring via the self-improving harness

Self-improving harness — after every run: judge scores the answer (0–10), tracks per-composition performance, proposes better agent/team configurations when scores drop, queues proposals for human approval in the console.


MCP — both directions

Claude Desktop ──▶ org_memory_search(query)   ──▶ Lore memory
Cursor         ──▶ org_memory_remember(text)  ──▶ Lore memory
Any MCP client ──▶ org_memory_forget(fact_id) ──▶ Lore memory

Lore ──▶ GitHub MCP server  ──▶ live repo search
Lore ──▶ Linear MCP server  ──▶ live issue search
Lore ──▶ Any MCP server     ──▶ merged into answer with org memory

One brain. Every surface your team already uses.


Potential impact

Within Slack teams: Every team of 10+ people loses institutional knowledge when Slack scrollback becomes the de-facto memory system. Lore makes capture a one-gesture habit — @Lore, /lore, a "Remember this" shortcut, or a file drop — so decisions are saved with provenance the moment they're made, instead of being re-derived months later.

Beyond Slack: Because Lore exposes memory as an MCP server, every AI tool the team uses gains the same knowledge base. A developer in Cursor asking "what did we decide about the API rate limits?" gets the same answer as someone asking @Lore in Slack. No duplication, no drift, no context switching.

Compounding value: Institutional memory compounds. Facts that survive correction become stronger. The team that uses Lore for 6 months has a searchable, attributed, non-stale knowledge graph — without any additional work.


Code quality

Metric Value
Python source ~10,000 lines across 28 modules
TypeScript source ~4,500 lines, strict mode, zero any
Test suite 809 tests (unit + integration)
Unit tests Zero live-service dependency
Integration tests Redis DB 13 + Postgres lore_test + Qdrant
Static analysis ruff (lint + format) + mypy (strict) — zero warnings
Crash-replay gate Kill-9 simulation → restart → idempotent replay → no duplicate facts
Exactly-once delivery Redis stream + XACK; admission idempotency key

Run it

Requires Python 3.12+, Node 18+, and Redis + PostgreSQL + Qdrant running locally.

git clone <repo>
cd lore
bash scripts/dev-setup.sh          # creates DBs, venv, installs deps
cp .env.example .env               # fill in Slack tokens
. .venv/bin/activate
lore db-init                       # idempotent schema
lore run                           # Socket Mode listener + worker
# Console: http://127.0.0.1:8096/console

Create the Slack app from slack-app-manifest.yml (Socket Mode), install to workspace, and set in .env:

LORE_SLACK_BOT_TOKEN=xoxb-…
LORE_SLACK_APP_TOKEN=xapp-…
LORE_MODEL_PROVIDER=openai_compat        # or: anthropic | fake
LORE_OPENAI_BASE_URL=http://127.0.0.1:8000/v1
LORE_OPENAI_API_KEY=…
# Capability flags (intent routing, RTS, vision, web search, digest, passive
# capture) are ON by default; each stays inert until its endpoint/channels are
# set. Add LORE_EMBEDDINGS_BASE_URL / LORE_VISION_BASE_URL etc. to light them up.

Full setup: docs/sandbox-testing-guide.md

Expose org memory to Claude Desktop / Cursor:

lore mcp        # MCP server (stdio default; --transport http|sse): org_memory_search / remember / forget

Tests:

pytest tests/unit                                    # no services needed
pytest tests/integration -m integration              # requires Redis + Postgres + Qdrant

Repository structure

src/lore/
├── main.py             entry point: wires all deps, starts Socket Mode + worker
├── config.py           all env-var config (dataclass, validated at startup)
├── runner.py           orchestrator: intent → dispatch → retrieval → answer
├── intake.py           durable Redis-stream admission (exactly-once)
├── store.py            memory CRUD: Postgres (facts) + Qdrant (vectors)
├── mcpio/client.py     MCP client: MCPResolver, stdio/http/sse, per-query construction
├── mcpio/server.py     MCP server: org_memory_search/remember/forget over stdio/http/sse
├── integrations.py     per-tenant MCP integration store + builder
├── rts.py              Real-Time Search API wrapper (assistant.search.context)
├── api.py              aiohttp REST API + SSE + CSRF guard (16 route groups)
├── agent/              ReAct tool loop: tools, provider, FakeToolProvider
├── approval/           approval gateway: Future bridge + Block Kit + Bolt actions
├── slackio/            Bolt event/action/shortcut handlers, Block Kit builders
├── teams/              router/council/auto team modes + harness
└── db.py               asyncpg pool + schema (CREATE TABLE IF NOT EXISTS)

src/console/src/        React 18 / TypeScript / Vite SPA
├── api/client.ts       typed API client, CSRF cookie, error handling
├── pages/              16 pages: Memory, Conflicts, Runs, Agents, Teams…
└── nav.ts              navigation manifest (path, label, icon, crumb)

tests/
├── unit/               47 test files, zero live-service dependency
└── integration/        crash-replay gate, store, API surface

Docs


License

Apache-2.0 — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured