Public Hosted Server: https://toolkit.caseyjhand.com/mcp
Overview
Everyday developer utilities: generate IDs, QR codes, and hashes, encode and decode values, and geolocate a public IP or hostname. Everything but the geolocation lookup runs locally.
Tools
Capability reference
toolkit_hash_value tool
valueread perinputEncoding(utf8default,hex,base64);algorithmissha256(default),sha384, orsha512, withsha1andmd5for checksum compatibility only;operationisgenerateorcompare, and when omitted it compares ifexpectedis sentgeneratereturnsdigestindigestEncoding(hexdefault,base64, orsrifor the SHA-2 algorithms) pluslengthInBytes;comparereturnsmatchesagainstexpected, given as hex, base64, or SRI, including a multi-entry npmintegrityvalue- A bad
expectedfails asexpected_malformed,expected_length_mismatch(the hint names the algorithm that length fits), orexpected_algorithm_mismatch
toolkit_generate_id tool
typeisuuid_v4(default),uuid_v7, orulid;countis 1–1000 (default 1)idsalways holds exactlycountvalues;uuid_v7andulidbatches are strictly increasing even within one millisecond, with random gaps so no id is derivable from another
toolkit_generate_qr tool
dataup to 2953 UTF-8 bytes aterrorCorrectionL, less atM(default),Q, andH;formatissvg(default),png_base64, orterminal;margin0–20 modules (default 4),scale1–32 px per module (default 4)- Returns
content, the symbolversion(1–40),mimeTypefor image formats, andbyteLengthfor PNG;png_base64also arrives as an MCP image block, andterminalis plain Unicode half-blocks drawn for a dark background - Over-capacity input fails as
data_too_largewith its byte count; a PNG over 2048 px per side fails asraster_too_largewith a scale that fits, whilesvgandterminalhave no pixel cap
toolkit_encode_value tool
operation(encodeordecode) andencoding(base64,base64url,hex,url) are required; whitespace inhex,base64, andbase64urlinput is ignored, so wrapped MIME and PEM bodies decode as-is- Decode returns
resultasutf8text unlessoutputEncodingasks forhexorbase64, which returns the bytes losslessly and transcodes between encodings; malformed input fails asdecode_failed, and binary bytes asdecode_not_utf8rather than with replacement characters
toolkit_geolocate_ip tool
targetis an IPv4/IPv6 address or a dotted hostname, DNS-resolved first; private or reserved addresses fail asprivate_target, unresolvable hostnames asunresolvable_host- Or send
targets(up to 1000) instead, never both: the first 100 return orderedresultswith per-target errors,failedCountcounts failures, andunprocessedTargetslists the rest to resubmit - Returns
country,countryCode,region,city,latitude/longitude,asn,org, andtimezonewithresolvedIpandsource; atrueinproxy,hosting, ormobilemeans the location describes infrastructure, not a person - Uses the keyless ip-api free tier over plaintext HTTP by default (
TOOLKIT_GEO_BASE_URL,TOOLKIT_GEO_API_KEY); results are cached per resolved IP - Single and batch lookups have separate rate limits (
TOOLKIT_GEO_RATE_LIMIT_PER_MIN=45,TOOLKIT_GEO_BATCH_RATE_LIMIT_PER_MIN=15); refusals reportrate_limitedwith seconds to wait, and cache hits stay free
toolkit_check_network tool
modeisping,traceroute,connectivity, orpublic_ip;targetis required except forpublic_ip, andport(1–65535) forconnectivity;count1–10 pings (default 3),timeoutMs100–30000 (default 3000)- A silent host is
reachable: false, not an error;pingaddsrttMs,sent,received, andpacketLossPercent,connectivityaddsoutcome(open,refused,timeout,unreachable), andtraceroutereturnshops; an unresolvable host or a ping/traceroute binary that can't run fails asunreachable - Registered only when
TOOLKIT_ENABLE_NET_DIAGNOSTICS=true; private and reserved targets fail asprivate_target_blockedunlessTOOLKIT_ALLOW_PRIVATE_NETWORK=true
toolkit_check_system tool
whatisos,cpu,memory,load, orinterfaces; exactly one matching facet object is populatedmemory.availableBytesis the allocation headroom andlimitBytesappears under a container memory limit;totalBytes,freeBytes, andusedBytesare raw OS figures that count reclaimable cache as used- Registered only when
TOOLKIT_ENABLE_SYSTEM_INFO=true, sinceosandinterfacesdisclose 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:
- Hashing, ID minting, QR encoding, and encode/decode run in-process on
node:cryptoand theqrcodelibrary, with no upstream calls - Geolocation calls the provider, never the target, and checks the DNS-resolved IP against private ranges, so a hostname can't reach an internal address
- Fail-closed gating:
toolkit_check_networkandtoolkit_check_systemare absent fromtools/listunless enabled. Both report on the server's host, not the caller's, so they belong on local or self-hosted deployments - Two-tier network gate: with diagnostics on, private, loopback, link-local, and reserved targets (the cloud-metadata endpoint included) stay blocked until
TOOLKIT_ALLOW_PRIVATE_NETWORK=true
Agent-friendly output:
- Provenance: geolocation echoes
resolvedIpandsource, and omits fields the provider didn't report instead of inventing them - Response shaping: provider strings are capped at 256 characters and stripped of control characters, so registry-controlled text like
orgcan't flood or format a model's context - Discriminated outputs:
operation,format,mode, andwhatecho what ran, and only that branch's fields are populated - Typed failures: every declared failure carries a
reasonand a recovery hint, and conflicting inputs (expectedwithgenerate,outputEncodingwithencode) are rejected by name, not 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.
{
"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
All variables are optional.
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 -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
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; a host-probing tool registers only behind an enable flag - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.