toolkit-mcp-server

v2.3.1

Generate random IDs, QR codes, and hashes, encode and decode values, and geolocate IPs, plus gated network and system diagnostics, via MCP. STDIO or Streamable HTTP.

toolkit.caseyjhand.com/mcp
claude mcp add --transport http toolkit-mcp-server https://toolkit.caseyjhand.com/mcp
codex mcp add toolkit-mcp-server --url https://toolkit.caseyjhand.com/mcp
{
  "mcpServers": {
    "toolkit-mcp-server": {
      "url": "https://toolkit.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http toolkit-mcp-server https://toolkit.caseyjhand.com/mcp
{
  "mcpServers": {
    "toolkit-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://toolkit.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "toolkit-mcp-server": {
      "type": "http",
      "url": "https://toolkit.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://toolkit.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

5

toolkit_hash_value

Generate a cryptographic digest of a value, or verify a value against an expected digest. Set operation to "generate" for a digest, or "compare" to constant-time-check value against the expected digest — compare is timing-safe and avoids manual string equality checks. Omitting operation compares when expected is supplied and generates otherwise. Algorithm defaults to sha256; sha384 and sha512 are also secure, while md5 and sha1 are exposed for checksum and file-integrity compatibility ONLY and must not be used for passwords, signatures, or any security purpose. digestEncoding selects the generated digest form: lowercase hex (default), base64, or sri (<algorithm>-<base64>, the npm lockfile integrity and Subresource Integrity form, sha256/sha384/sha512 only). expected is accepted as hex, base64, or SRI, recognized by its shape at the algorithm's digest length, so a published checksum can be pasted as-is; an SRI value may hold several space-separated entries, as an npm integrity field can, and matches when any entry for algorithm does. inputEncoding controls how value is read before hashing (utf8 default, or hex/base64 for raw binary data) so binary blobs need no decode round-trip. The canonical use is matching a download against a vendor-published checksum or a lockfile integrity entry.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "toolkit_hash_value",
    "arguments": {
      "value": "<value>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "operation": {
      "description": "\"generate\" produces a digest; \"compare\" constant-time-checks value against expected. When omitted, resolves to \"compare\" if expected is supplied and \"generate\" otherwise.",
      "type": "string",
      "enum": [
        "generate",
        "compare"
      ]
    },
    "value": {
      "type": "string",
      "description": "The data to hash, interpreted per inputEncoding (raw text by default)."
    },
    "algorithm": {
      "default": "sha256",
      "description": "Digest algorithm. sha256 (default), sha384, or sha512 for security; md5/sha1 are checksum/compat only — not for security.",
      "type": "string",
      "enum": [
        "sha256",
        "sha384",
        "sha512",
        "sha1",
        "md5"
      ]
    },
    "digestEncoding": {
      "default": "hex",
      "description": "Form of the generated digest: lowercase hex (default), standard base64, or sri (<algorithm>-<base64>, sha256/sha384/sha512 only). Applies to operation \"generate\".",
      "type": "string",
      "enum": [
        "hex",
        "base64",
        "sri"
      ]
    },
    "expected": {
      "description": "The digest to compare against, as hex (any case), standard base64, or SRI (<algorithm>-<base64>); the form is recognized from its shape at the algorithm's digest length, and a string of only hex digits is always read as hex. An SRI value may carry several space-separated entries: entries for other algorithms are skipped, and it matches when any entry for algorithm matches. Supplying it with operation omitted runs a compare; it is rejected with operation \"generate\".",
      "type": "string"
    },
    "inputEncoding": {
      "default": "utf8",
      "description": "How value is decoded before hashing: utf8 text, hex, or base64.",
      "type": "string",
      "enum": [
        "utf8",
        "hex",
        "base64"
      ]
    }
  },
  "required": [
    "value",
    "algorithm",
    "digestEncoding",
    "inputEncoding"
  ],
  "additionalProperties": false
}
view source ↗

toolkit_generate_id

Mint cryptographically-random identifiers using the platform CSPRNG — the correct source for IDs that must be unpredictable, unlike model-generated values. type selects the format: uuid_v4 (random, the default), uuid_v7 (time-ordered, sortable by creation), or ulid (26-char Crockford-base32, lexicographically sortable). Set count to mint a batch in one call (up to 1000); the returned ids array always contains exactly count values and is never truncated. For uuid_v7 and ulid, a batch is monotonic — strictly increasing even within the same millisecond — so the ids array stays in sorted creation order; ids minted in the same millisecond are separated by random gaps, so no id in a batch can be derived from another. IDs from this tool feed into toolkit_generate_qr (pass ids[0] as data) to create a scannable code.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "toolkit_generate_id",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "type": {
      "default": "uuid_v4",
      "description": "Identifier format: uuid_v4 (random), uuid_v7 (time-ordered), or ulid (sortable Crockford-base32).",
      "type": "string",
      "enum": [
        "uuid_v4",
        "uuid_v7",
        "ulid"
      ]
    },
    "count": {
      "default": 1,
      "description": "How many identifiers to mint (1–1000). The full batch is always returned.",
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    }
  },
  "required": [
    "type",
    "count"
  ],
  "additionalProperties": false
}
view source ↗

toolkit_generate_qr

Encode text or a URL into a QR code. data is the content to encode (a link, a generated identifier such as toolkit_generate_id's ids[0], or any string). format selects the output: svg returns inline SVG markup sized in pixels, png_base64 returns base64-encoded PNG bytes (with mimeType and byteLength), and terminal returns plain Unicode half-block characters (no escape codes) for a monospace display, drawn for a dark background: light modules, quiet zone included, are blocks and dark modules are spaces. errorCorrection (L/M/Q/H) trades data capacity for damage tolerance, margin sets the quiet-zone width in modules, and scale sets pixels per module for svg and png_base64, so both are (modules + 2 × margin) × scale pixels per side. The returned version (1–40) reflects how dense the encoded data is. png_base64 rejects an image past 2048 px per side with a typed raster_too_large error, so a dense symbol needs a lower scale; svg is vector markup and carries no such limit.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "toolkit_generate_qr",
    "arguments": {
      "data": "<data>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "data": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2953,
      "description": "The text or URL to encode, stored as UTF-8. Capacity is counted in bytes: 2953 UTF-8 bytes is the absolute ceiling (QR version 40, level L, byte mode). The 2953-character limit here is only an upper bound, since a non-ASCII character takes 2–4 bytes. Usable capacity drops at higher errorCorrection levels, so over-capacity data is rejected with a typed data_too_large error rather than a generic failure."
    },
    "format": {
      "default": "svg",
      "description": "Output format: svg markup, png_base64 (raster bytes), or terminal (plain Unicode half-blocks, drawn for a dark background).",
      "type": "string",
      "enum": [
        "svg",
        "png_base64",
        "terminal"
      ]
    },
    "errorCorrection": {
      "default": "M",
      "description": "Error-correction level: L (~7% recoverable) to H (~30%). Higher tolerance lowers data capacity.",
      "type": "string",
      "enum": [
        "L",
        "M",
        "Q",
        "H"
      ]
    },
    "margin": {
      "default": 4,
      "description": "Quiet-zone width in modules around the symbol. The spec recommends 4.",
      "type": "integer",
      "minimum": 0,
      "maximum": 20
    },
    "scale": {
      "default": 4,
      "description": "Pixels per module for svg (its width and height) and png_base64. Ignored for terminal. png_base64 also bounds the whole image at 2048 px per side, so a dense symbol or a wide margin admits a lower scale than 32 there.",
      "type": "integer",
      "minimum": 1,
      "maximum": 32
    }
  },
  "required": [
    "data",
    "format",
    "errorCorrection",
    "margin",
    "scale"
  ],
  "additionalProperties": false
}
view source ↗

