@shieldlabs-ai/mcp
OfficialServer Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| SHIELDLABS_DOMAIN | No | Registered domain for the Management API, for example `example.com`. With `SHIELDLABS_SECRET_KEY` it enables `shieldlabs_get_domain_profile`. | |
| SHIELDLABS_API_KEY | Yes | Private API Key (sec_...) of one domain, for the History API tools. Without it the server starts with the offline tools only and explains how to add the key. | |
| SHIELDLABS_MCP_TOKEN | No | Bearer token for the HTTP endpoint (for `--transport http`); generated and printed once when unset. | |
| SHIELDLABS_SECRET_KEY | No | Secret Key of the domain, for the Management API. | |
| SHIELDLABS_API_BASE_URL | No | History API origin, default `https://account.shieldlabs.ai` (development and tests). Must be https; plain http is accepted only for `localhost`, `127.0.0.1` and `[::1]`. | |
| SHIELDLABS_WEBHOOK_SECRET | No | Default endpoint signing secret (whsec_...) for `shieldlabs_verify_webhook_signature`; several separated by commas while you rotate. | |
| SHIELDLABS_MANAGEMENT_BASE_URL | No | Management API origin, default `https://api.shieldlabs.ai` (development and tests). Must be https; plain http is accepted only for `localhost`, `127.0.0.1` and `[::1]`. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| prompts | {
"listChanged": true
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| shieldlabs_get_identificationA | Read the verdict of one identification by its request ID from the ShieldLabs History API: Risk Score and band, weighted risk signals, the 19 detection flags, visitor, device, cookie and session IDs, User HID, public and local IP with country, connection type, OS, browser and traffic source. Use it when you have the request ID of a protected action (signup, login, payment) and need its verdict. The browser only ever sees the request ID; the verdict is read here, server-side. Scoring is asynchronous: the History row appears about 1 to 3 seconds after the browser call and can be refined for up to about 10 seconds while follow-up checks finish. This tool returns the first version of the row it finds. A verdict read in those first seconds can still be refined: read it again (wait=false is enough) once observed_at is about 10 seconds in the past for the final state. Integrations that start the identification when the user begins the action (for example on the first interaction with a form) find the row stored by the time the action reaches their backend. With wait=true it polls for up to about 10 seconds in total. A 429, a 5xx or a network error does not end the wait (its error is returned only when the last poll failed); a wrong key or base URL ends it at once. Args:
Returns (json): { "found": true, "identification": { request_id, visitor_id, device_id, session_id, cookie_id, user_hid, domain, public_ip: { ip, country }, local_ip: { ip, country }, connection_type, os, browser, device_type, traffic_source: { channel, referrer_domain, landing_url, click_id_type, utm_source, utm_medium, utm_campaign, utm_content, utm_term }, risk_score, risk_band, signals: [{ name, weight, description: null }], detection_flags: { vpn, proxy, tor, ... }, observed_at, source, truncated_fields?, escaped_fields? }, "untrusted_data_note": string } Errors: an error result when no identification is stored for the request ID (treat it as unverified, never as clean), when the key is wrong (401), or when the rate limit (429) or a server or network error prevents the read. Next steps: shieldlabs_explain_risk_score explains the score; shieldlabs_summarize_entity with the device_id or user_hid shows the history around it. |
| shieldlabs_search_historyA | List identifications for one identifier from the ShieldLabs History API, newest first, with paging. Use it to see individual identifications of an account (user_hid), a device (device_id), a browser visitor (visitor_id), a cookie (cookie_id), a visit (session_id) or an IPv4 address (ip). For counts and aggregates over many identifications, prefer shieldlabs_summarize_entity. Args:
Returns (json): { "lookup": { type, value }, "total": number, "count": number, "offset": number, "limit": number, "has_more": boolean, "next_offset": number (only when has_more), "identifications": [same shape as shieldlabs_get_identification], "untrusted_data_note": string, "truncated"?: boolean, "truncation_message"?: string } Examples:
Errors: invalid values are refused before any request (UUID or IPv4 expected; IPv6 is not searchable; a User HID that contains "/" cannot be searched). 401 means a wrong key; 429 means the History API rate limit (about 15 requests per second per domain) was reached. |
| shieldlabs_summarize_entityA | Aggregate the recent History API identifications of one account (user_hid), device (device_id), browser visitor (visitor_id), IPv4 address (ip) or cookie (cookie_id). The result is computed by this server from the returned history window (the most recent max_items identifications), and labelled as such: it is not a ShieldLabs verdict. It counts distinct devices, accounts, visitors, countries, IPs and connection types (with the top values), the highest and average Risk Score, band counts, rate-limit markers, detection flags and risk signals seen with counts, and the first and last observed time. Use it for questions such as: how many accounts used this device, how many devices this account used, which countries an account came from, whether an IP sent automated traffic. Use shieldlabs_search_history to see the individual identifications. Args:
Returns (json): { "lookup": { type, value }, "computed_from": string, "window": { identifications_analyzed, total_matching, max_items, complete }, "summary": { identifications_analyzed, first_observed_at, last_observed_at, devices: { distinct, top: [{ value, count, truncated? }] }, users, visitors, countries, ips, connection_types, anonymous_identifications, identifications_without_account, identifications_without_device_signals, risk: { max_risk_score, average_risk_score, worst_band, band_counts: { trusted, suspicious, dangerous }, rate_limit_markers }, flags_seen: [{ flag, count }], signals_seen: [{ name, count }], distinct_signals }, "untrusted_data_note": string } The user count ignores values that do not name an account: null, "anonymous", "fail", "-1" and "unknown". The device count ignores the all-zero device ID (no usable device signals). Averages ignore the 999 rate-limit marker. The History API limit (about 15 requests per second per domain) is shared with the site's own backend: start with the default max_items and raise it only when the window is incomplete and the question needs older identifications. |
| shieldlabs_explain_risk_scoreA | Explain why an identification got its Risk Score: the band (trusted 0-29, suspicious 30-59, dangerous 60-100, or the 999 rate-limit marker), each weighted risk signal with a plain-language meaning from the catalog bundled with this server, the detection flags that are set, the connection type and caveats. Args:
Returns (json): { "request_id": string | null, "risk_score": number, "risk_band": "trusted" | "suspicious" | "dangerous" | "rate_limited", "band_range": string, "band_meaning": string, "signals": [{ name, weight, label, meaning, reading, typical_weight, related_flag, in_catalog }], "detection_flags": [{ flag, label, scored, meaning }], "connection_type": { value, label, meaning } | null, "notes": [string], "source": "history" | "webhook" | "input", "truncated"?: true, "truncation_message"?: string } A pasted risk_score must be an integer from 0 to 100, or the 999 rate-limit marker, and weights must be integers. Weights come from the identification itself; the catalog's typical weights can change, and signal names outside the catalog are possible. The catalog is also available as the resource shieldlabs://reference/risk-signals. |
| shieldlabs_verify_webhook_signatureA | Check a received ShieldLabs webhook delivery: does its X-Shield-Signature header match the raw body for the endpoint signing secret? For debugging a webhook endpoint. SHIELDLABS_WEBHOOK_SECRET is not set on this server, so pass secret. The signature is "sha256=" plus the lowercase hex HMAC-SHA256 of the raw body, keyed with the full signing secret including its whsec_ prefix. While a secret is rotated, give several secrets separated by commas (in secret or in SHIELDLABS_WEBHOOK_SECRET): the delivery is valid when any of them matches, and matched_secret tells which. When the signature does not match a body of up to 64 KB, the tool tests common body changes (re-serialized JSON, unescaped characters, added newline) and says which one explains the mismatch. It never returns a secret or an expected signature. Args:
Returns (json): { "valid": boolean, "secret_source": "argument" | "environment", "secrets_checked": number, "matched_secret": number | null, "checks": [{ check, ok, detail }], "event": { event_type, schema_version, created_at, request_id, risk_score, risk_band } | null, "hint": string | null } |
| shieldlabs_current_timeA | Return the current time of the machine running this server, in UTC and optionally in one IANA time zone. Use it to judge freshness: for example whether an identification's observed_at is older than a 5-minute window, or how long ago an account was last seen. Args:
Returns (json): { "utc": string, "unix_seconds": number, "unix_ms": number, "timezone": string | null, "local_time": string | null, "utc_offset": string | null } |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| integrate_shieldlabs | Step-by-step plan to integrate ShieldLabs into the current application: browser identification, server-side verdict, webhooks and a verification checklist. Uses the published ShieldLabs setup skill, with a built-in guide when it cannot be fetched. |
| investigate_user | Investigate one account by its User HID: risk band, devices and other accounts on them, countries and IP addresses, detection flags, and a suggested next action. |
| review_request | Review one identification by its request ID: verdict, risk signals, freshness and the history of its device and account, ending with a suggested action for the protected request. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| identification-schema | JSON Schema of the normalized Identification returned by the tools and the ShieldLabs server SDKs. |
| webhook-event-schema | JSON Schema of a webhook delivery body (identification.scored and webhook.ping) with the signature scheme. |
| risk-signals | Plain-language meaning of every known risk signal slug, the 19 detection flags and the connection types. Weights can change and unknown slugs are possible. |
| risk-bands | The three risk bands (trusted 0-29, suspicious 30-59, dangerous 60-100) and the 999 rate-limit marker. |
TDQS
Scored across 6 tools
Each tool targets a distinct action: get one identification by request ID, list identifications for an identifier, aggregate history for an entity, explain a risk score, verify a webhook signature, and get server time. The descriptions explicitly cross-reference each other (e.g. search_history vs summarize_entity, and pointing to explain_risk_score for score explanations), leaving no real overlap.
All tools use snake_case with a consistent shieldlabs_ prefix and mostly follow a verb_noun pattern (get_identification, search_history, summarize_entity, explain_risk_score, verify_webhook_signature). The only minor deviation is current_time, which lacks a verb, but it still reads clearly as a command.
Six tools is well-scoped for a read-oriented risk/verdict API: single read, search, aggregate, score explanation, webhook verification, and a time helper. Each tool earns its place without redundancy or obvious padding.
The surface covers the read lifecycle well (single, list, aggregate, explain) plus webhook verification and time, and the risk-signal catalog is exposed as a resource. A minor gap is the absence of a tool to list recent identifications for a domain/tenant without first knowing an identifier, which some triage workflows would want.