birdweather-mcp 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. birdweather_mcp-0.2.2/.gitignore +41 -0
  2. birdweather_mcp-0.2.2/CHANGELOG.md +100 -0
  3. birdweather_mcp-0.2.2/LICENSE +21 -0
  4. birdweather_mcp-0.2.2/PKG-INFO +113 -0
  5. birdweather_mcp-0.2.2/README.md +78 -0
  6. birdweather_mcp-0.2.2/docs/README.md +15 -0
  7. birdweather_mcp-0.2.2/docs/assets/demo.svg +46 -0
  8. birdweather_mcp-0.2.2/docs/assets/header.jpg +0 -0
  9. birdweather_mcp-0.2.2/docs/clients.md +141 -0
  10. birdweather_mcp-0.2.2/docs/configuration.md +61 -0
  11. birdweather_mcp-0.2.2/docs/development.md +97 -0
  12. birdweather_mcp-0.2.2/docs/installation.md +87 -0
  13. birdweather_mcp-0.2.2/docs/self-hosting.md +326 -0
  14. birdweather_mcp-0.2.2/docs/tools.md +593 -0
  15. birdweather_mcp-0.2.2/docs/troubleshooting.md +34 -0
  16. birdweather_mcp-0.2.2/pyproject.toml +74 -0
  17. birdweather_mcp-0.2.2/server.json +53 -0
  18. birdweather_mcp-0.2.2/src/birdweather_mcp/__init__.py +3 -0
  19. birdweather_mcp-0.2.2/src/birdweather_mcp/__main__.py +6 -0
  20. birdweather_mcp-0.2.2/src/birdweather_mcp/auth.py +120 -0
  21. birdweather_mcp-0.2.2/src/birdweather_mcp/cache.py +119 -0
  22. birdweather_mcp-0.2.2/src/birdweather_mcp/client.py +1279 -0
  23. birdweather_mcp-0.2.2/src/birdweather_mcp/queries.py +235 -0
  24. birdweather_mcp-0.2.2/src/birdweather_mcp/server.py +710 -0
  25. birdweather_mcp-0.2.2/tests/conftest.py +14 -0
  26. birdweather_mcp-0.2.2/tests/test_analytics.py +387 -0
  27. birdweather_mcp-0.2.2/tests/test_auth.py +233 -0
  28. birdweather_mcp-0.2.2/tests/test_cache.py +138 -0
  29. birdweather_mcp-0.2.2/tests/test_client.py +424 -0
  30. birdweather_mcp-0.2.2/tests/test_live.py +85 -0
  31. birdweather_mcp-0.2.2/tests/test_prompts_resources.py +100 -0
  32. birdweather_mcp-0.2.2/tests/test_redact.py +103 -0
  33. birdweather_mcp-0.2.2/tests/test_server.py +192 -0
  34. birdweather_mcp-0.2.2/tests/test_startup_warnings.py +71 -0
  35. birdweather_mcp-0.2.2/tests/test_validation.py +136 -0