toolkit_encode_value

Encode or decode a value across base64, base64url, hex, or URL (percent) encoding, in either direction. Set operation to "encode" to transform raw UTF-8 text into the chosen encoding, or "decode" to recover the original bytes from an encoded value. Decoded bytes come back as UTF-8 text by default; set outputEncoding to "hex" or "base64" to receive them re-encoded instead, which is lossless for binary data and transcodes between encodings (a base64 digest to hex, for example). Decoding never substitutes replacement characters: bytes that are not valid UTF-8 text are reported as a recoverable error that points at outputEncoding. Whitespace in hex, base64, and base64url values is ignored, so line-wrapped MIME bodies and PEM bodies decode as-is (drop PEM's -----BEGIN/END----- lines, which are not base64). base64url uses the URL-safe alphabet (- and _ instead of + and /); url applies encodeURIComponent and percent-decoding. A value that is malformed for the chosen encoding is reported as a recoverable error, not a silent best-effort.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "toolkit_encode_value",
    "arguments": {
      "operation": "<operation>",
      "encoding": "<encoding>",
      "value": "<value>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "operation": {
      "type": "string",
      "enum": [
        "encode",
        "decode"
      ],
      "description": "\"encode\" transforms text into the encoding; \"decode\" recovers the bytes from an encoded value."
    },
    "encoding": {
      "type": "string",
      "enum": [
        "base64",
        "base64url",
        "hex",
        "url"
      ],
      "description": "The encoding to apply: base64, URL-safe base64url, hex, or URL percent-encoding."
    },
    "value": {
      "type": "string",
      "description": "The value to transform — raw text for encode, an encoded string for decode. Whitespace is ignored when decoding hex, base64, or base64url; a url value is taken literally."
    },
    "outputEncoding": {
      "description": "Decode only: how the recovered bytes are returned. utf8 (used when omitted) returns text and fails when the bytes are not valid UTF-8; hex and base64 return the raw bytes re-encoded, losslessly. Rejected when operation is \"encode\".",
      "type": "string",
      "enum": [
        "utf8",
        "hex",
        "base64"
      ]
    }
  },
  "required": [
    "operation",
    "encoding",
    "value"
  ],
  "additionalProperties": false
}
view source ↗

