# Scry

> Your Jira and Confluence, mirrored into one local SQLite file — web UI, TUI, desktop app, and agent SQL. Instant search, offline, one binary.

- **Type:** MCP server
- **Install:** `agentstack add mcp-midagedev-scry`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [midagedev](https://agentstack.voostack.com/s/midagedev)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [midagedev](https://github.com/midagedev)
- **Source:** https://github.com/midagedev/scry

## Install

```sh
agentstack add mcp-midagedev-scry
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

Ask your Jira the questions Jira can't answer.

scry mirrors Jira *and* Confluence into one local SQLite file — issues,
comments, history, wiki pages — indexed together and searchable in
milliseconds. Ask it yourself from a keyboard-driven web UI or a TUI; let your
coding agent ask in plain SQL. One binary, no server, no account.

**The mirror is a cache you can throw away.** If this project stops tomorrow,
you delete a directory and have lost nothing: Jira stays the source of truth,
and nothing you do here is stored anywhere else.

  ▶&nbsp; Open the live demo
  &nbsp;—&nbsp; 534 issues + 71 wiki pages, in your browser, right now.

  
  
  Every clip in this README is generated from a script against the committed demo snapshot —
  this one from e2e/demo/web-demo.spec.ts. What you see is what CI checks.

```bash
brew install midagedev/tap/scry

scry init && scry sync    # Jira (and Confluence) -> ~/.scry/scry.db
scry serve                # http://scry.localhost:7777
scry tui                  # same mirror, in your terminal (D toggles docs)
scry sql "select key, summary from issues_full where reopen_count > 1"
```

That last query is the point. `reopen_count` is not a Jira field — scry derives
it from the changelog while it syncs, along with `reopen_reason` and the epic a
sub-task ultimately rolls up to. Your site cannot answer "what keeps coming
back?" at all; a local mirror answers it in a line.
[`docs/RECIPES.md`](docs/RECIPES.md) has thirteen more, each verified against
the demo snapshot.

> **Status: working, pre-release.** Sync (both sources), the read API,
> write-through, the web UI, the TUI, the CLI, settings, the plugin boundary,
> and i18n are implemented and verified end to end against a live Atlassian
> site. `docs/STATE_OF_PLAY.md` is the honest inventory.

## Why

Every developer suddenly has a coding agent, and agents burn context paging
REST APIs and guessing at JQL. Worse, half of what an agent needs is not in
the tracker at all — it is in the wiki next door. A local file that holds both
answers "what do we know about X?" with one full-text query, joins across
sources, and never spends a token on pagination.

Beyond the agent, three complaints about living in a tracker and a wiki, one
root cause.

**Search is slow, and it is two searches.** Every filter change is a network
round trip against a multi-tenant service — and the answer to "what do we know
about idempotency?" is split between Jira search and Confluence search, which
do not talk to each other. Once both are on local disk there is one FTS index:
type a word, get the issues *and* the pages, instantly.

**Agents cannot read your team's context well.** A coding agent asked "what
did we already fix in the billing flow, and what did we decide in the design
doc?" has to page through two REST APIs, guess at JQL and CQL, and burn its
context on JSON envelopes. Give it a SQLite file instead and it writes one
query with a join and an FTS match. No tool schema, no pagination, no rate
limit.

**You cannot see your own team's shape.** "Which issues came back after we
closed them, and why?" is a join over the changelog. "Which epic is actually
stuck?" is a rollup over the hierarchy. In Jira neither is a question you can
ask; here they are `where reopen_count > 0` and a group-by on `epic_key`.

All three fall out of the same move: mirror the data locally, then let the UI,
the terminal, and the agent read the same store.

## Three surfaces, one store

| | For | Looks like |
| --- | --- | --- |
| **Web UI** | all-day triage — a browser tab (`scry serve`) or its own macOS window ([desktop app](docs/DESKTOP.md), no port at all) | a list you triage without the mouse (`j/k` walk, `x` multi-select, `s`/`a`/`c` status·assignee·comment in place), epic grouping and rollups, saved views, a ⌘K palette that finds issues *and* wiki pages, `/` to narrow whichever screen you are on, a freshness chip that shows the mirror's age and pulls it on click, full issue detail (rich text, comments, history, attachments), and wiki documents as a first-class citizen: recency-first lists with label chips, a filter that marks its matches, deep-linkable pages (`?doc=`), and cross-references both ways — the documents an issue's text mentions on the issue, the issues a page mentions on the page |
| **TUI** | people who live in the terminal | [`scry tui`](docs/TUI.md) — list, filter with live match highlight, `group_by=epic`, Ctrl+K palette, write actions, and `D` for the same wiki views with the same cross-references, all over the same mirror |
| **CLI + SQL** | agents, scripts, one-off questions | `scry issue`, `scry search` (issues and pages), `scry sql`, plus the file itself |

  
  
  Generated from tools/tapes/tui.tape (VHS).

Writes go through to Jira and then refresh the mirror, so the list is correct
a moment later without a full sync. Comment, transition, and assign work on
all three surfaces; field edits work in the web UI and the TUI (values always
come from what Jira allows, never free text). Issue creation is web-only
today. The wiki mirror is read-only on purpose — Confluence stays the place
where documents are written.

Hierarchy is first-class: `epic_key` is derived honestly (the nearest epic
*ancestor*, so a sub-task groups under its epic, not its story), group-by-epic
headers show the epic's actual title, an epic's detail rolls up its children
(`12 done / 14`), and both breadcrumbs — issue and document — are clickable.

So is the seam between the sources. Jira and Confluence never tell each other
what mentions what, but the text does: scry extracts issue keys from page
bodies and wiki links from issue text into an `item_refs` table while it
syncs. That is why an issue can list the design docs that cite it and a page
can list the tickets it references — a join neither product can make, and the
receipt that both really live in one database.

Attachments are local too. The first view of an image caches its bytes next to
the mirror and every later view is a disk read, so a screenshot-heavy issue
opens at the speed of the rest of the app — and keeps rendering offline.

## For agents

This is half the reason scry exists, so it has its own reference:
**[AGENTS.md](AGENTS.md)** — schema tour, query patterns, and the mistakes
that silently return nothing. [`docs/AGENT_SETUP.md`](docs/AGENT_SETUP.md) is
one paste per agent (Claude Code, Cursor, Codex, MCP). Hooking one up is one
line:

```bash
scry mcp install claude    # pins this binary and profile into the registration
```

  
  
  A real agent session — one-line MCP registration, then a live cross-source answer.
  Generated from tools/tapes/agent.tape (VHS, unscripted model output).

The interface is the database, so anything that can run a shell command has
full power:

```bash
# What keeps coming back? (reopen_count is derived here — Jira has no such field)
scry sql "select key, summary, reopen_count from issues_full
          where reopen_count > 0 order by reopened_at desc limit 20"

# Full-text across issues AND wiki pages — one index, one query
scry search "idempotency webhook"

# One issue whole, or a write straight through to Jira
scry issue NMB-140 --json
scry comment NMB-140 -m "Reproduced on staging."
```

Reads are safe by construction: `scry sql` opens the database `mode=ro`, and
MCP's `scry_query` additionally rejects anything that is not a SELECT — so an
agent can be given the mirror without being given arbitrary `sqlite3`. When
the mirror does not model an endpoint at all, [`scry api`](docs/AGENT_ACCESS.md)
passes the request through to your site: read-only unless you add `--write`,
never on MCP.

Everything can hold the file at once — WAL with one writer (the sync loop),
readers everywhere else — so `serve`, the TUI, and an agent coexist by design.

One caveat we would rather you read here than discover later: **an agent that
reads your mirror sends what it reads to whatever model it talks to.** scry
itself sends nothing anywhere ([`SECURITY.md`](SECURITY.md)), but the agent
will — scope the mirror to what the agent should see (project and space
allowlists, or a separate profile).

## Install

Atlassian Cloud only, and you need an
[API token](https://id.atlassian.com/manage-profile/security/api-tokens) — one
token covers Jira and Confluence on the same site.

**You install one thing.** There is a single binary and a single app, and the
app has the binary inside it:

```bash
brew install midagedev/tap/scry     # macOS + Linux — the CLI, the web UI, the TUI
```

or download `Scry--arm64.dmg` from the
[latest release](https://github.com/midagedev/scry/releases/latest) for the
[macOS app](docs/DESKTOP.md) — signed, notarized, sets itself up in its own
window with no terminal at any point.

If you took the app and later want an agent on the same mirror, the CLI is
already on your disk; macOS just does not put an app bundle on your `PATH`.
One command does:

```bash
/Applications/Scry.app/Contents/Resources/bin/scry install-cli
```

Then first run:

```bash
scry serve      # http://scry.localhost:7777 — setup happens in the browser
```

Other routes (install script, release archive, source build, Docker), wiki
mirroring, profiles for two sites, and the upgrade gotchas all live in
**[`docs/INSTALL.md`](docs/INSTALL.md)**.

## Making it yours

Two axes, no forking required — see **[docs/EXTENDING.md](docs/EXTENDING.md)**.

**Configuration** covers most of it, from the settings dialog or
`~/.scry/config.json`: map your custom fields (severity, environment, whatever
your site calls them), classify issues into teams by label or component, choose
which fields are inline-editable, set the staleness threshold and sync
intervals, toggle features. Most keys apply without restart; sync intervals
need a restart of `scry serve`. Full key table:
[`docs/CONFIGURATION.md`](docs/CONFIGURATION.md).

**The plugin boundary** covers the rest. The core contains zero GitHub, CD, or
test-management code on purpose. Anything else you want beside an issue — linked
pull requests, deploy status, QA context — arrives by writing rows into the
`enrichments` table and bumping a version counter, from any language on any
schedule. The server merges them; the UI surfaces them. Working examples live in
[`examples/plugins/`](examples/plugins/), and the contract is
[`docs/PLUGINS.md`](docs/PLUGINS.md).

## How it works

```mermaid
flowchart LR
  Jira["Jira Cloud REST"] -->|"incremental sync"| DB["SQLite + FTS5~/.scry/scry.db"]
  Wiki["Confluence REST"] -->|"incremental sync"| DB
  DB --> Serve["scry serve"]
  Serve --> UI["Web UI(IndexedDB cache)"]
  DB --> TUI["scry tui"]
  DB --> Agent["Coding agentsqlite3 / scry sql / MCP"]
  UI -->|"writes"| Serve
  Serve -->|"writes"| Jira
```

Sync is incremental with an overlap on the watermark, plus a reconcile pass so
deletions do not linger. Confluence needs one extra trick the API forces:
comment edits do not bump a page's version, so every incremental pass re-reads
comments for changed pages separately. Derived fields the sources do not
provide — reopen count and the reason it came back, last status change,
resolution date, clone origin, the honest `epic_key` — are computed during
sync and keyed on `statusCategory` and ids, never on a localized name.

The storage spine is source-neutral (`items` + per-kind projections + one FTS
index), which is not a slogan: Confluence merged without reshaping the
database, and the same spine is where the next source lands. See
[`docs/decisions/0006-confluence-connector.md`](docs/decisions/0006-confluence-connector.md).

### Why not a browser extension or a Forge app?

Jira Cloud deliberately sends no CORS headers on its REST API, so a static page
cannot call it. Both alternatives that avoid a local process were considered and
rejected because neither can hand a coding agent a queryable local database,
which is half the point. See `docs/decisions/0003-local-process.md`.

## Good fit / bad fit

| Use scry when… | Use Jira/Confluence directly when… |
| --- | --- |
| You search and triage the same projects every day and the latency hurts. | You need boards, sprints, reports, automation, permissions. |
| You want an agent to reason over your tracker's history *and* your wiki. | You need administration, workflow editing, or document authoring. |
| You want offline reading of everything you have access to. | A minute of staleness matters. |
| Your tracker holds tens of thousands of issues and Jira's UI struggles. | Your team is small enough that Jira already feels instant. |

**In scope:** issue fields, descriptions, comments, attachments, changelog,
links, epic hierarchy, status transitions, assignee, wiki pages (bodies,
comments, labels), full-text search across all of it, saved views, watches;
field edits and issue creation on the web UI.
**Out of scope:** boards and sprint mechanics, project administration, workflow
configuration, permission schemes, writing to the wiki, and anything requiring
Jira's own UI.
**Not a sync engine:** Jira and Confluence are the systems of record. The
mirror is disposable — delete it and re-sync.

## How it compares

- **[jira-cli](https://github.com/ankitpokhrel/jira-cli)** talks to Jira's REST
  API per command, so every listing is a network round trip and JQL is the query
  language. scry queries a local mirror: millisecond filters, SQL joins over the
  changelog, offline reads — plus a web UI and TUI over the same file. If all you
  want is "create an issue from the terminal", jira-cli is lighter.
- **Linear** is a different tracker. If your team can move, move. scry is for the
  (much larger) group whose org keeps Jira: it gives you Linear-ish speed and
  keyboard flow without asking anyone for permission — it is a mirror, not a
  migration.
- **Atlassian's Rovo MCP server** gives agents official, hosted access to the
  same data — worth using if it fits. The architectural difference: a network
  MCP cannot join issues to wiki pages, aggregate, or work offline, every call
  costs tokens and rate budget, and it answers only the questions its tools
  anticipated. A local SQLite file has none of those limits, and derived
  history (reopen counts and reasons, honest epic ancestry) exists only in the
  mirror.
- **Jira's own UI** stays the source of record and the place for boards,
  sprints, and admin. scry does not replace it; it replaces waiting on it.

## More sources later

Confluence was the proof: the second connector merged against the same spine,
the same FTS index, and the same read contracts without reshaping the database
(decision 0006). The pattern — mirror, project, index — is what the next
source rides too. Candidates are ranked by user demand, not by roadmap
romance; see [`docs/ROADMAP.md`](docs/ROADMAP.md) for what is actually next.

## Documentation

- [`docs/INSTALL.md`](docs/INSTALL.md) — every way in, first run, profiles, upgrades, Docker
- [`AGENTS.md`](AGENTS.md) — the agent reference: SQL, CLI, REST
- [`SECURITY.md`](SECURITY.md) — threat model, what leaves your machine, and where each claim lives in code
- [`MAINTENANCE.md`](MAINTENANCE.md) — who maintains this, the release cadence, and what is refused
- [`docs/FAQ.md`](docs/FAQ.md) — the hard questions: site load, one-person risk, concurrency, where agent data goes
- [`docs/AGENT_SETUP.md`](docs/AGENT_SETUP.md) — one paste per agent (Claude Code, Cursor, Codex, MCP)
- [`docs/DESKTOP.md`](docs/DESKTOP.md) — the macOS app: install, first run, and where the CLI fits
- [`docs/RECIPES.md`](docs/RECIPES.md) — 13 questions JQL cannot ask, as ready-to-run SQL
- [`docs/EXTENDING.md`](docs/EXTENDING.md) — fitting scry to your team
- [`docs/STATE_OF_PLAY.md`](docs/STATE_OF_PLAY.md) — what exists, what does not
- [`docs/CONCEPT.md`](docs/CONCEPT.md) — the product idea and the loop it optimizes
- [`docs/PAIN_POINTS.md`](docs/PAIN_POINTS.md) — the Jira complaints scry answers, with sources
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — components and data

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [midagedev](https://github.com/midagedev)
- **Source:** [midagedev/scry](https://github.com/midagedev/scry)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-midagedev-scry
- Seller: https://agentstack.voostack.com/s/midagedev
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
