io.github.cyanheads/toolkit-mcp-server MCP Server
io.github.cyanheads/toolkit-mcp-server
Generate IDs, QR codes, hashes, encode values, geolocate IPs, and run host diagnostics via MCP.
What is the io.github.cyanheads/toolkit-mcp-server MCP server?
The toolkit-mcp-server is an MCP server that provides developer utilities for generating cryptographic identifiers, QR codes, and hashes, encoding/decoding values, and geolocating IP addresses. It includes optional gated tools for network diagnostics and system information from the server host, with no upstream API keys required for core functionality.
A standalone utility server exposing seven tools: five always-on (hash generation, ID minting, QR encoding, value encoding/decoding, IP geolocation) and two optional gated diagnostics (network checks and system state). Runs locally via stdio or HTTP, or via a public hosted endpoint. No API keys needed for the core five tools.
How to install io.github.cyanheads/toolkit-mcp-server
Copy-paste configuration for popular MCP clients.
MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
TOOLKIT_ENABLE_NET_DIAGNOSTICSRegister the gated toolkit_check_network tool. Off by default — leave off for hosted/shared deployments.
TOOLKIT_ENABLE_SYSTEM_INFORegister the gated toolkit_check_system tool. Off by default — only meaningful on a local deployment.
TOOLKIT_ALLOW_PRIVATE_NETWORKWith network diagnostics enabled, permit private/reserved/loopback targets. The second explicit gate; off by default.
TOOLKIT_GEO_API_KEYsecretAPI key for the geolocation endpoint, if it requires one. The default ip-api tier is keyless.
TOOLKIT_GEO_BASE_URLBase URL for an ip-api-compatible geolocation endpoint. Default is the keyless ip-api endpoint, which is plaintext HTTP.
TOOLKIT_GEO_CACHE_TTL_SECONDSGeolocation cache TTL in seconds. Geolocation is stable, so repeats are cached.
TOOLKIT_GEO_RATE_LIMIT_PER_MINMax geolocation requests per minute; excess requests are rejected with a retryable rate-limit error. Default 45 matches the ip-api free tier.
MCP_HTTP_HOSTThe hostname for the HTTP server.
MCP_HTTP_PORTThe port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.
MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.
Tools & capabilities
Tools this server exposes to the agent.
toolkit_hash_value— Generate cryptographic digests (sha256/sha384/sha512/sha1/md5) in hex, base64, or SRI format, or perform constant-time comparison against an expected digest.toolkit_generate_id— Mint cryptographically-random identifiers as UUIDv4, UUIDv7, or ULID, singly or in batches up to 1000.toolkit_generate_qr— Encode text or URLs into QR codes as SVG markup, base64 PNG, or terminal-renderable Unicode strings.toolkit_encode_value— Encode or decode values across base64, base64url, hex, and URL percent-encoding in either direction.toolkit_geolocate_ip— Resolve a public IP or hostname to geographic and network metadata including country, city, coordinates, ASN, organization, and timezone.toolkit_check_network— Gated, off by default. Read-only network diagnostics from the server host: ping, traceroute, TCP connectivity, or egress-IP detection.toolkit_check_system— Gated, off by default. Report server host system state: OS, CPU, memory, load average, or network interfaces.
Use cases
- Generate UUIDs, ULIDs, or UUIDv7 identifiers for applications and databases
- Create QR codes for URLs or text in multiple formats (SVG, PNG, terminal)
- Hash files or values and verify them against published checksums or SRI integrity entries
- Encode/decode data between base64, hex, and URL-safe formats for APIs and storage
- Geolocate public IP addresses to determine country, city, ASN, and timezone information
- Diagnose network connectivity from the server host via ping, traceroute, or TCP checks
io.github.cyanheads/toolkit-mcp-server MCP server FAQ
A developer-utilities MCP server providing ID generation, QR encoding, hashing, value encoding/decoding, IP geolocation, and optional host diagnostics. Five core tools require no API keys; two diagnostic tools are gated off by default.
Yes. The five core tools (hash, ID, QR, encode, geolocate) are free and require no API keys. Geolocation uses the free ip-api tier by default; optional paid tiers are available via TOOLKIT_GEO_API_KEY.
Add the server to your MCP client config pointing to the npm package (@cyanheads/toolkit-mcp-server) via stdio, or use the public hosted endpoint at https://toolkit.caseyjhand.com/mcp via Streamable HTTP. One-click install buttons are available in the repository.
No. The server works out of the box with no API keys for core functionality. The optional gated tools (network and system diagnostics) are disabled by default and require environment flags to enable.
Yes. Install via npm/bunx/Docker and run as a stdio process or local HTTP server. A public hosted instance is also available at https://toolkit.caseyjhand.com/mcp.
toolkit_check_network and toolkit_check_system are disabled by default. Enable them with TOOLKIT_ENABLE_NET_DIAGNOSTICS and TOOLKIT_ENABLE_SYSTEM_INFO flags on self-hosted deployments to diagnose the server's own network and system state.
README (reference)
Source of truth, from the repository.
Public Hosted Server: https://toolkit.caseyjhand.com/mcp
</div>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 |
|---|---|
toolkit_hash_value | Generate a cryptographic digest (sha256/sha384/sha512/sha1/md5) as hex, base64, or SRI, or constant-time-compare a value against an expected digest. |
toolkit_generate_id | Mint cryptographically-random identifiers — UUIDv4, UUIDv7, or ULID — singly or in batches up to 1000. |
toolkit_generate_qr | Encode text or a URL into a QR code as SVG markup, base64 PNG, or a terminal-renderable string. |
toolkit_encode_value | Encode or decode a value across base64, base64url, hex, or URL percent-encoding, in either direction. |
toolkit_geolocate_ip | Resolve a public IP or hostname to geographic and network metadata — country, city, coordinates, ASN, timezone. |
toolkit_check_network | Gated, off by default. Read-only network diagnostics from the server host — ping, traceroute, TCP connectivity, or egress-IP detection. |
toolkit_check_system | Gated, off by default. Report a facet of the server host's system state — OS, CPU, memory, load average, or network interfaces. |
Capability reference
toolkit_hash_value <sub>tool</sub>
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 ignoringexpected- Algorithms:
sha256(default),sha384, andsha512for security;sha1andmd5are exposed for checksum and file-integrity compatibility only — never for passwords or signatures digestEncodingsets 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 foralgorithmdoes- Typed 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-trip- Canonical use: match a download against a vendor-published checksum or a lockfile integrity entry
toolkit_generate_id <sub>tool</sub>
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 purpose- Read-only — minting changes nothing — but never idempotent, so a client won't cache or deduplicate a batch
toolkit_generate_qr <sub>tool</sub>
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 side- The returned
version(1–40) reflects how dense the encoded data is png_base64also arrives as an MCP image content block, so a client readingcontent[]can render the code without decodingstructuredContent- A 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 unbounded datais 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 <sub>tool</sub>
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_applicableerror- Decode 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 kept - Whitespace 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 literally - Malformed decode input returns a typed
decode_failederror with a recovery hint, not a silent best-effort
toolkit_geolocate_ip <sub>tool</sub>
- 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 them- A hostname is DNS-resolved first;
resolvedIpechoes the IP actually located, andsourcenames the answering provider - SSRF-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 context - Keyless 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 <sub>tool</sub>
- Gated — registered only when
TOOLKIT_ENABLE_NET_DIAGNOSTICS=true; absent fromtools/listotherwise mode: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 instead pingreportssent,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 open- Diagnoses 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 <sub>tool</sub>
- Gated — registered only when
TOOLKIT_ENABLE_SYSTEM_INFO=true; absent fromtools/listotherwise what:os,cpu,memory,load, orinterfaces- Exactly one facet object is populated per call, matching
what memoryreportsavailableBytes(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 container- Describes 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 calls toolkit_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 address- Fail-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 default - Two-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 invented - Response 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 context - Discriminated 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 error - Typed 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/mcp
Prerequisites
- 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.git
- Navigate into the directory:
cd toolkit-mcp-server
- Install dependencies:
bun install
Configuration
Every variable is optional. Server-specific options are validated at startup via the Zod schema in src/config/server-config.ts.
| Variable | Description | Default |
|---|---|---|
TOOLKIT_ENABLE_NET_DIAGNOSTICS | Register the gated toolkit_check_network tool. Leave off for hosted or shared deployments. | false |
TOOLKIT_ENABLE_SYSTEM_INFO | Register the gated toolkit_check_system tool. Meaningful only on a local or self-hosted deployment. | false |
TOOLKIT_ALLOW_PRIVATE_NETWORK | With network diagnostics on, permit private/reserved/loopback targets. The second explicit gate. | false |
TOOLKIT_GEO_API_KEY | API key for the geolocation endpoint, if it requires one. | none |
TOOLKIT_GEO_BASE_URL | 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 403 SSL unavailable for this endpoint without a paid key. Point this at an HTTPS endpoint (with TOOLKIT_GEO_API_KEY) to encrypt the provider request. | http://ip-api.com |
TOOLKIT_GEO_CACHE_TTL_SECONDS | In-memory geolocation cache TTL in seconds. | 3600 |
TOOLKIT_GEO_RATE_LIMIT_PER_MIN | Max geolocation requests per minute. | 45 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_SESSION_MODE | auto, stateful, or stateless. No tool requests multi-round input. auto is the framework schema default and resolves to stateful, but with MCP_SESSION_MODE unset the server resolves stateless from createApp({ sessionMode }); an explicit MCP_SESSION_MODE value still overrides it. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
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:http -
Run 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-server
The 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 |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits services, with fail-closed gating for the two host-probing tools. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Seven tools — five always-on, two gated. |
src/services/geo | Geolocation service — DNS resolution, provider call with retry/backoff, normalization, in-memory cache. |
src/services/network | Network-diagnostic service plus the shared target validator and private-range classifier. |
tests/ | Unit and integration tests mirroring the src/ structure. |
Development guide
See CLAUDE.md / AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools in the
createApp()arrays insrc/index.ts - The 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 test
License
Apache-2.0 — see LICENSE for details.
Related MCP servers
Global transit via Transitland v2 — operators, GTFS/GTFS-RT/GBFS feeds, routes, stops, departures.
Query US Treasury national debt, interest rates, exchange rates, and fiscal datasets via MCP.
Search TVmaze shows, next episodes in your timezone, episode guides, daily TV schedules, and cast.
Search and read UK legislation at any date, resolve citations, list amendments, track changes.
UN Comtrade international trade statistics via MCP. Country/HS lookups, flows, balances, rankings.
Query UNHCR refugee, IDP, and stateless populations, asylum decisions, returns, and resettlement.
