toolkit-mcp-server
A developer-utilities MCP server offering cryptographic, encoding, QR, and geolocation tools, plus gated host diagnostics.
Hash values — generate sha256/sha384/sha512/sha1/md5 digests as hex, base64, or SRI, or constant-time compare against an expected digest.
Generate IDs — mint cryptographically-random UUIDv4, UUIDv7, or ULID identifiers, singly or in batches up to 1000.
Generate QR codes — encode text/URLs into QR codes as SVG markup, base64 PNG, or a terminal-renderable string.
Encode/decode values — transform data across base64, base64url, hex, and URL percent-encoding, in either direction.
Geolocate IPs — resolve a public IP or hostname to country, city, coordinates, ASN, org, and timezone, with proxy/hosting/mobile flags.
Check network (gated) — run ping, traceroute, raw TCP connectivity, and egress-IP detection from the server host.
Check system (gated) — report the host's OS, CPU, memory, load average, and network interfaces.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@toolkit-mcp-servergenerate a QR code for https://example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://toolkit.caseyjhand.com/mcp
Overview
A standalone developer-utilities server — the five always-on tools need no upstream API: generate identifiers, QR codes, and cryptographic digests, encode and decode values, and geolocate a public IP or hostname. Two more tools report diagnostics about the server's own host, gated off by default. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| Generate a cryptographic digest (sha256/sha384/sha512/sha1/md5) as hex, base64, or SRI, or constant-time-compare a value against an expected digest. |
| Mint cryptographically-random identifiers — UUIDv4, UUIDv7, or ULID — singly or in batches up to 1000. |
| Encode text or a URL into a QR code as SVG markup, base64 PNG, or a terminal-renderable string. |
| Encode or decode a value across base64, base64url, hex, or URL percent-encoding, in either direction. |
| Resolve a public IP or hostname to geographic and network metadata — country, city, coordinates, ASN, timezone. |
| Gated, off by default. Read-only network diagnostics from the server host — ping, traceroute, TCP connectivity, or egress-IP detection. |
| Gated, off by default. Report a facet of the server host's system state — OS, CPU, memory, load average, or network interfaces. |
Related MCP server: IT Tools MCP Server
Capability reference
toolkit_hash_value tool
operation:generate(a digest) orcompare(timing-safe check viatimingSafeEqual); omitted, it compares whenexpectedis sent and generates otherwise.generatesent together withexpectedis rejected with a typedexpected_without_compareerror rather than ignoringexpectedAlgorithms:
sha256(default),sha384, andsha512for security;sha1andmd5are exposed for checksum and file-integrity compatibility only — never for passwords or signaturesdigestEncodingsets the generated digest's form:hex(lowercase, default),base64, orsri(sha512-<base64>, the npm lockfileintegrityand Subresource Integrity form — sha256/sha384/sha512 only)expectedis accepted as hex, base64, or SRI, recognized by its shape at the algorithm's digest length, so a published checksum is pasted as-is. An SRI value may hold several space-separated entries, as an npmintegrityfield can: entries for other algorithms are skipped, and it matches when any entry foralgorithmdoesTyped errors separate an unrecognizable digest (
expected_malformed), one of the wrong length (expected_length_mismatch, whose hint names the algorithm that length belongs to), and an SRI value with no entry foralgorithm(expected_algorithm_mismatch)inputEncodingreadsvalueasutf8(default),hex, orbase64, so binary blobs skip a decode round-tripCanonical use: match a download against a vendor-published checksum or a lockfile integrity entry
toolkit_generate_id tool
type:uuid_v4(random, default),uuid_v7(time-ordered, sortable by creation), orulid(26-char Crockford base32, lexicographically sortable)countmints a batch up to 1000 in one call; the returnedidsarray always holds exactlycountvaluesuuid_v7andulidbatches are monotonic — strictly increasing even within the same millisecond — soidsstays in sorted creation order. Ids minted in the same millisecond are separated by random gaps (a 32-bit draw plus one), so no id in a batch is derivable from another; forulidthis departs from the spec's reference +1 increment on purposeRead-only — minting changes nothing — but never idempotent, so a client won't cache or deduplicate a batch
toolkit_generate_qr tool
format:svg(inline markup),png_base64(raster bytes withmimeTypeandbyteLength), orterminal(plain Unicode half-blocks with no escape codes, fenced incontent[])terminalis drawn for a dark background: light modules, quiet zone included, are blocks and dark modules are spaceserrorCorrection(L/M/Q/H) trades data capacity for damage tolerance;marginsets the quiet-zone width in modules for every format;scalesets pixels per module forsvg(itswidth/height) andpng_base64, so both are(modules + 2 × margin) × scalepx per sideThe returned
version(1–40) reflects how dense the encoded data ispng_base64also arrives as an MCP image content block, so a client readingcontent[]can render the code without decodingstructuredContentA rendered PNG is bounded at 2048 px per side —
(modules + 2 × margin) × scale— so a dense symbol at a highscaleis rejected with a typedraster_too_largeerror naming a scale that fits;svgandterminalare unboundeddatais encoded as UTF-8 and capped at 2953 bytes — the absolute ceiling (version 40, level L, byte mode); a non-ASCII character takes 2–4 bytes, and usable capacity is lower at highererrorCorrectionlevels, so over-capacity input is rejected with a typeddata_too_largeerror that reports the payload's byte count
toolkit_encode_value tool
encoding:base64,base64url(URL-safe alphabet),hex, orurl(percent-encoding)operation:encode(raw UTF-8 → encoding) ordecode(encoded value → bytes)outputEncoding(decode only) returns the recovered bytes asutf8text (when omitted),hex, orbase64— lossless for binary data, and a direct transcode between encodings (a base64 digest to hex, for example). Sent withencode, it is rejected with a typedoutput_encoding_not_applicableerrorDecode never substitutes replacement characters: bytes that aren't valid UTF-8 return a typed
decode_not_utf8error pointing atoutputEncoding, and a leading byte-order mark is keptWhitespace in
hex,base64, andbase64urlinput is ignored, so line-wrapped MIME and PEM bodies decode as-is (without PEM's-----BEGIN/END-----lines, which aren't base64); aurlvalue is taken literallyMalformed decode input returns a typed
decode_failederror with a recovery hint, not a silent best-effort
toolkit_geolocate_ip tool
Returns country, region, city, latitude/longitude, ASN, owning organization, and timezone
proxy,hosting, andmobileflag when the address is a proxy/VPN/Tor exit, a datacenter network, or a mobile carrier — atrueon any of them means the coordinates describe infrastructure, not a person. Absent when the provider doesn't report themA hostname is DNS-resolved first;
resolvedIpechoes the IP actually located, andsourcenames the answering providerSSRF-free — the server calls the provider, never the target; the resolved IP is re-checked against private ranges, and private/reserved addresses are rejected (they have no public geolocation)
Best-effort and provider-bounded: VPNs, proxies, mobile NAT, and anycast all defeat IP-to-location, accuracy is city-level at best, and absent fields are reported as unknown rather than invented
Provider-supplied strings are truncated and stripped of control characters before they reach the response, so registry-controlled text (
org,isp,as) cannot flood or format a model's contextKeyless by default (ip-api free tier, which is plaintext HTTP — see
TOOLKIT_GEO_BASE_URL); results are cached in memory by resolved IP under a fixed entry cap
toolkit_check_network tool
Gated — registered only when
TOOLKIT_ENABLE_NET_DIAGNOSTICS=true; absent fromtools/listotherwisemode:ping(ICMP round-trip),traceroute(hop path to the target),connectivity(raw TCP connect totargetonport), orpublic_ip(the host's own egress IP)A host that does not respond is reported as
reachable: false— a valid result, not an error. A ping or traceroute binary that is missing, or that exits without a result, is anunreachableerror naming the binary insteadpingreportssent,received, andpacketLossPercentalongside the averagerttMs; on macOS/BSD an IPv6 target runsping6/traceroute6connectivityreports anoutcome—open,refused(nothing listening),timeout(traffic dropped), orunreachable(no route) — and the connect time asrttMswhen openDiagnoses the server's own network, so it is useful on a local or self-hosted deployment; reaching a private/reserved/internal target additionally requires
TOOLKIT_ALLOW_PRIVATE_NETWORK=true, which keeps the cloud-metadata endpoint blocked by default
toolkit_check_system tool
Gated — registered only when
TOOLKIT_ENABLE_SYSTEM_INFO=true; absent fromtools/listotherwisewhat:os,cpu,memory,load, orinterfacesExactly one facet object is populated per call, matching
whatmemoryreportsavailableBytes(headroom for new allocations) and, when the server runs under a container memory limit,limitBytes;totalBytes,freeBytes, andusedBytesare the raw OS figures, which count reclaimable cache as used and read the host's RAM inside a containerDescribes the host this server runs on, not the calling client — meaningful on a local or self-hosted deployment; gated off by default because
osandinterfacesdisclose host topology and version details
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Toolkit-specific:
Local, pure-compute core — hashing, ID minting, QR encoding, and value encode/decode run entirely in-process via
node:cryptoand theqrcodelibrary; no upstream callstoolkit_geolocate_ipis the one keyless-by-default network call (ip-api free tier, optionalTOOLKIT_GEO_API_KEY); the server calls the provider directly and re-checks the DNS-resolved IP against private ranges, so a hostname can't smuggle a request to an internal addressFail-closed gating — the two host-probing tools (
toolkit_check_network,toolkit_check_system) are absent fromtools/listunless explicitly enabled, so a hosted instance exposes no SSRF or info-disclosure surface by defaultTwo-tier network gate — even with diagnostics enabled, private/reserved/loopback/link-local targets (including the cloud-metadata endpoint) stay blocked until a second flag permits them
Bounded inputs — QR
datacapped at 2953 bytes, rendered PNGs capped at 2048 px per side, ID batches capped at 1000; CSPRNG-backed primitives with constant-time hash comparison viatimingSafeEqual
Agent-friendly output:
Provenance — geolocation echoes
resolvedIp(the IP actually located) andsource(the answering provider); absent upstream fields are reported as unknown, never inventedResponse shaping — provider-supplied strings (
org,isp,as) are length-bounded and stripped of control characters before they reach the response, so untrusted registry text can't flood or format a model's contextDiscriminated output contracts —
operation,format,mode, andwhatfields echo back exactly what ran, with only the branch-relevant fields populated per call; an unreachable host intoolkit_check_networkreportsreachable: falseas valid data, not an errorTyped failure reasons — decode, hashing, QR, geolocation, and network failures each carry a structured
reasonplus a next-step recovery hint (e.g.decode_not_utf8,expected_malformed,raster_too_large,private_target_blocked);expectedsent withgenerate, andoutputEncodingsent withencode, are rejected by name rather than silently ignored
Getting started
Public Hosted Instance
A public instance is available at https://toolkit.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"toolkit-mcp-server": {
"type": "streamable-http",
"url": "https://toolkit.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file. No API key is required — the five always-on tools and the default keyless geolocation tier work out of the box.
{
"mcpServers": {
"toolkit-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/toolkit-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"toolkit-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/toolkit-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"toolkit-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/toolkit-mcp-server:latest"]
}
}
}To enable the gated host-probing tools, add their flags to env (or -e for Docker):
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"TOOLKIT_ENABLE_NET_DIAGNOSTICS": "true",
"TOOLKIT_ENABLE_SYSTEM_INFO": "true"
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
No API key needed — geolocation uses the keyless ip-api free tier by default.
Installation
Clone the repository:
git clone https://github.com/cyanheads/toolkit-mcp-server.gitNavigate into the directory:
cd toolkit-mcp-serverInstall dependencies:
bun installConfiguration
Every variable is optional. Server-specific options are validated at startup via the Zod schema in src/config/server-config.ts.
Variable | Description | Default |
| Register the gated |
|
| Register the gated |
|
| With network diagnostics on, permit private/reserved/loopback targets. The second explicit gate. |
|
| API key for the geolocation endpoint, if it requires one. | none |
| Base URL for an ip-api-compatible geolocation endpoint. The default is plaintext HTTP — ip-api's HTTPS endpoint is not part of the keyless free tier and answers |
|
| In-memory geolocation cache TTL in seconds. |
|
| Max geolocation requests per minute. |
|
| Transport: |
|
| Port for the HTTP server. |
|
|
|
|
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Enable OpenTelemetry instrumentation (spans, metrics, completion logs). |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t toolkit-mcp-server .
docker run --rm -e MCP_TRANSPORT_TYPE=http -p 3010:3010 toolkit-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/toolkit-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Geolocation service — DNS resolution, provider call with retry/backoff, normalization, in-memory cache. |
| Network-diagnostic service plus the shared target validator and private-range classifier. |
| Unit and integration tests mirroring the |
Development guide
See CLAUDE.md / AGENTS.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools in the
createApp()arrays insrc/index.tsThe two host-probing tools register behind their enable-flags; the network target gate validates after DNS resolution — never fabricate a result for an unlocatable or unreachable target
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
Available Tools
5 toolstoolkit_encode_valuetoolkit-mcp-server: encode valueARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | 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. | |
| encoding | Yes | The encoding to apply: base64, URL-safe base64url, hex, or URL percent-encoding. | |
| operation | Yes | "encode" transforms text into the encoding; "decode" recovers the bytes from an encoded value. | |
| outputEncoding | No | 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". |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| result | No | The transformed value: encoded text for encode; for decode, the recovered bytes as UTF-8 text, hex, or base64 per outputEncoding. |
| encoding | No | The encoding that was applied. |
| operation | No | The operation that was performed. |
| outputEncoding | No | How result renders the decoded bytes: utf8 text, hex, or base64. Present for operation "decode". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the readOnlyHint/idempotentHint annotations by disclosing key behavior: decoding never substitutes replacement characters, malformed values produce recoverable errors, whitespace is ignored in certain encodings, base64url uses the URL-safe alphabet, and url uses encodeURIComponent. This is exactly the kind of behavioral context an agent needs beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average but every sentence carries useful information, including edge cases, error behavior, and encoding-specific details. The first sentence front-loads the core purpose. It is dense rather than redundant, though it could be tightened slightly without losing value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity — four parameters, three enums, two operations, and multiple encoding formats — the description is remarkably complete. It covers error handling, whitespace tolerance, PEM/MIME scenarios, binary data handling, and output format options. With an output schema also present, nothing an agent needs to call and understand this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema coverage is 100%, the description adds substantial meaning to the parameters: it explains what "decode" returns by default, how outputEncoding enables lossless transcoding, how whitespace handling affects the value parameter, and which alphabet base64url uses. This is meaningful value beyond the schema's enumerated definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource combination: "Encode or decode a value across base64, base64url, hex, or URL (percent) encoding, in either direction." This unambiguously identifies the tool's operation and scope, and clearly separates it from siblings like hash_value or generate_id, which perform different transformations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear operational guidance: when to use "encode" vs "decode", and when to set outputEncoding. It also gives practical use cases like decoding base64 digests and PEM bodies. However, it does not explicitly name sibling tools or state when this tool should be preferred over them, though the context is strong enough that an agent can infer appropriate usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
toolkit_generate_idtoolkit-mcp-server: generate idARead-onlyInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Identifier format: uuid_v4 (random), uuid_v7 (time-ordered), or ulid (sortable Crockford-base32). | uuid_v4 |
| count | No | How many identifiers to mint (1–1000). The full batch is always returned. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ids | No | The minted identifiers — exactly count of them, in mint order; for uuid_v7 and ulid that order is strictly increasing (sorted by creation), with random gaps between ids minted in the same millisecond. |
| type | No | The identifier format that was minted. |
| count | No | The number of identifiers minted (equals the requested count). |
| error | No | Present when the call failed. Absent on success. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description goes far beyond: it discloses the source (platform CSPRNG), output guarantees ('always contains exactly count values and is never truncated'), monotonic ordering for uuid_v7/ulid, strict increasing within the same millisecond, and the security property that 'no id in a batch can be derived from another'. This rich behavioral disclosure is not present in annotations and is critical for correct use.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Each sentence earns its place: purpose and source are front-loaded, then type semantics, batch behavior, ordering guarantees, and downstream integration. There is no fluff or repetition of schema verbatim; the description is dense but well-structured, guiding the agent from conceptual purpose to invocation details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with an output schema and clear annotations, the description fully covers what an agent needs: when to use, format selection, batching limits, return-count guarantees, ordering behavior, and integration with a sibling. No critical information is missing, and the output schema handles return-shape details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds meaningful semantics beyond the schema: it explains the default (uuid_v4), clarifies each type's ordering properties, specifies 'up to 1000' for count, and introduces the guarantee that the full batch is always returned without truncation. This adds real value over the schema alone, though the schema already covers basic type and count limits.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description opens with 'Mint cryptographically-random identifiers using the platform CSPRNG' — a specific verb ('mint'), resource ('identifiers'), and method (CSPRNG). It distinguishes this tool from siblings by stating it is the correct source for unpredictable IDs and explicitly contrasts with 'model-generated values'. The purpose is unambiguous and differentiates from toolkit_hash_value, toolkit_encode_value, etc.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description says to use this tool when IDs 'must be unpredictable' and indicates 'unlike model-generated values' — an explicit when-not. It also provides a concrete downstream workflow: 'feed into toolkit_generate_qr (pass ids[0] as data)', which acts as a usage directive. Combined with format-selection guidance for type and batching with count, the agent knows exactly when and how to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
toolkit_generate_qrtoolkit-mcp-server: generate QR codeARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | 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. | |
| scale | No | 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. | |
| format | No | Output format: svg markup, png_base64 (raster bytes), or terminal (plain Unicode half-blocks, drawn for a dark background). | svg |
| margin | No | Quiet-zone width in modules around the symbol. The spec recommends 4. | |
| errorCorrection | No | Error-correction level: L (~7% recoverable) to H (~30%). Higher tolerance lowers data capacity. | M |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| format | No | The format that was produced. |
| content | No | The QR artifact: SVG markup, the terminal half-block grid (newline-separated rows), or base64 PNG bytes for png_base64. |
| version | No | QR symbol version (1–40); higher versions hold denser data and indicate denser content. |
| mimeType | No | MIME type of content for image formats. Absent for the terminal format. |
| byteLength | No | Decoded byte size of the PNG. Present only for png_base64. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and idempotentHint annotations, the description discloses significant behavioral detail: format-specific output shapes (SVG markup, base64 PNG bytes with mimeType and byteLength, terminal Unicode blocks), typed error conditions (data_too_large, raster_too_large), the pixel-size formula, and the version range reflecting data density. It even clarifies terminal rendering for dark backgrounds. This far exceeds what annotations alone provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is information-dense and front-loaded with the core purpose in the first sentence. Each subsequent sentence introduces a distinct parameter or constraint, and the flow from format to error behavior is logical. It is longer than two sentences, but given the three output formats and several interacting parameters, the length is justified without wasteful repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 5 parameters, 3 formats, and a moderately complex output, the description is thorough: it covers all parameters, format-specific behaviors, encoding boundaries, and error conditions. An output schema exists, so return values are already documented. No critical information an agent needs to invoke the tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema already has 100% parameter coverage, the description adds meaningful semantics not present in the schema: how scale and margin combine into final image dimensions, which parameters are ignored by which format, how errorCorrection trades capacity against tolerance, and the pixel limit interaction with scale for png_base64. This elevates the description well above the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Encode text or a URL into a QR code', which clearly states the tool's function. It goes beyond the title by naming concrete use cases (links, generated identifiers, strings) and enumerating the three output formats. Sibling tools like toolkit_encode_value, toolkit_generate_id, and toolkit_hash_value are clearly different in purpose, so an agent can distinguish this tool without confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides rich context for when to use the tool: what kinds of data are acceptable (links, identifiers, arbitrary strings), what each format yields, and how parameters interact. It does not explicitly state when not to use this tool or name alternative siblings for specific scenarios, but the sibling set is distinct enough that the usage is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
toolkit_geolocate_iptoolkit-mcp-server: geolocate IPARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| target | Yes | A public IPv4/IPv6 address or a hostname (e.g. "8.8.8.8" or "example.com"). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asn | No | Autonomous System number, e.g. "AS15169". Absent on providers that omit it. |
| org | No | Owning organization or ISP, e.g. "Google LLC". Absent when unknown. |
| city | No | City name. Absent when unknown. |
| error | No | Present when the call failed. Absent on success. |
| proxy | No | True when the address is a known proxy, VPN, or Tor exit — the location describes the exit node, not the user. Absent when the provider does not report it. |
| mobile | No | True when the address belongs to a mobile carrier network, where NAT can place the location far from the device. Absent when unreported. |
| region | No | Region or state name. Absent when unknown. |
| source | No | The provider that answered the lookup, e.g. "ip-api". |
| target | No | The target as supplied (IP or hostname). |
| country | No | Country name. Absent when the provider does not report it. |
| hosting | No | True when the address belongs to a hosting or datacenter network, so the location is a facility rather than a person. Absent when unreported. |
| latitude | No | Latitude in decimal degrees. Absent when unknown. |
| timezone | No | IANA timezone, e.g. "America/Los_Angeles". Absent when unknown. |
| longitude | No | Longitude in decimal degrees. Absent when unknown. |
| resolvedIp | No | The IP that was actually located (a supplied hostname is resolved to this first). |
| countryCode | No | ISO 3166-1 alpha-2 country code. Absent when unknown. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true and destructiveHint=false already in annotations, the bar is lower, yet the description still adds real context: the provider is called directly (never the target), so it is safe on untrusted input; accuracy is provider-bounded; behavior on private/reserved ranges is stated; proxy/VPN/mobile flags are defined as reliability warnings; and the source field is disclosed. Nothing contradicts the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
All four sentences are substantive and the operation is stated up front in the first sentence, with caveats and security notes after. No filler. Minor redundancy between 'accuracy is best-effort' and 'VPNs, proxies, anycast...' slightly thins the density, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param, read-only tool whose output is not schema-described, the description covers: the input types, DNS resolution behavior, the output fields, the meaning of proxy/mobile flags for reliability, and failure modes (private ranges rejected). An agent has everything needed to call it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (the single param is fully defined with three alternates: IPv4, IPv6, hostname). The description adds value beyond the schema by stating that hostnames are DNS-resolved first and that the resolved address is echoed in the response — behavior the schema cannot express. Slightly more caveat detail (e.g., punycode) would push to 5, but coverage is already high.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a clear verb-resource pair — resolve a public IP or hostname to a set of geographic and network metadata — and enumerates every returned field, so an agent immediately knows what it does and what it returns. It also carves out scope (public only) that distinguishes it in a toolkit whose other tools are QR, hash, and weather related.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when results are reliable and when they are not (VPNs, proxies, anycast, mobile NAT, reserved ranges), which is implicit guidance to the caller on trusting the output. It does not explicitly contrast with a sibling geolocation alternative, but the sibling set contains no competing tool, so a 4 is appropriate rather than a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
toolkit_hash_valuetoolkit-mcp-server: hash valueARead-onlyIdempotentInspect
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 (-, 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.
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | The data to hash, interpreted per inputEncoding (raw text by default). | |
| expected | No | 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". | |
| algorithm | No | Digest algorithm. sha256 (default), sha384, or sha512 for security; md5/sha1 are checksum/compat only — not for security. | sha256 |
| operation | No | "generate" produces a digest; "compare" constant-time-checks value against expected. When omitted, resolves to "compare" if expected is supplied and "generate" otherwise. | |
| inputEncoding | No | How value is decoded before hashing: utf8 text, hex, or base64. | utf8 |
| digestEncoding | No | Form of the generated digest: lowercase hex (default), standard base64, or sri (<algorithm>-<base64>, sha256/sha384/sha512 only). Applies to operation "generate". | hex |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present when the call failed. Absent on success. |
| digest | No | Digest of value in the requested digestEncoding: lowercase hex, base64, or <algorithm>-<base64>. Present for operation "generate". |
| matches | No | Constant-time equality of the computed digest against expected. Present for operation "compare". |
| algorithm | No | The algorithm used. |
| operation | No | The operation performed, after resolving an omitted operation. |
| lengthInBytes | No | Digest size in bytes (32 for sha256, 48 for sha384, 64 for sha512, 20 for sha1, 16 for md5). Present for "generate". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as readOnly and idempotent. The description adds meaningful behavioral detail: constant-time comparison, security caveats for weak algorithms, flexible expected-format recognition, and SRI multi-entry matching. These go well beyond the annotations and give the agent a clear model of how the tool behaves without contradicting the structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long (~150 words) but every sentence contributes a distinct piece of information: purpose, operation behavior, algorithm security, digest encoding, expected format handling, input encoding, and a canonical use case. It is front-loaded with the core purpose and then systematically covers each nuance. While it could be tightened, the density is justified by the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not specify return values. It thoroughly covers all parameters, their defaults, and edge cases (omitted operation, SRI multi-entries, binary input). It does not mention error conditions or limits, but these are minor given the extensive guidance and the presence of structured schemas. Overall, an agent has enough context to invoke this tool correctly in typical scenarios.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter already has a description. The tool description enriches this by explaining the interaction between operation and expected (omission logic), the shape-based recognition of expected formats, the meaning of SRI, and the rationale for inputEncoding. This adds genuine value beyond the schema's individual property descriptions, making the parameter semantics clearer and more actionable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise statement of both capabilities: 'Generate a cryptographic digest of a value, or verify a value against an expected digest.' It names the verb (generate/verify), the resource (value), and clearly distinguishes the two operations. This is far from a tautology and immediately separates it from sibling tools like encode or generate_id.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides strong contextual guidance: it explains the default operation resolution, warns against using md5/sha1 for security, and gives a canonical use case ('matching a download against a vendor-published checksum or a lockfile integrity entry'). It does not explicitly name alternatives or exclusions, but the unique function makes that less critical. The 'compare is timing-safe and avoids manual string equality checks' also informs when to use this tool over manual comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v2.3.1- Changed
toolkit_encode_value7 fields changed- changed
Input schema / properties / operation / descriptionPrevious value: -"\"encode\" transforms text into the encoding; \"decode\" recovers text from an encoded value."New value: +"\"encode\" transforms text into the encoding; \"decode\" recovers the bytes from an encoded value." - added
Input schema / properties / outputEncodingAdded value: +{ + "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\".", + "enum": [ + "utf8", + "hex", + "base64" + ], + "type": "string" +} - changed
Input schema / properties / value / descriptionPrevious value: -"The value to transform — raw text for encode, an encoded string for decode."New value: +"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." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `decode_failed`: operation is \"decode\" but value is malformed for the chosen encoding. Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `decode_failed`: operation is \"decode\" but value is malformed for the chosen encoding. `decode_not_utf8`: operation is \"decode\", outputEncoding is utf8 (or omitted), and the decoded bytes are not valid UTF-8 text. `output_encoding_not_applicable`: operation is \"encode\" and outputEncoding was supplied; it selects how decoded bytes are returned. Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "decode_failed" -]New value: +[ + "decode_failed", + "decode_not_utf8", + "output_encoding_not_applicable" +] - added
Output schema / properties / outputEncodingAdded value: +{ + "description": "How result renders the decoded bytes: utf8 text, hex, or base64. Present for operation \"decode\".", + "enum": [ + "utf8", + "hex", + "base64" + ], + "type": "string" +} - changed
Output schema / properties / result / descriptionPrevious value: -"The transformed value (encoded text, or the decoded original)."New value: +"The transformed value: encoded text for encode; for decode, the recovered bytes as UTF-8 text, hex, or base64 per outputEncoding."
- Changed
toolkit_generate_id1 field changed- changed
Output schema / properties / ids / descriptionPrevious value: -"The minted identifiers — exactly count of them, in mint order; for uuid_v7 and ulid that order is strictly increasing (sorted by creation)."New value: +"The minted identifiers — exactly count of them, in mint order; for uuid_v7 and ulid that order is strictly increasing (sorted by creation), with random gaps between ids minted in the same millisecond."
- Changed
toolkit_generate_qr4 fields changed- changed
Input schema / properties / data / descriptionPrevious value: -"The text or URL to encode. 2953 is the absolute ceiling (QR version 40, level L, byte mode); 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."New value: +"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." - changed
Input schema / properties / format / descriptionPrevious value: -"Output format: svg markup, png_base64 (raster bytes), or a terminal-renderable string."New value: +"Output format: svg markup, png_base64 (raster bytes), or terminal (plain Unicode half-blocks, drawn for a dark background)." - changed
Input schema / properties / scale / descriptionPrevious value: -"Pixels per module for raster (png_base64) output. 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."New value: +"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." - changed
Output schema / properties / content / descriptionPrevious value: -"The QR artifact: SVG markup, a terminal-renderable string, or base64 PNG bytes for png_base64."New value: +"The QR artifact: SVG markup, the terminal half-block grid (newline-separated rows), or base64 PNG bytes for png_base64."
- Changed
toolkit_hash_value13 fields changed- changed
Input schema / properties / algorithm / descriptionPrevious value: -"Digest algorithm. sha256 (default) or sha512 for security; md5/sha1 are checksum/compat only — not for security."New value: +"Digest algorithm. sha256 (default), sha384, or sha512 for security; md5/sha1 are checksum/compat only — not for security." - changed
Input schema / properties / algorithm / enumPrevious value: -[ - "sha256", - "sha512", - "sha1", - "md5" -]New value: +[ + "sha256", + "sha384", + "sha512", + "sha1", + "md5" +] - added
Input schema / properties / digestEncodingAdded value: +{ + "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\".", + "enum": [ + "hex", + "base64", + "sri" + ], + "type": "string" +} - changed
Input schema / properties / expected / descriptionPrevious value: -"The expected lowercase-hex digest to compare against. Required when operation is \"compare\"."New value: +"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\"." - changed
Input schema / properties / inputEncoding / descriptionPrevious value: -"How value (and expected's pre-image, when relevant) is decoded before hashing: utf8 text, hex, or base64."New value: +"How value is decoded before hashing: utf8 text, hex, or base64." - removed
Input schema / properties / operation / defaultRemoved value: -"generate" - changed
Input schema / properties / operation / descriptionPrevious value: -"\"generate\" produces a digest; \"compare\" constant-time-checks value against expected."New value: +"\"generate\" produces a digest; \"compare\" constant-time-checks value against expected. When omitted, resolves to \"compare\" if expected is supplied and \"generate\" otherwise." - changed
Output schema / properties / algorithm / enumPrevious value: -[ - "sha256", - "sha512", - "sha1", - "md5" -]New value: +[ + "sha256", + "sha384", + "sha512", + "sha1", + "md5" +] - changed
Output schema / properties / digest / descriptionPrevious value: -"Lowercase-hex digest of value. Present for operation \"generate\"."New value: +"Digest of value in the requested digestEncoding: lowercase hex, base64, or <algorithm>-<base64>. Present for operation \"generate\"." - changed
Output schema / properties / error / properties / data / properties / reason / descriptionPrevious value: -"Machine-readable failure mode. Declared by this tool: `missing_expected`: operation is \"compare\" but no expected digest was supplied. `expected_length_mismatch`: The expected digest length does not match the algorithm, so compare would always fail. `invalid_input_encoding`: value is not valid for the declared inputEncoding (e.g. non-hex characters with inputEncoding \"hex\"). Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `missing_expected`: operation is \"compare\" but no expected digest was supplied. `expected_without_compare`: operation is \"generate\" but an expected digest was also supplied, so it would be ignored. `expected_malformed`: expected is not a hex, standard base64, or sha256/sha384/sha512 SRI digest, or an SRI value holds a token that is not an SRI entry. `expected_length_mismatch`: expected is a recognized digest form but its length does not match the algorithm, so compare would always fail. `expected_algorithm_mismatch`: expected is SRI and none of its entries names the chosen algorithm. `sri_unsupported_algorithm`: digestEncoding is \"sri\" and algorithm is md5 or sha1, which SRI does not define. `invalid_input_encoding`: value is not valid for the declared inputEncoding (e.g. non-hex characters with inputEncoding \"hex\"). Other values are possible when a failure originates below the handler." - changed
Output schema / properties / error / properties / data / properties / reason / examplesPrevious value: -[ - "missing_expected", - "expected_length_mismatch", - "invalid_input_encoding" -]New value: +[ + "missing_expected", + "expected_without_compare", + "expected_malformed", + "expected_length_mismatch", + "expected_algorithm_mismatch", + "sri_unsupported_algorithm", + "invalid_input_encoding" +] - changed
Output schema / properties / lengthInBytes / descriptionPrevious value: -"Digest size in bytes (32 for sha256, 64 for sha512, 20 for sha1, 16 for md5). Present for \"generate\"."New value: +"Digest size in bytes (32 for sha256, 48 for sha384, 64 for sha512, 20 for sha1, 16 for md5). Present for \"generate\"." - changed
Output schema / properties / operation / descriptionPrevious value: -"The operation performed."New value: +"The operation performed, after resolving an omitted operation."
5 tool updates
v2.2.2- Changed
toolkit_encode_value6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "encoding", + "operation", + "result" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `decode_failed`: operation is \"decode\" but value is malformed for the chosen encoding. Other values are possible when a failure originates below the handler.", + "examples": [ + "decode_failed" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "encoding", - "operation", - "result" -]
- Changed
toolkit_generate_id6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "type", + "ids", + "count" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode.", + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "type", - "ids", - "count" -]
- Changed
toolkit_generate_qr6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "format", + "content", + "version" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `data_too_large`: data exceeds the QR capacity for the chosen errorCorrection level and encoding mode. `raster_too_large`: format is png_base64 and (modules + 2 × margin) × scale exceeds the pixel budget. Other values are possible when a failure originates below the handler.", + "examples": [ + "data_too_large", + "raster_too_large" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "format", - "content", - "version" -]
- Changed
toolkit_geolocate_ip6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "target", + "resolvedIp", + "source" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `unresolvable_host`: A hostname target failed DNS resolution. `private_target`: The target resolves to a private/reserved IP with no public geolocation. Other values are possible when a failure originates below the handler.", + "examples": [ + "unresolvable_host", + "private_target" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "target", - "resolvedIp", - "source" -]
- Changed
toolkit_hash_value6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Input schema / additionalPropertiesAdded value: +false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / anyOfAdded value: +[ + { + "not": { + "required": [ + "error" + ] + }, + "required": [ + "algorithm", + "operation" + ] + }, + { + "required": [ + "error" + ] + } +] - added
Output schema / properties / errorAdded value: +{ + "additionalProperties": {}, + "description": "Present when the call failed. Absent on success.", + "properties": { + "code": { + "description": "JSON-RPC error code for this failure.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "reason": { + "description": "Machine-readable failure mode. Declared by this tool: `missing_expected`: operation is \"compare\" but no expected digest was supplied. `expected_length_mismatch`: The expected digest length does not match the algorithm, so compare would always fail. `invalid_input_encoding`: value is not valid for the declared inputEncoding (e.g. non-hex characters with inputEncoding \"hex\"). Other values are possible when a failure originates below the handler.", + "examples": [ + "missing_expected", + "expected_length_mismatch", + "invalid_input_encoding" + ], + "type": "string" + }, + "recovery": { + "additionalProperties": {}, + "description": "Actionable next step for the caller.", + "properties": { + "hint": { + "type": "string" + } + }, + "required": [ + "hint" + ], + "type": "object" + }, + "retryable": { + "description": "Whether retrying may succeed.", + "type": "boolean" + } + }, + "type": "object" + }, + "message": { + "description": "Human-readable description of what went wrong.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" +} - removed
Output schema / requiredRemoved value: -[ - "algorithm", - "operation" -]
2 tool updates
v2.2.0- Changed
toolkit_generate_qr1 field changed- changed
Input schema / properties / scale / descriptionPrevious value: -"Pixels per module for raster (png_base64) output. Ignored for terminal."New value: +"Pixels per module for raster (png_base64) output. 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."
- Changed
toolkit_geolocate_ip10 fields changed- added
Output schema / properties / asn / maxLengthAdded value: +256 - added
Output schema / properties / city / maxLengthAdded value: +256 - added
Output schema / properties / country / maxLengthAdded value: +256 - added
Output schema / properties / countryCode / maxLengthAdded value: +256 - added
Output schema / properties / hostingAdded value: +{ + "description": "True when the address belongs to a hosting or datacenter network, so the location is a facility rather than a person. Absent when unreported.", + "type": "boolean" +} - added
Output schema / properties / mobileAdded value: +{ + "description": "True when the address belongs to a mobile carrier network, where NAT can place the location far from the device. Absent when unreported.", + "type": "boolean" +} - added
Output schema / properties / org / maxLengthAdded value: +256 - added
Output schema / properties / proxyAdded value: +{ + "description": "True when the address is a known proxy, VPN, or Tor exit — the location describes the exit node, not the user. Absent when the provider does not report it.", + "type": "boolean" +} - added
Output schema / properties / region / maxLengthAdded value: +256 - added
Output schema / properties / timezone / maxLengthAdded value: +256
2 tool updates
v2.0.1- Changed
toolkit_generate_id1 field changed- changed
Output schema / properties / ids / descriptionPrevious value: -"The minted identifiers — exactly count of them, in mint order."New value: +"The minted identifiers — exactly count of them, in mint order; for uuid_v7 and ulid that order is strictly increasing (sorted by creation)."
- Changed
toolkit_generate_qr1 field changed- changed
Input schema / properties / data / descriptionPrevious value: -"The text or URL to encode. Capped at 2953 bytes — the absolute QR capacity (version 40, level L)."New value: +"The text or URL to encode. 2953 is the absolute ceiling (QR version 40, level L, byte mode); 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."
21 tool updates
v2.0.0- Removed
checkConnectivity - Removed
clearGeoCache - Removed
compareHashes - Removed
convertTimezone - Removed
generateQRCode - Removed
generateUUID - Removed
geolocate - Removed
getCurrentTime - Removed
getLoadAverage - Removed
getNetworkInterfaces - Removed
getPublicIP - Removed
getSystemInfo - Removed
hashData - Removed
listTimezones - Removed
pingHost - Added
toolkit_encode_value - Added
toolkit_generate_id - Added
toolkit_generate_qr - Added
toolkit_geolocate_ip - Added
toolkit_hash_value - Removed
traceroute
16 tool updates
- First observed
checkConnectivity - First observed
clearGeoCache - First observed
compareHashes - First observed
convertTimezone - First observed
generateQRCode - First observed
generateUUID - First observed
geolocate - First observed
getCurrentTime - First observed
getLoadAverage - First observed
getNetworkInterfaces - First observed
getPublicIP - First observed
getSystemInfo - First observed
hashData - First observed
listTimezones - First observed
pingHost - First observed
traceroute
TDQS
Scored across 5 tools
Each tool serves a clearly distinct purpose: QR generation, hashing, ID generation, encoding/decoding, and IP geolocation. There is no overlap or possibility of confusion between tools. Descriptions are detailed and unambiguous.
All tools use the consistent 'toolkit_' prefix with snake_case names following a verb_noun pattern (generate_qr, hash_value, generate_id, encode_value, geolocate_ip). The naming is predictable and uniform across the entire set.
With 5 tools, the server is well-scoped for a general-purpose toolkit. Each tool is substantial and earns its place, covering a broad range of utility functions without redundancy. The count is neither thin nor bloated.
The toolkit covers a solid variety of utility categories (generation, hashing, encoding, geolocation), but lacks common text/data manipulation features like string transformation or JSON handling. The core workflows within each tool are complete, with no dead ends, though the breadth could be broader for a general toolkit.
Maintenance
Related MCP Connectors
The Mercado Pago MCP Server implements the Model Context Protocol to provide AI agents and LLMs with access to Mercado Pago's APIs and tools within compatible development environments. It acts as an intermediary that translates Mercado Pago resources into executable functions (tools) that AI applications can invoke to perform actions and automate flows. The server simplifies integration, enables using documentation to implement or improve code, and optimizes operations through natural language interactions without manual implementations.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Real-time planetary signal engine and Model Context Protocol (MCP) server for autonomous AI agents.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA comprehensive Model Context Protocol server implementation that enables AI assistants to interact with file systems, databases, GitHub repositories, web resources, and system tools while maintaining security and control.65 npm2MIT
- AlicenseBqualityFmaintenanceA comprehensive Model Context Protocol server providing access to 70+ IT tools for developers and system administrators, including encoding/decoding, text manipulation, hashing, and network utilities.10098 npm22TypeScriptMIT
- FlicenseNot gradedqualityCmaintenanceA secure Model Context Protocol server providing HTTP endpoints for AI agent tool execution, including file system operations, shell commands, and LLM-based code generation.1-
- AlicenseAqualityDmaintenanceA Model Context Protocol server providing network diagnostic tools for AI agents, including connectivity testing, batch operations, local network info, and pcap analysis.344MIT