Check whether a URL or IP is safe before an AI agent fetches or opens it.
Runs on your machine from its package; the steps are below.
At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Run
npx -y @skanqrcode/mcp-server
MCP client config
{
"mcpServers": {
"skanqrcode": {
"command": "npx",
"args": [
"-y",
"@skanqrcode/mcp-server"
]
}
}
}Code examples and installable SDK packages for SkanQRCode, a
real-time URL/QR-code safety API — POST a URL or IP to /v1/check and get back
malicious / suspicious / not_malicious in under 200ms, meant to gate "should I open
this link" decisions right after scanning a QR code or following an inbound link.
Start here: docs/api-contract.md — the exact request/response
contract every example in this repo follows. It mirrors the published OpenAPI spec (v1.7.0) at
docs.skanqrcode.com/openapi.json; when that spec
changes, update the contract doc first, then the SDKs.
docs/
api-contract.md the canonical request/response contract (read this first)
quickstart/<lang>/ raw HTTP usage, no SDK — good for a 5-minute "does this work" test
sdk/<lang>/ installable SDK package with a typed SkanQRCodeClient
mobile/<platform>/ a QR-scan-then-check screen for a real mobile app
mcp/ MCP server + client examples for agent/LLM tool-calling
| Language | Quickstart | SDK package | Mobile example |
|---|---|---|---|
| Swift | quickstart/swift | sdk/swift — SPM SkanQRCode | mobile/ios-swift |
| Kotlin | quickstart/kotlin | sdk/kotlin — Gradle com.skanqrcode:skanqrcode-sdk | mobile/android-kotlin |
| Java | quickstart/java | sdk/java — Maven com.skanqrcode:skanqrcode-sdk | mobile/android-java |
| JavaScript | quickstart/javascript | sdk/javascript — npm skanqrcode | mobile/react-native |
| TypeScript | quickstart/typescript | sdk/typescript — npm @skanqrcode/sdk | — |
| Dart | quickstart/dart | sdk/dart — pub skanqrcode | mobile/flutter-dart |
| Python | quickstart/python | sdk/python — pip skanqrcode | — |
| Go | quickstart/go | sdk/go — github.com/skanqrcode/skanqrcode-go | — |
| Rust | quickstart/rust | sdk/rust — crate skanqrcode | — |
Every SDK exposes the same shape adapted to its language's conventions: a SkanQRCodeClient
(or Client) constructed with an API key, plus one method per API operation:
| Operation | Method (checkUrl / CheckURL / check_url style) |
|---|---|
POST /v1/check | checkUrl(target, userId?) → CheckResult with verdict, the recommended action (allow/warn/block), reasons, executionTimeMs, environment, … |
GET /v1/usage | getUsage(month?) → monthly quota, requests used, requests available |
GET /v1/usage/hourly | getUsageHourly(month?) → per-hour usage with rate-limit utilization |
/v1/allow-list, /v1/block-list | list…, add…Entry, delete…Entry (writes need an admin-scope key; the allow list is Pro/Business only) |
/v1/billing/checkout, /v1/billing/portal | createCheckoutSession, createPortalSession — return a URL to hand to a person |
GET /health | getHealth() |
Errors are typed and carry code/message/requestId, the HTTP status and, for a 429,
retryAfter seconds. A shouldBlock/isSafe-style helper is built on action so callers
don't have to switch on the raw enum themselves. The billing webhook isn't exposed — it isn't
for API clients. Every mobile example scans a QR code with the platform's standard local
decoder, calls checkUrl before opening the link, and fails closed (doesn't auto-open) on a
network error or timeout.
API keys are sk_live_… (paid plans) or sk_test_… (free sandbox plan); the examples read
theirs from SKANQRCODE_API_KEY. Results from a sandbox key are for integration testing only.
mcp/server is the official @skanqrcode/mcp-server package (check_url and
get_usage tools over stdio). mcp/ also has TypeScript and Python examples for calling
it from your own agent, and the Claude Desktop config snippet.
Use a quickstart/<lang> example if you just want to see the HTTP call work. Use an
sdk/<lang> package if you're integrating this into a real app — it gives you typed
responses, a typed error, request timeouts, and the action-based helper instead of hand-
parsing JSON on every call site.