SkimGuard MCP Server
SkimGuard runs a Model Context Protocol server. Point Claude, ChatGPT, Perplexity, or any MCP client at it and your assistant can answer "is the Shell on Riverside safe to use my card at?" from real scan data instead of guessing — by name, no Google Place ID required.
The public tier is free, unauthenticated, and read-only. No signup, no API key, no waiting list — it exists so assistants can find the answer.
What it is
MCP is the open standard for giving an AI assistant real tools. The SkimGuard MCP server exposes our scan corpus — status for a place found by name or by Google Place ID, nearby activity, risk on the road ahead, Bluetooth manufacturer identification, and network-wide coverage — as tools an assistant can call mid-conversation. It is a single stateless HTTPS endpoint; there is nothing to install and nothing to run locally. The corpus covers any place with a payment terminal — gas pumps, ATMs, and checkout lanes, and equally bars, restaurants, stadiums, and festival grounds — so a lookup works for a night out as readily as for a fill-up.
The safety-lookup tools need no credential at all. Anonymous callers get 30 requests per minute against the same live data everything else reads.
There are no write tools on the server — not gated ones, none. Every tool is annotated read-only and idempotent.
Residential scans are never published. A public lookup is checked against the public-location allowlist before any aggregate is returned, so a home address can't be queried out of the corpus.
The server registers only the tools your credential's tier allows. A caller cannot invoke — or even enumerate — a tool above their tier.
SkimGuard detects skimmers that transmit a Bluetooth signal. A clear result is not a guarantee that a terminal is safe — the tools return that caveat with every answer, so assistants repeat it too.
Quick test
Two ways in. Paste the config into your MCP client, or run the curl calls below — the public tier is unauthenticated, so both work on a machine that has never heard of SkimGuard.
Hosted assistants add a remote MCP server from a settings screen — there is no file to edit. Open your assistant's Connectors / MCP servers settings, choose to add a custom or remote server, and paste the URL below. The public tier needs no credential, so it connects immediately.
https://mcp.skimguard.io/mcp
Give it any name you like (“SkimGuard”) and leave authentication set to none — the public tools connect straight away. When you later ask for data from your own account, the server prompts you to sign in. If the screen offers a transport choice, pick HTTP / Streamable HTTP — not SSE, and not stdio.
Paid tiers in hosted assistants: sign in. Claude.ai, ChatGPT and similar connectors can't attach a custom header, so a paid key won't travel there. They don't need one — SkimGuard supports OAuth 2.1. Add the server by URL, then ask for something from your own account (“how are my locations doing?”). The server answers with an authentication challenge, your assistant offers to connect your SkimGuard account, and once you approve, your Business, Partner or Data Licensee tools appear. The free public tools keep working throughout, signed in or not. In clients that do support headers — Claude Desktop, Claude Code, Cursor — an X-MCP-Key works too; use whichever suits you.
Desktop and editor clients read an mcpServers block from a JSON file. Drop the config below into yours and restart the client — the SkimGuard tools appear in the tool list.
| Client | Config file |
|---|---|
| Claude Desktop · macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop · Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Desktop · Linux | ~/.config/Claude/claude_desktop_config.json |
| Claude Code | .mcp.json in the project root (or claude mcp add) |
| Cursor | .cursor/mcp.json in the project, or ~/.cursor/mcp.json globally |
| Other MCP clients | Any file holding an mcpServers block |
{
"mcpServers": {
"skimguard": {
"url": "https://mcp.skimguard.io/mcp"
}
}
}
Holding a paid key? Add it as a header. The server also accepts a Firebase ID token as Authorization: Bearer <token> if you are calling from an authenticated SkimGuard portal session.
{
"mcpServers": {
"skimguard": {
"url": "https://mcp.skimguard.io/mcp",
"headers": { "X-MCP-Key": "YOUR_KEY_HERE" }
}
}
}
The endpoint speaks JSON-RPC 2.0 over the MCP Streamable HTTP transport. It is stateless, so you do not need an initialize handshake first. The Accept header is required and must list both application/json and text/event-stream — the transport returns 406 without it.
curl -s https://mcp.skimguard.io/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Start here — this is the one you can run with nothing but a place name. skimguard_search_locations resolves the name first, then reports SkimGuard's scan status for each match, so a single call goes from "the Shell on Riverside" to an answer. Passing latitude/longitude is optional but sharply improves matching on common brand names.
curl -s https://mcp.skimguard.io/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
"name":"skimguard_search_locations",
"arguments":{"query":"Shell gas station Riverside Austin TX",
"latitude":30.2453,"longitude":-97.7431,
"limit":5,"days":30,"response_format":"markdown"}}}'
curl -s https://mcp.skimguard.io/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"skimguard_coverage_stats",
"arguments":{"days":30,"response_format":"markdown"}}}'
curl -s https://mcp.skimguard.io/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{
"name":"skimguard_get_location_status",
"arguments":{"placeId":"ChIJN1t_tDeuEmsRUsoyG83frY4",
"days":30,"response_format":"json"}}}'
Swap in the Google Place ID of a location you care about. If SkimGuard has no data for it yet you get a plain "no data" answer — that means unknown, not unsafe. Private residences are deliberately excluded from public data and always answer that way.
curl -s https://mcp.skimguard.io/health
What it supports
Seven public tools, then four more for Business, two for Partner, and two for Data Licensee. Every tool takes an optional response_format of markdown (default) or json, and every windowed tool takes days (1–365, default 30). All fifteen are read-only.
| Tool | Tier | What it does | Key parameters |
|---|---|---|---|
| Public — free, no credential, 30 req/min · every tier keeps these | |||
| skimguard_search_locations | Public | "Is the Shell on Riverside safe?" Finds a place by name or address and reports SkimGuard's scan status for each match in the same call — the tool to use when you have a name rather than a Place ID. Locations with no data are reported as unknown, never as unsafe. | query (required, 3–120 chars), latitude + longitude (optional bias — sharply improves matching on common brand names), limit (1–8, default 5), days |
| skimguard_get_location_status | Public | Skimmer scan status for one location you already have the Google Place ID for: how recently it was scanned, how many scans, and whether anything suspicious was seen. | placeId (required), days |
| skimguard_find_nearby_activity | Public | "Any skimmers reported near me?" Publicly visible locations near a point that have been scanned recently, with suspicious-detection counts. | latitude, longitude, radius_meters (50–50 000, default 2 000), days, limit |
| skimguard_route_risk | Public | Locations with recent suspicious activity or stale coverage along the road ahead. This is a lookahead, not a whole-trip planner: at most 20 km of the route you supply is examined, and the response states how much it actually checked. Pass real route geometry from a directions provider — a bare start and end point checks a straight line that will not follow the road. | polyline (required, 2–100 ordered points, start first), corridor_meters (10–200, default 50), lookahead_meters (100–20 000, default 5 000) |
| skimguard_lookup_bluetooth_manufacturer | Public | Resolves a Bluetooth SIG company identifier to a manufacturer name and SkimGuard risk rating — what a device seen in a scan actually is. | company_code (decimal or 0x-hex) |
| skimguard_coverage_stats | Public | Network-wide aggregates over a window: total scans, suspicious detections, distinct locations, states covered. | days |
| skimguard_about | Public | Authoritative description of SkimGuard, how detection works, and its limitations. Grounding — call it before answering general questions so the answer is current. | none |
| Business — paid key, 120 req/min · scoped to your own locations and hardware | |||
| skimguard_my_locations | Business | Scan coverage across your locations — counts, suspicious detections, and last-scanned per location. | days, limit |
| skimguard_my_stale_locations | Business | "Where do I send someone next?" Which of your locations are overdue for a scan, worst-first, with never-scanned listed first — plus each one's freshness tier and how long it has been. | stale_after_hours (1–8 760, default 72), limit |
| skimguard_my_scanner_health | Business | "Are my scanners actually working?" Online/offline state for your always-on agents and enrolled handhelds, when each last reported, and its last scan result. A silent agent is a silent failure — the location looks covered but is not. | offline_after_minutes (5–1 440, default 60), limit |
| skimguard_location_devices | Business | "What did SkimGuard actually see at my store?" Every device witnessed at one of your locations, grouped by name, manufacturer and transport (BLE / Bluetooth Classic / Zigbee), with sighting counts, signal strength and which detection rule matched. The Place ID must belong to your business; any other is refused. | place_id (required — one of yours), suspicious_only (default false), days, limit |
| Partner — paid key, 120 req/min · scoped to your own reseller account | |||
| skimguard_my_merchants | Partner | Scan volume for the merchants attributed to your reseller account — per-merchant counts, locations covered, last activity. | days, limit |
| skimguard_my_earnings | Partner | "Where is my money?" Your commission ledger — totals by pending / paid / voided, recent rows, merchants whose subscription has lapsed, and, first, whether your payouts are blocked. Commissions only transfer once Stripe has verified your bank details and business identity, so a growing pending balance usually means onboarding is unfinished. | days, limit |
| Data Licensee — paid key, 300 req/min · aggregate corpus, outranks Business and Partner | |||
| skimguard_regional_risk | Data Licensee | Aggregate skimmer risk by US state, ranked by suspicious activity. Aggregate only — no location, business, or user identifiers; states under 5 scans in the window are suppressed. | days, limit |
| skimguard_device_prevalence | Data Licensee | What hardware is out there. Aggregate trends across every device SkimGuard has witnessed — the transport mix (BLE / Bluetooth Classic / Zigbee) and the top Bluetooth SIG manufacturers, ranked both by sighting volume and by suspicious rate. Aggregate only; buckets under 5 sightings are suppressed. | days, limit |
Scoped tools filter on the identifier resolved from your credential, never from tool input — for all but one there is no parameter through which another account's data could be requested. The exception is skimguard_location_devices, which takes a Place ID and therefore checks ownership before it queries anything.
Business and Partner are peers: a merchant never sees a reseller's tools and vice versa. Data Licensee outranks both — a licensee key that also carries a business or reseller id gets those scoped tools too, still filtered to its own ids.
The canonical description of SkimGuard as a readable resource, so a client can ground itself without spending a tool call.
A ready-made prompt for the question this server exists to answer — including the instruction to always carry the "detects transmitting skimmers only" caveat.
30 req/min public · 120 req/min Business and Partner · 300 req/min Data Licensee. Enforced per principal, server-side. Exceeding it returns 429 with a Retry-After.
Access
Paid tiers do not unlock "more of the public data" — they add tools scoped to data that is yours, plus a higher rate limit. Every tier keeps all seven public tools.
The AI-discovery surface. Free forever, and deliberately not behind a paywall.
skimguard_search_locations, no Place ID neededFor a merchant with SkimGuard locations who wants their own coverage, their gaps, and their hardware answerable in the assistant.
skimguard_my_locationsskimguard_my_stale_locationsskimguard_my_scanner_healthskimguard_location_devicesFor a reseller who wants attributed-merchant volume — and their commission ledger — answerable in-conversation.
skimguard_my_merchantsskimguard_my_earningsFor licensing customers who want aggregate risk — geographic and by device — queryable from an agent. Outranks Business and Partner.
skimguard_regional_riskskimguard_device_prevalencePricing is shown at checkout — each paid tier is a Stripe subscription you start from your portal. Annual billing is 10× the monthly price, so two months are free. Cancelling revokes every key that subscription minted; the public tools keep working.
A key is shown exactly once when it is created — only its SHA-256 hash is stored, so it cannot be recovered later. Store it somewhere safe or mint a new one.
Ground rules
The tools are built to keep an assistant honest. If you are wiring SkimGuard into a product, these are the constraints to design around.
SkimGuard detects skimmers that transmit a Bluetooth signal. A purely mechanical or non-transmitting skimmer is invisible to it, so "clear" means "nothing detected", not "safe". Every tool response repeats this.
Scans at homes exist in the corpus but are never published. Public tools check the public-location allowlist before returning any aggregate, so a home address can't be queried out.
Public and licensee tools return counts, verdicts, and timestamps — never user IDs, report photos, or device identifiers. The regional summary suppresses thin cells.
SkimGuard does not use NFC. Apple's CoreBluetooth is BLE-only, so iPhone coverage is narrower than Android for Classic-only skimmer hardware — worth stating when you summarise a result.
skimguard_route_risk examines at most 20 km of the route you pass it, and every response says how far it actually got. "Nothing found" over 5 km of a 300 km drive is not a clear route — surface the examined distance, never a whole-trip verdict. Pass real geometry from a directions provider too; two points describe a straight line, not a road. To check a whole drive: split your route geometry into consecutive 20 km segments and call skimguard_route_risk once per segment, then combine the results — a 500 km trip is about 25 calls, which fits inside the free anonymous rate limit of 30 requests per minute. That is the supported way to cover a full trip.
Ask about a Google Place ID we have never seen and it is registered on the way past, so the next scan near it attaches to a stable location instead of the question being discarded. You still get a plain "no data" answer — which means unknown, not unsafe.
If your assistant cites SkimGuard, cite the caveat too. That is the difference between a useful safety signal and a false sense of security.
Higher volume
If you need throughput above the published limits, a bespoke field set, or bulk delivery rather than per-call lookups, that is a data-licensing conversation rather than an MCP subscription — and we will point you at whichever actually fits.
Tell us what you are building and which tools you need. We answer within 2 business days.
Send a messageGet in touch
Integration questions, higher limits, or a tool you wish existed — tell us what you are building and we will get back to you within 2 business days.