Skip to main content
Glama
ShieldLabs-ai

@shieldlabs-ai/mcp

Official

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
SHIELDLABS_DOMAINNoRegistered domain for the Management API, for example `example.com`. With `SHIELDLABS_SECRET_KEY` it enables `shieldlabs_get_domain_profile`.
SHIELDLABS_API_KEYYesPrivate 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_TOKENNoBearer token for the HTTP endpoint (for `--transport http`); generated and printed once when unset.
SHIELDLABS_SECRET_KEYNoSecret Key of the domain, for the Management API.
SHIELDLABS_API_BASE_URLNoHistory 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_SECRETNoDefault endpoint signing secret (whsec_...) for `shieldlabs_verify_webhook_signature`; several separated by commas while you rotate.
SHIELDLABS_MANAGEMENT_BASE_URLNoManagement 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

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
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:

  • request_id (string): UUID returned by the browser agent

  • wait (boolean): poll until the verdict is stored, for up to about 10 s in total (default true); false reads once

  • response_format ('markdown' | 'json'): default 'markdown'

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:

  • type ('request_id' | 'user_hid' | 'device_id' | 'visitor_id' | 'ip' | 'session_id' | 'cookie_id')

  • value (string): UUID for the ID types, dotted IPv4 for ip, exact User HID for user_hid

  • limit (number): 1-100, default 20

  • offset (number): default 0

  • response_format ('markdown' | 'json'): default 'markdown'

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:

  • Every identification of one account: type="user_hid", value=""

  • Which accounts used this device: type="device_id", value=""

  • Next page: repeat with offset=next_offset

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:

  • type ('user_hid' | 'device_id' | 'visitor_id' | 'ip' | 'cookie_id')

  • value (string): UUID for the ID types, dotted IPv4 for ip, exact User HID for user_hid

  • max_items (number): 1-500, default 100

  • response_format ('markdown' | 'json'): default 'markdown'

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:

  • request_id (string, optional): read the identification from the History API, waiting up to about 10 s for a new one

  • identification (object or JSON string, optional): explain a pasted identification instead (normalized identification, webhook event or data object, or raw History API row)

  • response_format ('markdown' | 'json'): default 'markdown' Give exactly one of request_id and identification.

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:

  • payload (string): raw body exactly as received

  • signature_header (string): value of X-Shield-Signature

  • secret (string, optional): whsec_... signing secret of the endpoint, or several separated by commas

  • payload_encoding ('utf8' | 'base64'): default 'utf8'

  • response_format ('markdown' | 'json'): default 'markdown'

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:

  • timezone (string, optional): IANA time zone such as "Europe/Berlin"

  • response_format ('markdown' | 'json'): default 'markdown'

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

NameDescription
integrate_shieldlabsStep-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_userInvestigate 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_requestReview 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

NameDescription
identification-schemaJSON Schema of the normalized Identification returned by the tools and the ShieldLabs server SDKs.
webhook-event-schemaJSON Schema of a webhook delivery body (identification.scored and webhook.ping) with the signature scheme.
risk-signalsPlain-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-bandsThe three risk bands (trusted 0-29, suspicious 30-59, dangerous 60-100) and the 999 rate-limit marker.

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues