Skip to main content
Glama
minikdj
by minikdj
README.md
# Birding Planner

MCP server + daily / on-demand email briefing for migration monitoring.
Defaults to Cincinnati, configurable for any region.

**Full specification:** [SPEC.md](SPEC.md). **Tests:** [TESTING.md](TESTING.md).
**Email rendering rules:** [routine-prompt.md](routine-prompt.md).

## MCP Server Tools

All 11 tools, used interactively from Claude Desktop:

| Tool | What it does |
|------|-------------|
| `plan_birding_trip` | Ranks nearby hotspots by recent species count + migration activity |
| `migration_forecast` | BirdCast radar data + NWS weather interpretation |
| `hotspot_details` | Recent species and notable sightings at a single hotspot |
| `compare_hotspots` | Side-by-side species comparison with iNaturalist verification |
| `species_finder` | Where a species has been seen recently near a location |
| `best_day_to_bird` | Recommends the best day in a date range using migration + weather |
| `birding_weather` | NWS overnight/morning forecast interpreted for migration prediction |
| `verify_sighting` | Cross-references eBird reports against iNaturalist photo-verified obs |
| `birding_window` | Sunrise, civil twilight, and recommended arrival time |
| `species_frequency` | Historical peak week and current phenology status via BirdCast |
| `plan_vacation_birding` | Discovery report for a travel destination: target species, top hotspots, birding window. Works weeks or months ahead using historical bar-chart data. |

Per-tool details (inputs/outputs, edge cases) are in SPEC §3.5; each tool
lives in `src/handlers/<name>.js`.

## Setup

### 1. API keys

- **eBird API key** (required): https://ebird.org/api/keygen — free
- **BirdCast API key** (required): contact https://birdcast.info
- **Resend API key** (for email): https://resend.com — 3,000 emails/month free
- **Anthropic API key** (for on-demand briefing only): console.anthropic.com

### 2. Environment

```bash
cp .env.example .env   # then fill in keys
```

Every env var is documented in SPEC §6.2.

### 3. Install dependencies

```bash
npm install
```

`ajv` is required for schema validation; `sanitize-html` for email
delivery. Both ship in `package.json` dependencies — no extra steps.

### 4. Claude Desktop integration

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "ebird-birding-planner": {
      "command": "node",
      "args": ["/absolute/path/to/ebird-birding-planner/src/index.js"],
      "env": {
        "EBIRD_API_KEY": "your_key_here",
        "BIRDCAST_API_KEY": "your_key_here",
        "EBIRD_LIFE_LIST_CSV": "/path/to/MyEBirdData.csv"
      }
    }
  }
}
```

## Daily briefing (Anthropic Routine)

Cloud-hosted scheduled agent — no machine needs to be on.

1. Routine runs at 09:00 UTC daily
2. `scripts/triage.js` outputs a JSON decision (FULL_BRIEFING /
   QUIET_PERIOD / SILENT_SKIP)
3. `scripts/aggregate.js` runs comprehensive data aggregation → single
   JSON blob (conforms to `schemas/aggregate-output.schema.json`)
4. Agent reads the JSON, writes the email body as HTML, saves to
   `./briefing-draft.json`
5. `scripts/send.js` delivers via Resend (SendGrid + disk fallbacks)

See `routine-prompt.md` for the exact prompt to paste into the Routine.
Required secrets: SPEC §6.2.

## On-demand reports (mobile)

Trigger an ad-hoc report from your iPhone via the home-screen web app
(`bird-report.html`). The page POSTs `workflow_dispatch` to
`.github/workflows/report-on-demand.yml`, which runs the same
triage → aggregate → generate-email → send pipeline with
`claude-sonnet-4-5` (Anthropic SDK, tool-use mode) writing the HTML.

The PAT stored in `localStorage` must be a **fine-grained** PAT scoped to
this repo only, Actions Read+Write. Classic PATs are not supported (see
SPEC §5.2). Workflow rate-capped at 20 dispatches per 24h.

## Local testing

```bash
npm run test:unit                                  # 171 unit tests, no keys
node scripts/test-regressions.js                   # ~30 security/contract tests
BRIEFING_TEST_FIXTURE=full_lifer npm run aggregate # offline fixture run
node scripts/aggregate.js | npm run validate:schema -- /dev/stdin
node scripts/triage.js                             # live triage (keys required)
```

Fixture scenarios: `full_lifer`, `full_rain`, `full_fallout`,
`quiet_period`, `silent_skip`. See TESTING.md.

## Architecture (post Wave 2C decomp)

```
src/
  index.js              entry: loadConfig + clients + startServer
  server.js             MCP stdio dispatch
  config.js             frozen env-var config object
  lifelist.js           JSON-cache-first life list loader
  migration-scoring.js  unified rateNight() + threshold loader
  utils.js              Cache, fetchWithRetry, resolveLocation, …
  handlers/             one file per MCP tool
    _shared.js          createContext(), InputError, helpers
    index.js            HANDLERS[] + TOOL_HANDLERS Map
    <tool>.js           { tool, handle } per tool
  *-client.js           6 external API wrappers (retry + timeout + redaction)

scripts/
  triage.js             fast decision (~10s)
  aggregate.js          comprehensive data (~25s, schema-validated)
  generate-email.js     on-demand: Anthropic tool-use → draft
  send.js               sanitize → Resend → SendGrid → disk; idempotency
  validate-schema.js    Ajv against schemas/aggregate-output.schema.json
  test-unit.js          171 tests
  test-regressions.js   ~30 security + contract invariants
  fixtures/             pre-baked triage / aggregate JSON

schemas/aggregate-output.schema.json   data contract (CI-gated)
.github/workflows/report-on-demand.yml on-demand pipeline
routine-prompt.md                       daily briefing prompt + design system
```

See SPEC.md for the full specification.

TDQS

A4/5.0

Scored across 10 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: from finding the best day, weather, and timing to hotspot comparison, species finding, and sighting verification. There is no overlapping functionality; even related tools like 'best_day_to_bird' and 'migration_forecast' serve different needs.

Naming Consistency4/5

Tool names are predominantly descriptive with a consistent verb_noun or noun_noun pattern using snake_case (e.g., 'compare_hotspots', 'species_finder'). The only minor inconsistency is 'best_day_to_bird', which uses a phrase instead, but it remains clear and does not cause confusion.

Tool Count5/5

With 10 tools, the server is well-scoped for the birding planning domain. Each tool covers a specific aspect without redundancy, and the number is neither too few nor too many for effective use by an agent.

Completeness5/5

The tool set offers comprehensive coverage of birding planning: trip planning, weather, timing, hotspot details, species frequency, migration forecasts, and sighting verification. There are no obvious gaps; users can perform end-to-end planning without dead ends.

Maintenance

ActivityInactive
ResponsivenessNo issues