toolkit_geolocate_ip

open-world

Resolve a public IP address (or hostname) to geographic and network metadata: country, region, city, latitude/longitude, the owning ASN and organization, timezone, and the proxy/hosting/mobile quality flags. target accepts an IPv4/IPv6 address or a hostname — a hostname is DNS-resolved first and the resolvedIp field echoes which IP was actually located. The provider is called directly (never the target), so this is SSRF-free and safe to expose anywhere. Results are best-effort and provider-bounded: VPNs, proxies, mobile NAT, and anycast all defeat IP-to-location, accuracy is city-level at best, and many fields can be absent for reserved or thinly-documented ranges — absent fields are reported as unknown, never invented. Read proxy, hosting, and mobile before trusting the coordinates: a true on any of them means the location describes infrastructure, not the user. Private/reserved addresses have no public geolocation and are rejected. The source field names which provider answered.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "toolkit_geolocate_ip",
    "arguments": {
      "target": "<target>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "target": {
      "anyOf": [
        {
          "type": "string",
          "format": "ipv4",
          "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$",
          "description": "A raw IPv4 address."
        },
        {
          "type": "string",
          "format": "ipv6",
          "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$",
          "description": "A raw IPv6 address."
        },
        {
          "type": "string",
          "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$",
          "description": "A dotted hostname, e.g. \"example.com\"."
        }
      ],
      "description": "A public IPv4/IPv6 address or a hostname (e.g. \"8.8.8.8\" or \"example.com\")."
    }
  },
  "required": [
    "target"
  ],
  "additionalProperties": false
}
view source ↗