Mining claim search and professional mineral exploration maps from public registries.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
One-click editor setup isnβt available for this listing yet β we donβt have a confirmed install command, and weβd rather show nothing than point your editor at the wrong package or host. Follow the projectβs own setup instructions, linked above.
Browser-based map builder for mineral exploration: search provincial claim registries, import drill/geology data, style investor-ready maps, and export them as PNG/SVG/PDF. Live at explorationmaps.com.
src/), Leaflet map engineapi/)public/
(see scripts/generate-blog.js and scripts/pseo/)package-lock.json is committed β use npm ci for reproducible installs)The serverless functions under api/ run on Vercel. For full-stack local
work use vercel dev; with plain npm run dev the claims search and
analytics endpoints are absent (the UI degrades gracefully).
| Command | What it does |
|---|---|
npm run dev | Vite dev server |
npm run build | Generates the blog, builds to dist/, copies the admin shell |
npm test | Vitest run (CI mode) |
npm run test:watch | Vitest watch mode |
npm run pseo:fixture | pSEO company-pages pipeline against fixture data |
Documented in .env.example. Summary:
Public (VITE_ β compiled into the client bundle, never secret):
VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY β Supabase project + anon key
(production-required; without them auth/cloud features disable themselves)VITE_ADMIN_EMAIL β controls admin dashboard visibility only; real
authorization is server-side (admin_users table + is_admin())Server-only secrets (set in Vercel, never referenced by client code):
SUPABASE_SERVICE_ROLE_KEY β used by /api/track for analytics ingestion.
Production-required once migration 20260710000004 is applied.ADMIN_API_SECRET β optional; unlocks the claims-API diagnostic modes in
production via the x-admin-secret header.SUPABASE_URL / SUPABASE_ANON_KEY β optional server-side aliases; the
VITE_-prefixed values are used as fallbacks by api/claims.js (Quebec)
and api/track.js.STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_MONTHLY_ID,
STRIPE_PRICE_YEARLY_ID β Pro-subscription billing (see docs/billing.md).
Until set, billing endpoints return 503 and all plan checks fail open β
safe to deploy the code before configuring Stripe./tenure-monitor)Watches a saved portfolio of B.C. mineral tenures: days remaining against each claim's good-to-date, email reminders, change detection, and one-click hand-off into the map editor. Read-only with respect to government transactions β it never touches MTO on a user's behalf.
MTA_ACQUIRED_TENURE_SVW layer, loaded by
scripts/tenure-sync/ from GitHub Actions (nightly full + twice-daily
targeted). A partial or failed government response aborts without writing,
so a bad day at the province cannot damage stored portfolios.scripts/tenure-alerts/, daily. De-duplication is a unique
database constraint rather than application logic.America/Vancouver throughout
(src/utils/tenureDates.js), never in the browser's timezone.docs/tenure-monitor.md.
User help: docs/tenure-monitor-help.md.api/)api/claims.js β multi-province claims search proxy (BC WFS, ArcGIS
provinces ON/SK/MB/NL/YT, Quebec via a self-hosted Supabase table). Full
pagination with honest meta: { totalKnown, returned, truncated, pagesFetched, provider }; rate-limited; CORS-restricted; sanitized errors.api/bc-claims.js β BC-only WFS proxy (nearby-claims bbox + legacy search).api/tenure-search.js β Tenure Monitor search over the Exploration Maps
mirror of the B.C. mineral tenure registry (tenure number, pasted list, owner
name, client number, map extent, geometry). Anonymous-safe, rate-limited, and
every response states when the mirror was last synchronized. Reads with the
ANON key under the public-read policy, never the service role.api/track.js β all analytics ingestion (page views, live-presence pings,
product/search events, landing clicks, leads). Enforces an event-name
allowlist, payload size/depth limits, and session-id shape; derives geo
from edge headers (never the body); resolves user identity from a verified
Supabase access token; writes with the service role; rate-limits per IP.
Without SUPABASE_SERVICE_ROLE_KEY it accepts-and-drops so analytics can
never break the app.api/stripe-checkout.js / api/stripe-portal.js / api/stripe-webhook.js
β Pro-subscription billing (Stripe Checkout + customer portal + the
signature-verified webhook that syncs public.user_plans). Grandfathered
accounts (pre-launch) are never downgraded. See docs/billing.md.api/_lib/ β shared helpers (pagination, request guards, esriβGeoJSON);
the underscore path means Vercel does not expose them as endpoints.Share links are /map/<id> where <id> is a client-generated
crypto.randomUUID() (a 122-bit random token). Reads go through the
get_shared_map(share_id) RPC β table-level SELECT is revoked, so
shared_maps cannot be enumerated from the public client. Old links keep
working: the id remains the lookup key.
Supabase auth (magic-link default, password fallback). Admin access is a row
in public.admin_users checked by is_admin() inside SECURITY DEFINER
reporting functions; all definer functions have a pinned search_path and
explicit execute grants. To add an admin:
src/utils/projectStorage.js: projects + the working draft live in
localStorage, deflate-compressed (gz1: prefix), with a schema version and
deterministic migrations. Corrupted records are preserved under a
.recovery key (never auto-deleted) and surfaced with manual export/discard
helpers. Writes return structured results β the UI never claims success on a
failed write. On sign-in, local projects migrate to the cloud with
per-project status + retry (src/utils/cloudMigration.js).
CSV (RFC 4180 via Papa Parse; auto-detected lat/long columns, plus azimuth,
dip and length for drill traces), GeoJSON (validated), zipped shapefiles,
loose .shp/.dbf/.prj/.shx sets (the .prj is honored β projected files are
reprojected to WGS84 via proj4), KML, KMZ (bounded: entry count, uncompressed
size, path traversal), and georeferenced images (.png/.jpg/.gif/.webp with
a world file or typed-in edges, lat/long or UTM; resampled to 2048 px and
stored in the project). Published tile ({z}/{x}/{y}) and WMS services can
be added as layers under Reference Overlays.
Canada: BC (WFS), Ontario/Saskatchewan/Manitoba/Newfoundland &
Labrador/Yukon (official ArcGIS services), Quebec (weekly-synced Supabase
mirror). United States: federal BLM MLRS claims for 11 western states,
behind VITE_ENABLE_US_CLAIMS β federal claims only, no state-managed
tenure (Alaska state claims not included); boundaries are generalized BLM
representations, not legal surveys. See docs/us-claims.md for the data
source, field mapping, and the post-deploy verification checklist.
Timestamped, additive migrations live in supabase/migrations/. The legacy
supabase-*.sql files in the repo root are the historical hand-run setup
scripts β they document existing production state; new changes go in
supabase/migrations/ only.
Apply order matters β two migrations are deploy-coupled:
| Step | Action | When |
|---|---|---|
| 1 | 20260710000001_shared_map_lookup_rpc.sql | Any time (additive) |
| 2 | 20260710000003_live_pings_read_lockdown.sql | Any time (the deployed app never reads live_pings) |
| 3 | 20260710000005_admin_authorization.sql | Any time (additive; seeds the current admin) |
| 4 | Deploy the frontend (uses get_shared_map + /api/track) and set SUPABASE_SERVICE_ROLE_KEY in Vercel | β |
| 5 | 20260710000002_shared_maps_lockdown.sql | Only after step 4 |
| 6 | 20260710000004_analytics_ingest_lockdown.sql | Only after step 4 |
Each migration header includes rollback instructions. After applying, verify
RLS as an anonymous client, a normal authenticated user, and the admin β
verification queries are embedded in ...000005.
20260901000001_shared_rate_limit.sql is additive and can be applied any
time, but until it is, the cross-instance rate limiter in api/_lib/guard.js
has nothing to call and fails open (only the per-instance limiter applies).
The send-welcome edge function must also be redeployed
(supabase functions deploy send-welcome) to pick up its lead-row check.
Pushes to main deploy via Vercel (npm run build β dist/, plus api/
functions). Rollback = redeploy the previous Vercel deployment (instant);
if a deploy-coupled migration was applied after the deploy being rolled
back, also run the rollback SQL from that migration's header.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/explorationmaps)<a href="https://allmcps.com/mcp/explorationmaps"><img src="https://allmcps.com/api/badge/explorationmaps?style=directory" alt="ExplorationMaps on AllMCPs" /></a>