@@ -0,0 +1,41 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ dist/
9
+ wheels/
10
+ *.egg-info/
11
+ .eggs/
12
+ .venv/
13
+ venv/
14
+ ENV/
15
+
16
+ # Test / coverage
17
+ .pytest_cache/
18
+ .coverage
19
+ htmlcov/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+
23
+ # Env & secrets — never commit tokens
24
+ .env
25
+ .env.*
26
+ !.env.example
27
+
28
+ # Editors / OS
29
+ .idea/
30
+ .vscode/
31
+ *.swp
32
+ .DS_Store
33
+
34
+ # Local reference scripts (not part of the published package)
35
+ reference/
36
+
37
+ # Misc
38
+ *.db
39
+ .uv/
40
+ uv.lock
41
+ dist/
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.2] — 2026-11-14
9
+
10
+ ### Security
11
+
12
+ - Compare HTTP bearer tokens with `hmac.compare_digest`; reject websocket scopes when `MCP_AUTH_TOKEN` is set; keep only exact `/health` public.
13
+ - Raise `httpx`/`httpcore` loggers to WARNING; install a root logging filter that redacts station and MCP auth tokens (raw and URL-encoded); harden `_redact` and `_err` so unexpected errors never leak token-bearing URLs or tracebacks.
14
+ - Warn at startup when HTTP binds a non-loopback host (or `MCP_ALLOWED_HOSTS=*`) without `MCP_AUTH_TOKEN` (still starts for compatibility).
15
+ - Validate `station_id`, date windows (max 366 days), species query length, granularity/period enums, and allowlisted REST path segments; keep GraphQL values in variables.
16
+ - Run the container as non-root (`USER app`, uid 10001); add `.dockerignore`; tighten compose with `read_only`, `cap_drop: ALL`, `no-new-privileges`, and `/tmp` tmpfs.
17
+ - Pin GitHub Actions to full commit SHAs, set `permissions: contents: read`, `persist-credentials: false` on checkout, and add Dependabot for Actions/pip/Docker.
18
+ - Expand `SECURITY.md` reporting policy, response expectations, and an HTTP hardening checklist; update configuration and self-hosting docs.
19
+
20
+ ## [0.2.1] — 2026-11-14
21
+
22
+ ### Changed
23
+
24
+ - Documentation split into focused guides under `docs/` (installation, configuration, clients, tools, self-hosting, development, troubleshooting); README is a concise landing page.
25
+ - Homebrew install documented (`brew install pfrederiksen/tap/birdweather-mcp`).
26
+
27
+ ## [0.2.0] — 2026-11-14
28
+
29
+ ### Added
30
+
31
+ - MCP prompts: `daily_station_summary`, `weekly_report`, `species_deep_dive`.
32
+ - MCP resources: `birdweather://station/{station_id}` and `birdweather://station/{station_id}/species`.
33
+ - README demo illustration (`docs/assets/demo.svg`) with placeholder Example Station conversation.
34
+
35
+ ### Changed
36
+
37
+ - Version bump to 0.2.0 consolidating reliability, packaging, analytics tools, and prompts/resources.
38
+
39
+ ## [0.1.4] — 2026-11-14
40
+
41
+ ### Added
42
+
43
+ - Tools: `species_trend`, `first_of_year` / `new_arrivals`, `compare_stations`, `activity_by_hour` (with unit tests and docs/tools.md entries).
44
+ - Detection payloads include `audio_url`, species image/thumbnail URLs, and `spectrogram_url` when the API provides them.
45
+
46
+ ## [0.1.3] — 2026-11-14
47
+
48
+ ### Added
49
+
50
+ - GitHub Actions workflow to publish multi-arch Docker images to `ghcr.io/pfrederiksen/birdweather-mcp` (`latest` + SHA on `main`; semver on version tags).
51
+ - PyPI-oriented packaging metadata and a trusted-publishing release workflow on version tags (configure the publisher on pypi.org; this repo does not publish automatically until that is set up).
52
+ - Optional `MCP_AUTH_TOKEN` bearer auth for HTTP mode (`/health` stays open).
53
+ - `server.json` for MCP registry metadata and [docs/clients.md](docs/clients.md) for Claude Desktop / Cursor / uvx / HTTP configs.
54
+
55
+ ### Changed
56
+
57
+ - `docker-compose.yml` and self-hosting / Synology docs prefer pulling the prebuilt GHCR image; build-from-source remains an alternative.
58
+
59
+ ## [0.1.2] — 2026-11-14
60
+
61
+ ### Added
62
+
63
+ - In-memory TTL response cache for GraphQL and REST (`BIRDWEATHER_CACHE_TTL`, `BIRDWEATHER_CACHE_MAX_ENTRIES`, `BIRDWEATHER_CACHE_ENABLED`).
64
+ - Retries with exponential backoff and jitter on HTTP 429/5xx and timeouts (`BIRDWEATHER_MAX_RETRIES`).
65
+ - `GET /health` liveness endpoint in streamable-HTTP mode (no upstream call); Dockerfile and compose healthchecks use it.
66
+ - GitHub Actions CI: ruff + unit tests on Python 3.11–3.13 (no live tests).
67
+
68
+ ## [0.1.1] — 2026-11-14
69
+
70
+ ### Fixed
71
+
72
+ - `daily_counts` now aggregates detections into station-local calendar days (GraphQL `dailyDetectionCounts` buckets by UTC and can return an extra day when `from == to`). Rows outside the requested range are omitted; quiet days are included with `total: 0`.
73
+
74
+ ### Added
75
+
76
+ - `MCP_ALLOWED_HOSTS` for streamable-HTTP Host-header allowlisting (comma-separated, or `*` on trusted networks) to avoid `421 Invalid Host header` when clients use LAN/MagicDNS names.
77
+
78
+ ### Changed
79
+
80
+ - Synology self-hosting docs: off-NAS `linux/arm64` buildx + image import, `env_file` for tokens, LAN bind + MagicDNS, Container Manager / error 2202 notes, free-port and folder-layout examples.
81
+
82
+ ## [0.1.0] — 2026-11-14
83
+
84
+ ### Added
85
+
86
+ - MCP server with GraphQL tools: `get_station`, `station_counts`, `get_weather`, `recent_detections`, `top_species` / `species_list`, `daily_counts`, `species_info`, `search_species`, `search_stations`.
87
+ - Optional `BIRDWEATHER_STATION_TOKEN` for station REST detections and all-time stats (token never logged).
88
+ - Transports: `stdio` (default), `streamable-http`, `sse`.
89
+ - Dockerfile (`python:3.12-slim`, multi-arch friendly) and `docker-compose.yml` for long-lived HTTP hosting.
90
+ - Docs: README, self-hosting guide, tool reference with live samples, contributing, security policy.
91
+ - Pytest suite with mocked unit tests and optional `@pytest.mark.live` smoke (set `BIRDWEATHER_TEST_STATION_ID`).
92
+
93
+ [0.2.2]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.2.2
94
+ [0.2.1]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.2.1
95
+ [0.2.0]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.2.0
96
+ [0.1.4]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.1.4
97
+ [0.1.3]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.1.3
98
+ [0.1.2]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.1.2
99
+ [0.1.1]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.1.1
100
+ [0.1.0]: https://github.com/pfrederiksen/birdweather-mcp/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paul Frederiksen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.5
2
+ Name: birdweather-mcp
3
+ Version: 0.2.2
4
+ Summary: Self-hostable MCP server for BirdWeather stations (detections, species, stats).
5
+ Project-URL: Homepage, https://github.com/pfrederiksen/birdweather-mcp
6
+ Project-URL: Documentation, https://github.com/pfrederiksen/birdweather-mcp#readme
7
+ Project-URL: Repository, https://github.com/pfrederiksen/birdweather-mcp
8
+ Project-URL: Issues, https://github.com/pfrederiksen/birdweather-mcp/issues
9
+ Project-URL: Changelog, https://github.com/pfrederiksen/birdweather-mcp/blob/main/CHANGELOG.md
10
+ Author-email: Paul Frederiksen <pfrederiksen@users.noreply.github.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: birdnet,birds,birdweather,mcp,model-context-protocol
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: Science/Research
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: mcp<2,>=1.9
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
31
+ Requires-Dist: pytest>=8; extra == 'dev'
32
+ Requires-Dist: respx>=0.21; extra == 'dev'
33
+ Requires-Dist: ruff>=0.17; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ <p align="center">
37
+ <img src="docs/assets/header.jpg" alt="birdweather-mcp" width="100%" />
38
+ </p>
39
+
40
+ <p align="center"><em>Ask your AI about the birds your station is hearing — detections, species, and stats via MCP.</em></p>
41
+
42
+ <p align="center">
43
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License" /></a>
44
+ <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+" /></a>
45
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-compatible-green.svg" alt="MCP compatible" /></a>
46
+ <a href="docs/self-hosting.md"><img src="https://img.shields.io/badge/docker-ready-2496ED.svg" alt="Docker ready" /></a>
47
+ </p>
48
+
49
+ # birdweather-mcp
50
+
51
+ Self-hostable [MCP](https://modelcontextprotocol.io) server for [BirdWeather](https://www.birdweather.com). Point Claude, Cursor, or any MCP client at your (or any public) station and ask natural-language questions about what was detected, what’s trending, and what’s nearby.
52
+
53
+ Works out of the box against the **public GraphQL API** — no account required. Optionally set a **station token** for richer REST fields. **The token is never logged or echoed.**
54
+
55
+ ## Features
56
+
57
+ - **15 MCP tools** — station info, counts, weather, detections, top species, daily series, species trends, new arrivals, station compare, hourly activity, species search/profiles, nearby stations
58
+ - **Prompts & resources** — daily/weekly summaries, species deep-dives, and `birdweather://station/…` URIs
59
+ - **No auth required** for public GraphQL; optional `BIRDWEATHER_STATION_TOKEN` for REST
60
+ - **stdio** (Claude Desktop / Cursor) or **streamable-HTTP** (Docker / Synology / Tailscale)
61
+ - **Token-safe** — redacted in logs and errors ([SECURITY.md](SECURITY.md))
62
+ - **Docker + compose** — prebuilt multi-arch images on GHCR (`ghcr.io/pfrederiksen/birdweather-mcp`)
63
+
64
+ ## Quickstart
65
+
66
+ **uvx** (no clone):
67
+
68
+ ```bash
69
+ uvx birdweather-mcp
70
+ ```
71
+
72
+ **Homebrew:**
73
+
74
+ ```bash
75
+ brew install pfrederiksen/tap/birdweather-mcp
76
+ birdweather-mcp
77
+ ```
78
+
79
+ **Docker** (stdio):
80
+
81
+ ```bash
82
+ docker pull ghcr.io/pfrederiksen/birdweather-mcp:latest
83
+ docker run --rm -i ghcr.io/pfrederiksen/birdweather-mcp:latest
84
+ ```
85
+
86
+ Long-lived HTTP on a NAS → [Self-hosting](docs/self-hosting.md). More install paths → [Installation](docs/installation.md).
87
+
88
+ Configure Claude Desktop / Cursor / VS Code → [Clients](docs/clients.md).
89
+
90
+ ## Documentation
91
+
92
+ | Guide | Description |
93
+ |-------|-------------|
94
+ | [docs/README.md](docs/README.md) | Index of all guides |
95
+ | [Installation](docs/installation.md) | uvx, pip, Homebrew, Docker/GHCR, from source |
96
+ | [Configuration](docs/configuration.md) | Environment variables, station ID/token |
97
+ | [Clients](docs/clients.md) | Claude Desktop, Cursor, Claude Code, VS Code, HTTP |
98
+ | [Tools](docs/tools.md) | Tools, prompts, and resources |
99
+ | [Self-hosting](docs/self-hosting.md) | Docker, Synology/arm64, LAN/Tailscale, updates |
100
+ | [Development](docs/development.md) | Dev setup, tests, lint, release process |
101
+ | [Troubleshooting](docs/troubleshooting.md) | Common problems and FAQ |
102
+
103
+ ## Demo
104
+
105
+ <p align="center">
106
+ <img src="docs/assets/demo.svg" alt="Demo conversation about Example Station 12345" width="100%" />
107
+ </p>
108
+
109
+ Placeholder illustration of asking an MCP client about **Example Station** (`12345`) — not live data.
110
+
111
+ ## License
112
+
113
+ Licensed under [MIT](LICENSE). See also [CHANGELOG.md](CHANGELOG.md), [CONTRIBUTING.md](CONTRIBUTING.md), and [SECURITY.md](SECURITY.md).
@@ -0,0 +1,78 @@
1
+ <p align="center">
2
+ <img src="docs/assets/header.jpg" alt="birdweather-mcp" width="100%" />
3
+ </p>
4
+
5
+ <p align="center"><em>Ask your AI about the birds your station is hearing — detections, species, and stats via MCP.</em></p>
6
+
7
+ <p align="center">
8
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License" /></a>
9
+ <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+" /></a>
10
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-compatible-green.svg" alt="MCP compatible" /></a>
11
+ <a href="docs/self-hosting.md"><img src="https://img.shields.io/badge/docker-ready-2496ED.svg" alt="Docker ready" /></a>
12
+ </p>
13
+
14
+ # birdweather-mcp
15
+
16
+ Self-hostable [MCP](https://modelcontextprotocol.io) server for [BirdWeather](https://www.birdweather.com). Point Claude, Cursor, or any MCP client at your (or any public) station and ask natural-language questions about what was detected, what’s trending, and what’s nearby.
17
+
18
+ Works out of the box against the **public GraphQL API** — no account required. Optionally set a **station token** for richer REST fields. **The token is never logged or echoed.**
19
+
20
+ ## Features
21
+
22
+ - **15 MCP tools** — station info, counts, weather, detections, top species, daily series, species trends, new arrivals, station compare, hourly activity, species search/profiles, nearby stations
23
+ - **Prompts & resources** — daily/weekly summaries, species deep-dives, and `birdweather://station/…` URIs
24
+ - **No auth required** for public GraphQL; optional `BIRDWEATHER_STATION_TOKEN` for REST
25
+ - **stdio** (Claude Desktop / Cursor) or **streamable-HTTP** (Docker / Synology / Tailscale)
26
+ - **Token-safe** — redacted in logs and errors ([SECURITY.md](SECURITY.md))
27
+ - **Docker + compose** — prebuilt multi-arch images on GHCR (`ghcr.io/pfrederiksen/birdweather-mcp`)
28
+
29
+ ## Quickstart
30
+
31
+ **uvx** (no clone):
32
+
33
+ ```bash
34
+ uvx birdweather-mcp
35
+ ```
36
+
37
+ **Homebrew:**
38
+
39
+ ```bash
40
+ brew install pfrederiksen/tap/birdweather-mcp
41
+ birdweather-mcp
42
+ ```
43
+
44
+ **Docker** (stdio):
45
+
46
+ ```bash
47
+ docker pull ghcr.io/pfrederiksen/birdweather-mcp:latest
48
+ docker run --rm -i ghcr.io/pfrederiksen/birdweather-mcp:latest
49
+ ```
50
+
51
+ Long-lived HTTP on a NAS → [Self-hosting](docs/self-hosting.md). More install paths → [Installation](docs/installation.md).
52
+
53
+ Configure Claude Desktop / Cursor / VS Code → [Clients](docs/clients.md).
54
+
55
+ ## Documentation
56
+
57
+ | Guide | Description |
58
+ |-------|-------------|
59
+ | [docs/README.md](docs/README.md) | Index of all guides |
60
+ | [Installation](docs/installation.md) | uvx, pip, Homebrew, Docker/GHCR, from source |
61
+ | [Configuration](docs/configuration.md) | Environment variables, station ID/token |
62
+ | [Clients](docs/clients.md) | Claude Desktop, Cursor, Claude Code, VS Code, HTTP |
63
+ | [Tools](docs/tools.md) | Tools, prompts, and resources |
64
+ | [Self-hosting](docs/self-hosting.md) | Docker, Synology/arm64, LAN/Tailscale, updates |
65
+ | [Development](docs/development.md) | Dev setup, tests, lint, release process |
66
+ | [Troubleshooting](docs/troubleshooting.md) | Common problems and FAQ |
67
+
68
+ ## Demo
69
+
70
+ <p align="center">
71
+ <img src="docs/assets/demo.svg" alt="Demo conversation about Example Station 12345" width="100%" />
72
+ </p>
73
+
74
+ Placeholder illustration of asking an MCP client about **Example Station** (`12345`) — not live data.
75
+
76
+ ## License
77
+
78
+ Licensed under [MIT](LICENSE). See also [CHANGELOG.md](CHANGELOG.md), [CONTRIBUTING.md](CONTRIBUTING.md), and [SECURITY.md](SECURITY.md).
@@ -0,0 +1,15 @@
1
+ # Documentation
2
+
3
+ Guides for installing, configuring, and running [birdweather-mcp](../README.md).
4
+
5
+ | Guide | Description |
6
+ |-------|-------------|
7
+ | [Installation](installation.md) | uvx, pip, Homebrew, Docker/GHCR, from source |
8
+ | [Configuration](configuration.md) | Environment variables, defaults, station ID/token |
9
+ | [Clients](clients.md) | Claude Desktop, Cursor, Claude Code, VS Code, HTTP |
10
+ | [Tools](tools.md) | MCP tools, prompts, and resources |
11
+ | [Self-hosting](self-hosting.md) | Docker, compose, Synology/arm64, LAN/Tailscale |
12
+ | [Development](development.md) | Dev setup, tests, lint, release process |
13
+ | [Troubleshooting](troubleshooting.md) | Common problems and FAQ |
14
+
15
+ Also see [SECURITY.md](../SECURITY.md), [CHANGELOG.md](../CHANGELOG.md), and [CONTRIBUTING.md](../CONTRIBUTING.md).
@@ -0,0 +1,46 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540" role="img" aria-labelledby="title desc">
2
+ <title id="title">birdweather-mcp demo conversation</title>
3
+ <desc id="desc">Example chat asking about Example Station 12345 detections with placeholder data.</desc>
4
+ <defs>
5
+ <linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
6
+ <stop offset="0%" stop-color="#1a2f28"/>
7
+ <stop offset="55%" stop-color="#243f36"/>
8
+ <stop offset="100%" stop-color="#3d5a4c"/>
9
+ </linearGradient>
10
+ <linearGradient id="panel" x1="0" y1="0" x2="0" y2="1">
11
+ <stop offset="0%" stop-color="#f7f3ea"/>
12
+ <stop offset="100%" stop-color="#ebe4d6"/>
13
+ </linearGradient>
14
+ <filter id="soft" x="-10%" y="-10%" width="120%" height="120%">
15
+ <feDropShadow dx="0" dy="8" stdDeviation="12" flood-color="#0b1612" flood-opacity="0.35"/>
16
+ </filter>
17
+ </defs>
18
+
19
+ <rect width="960" height="540" fill="url(#bg)"/>
20
+ <!-- soft foliage shapes -->
21
+ <circle cx="70" cy="480" r="120" fill="#2f4a3f" opacity="0.55"/>
22
+ <circle cx="900" cy="40" r="140" fill="#2a4439" opacity="0.45"/>
23
+ <circle cx="820" cy="500" r="90" fill="#4a6b58" opacity="0.25"/>
24
+
25
+ <text x="48" y="52" fill="#d8e5dd" font-family="Georgia, 'Times New Roman', serif" font-size="28" font-weight="700">birdweather-mcp</text>
26
+ <text x="48" y="78" fill="#a9c0b4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13">Ask your AI what station 12345 has been hearing</text>
27
+
28
+ <rect x="48" y="108" width="864" height="380" rx="18" fill="url(#panel)" filter="url(#soft)"/>
29
+
30
+ <!-- user bubble -->
31
+ <rect x="420" y="140" width="460" height="64" rx="14" fill="#2f5d4a"/>
32
+ <text x="440" y="168" fill="#f4faf6" font-family="ui-sans-serif, system-ui, sans-serif" font-size="15">What has Example Station been hearing this week?</text>
33
+ <text x="440" y="188" fill="#c5ddd2" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">station_id 12345 · last 7 days</text>
34
+
35
+ <!-- assistant bubble -->
36
+ <rect x="80" y="230" width="620" height="210" rx="14" fill="#ffffff" stroke="#d7cfbf"/>
37
+ <text x="100" y="258" fill="#1f2a24" font-family="Georgia, 'Times New Roman', serif" font-size="16" font-weight="700">Assistant</text>
38
+ <text x="100" y="286" fill="#334038" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14">Called top_species + station_counts for Example Station.</text>
39
+ <text x="100" y="312" fill="#334038" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14">• House Finch — 273 detections</text>
40
+ <text x="100" y="334" fill="#334038" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14">• Anna&#39;s Hummingbird — 51</text>
41
+ <text x="100" y="356" fill="#334038" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14">• ~497 detections · 31 species</text>
42
+ <text x="100" y="386" fill="#5b6b62" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">Timezone America/Los_Angeles · placeholder sample data</text>
43
+ <text x="100" y="412" fill="#2f5d4a" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">soundscape.url available on recent_detections when present</text>
44
+
45
+ <text x="48" y="520" fill="#8eaa9b" font-family="ui-sans-serif, system-ui, sans-serif" font-size="11">Demo illustration · no live station data</text>
46
+ </svg>
@@ -0,0 +1,141 @@
1
+ # MCP client configurations
2
+
3
+ Configure Claude Desktop, Cursor, and other MCP clients to talk to birdweather-mcp over **stdio** (local process), **uvx** / Homebrew, or **streamable-HTTP** (self-hosted Docker / NAS).
4
+
5
+ Use placeholder station id `12345` in prompts. Never put a real `BIRDWEATHER_STATION_TOKEN` or `MCP_AUTH_TOKEN` in committed files. Env reference: [configuration.md](configuration.md). Install paths: [installation.md](installation.md).
6
+
7
+ ## stdio via uvx (recommended for desktop clients)
8
+
9
+ ```json
10
+ {
11
+ "mcpServers": {
12
+ "birdweather": {
13
+ "command": "uvx",
14
+ "args": ["birdweather-mcp"]
15
+ }
16
+ }
17
+ }
18
+ ```
19
+
20
+ From git:
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "birdweather": {
26
+ "command": "uvx",
27
+ "args": ["--from", "git+https://github.com/pfrederiksen/birdweather-mcp", "birdweather-mcp"]
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## stdio via Homebrew
34
+
35
+ After `brew install pfrederiksen/tap/birdweather-mcp`:
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "birdweather": {
41
+ "command": "birdweather-mcp"
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ Optional env:
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "birdweather": {
53
+ "command": "uvx",
54
+ "args": ["birdweather-mcp"],
55
+ "env": {
56
+ "BIRDWEATHER_STATION_TOKEN": ""
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## stdio via local checkout
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "birdweather": {
69
+ "command": "uv",
70
+ "args": ["run", "--directory", "/absolute/path/to/birdweather-mcp", "birdweather-mcp"]
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ## Claude Desktop
77
+
78
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the Windows equivalent. Use either uvx block above under `mcpServers`.
79
+
80
+ ## Cursor
81
+
82
+ Project `.cursor/mcp.json` or Cursor MCP settings — same `mcpServers` shape as Claude Desktop.
83
+
84
+ ## Claude Code
85
+
86
+ ```bash
87
+ claude mcp add birdweather -- uvx birdweather-mcp
88
+ # or from git:
89
+ claude mcp add birdweather -- uvx --from git+https://github.com/pfrederiksen/birdweather-mcp birdweather-mcp
90
+ ```
91
+
92
+ ## VS Code
93
+
94
+ `.vscode/mcp.json`:
95
+
96
+ ```json
97
+ {
98
+ "servers": {
99
+ "birdweather": {
100
+ "type": "stdio",
101
+ "command": "uvx",
102
+ "args": ["birdweather-mcp"]
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## streamable-HTTP (Docker / Synology / LAN)
109
+
110
+ Run the server (see [self-hosting.md](self-hosting.md)), then point the client at `/mcp`:
111
+
112
+ ```json
113
+ {
114
+ "mcpServers": {
115
+ "birdweather": {
116
+ "url": "http://127.0.0.1:8000/mcp"
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ If `MCP_AUTH_TOKEN` is set on the server, send a bearer header (exact client support varies):
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "birdweather": {
128
+ "url": "http://127.0.0.1:8000/mcp",
129
+ "headers": {
130
+ "Authorization": "Bearer <your-mcp-auth-token>"
131
+ }
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ `GET /health` stays unauthenticated for probes. Prefer LAN / Tailscale over public exposure — see [SECURITY.md](../SECURITY.md).
138
+
139
+ ## Registry metadata
140
+
141
+ [`server.json`](../server.json) describes this server for the official MCP registry (PyPI + GHCR package entries). Publishing to the registry is a separate step after PyPI/GHCR packages exist.
@@ -0,0 +1,61 @@
1
+ # Configuration
2
+
3
+ All settings are environment variables (or CLI flags that mirror the transport trio). Copy [`.env.example`](../.env.example) for a local template. **Never commit real tokens.**
4
+
5
+ ## Environment variables
6
+
7
+ | Variable | Required | Default | Description |
8
+ |----------|----------|---------|-------------|
9
+ | `BIRDWEATHER_STATION_TOKEN` | No | unset | Station API token for REST detections / all-time stats. **Never logged.** Without it, public GraphQL only. |
10
+ | `MCP_TRANSPORT` | No | `stdio` | `stdio`, `streamable-http`, or `sse`. Overridable with `--transport`. |
11
+ | `MCP_HOST` | No | `127.0.0.1` | Bind host for HTTP transports. Overridable with `--host`. Inside Docker use `0.0.0.0` and restrict with host port publish (prefer `127.0.0.1` or LAN-only on the host). Non-loopback bind without `MCP_AUTH_TOKEN` logs a SECURITY warning. |
12
+ | `MCP_PORT` | No | `8000` | Bind port for HTTP transports. Overridable with `--port`. |
13
+ | `MCP_ALLOWED_HOSTS` | No | unset (loopback only) | Comma-separated Host header patterns for streamable-HTTP DNS-rebinding protection (e.g. `nas.example.local:*,192.168.1.10:*`). Unset = FastMCP loopback defaults. `*` = allow any host (**trusted networks only**; warns if `MCP_AUTH_TOKEN` is unset). Fixes `421 Invalid Host header` for MagicDNS/LAN names. |
14
+ | `MCP_AUTH_TOKEN` | No | unset | When set, HTTP `/mcp` requires `Authorization: Bearer …` (constant-time compare). Exact `/health` stays open; websockets are rejected. Strongly recommended for non-loopback HTTP. Never logged. |
15
+ | `BIRDWEATHER_CACHE_TTL` | No | `60` | In-memory upstream cache TTL in seconds. Set `0` to disable. |
16
+ | `BIRDWEATHER_CACHE_MAX_ENTRIES` | No | `256` | Max cached GraphQL/REST responses. |
17
+ | `BIRDWEATHER_CACHE_ENABLED` | No | enabled when TTL &gt; 0 | Set `false` / `0` / `no` / `off` to disable caching; `true` / `1` / `yes` / `on` to force on. |
18
+ | `BIRDWEATHER_MAX_RETRIES` | No | `5` | Retries with exponential backoff + jitter on HTTP 429/5xx and timeouts (minimum effective value `1`). |
19
+ | `BIRDWEATHER_TEST_STATION_ID` | No | unset | Public station id for optional live pytest (`pytest -m live`). Prefer shell-only; do not commit a personal id. |
20
+
21
+ ### Logging
22
+
23
+ The server logs to stderr at **INFO** with format `%(levelname)s %(name)s: %(message)s`. There is no log-level env var today. Station and MCP auth tokens are **never** written to logs or tool/error payloads (raw and URL-encoded forms are redacted via a logging filter; `httpx`/`httpcore` are set to WARNING so request URLs are not printed). See [SECURITY.md](../SECURITY.md).
24
+
25
+ ### Health endpoint
26
+
27
+ In `streamable-http` mode, `GET /health` returns `{"status":"ok","version":"..."}` with **no** upstream BirdWeather call. Used by Docker/compose healthchecks. Unaffected by `MCP_AUTH_TOKEN` (exact path only — `/health/../mcp` is not public).
28
+
29
+ ## Finding a station ID and token
30
+
31
+ **Station ID** (public, numeric — docs use `12345`):
32
+
33
+ 1. Open your station on [app.birdweather.com](https://app.birdweather.com) (web) or in the BirdWeather app.
34
+ 2. Check the URL: `https://app.birdweather.com/stations/<id>` — that number is `station_id`.
35
+ 3. Or search by name/coords with the `search_stations` tool once the server is running.
36
+
37
+ **Station token** (secret — optional):
38
+
39
+ 1. In the BirdWeather app or web UI, open **your** station’s settings.
40
+ 2. Find the **API / token** section (used for `https://app.birdweather.com/api/v1/stations/<token>/...`).
41
+ 3. Copy into `BIRDWEATHER_STATION_TOKEN` in MCP config or `.env` — never commit it.
42
+
43
+ Without a token, all GraphQL tools still work for any public station. With a token, `get_station` can include all-time REST stats and `recent_detections` prefers REST (extra fields).
44
+
45
+ ## CLI flags
46
+
47
+ ```bash
48
+ birdweather-mcp --transport streamable-http --host 127.0.0.1 --port 8000
49
+ ```
50
+
51
+ | Flag | Env equivalent |
52
+ |------|----------------|
53
+ | `--transport` | `MCP_TRANSPORT` |
54
+ | `--host` | `MCP_HOST` |
55
+ | `--port` | `MCP_PORT` |
56
+
57
+ ## Related
58
+
59
+ - [Clients](clients.md) — where to put env in Claude / Cursor / HTTP
60
+ - [Self-hosting](self-hosting.md) — Docker, Synology, `MCP_ALLOWED_HOSTS`
61
+ - [Troubleshooting](troubleshooting.md)