Back to Browse

Firstch Tools MCP Server

Developer ToolsModerate6.8MCP RegistryLocal
Free

Server data from the Official MCP Registry

MCP tools: WCAG contrast, JP char/X-weight count, WebP convert, JSON-LD, llms.txt.

About

MCP tools: WCAG contrast, JP char/X-weight count, WebP convert, JSON-LD, llms.txt.

Security Report

6.8
Moderate6.8Moderate Risk

This is a well-structured MCP server providing text processing and image conversion utilities. Authentication and authorization are appropriately scoped (none required—tools are stateless utilities). The codebase demonstrates good security practices with optional telemetry, proper file handling, and vendored dependencies with checksum verification. Minor code quality observations (broad exception handling in WebP conversion, lack of explicit input validation helpers) do not significantly impact the security posture. Permissions are well-justified by the server's stated purpose. Supply chain analysis found 1 known vulnerability in dependencies (0 critical, 1 high severity). Package verification found 1 issue.

3 files analyzed · 5 issues found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

File System Read

Reads files on your machine. Normal for tools that analyze or process local data.

File System Write

Writes or modifies files on your machine. Check that this is expected for the tool.

env_vars

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

Optional. Path to a local JSONL file for opt-in usage logging. No logging when unset.Optional

Environment variable: FIRSTCH_TOOLS_USAGE_LOG

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-first-ch-tools-mcp": {
      "env": {
        "FIRSTCH_TOOLS_USAGE_LOG": "your-firstch-tools-usage-log-here"
      },
      "args": [
        "-y",
        "@first-ch/tools-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

@first-ch/tools-mcp

MCP server exposing First CH Tools' free web-tool logic — WCAG contrast, JP character/X-weight counting, WebP conversion, JSON-LD generation, llms.txt generation, encoding/line-ending conversion, Marp Markdown→slide rendering, Japanese/English test-data generation, text/code diffing, cron-expression explanation, Base64/data-URI encoding, URL query-parameter editing, HTML entity escaping/unescaping, JSON⇄YAML conversion, px ⇄ rem/em unit conversion, colour-code conversion with alpha compositing, MD5/SHA-1/SHA-256/SHA-384/SHA-512 hashing, JWT decoding with expiry and signature checks, User-Agent parsing with device/bot detection, bulk UUID v4 / ULID generation, aspect-ratio calculation with responsive sizing, case conversion between camelCase, snake_case and kebab-case, CSV/TSV ⇄ JSON conversion, IP/CIDR calculation with subnet splitting and IP-range reduction, business-day date calculation with Japanese public holidays, HTML-to-Markdown conversion, Japanese era ⇄ Western date conversion with age calculation, and URL-slug generation from Japanese titles — to AI agents such as Claude Code.

日本語版は 後半セクション を参照してください。

Install

Three ways to add this server, pick whichever fits your client.

Requires Node.js >=24 (all three methods below run the server via npx, so Node must be installed even when the MCP client itself — e.g. Claude Code's native, no-Node install — doesn't strictly require it).

1. npm, via the Claude Code CLI

claude mcp add firstch-tools -- npx -y @first-ch/tools-mcp

2. Claude Code plugin (also installs the same MCP server)

/plugin marketplace add First-CH/firstch-tools-mcp
/plugin install firstch-tools@first-ch

3. Any other MCP client (generic JSON config)

Add to your client's server config (e.g. mcp.json / claude_desktop_config.json):

{
  "mcpServers": {
    "firstch-tools": {
      "command": "npx",
      "args": ["-y", "@first-ch/tools-mcp"]
    }
  }
}

This server is also registered in the MCP Registry as io.github.First-CH/tools-mcp (see server.json), so registry-aware clients can discover and install it by that name too.

Tools

ToolWhat it doesMain input
contrast_checkComputes the WCAG 2.1 contrast ratio between a foreground and background color and returns AA/AAA pass/fail (normal text, large text, UI components)fg, bg (hex, e.g. #333333 / 333 / fff)
count_charsCounts Japanese text by grapheme, breaks it down into zenkaku/hankaku, counts lines, and computes the X (Twitter) post weight (zenkaku=2, hankaku=1, URL=23 flat, limit 280)text
webp_convertConverts PNG/JPEG files (absolute paths) to WebP using the same libwebp WASM encoder (default quality 80) as the browser tool at tools.first-ch.com/webp/. Output defaults to the same directory as each input with a .webp extensionpaths[] (absolute paths), quality? (1-100), outputDir?
jsonld_generateGenerates schema.org JSON-LD for organization / faqpage / service / breadcrumb. Empty fields are omitted automatically. Returns both a json object and a ready-to-embed <script> snippettype, plus the matching organization / faq / service / breadcrumb object
llmstxt_generateGenerates an llms.txt file (per the llmstxt.org proposed format) summarizing a site for AI crawlers/agentssiteName, summary?, notes?, sections?
encoding_convertDetects the character encoding (UTF-8 / Shift_JIS), BOM and line endings (CRLF / LF / CR) of a file or text and converts it to UTF-8. Useful for diagnosing garbled Japanese CSVs and for normalising line endings. Output is UTF-8 only — encoding to Shift_JIS is not supported (no standard API, and a mapping table would be required).base64 or text, mode (analyze | convert), encoding, newline, bom
marp_renderRenders Marp Markdown to slides. Emits a self-contained HTML file (theme CSS inlined; opens in a browser and prints one-slide-per-page) and optionally PDF. Ships a bundled Japanese theme firstch (paper/ink/vermilion; uses IBM Plex Sans JP if installed) used as the default theme. Marp front-matter in the Markdown (theme: / paginate: / size: / ``) is honored.markdown or inputPath, theme?, formats? (html | pdf), outputPath?, title?
testdata_generateGenerates dummy data for form / CSV-import testing. mode=records returns names, kana readings, addresses, postal codes, emails and phone numbers as CSV/TSV/JSON/XLSX with a choice of encoding (UTF-8 / Shift_JIS), BOM and line endings. format=xlsx returns a real Excel workbook as base64 (or writes it to outputPath) — the ZIP/OOXML parts are assembled directly, with no spreadsheet dependency, and postal codes and phone numbers are written as text cells so leading zeros survive; mode=text returns strings of exactly n-1 / n / n+1 characters for maxlength boundary tests. All output is fictional (emails use the RFC 2606 example.com family). Passing a seed makes the output reproduciblemode?, rows?, fields?, format?, locale?, encoding?, newline?, bom?, header?, seed?, preset?, length?, outputPath?
diff_checkCompares two texts (or two files) and returns the added/removed/changed line counts plus a unified diff (.patch) — the same logic as the browser tool at tools.first-ch.com/diff/. Lines are matched with patience diff (lines occurring exactly once in both sides become anchors), falling back to Myers only inside anchor-less ranges. With format=blocks / both, paired changed lines are also compared at token level (runs of letters/digits are one token, CJK characters one each) and returned as changed_parts, so you can see which words changed. CRLF/CR/LF all count as the same line break; trailing-whitespace-only differences are ignored by defaulta/b (text) or pathA/pathB (absolute paths), format? (unified | blocks | both), context?, ignoreWhitespace?, ignoreCase?, words?
cron_explainExplains a cron expression in plain language and returns the upcoming run times — the same logic as the browser tool at tools.first-ch.com/cron/. Parsing follows Vixie cron (crontab(5)): ranges, steps, lists, JAN-DEC / SUN-SAT names and the @daily-style shorthands; six fields means the first one is seconds (node-cron / Spring style). warnings call out the traps — day-of-month and day-of-week are OR'd (not AND'd) when both are restricted, */n that does not divide its range evenly is not a uniform interval, and impossible dates such as February 30th never fire. Run times are found on the wall clock of the target time zone and converted back to real instants, so they stay correct across daylight-saving transitionsexpression, timeZone? (IANA, default UTC), count? (default 5, max 100), from? (ISO 8601)
base64_encodeEncodes text or a file as Base64 and a data: URI, and returns ready-to-paste HTML <img> / CSS background-image snippets — the same logic as the browser tool at tools.first-ch.com/base64/. With mode="decode" it turns Base64 or a data URI back into bytes, writing them to outputPath when given. For SVG it returns both encodings and defaults to the shorter one (percent-encoding beats Base64, which always inflates by ~33%), always escaping & " < > # %, whitespace and non-ASCII so the URI drops straight into an HTML attribute or a CSS url("…"). Decoding accepts standard or URL-safe Base64, tolerates whitespace and newlines, does not require padding, and trusts the actual magic numbers (PNG/JPEG/GIF/WebP/ico/PDF/zip/woff/woff2/SVG) over the MIME type a data URI claimsmode? (encode default / decode), text? or path?, base64?, outputPath?, urlSafe?, wrap? (76 for MIME), dataUri?, mimeType?, snippets?
url_paramsBreaks a URL's query string into keys and values, edits it (set / remove / utm / removeTracking / sort) and rebuilds it — the same logic as the browser tool at tools.first-ch.com/url/. Values come back decoded (%XX to characters, + to a space), and parameters you did not touch are written back byte-for-byte, so calling it with nothing but a url returns exactly what you passed in — signed URLs survive a round trip. reencode normalises the whole query with encodeURIComponent rules instead. warnings flag duplicate keys, unencoded spaces and non-ASCII, broken %XX, + being read as a space, mixed-case UTM values, a missing utm_source/utm_medium, passwords in the URL, credential-looking keys and URLs over 2,000 characters. Relative paths and broken percent-encoding are parsed as far as they can be read instead of throwing. mode="encode" / "decode" converts a bare string instead (scheme: component / uri / form). No network access — the URL is never fetchedurl?, mode? (parse default / encode / decode), text?, scheme?, set?, remove?, utm?, removeTracking?, sort?, reencode?, spaceAsPlus?
html_escapeEscapes < > & " ' into HTML entities, or with mode="unescape" turns entities such as &amp;, &#39; and &#x3042; back into characters — the same logic as the browser tool at tools.first-ch.com/html-escape/. Escaping handles & first, so a second pass never double-escapes what the first pass produced; pick named or numeric references (numeric), decide whether quotes are escaped (quotes, mandatory inside an attribute value) and whether ' is written as &#39; or &apos; (apos — &apos; does not exist in HTML 4.01), and encode non-ASCII characters as references (nonAscii) when the charset may not survive the pipeline. Unescaping covers all 252 named references from HTML 4.01 plus decimal and hexadecimal ones, maps C1-range references such as &#128; to their Windows-1252 characters as the spec requires, and leaves unknown names, out-of-range numbers and semicolon-less references untouched rather than guessing. notes reports already-escaped input, bare &, missing semicolons, unknown entity names and no-break spaces (U+00A0)mode? (escape default / unescape), text? or path?, outputPath?, quotes?, apos?, numeric?, nonAscii? (none / named / decimal / hex)
json_to_yamlConverts JSON to formatted YAML, and yaml_to_json converts back — the same logic as the browser tool at tools.first-ch.com/json-yaml/, with no YAML dependency (the parser and writer are implemented in this package). Choose the indent width, the quoting style (quote), how null is written (nullStyle), whether multi-line strings become ` blocks (block), whether keys are sorted (sortKeys) and whether the output starts with --- (docStart). Strings another parser could read as a different type — yes/no/on/off, 0755, 12:30, 2026-08-12, anything numeric-looking — plus strings with surrounding whitespace or a leading -/*/#are quoted automatically, so the output means the same thing to a YAML 1.1 parser such as PyYAML. JSON containing comments, trailing commas, single quotes or unquoted keys (as intsconfig.json) is read and converted, with notes saying it is not valid JSON (relaxed=false` rejects it strictly instead)
yaml_to_jsonConverts YAML to JSON — useful for turning docker-compose, GitHub Actions, Kubernetes and CI config into something a program can handle, and for checking that a file parses at all. A syntax error is returned as an error naming the line, the column, the cause and the fix, with the two surrounding lines quoted and a ^ under the column. Multiple documents (---) become a single JSON array, and anchors (&name), aliases (*name) and merge keys (<<) are expanded because JSON has no references (notes says when that happened). Scalars follow the YAML 1.2 core schema, so yes / no / on / off / NO stay strings — but notes flags them, along with 0755 (decimal 755, not octal), 12:30 (750 in YAML 1.1's base 60), date-like values, duplicate keys and integers beyond 2^53. Supports block mappings and sequences, flow style, quoted scalars (multi-line, with escapes), block scalars (` > with chomping and an explicit indent), tags (!!str !!int !!float !!bool !!null !!binary) and comments; only the explicit ? key` notation is unsupported
px_rem_convertConverts CSS lengths between px, rem, em and pt — the same logic as the browser tool at tools.first-ch.com/px-rem/. Pass value for a single conversion and you get px/rem/em/pt, a ready-to-paste font-size line and the scale of common font sizes (12–64px, one row per size with its typical use); pass css or path and the whole stylesheet is rewritten (direction: px2rem default / px2em / rem2px / em2px). The bulk pass never touches comments, strings (content: "10px"), the contents of url() or digits inside identifiers such as --size-16px, and by default keeps hairlines in px (minPx=2, because a 1px border in rem varies in thickness between devices) and leaves the conditions of @media and other at-rules alone (skipMedia), which is where breakpoints live. ignoreProps excludes properties by prefix, zeroUnitless writes a bare 0. The root can be given as a percentage (root="62.5%" → 10px, read against the 16px browser default), and notes reports rounding, skipped values and the accessibility cost of the 62.5% trickvalue? (24 / "1.5rem") or css? / path?, unit?, outputPath?, direction?, root?, parent?, precision? (auto or 0-6), minPx?, zeroUnitless?, skipMedia?, ignoreProps?, scale?
color_convertConverts a colour between HEX, RGB, HSL and OKLCH and builds the rgba() / hsla() / 8-digit HEX code at any alpha — the same logic as the browser tool at tools.first-ch.com/color/. Input can be HEX (3/4/6/8 digits), rgb(), hsl(), hwb(), oklch(), oklab(), one of the 148 CSS named colours or transparent, in either the legacy comma form or the modern slash form, with angles in deg / grad / rad / turn. Pass a background and flattened returns the colour that actually reaches the screen once the transparency is composited over it (foreground × α + background × (1−α)) — what you need to turn a semi-transparent layer from a mockup into a solid HEX. It also returns the WCAG 2.1 contrast against white and black, an alpha_table stepped by step%, and an 11-step lightness palette (50–950) that keeps the hue and chroma. An OKLCH value outside sRGB has its chroma lowered by binary search until it fits, keeping the lightness and hue, because clipping the RGB channels would shift the hue; notes says when that happened, when the colour matches a named colour exactly, and when it is a neutral greycolor, alpha? (0-1, 0-100 or "50%"), background? (default #ffffff), syntax? (modern default / legacy), uppercase?, alphaPercent?, step? (1-50, default 10), alphaTable?, palette?
hash_generateComputes the MD5, SHA-1, SHA-256, SHA-384 and SHA-512 digests of a string or a file in one call — the same logic as the browser tool at tools.first-ch.com/hash/. Pass expected and the digest is verified against it: the algorithm is inferred from the length, and verification says whether it matched. expected takes command output as-is — the <digest>␣␣<filename> form from sha256sum, the output of shasum -a 256, the SHA256 (file) = … form, a sha256: prefix, colon-separated hex, Base64 and base64url are all understood. Output is lower-case hex by default, or HEX / base64 / base64url. For text, newline (lf / crlf) and bom control the exact bytes that get hashed, so a digest produced from a Windows file can be reproduced (the encoding is always UTF-8); neither applies to path, which is hashed byte for byte and streamed in a single pass when large. notes warns that MD5 and SHA-1 are broken for collision resistance and that a plain digest is not password storagetext? or path?, algorithms? (default ["md5","sha1","sha256","sha512"]), format? (hex default / HEX / base64 / base64url), newline?, bom?, expected?
jwt_decodeDecodes a JWT (JSON Web Token) into its header and payload and reports on the expiry — the same logic as the browser tool at tools.first-ch.com/jwt/. token can be a whole Authorization: Bearer <token> line: the header name, the Bearer prefix, surrounding quotes, trailing commas and line breaks inside the token are all stripped. expiry gives the status (valid / expired / not_yet / no_exp), the ISO timestamps of exp / nbf / iat, the seconds remaining and how far through its lifetime the token is; clockTolerance allows for clock skew, and now pins the current time so a check is reproducible. Pass key and the signature is verified with Web Crypto: HS256/384/512 take the shared secret as a string (keyEncoding accepts base64url / hex), while RS / PS / ES / EdDSA take an SPKI PEM public key or a JWK / JWKS document (a JWKS is matched against the header's kid). A private key, a certificate or a PKCS#1 key is refused with the command that converts it. warnings cover alg: none, a missing signature, an expired or not-yet-valid token, exp given in milliseconds (Date.now() without dividing by 1000), a lifetime that is too long for an access token, and secrets or personal data left in the payload — which anyone holding the token can read, because base64url is encoding, not encryption. A five-segment JWE returns its header only (it is not decrypted), and nothing is ever fetched: JWKS documents must be passed intoken, key?, keyEncoding? (utf8 default / base64url / base64 / hex), clockTolerance? (seconds), now? (Unix seconds)
user_agent_parseParses a User-Agent string into browser name and version, rendering engine, OS and version, device type (desktop / mobile / tablet / tv / console / wearable / bot), vendor and model, and CPU architecture — the same logic as the browser tool at tools.first-ch.com/user-agent/. ua can be a raw access-log line: a leading User-Agent:, surrounding quotes and a trailing comma are stripped. Detection tries the more specific token first (Edg/ → OPR/ → Chrome/ → Safari/), because Chrome, Edge and Opera all claim both Chrome/ and Safari/ and a substring match misclassifies them. tokens breaks the string down token by token and explains the fossils (Mozilla/5.0, KHTML, like Gecko, Mobile/15E148). notes reports what the UA cannot tell you: Chrome's reduced UA (minor version frozen to 0.0.0, Android model frozen to K), macOS always reporting 10_15_7, Windows 10 being indistinguishable from 11, an iPad sending the same UA as a Mac, in-app browsers (LINE / Instagram / Facebook / Android WebView), and the fact that a UA is self-declared and must never be used for access control. Crawlers (Googlebot, bingbot, GPTBot, ClaudeBot, PerplexityBot) and HTTP clients (curl, python-requests, axios) are identified as well. Pass uas to parse many at once and get a summary breakdown by browser, OS and device typeua? or uas? (array), includeTokens? (default: on for 20 strings or fewer)
uuid_generateGenerates 1-100 UUID v4 or ULID values at once — the same logic as the browser tool at tools.first-ch.com/uuid/. A UUID v4 is 128 bits of which 122 are random (the other 6 carry the version and variant); a ULID is 26 characters where the first 10 encode the creation time (Unix milliseconds, 48 bits) and the last 16 are random (80 bits), written in Crockford's Base32. Because a ULID leads with the time, sorting the strings lexicographically sorts them chronologically, and timestamp (ISO 8601, Unix seconds or Unix milliseconds) pins that time for reproducible output. Values minted inside the same millisecond follow the monotonic rule from the ULID spec — the random part is incremented by one — so a batch of 100 still comes out in creation order. Randomness comes from node:crypto randomBytes (CSPRNG); Math.random is never used. format shapes text (one per line / JSON array / comma separated / quoted for a SQL INSERT), and uppercase / hyphens / braces control the spelling (UUID defaults to lower case per RFC 9562, ULID to upper case; hyphens: false gives the 32-character form for MySQL BINARY(16), braces: true the Windows GUID form)type? (uuid | ulid), count? (1-100), format?, uppercase?, hyphens?, braces?, timestamp? (ULID only)
aspect_ratio_calcCalculates between an aspect ratio and a size — the same logic as the browser tool at tools.first-ch.com/aspect-ratio/. Pass ratio (16:9, 16/9, 16x9 or a decimal such as 1.85) with either width or height and the other side comes back, along with the simplified ratio, the decimal, the padding-top percentage and an aspect-ratio declaration. Pass width and height without a ratio and it works backwards: the ratio simplified by the greatest common divisor, the orientation, the megapixel count, the closest common ratio (16:9, 4:3, 3:2, 1:1, 4:5, 9:16, 21:9, 1.85:1, 2.39:1, 1.91:1 for OGP, the golden ratio, A-series paper) with the percentage it is off by, and the name of the size where there is one (1920×1080 is FHD). round takes the result to the nearest whole pixel, an even number, down or up, and notes then reports the real ratio that rounding produced and how far it drifts — H.264 / H.265 store colour at half resolution (YUV 4:2:0), so round: "even" is what video needs. box fits the size into a frame with contain or cover and returns the rendered size, the scale, the letterbox / pillarbox bars, how many pixels are cropped and how much stays visible. widths (or table: true) returns the height at every breakpoint, and snippet: true returns the CSS — with an optional @supports padding-top fallback — plus HTML carrying the width / height attributes that prevent layout shiftratio? and/or width? / height?, round? (none default / round / floor / ceil / even), widths?, table?, box? ("1280x400"), fit? (cover default / contain), snippet?, selector?, target? (img / video / iframe / background), objectFit?, fallback?
markdown_tableTurns TSV or CSV copied from a spreadsheet into a Markdown table, and converts a Markdown table back to CSV, TSV, HTML or JSON — the same logic as the browser tool at tools.first-ch.com/markdown-table/. Copying a range in Excel, Google Sheets or Numbers puts tab-separated text on the clipboard, not comma-separated, so the delimiter is detected by parsing with tabs, commas and semicolons in turn and keeping whichever gives the most consistent column count — thousands separators (1,200) never split a column. CSV input follows RFC 4180 quoting (commas, newlines and doubled quotes inside a quoted field). When padding cells, full-width characters are counted as two columns following the Unicode East Asian Width property, so the pipes line up in a monospaced editor. Columns whose non-empty cells are all numeric (thousands separators, decimals, currency symbols, percent signs, units) are right-aligned with ---:, and aligns overrides any column. Pipes inside cells become |, line breaks become <br> (or a space), short rows are padded with empty cells, and every fix is reported in notes rather than applied silently. Reading a Markdown table picks up the alignment colons and turns <br> back into a real newline, so a CSV export reopens cleanly in a spreadsheettext or path, outputPath?, from? (auto default / tsv / csv / ssv / markdown), to? (markdown default / csv / tsv / ssv / html / json), header? (first default / auto / none), align?, aligns?, pad?, eastAsian?, autoNumber?, trim?, skipEmpty?, transpose?, multiline? (br default / space), eol?
sql_formatFormats a SQL query that has been squashed onto a single line — uppercase keywords, a line break per clause and real indentation — the same logic as the browser tool at tools.first-ch.com/sql-format/. SELECT / FROM / WHERE / GROUP BY / HAVING / ORDER BY / LIMIT / INSERT INTO / VALUES / UPDATE / SET / DELETE FROM / WITH / UNION start a line and their contents are indented one level; joins start a line with ON indented below them; AND / OR break per condition, except the AND of BETWEEN a AND b. A parenthesis becomes an indented subquery only when SELECT, WITH or VALUES follows it, so function calls (SUM(…), IN (1, 2, 3), OVER (PARTITION BY … ORDER BY …)) stay on one line, and CASE gets WHEN / ELSE / END stacked. Only keywords and type names are re-cased — table, column and alias spellings are left exactly as typed, because identifier folding differs per database. Strings, quoted identifiers ("…" / `…` / […]), comments and placeholders (? / :name / $1 / @var) pass through verbatim. notes reports UPDATE or DELETE without a WHERE, unbalanced parentheses and quotes, SELECT *, implicit comma joins and placeholder usage. compact collapses everything back onto one line. It is a lexical formatter rather than a parser for one database, so MySQL, PostgreSQL, SQL Server, SQLite and Oracle dialects survive as written (syntax errors are not detected)text or path, outputPath?, keywordCase? (upper default / lower / preserve), functionCase?, indent? (2 / 4 default / 8 / tab), commaStyle? (trailing default / leading), logicStyle? (leading default / trailing), breakColumns?, breakLogic?, breakOn?, breakCase?, breakSubquery?, expandClauses?, compact?, eol?
qr_generateTurns a URL or any text into a QR code and returns it as SVG (vector), PNG or terminal-friendly text art — the same logic as the browser tool at tools.first-ch.com/qr/. Encoding (numeric, alphanumeric or UTF-8 byte mode, picked automatically from the input), Reed–Solomon error correction, the layout of finder, timing and alignment patterns, version information and the choice between the eight mask patterns are all implemented here (JIS X 0510 / ISO 18004, versions 1–40); there is no external API or image service. ecLevel trades capacity for damage tolerance (L about 7%, M about 15%, Q about 25%, H about 30% — use Q or H for print), size is the edge length in pixels, and margin is the quiet zone in modules (4 is the recommended default; 0 can break scanning over a patterned background). Wi-Fi (WIFI:T:WPA;S:…;P:…;;), mailto:, tel:, SMSTO: and geo: strings just go in as text. outputPath writes the file instead of returning the body; format="png" without it returns a data URI. Capacity tops out at 7,089 digits, 4,296 alphanumeric characters or 2,953 bytes (all at level L)text, ecLevel? (L / M default / Q / H), size? (64–4096, default 320), margin? (0–32, default 4), format? (svg default / png / text), mode? (auto default / numeric / alnum / byte), mask? (0–7), minVersion?, outputPath?
unixtime_convertConverts Unix seconds, milliseconds, microseconds and nanoseconds to and from ISO 8601 and ordinary date strings — the same logic as the browser tool at tools.first-ch.com/unixtime/. The unit of a plain number is detected from its digit count (up to 10 digits seconds, up to 13 milliseconds, up to 16 microseconds, longer nanoseconds); unit states it outright instead. Digits below the millisecond are dropped and reported in notes. On the date side it accepts 2026-08-24T09:30:00Z (ISO 8601), 2026-08-24 18:30, 2026/8/24 9:05, the Japanese 2026年8月24日 18時30分, Sun, 24 Aug 2026 03:00:00 GMT (HTTP-date) and now, stripping the quotes, brackets and trailing commas that come with a paste from CSV or JSON. input takes one value per line, up to 500 lines at a time, and every row comes back with Unix seconds, milliseconds, ISO 8601 in UTC, local time in timeZone (with weekday and UTC offset) and a relative reading ("30分後" / "in 30 minutes"); a line that cannot be read fails on its own without taking the others down. A date with no offset is read as a wall-clock time in timeZone and always says so in notes; an explicit +09:00 or Z in the input wins over timeZone. A wall-clock time that daylight saving skips is moved forward to the moment after the change, also noted. An 8-digit number such as 20260824 is Unix seconds here, so it is flagged in case a date was meant. Negative values (before 1970) and fractional seconds workinput, timeZone? (IANA name, default UTC), unit? (auto default / s / ms / us / ns), now? (Unix milliseconds or a date string, default the current time), lang? (ja default / en)
robotstxt_generateAssembles a robots.txt from crawl rules, sitemap declarations and a preset for AI crawlers — the same logic as the browser tool at tools.first-ch.com/robots-txt/. ai.preset decides how 24 known AI crawlers are treated in one move: training (the default: refuse the ones that collect training data — GPTBot, ClaudeBot, Google-Extended, Bytespider, CCBot and the rest — while allowing AI search and on-demand fetchers such as OAI-SearchBot, Claude-SearchBot, PerplexityBot and ChatGPT-User), allow, block, none (leave AI crawlers out) or custom with ai.overrides naming them one by one. A crawler obeys exactly one matching group, so writing a group for GPTBot stops the User-agent: * rules from ever reaching it; by default the shared disallow paths are copied into the AI groups to close that gap (ai.inherit: false turns it off). Paths get a leading slash added and full URLs reduced to their path, and warnings reports spaces inside a path, non-ASCII paths that need percent-encoding, wildcards that not every crawler supports, a Crawl-delay Googlebot will ignore, a missing sitemap, a User-agent listed twice and a site blocked in full. listCrawlers: true returns just the crawler list (name, vendor, purpose) without generating anythingsiteUrl?, disallow?, allow?, userAgents? (default *), crawlDelay?, blockCrawlers?, sitemaps?, ai? (preset?, overrides?, inherit?), groups?, comments? (default true), allowStyle? (disallow-empty default / allow-slash), listCrawlers?, lang? (ja default / en), outputPath?
case_convertConverts identifiers between eleven cases — camelCase, PascalCase, snake_case, CONSTANT_CASE, kebab-case, Train-Case, dot.case, Title Case, Sentence case, lower case and UPPER CASE — the same logic as the browser tool at tools.first-ch.com/case/. Built for the mechanical jobs at the boundary between layers: renaming variables in bulk, moving between snake_case database columns and camelCase JSON keys, tidying CSV headers. scope sets the unit of work: lines (the default, one item per line), items (every comma or tab separated field of a line, for CSV header rows) or whole. Leading and trailing spaces, indentation, line endings (LF/CRLF) and the separators are preserved, so only the names change. A run of capitals is broken only before a capital followed by a lower-case letter (XMLHttpRequest → XML / Http / Request), and digits stay attached to the word before them (sha256Hash → sha256 / Hash; splitDigits splits them). Acronyms fold to parseXmlData by default and stay capitalised with keepAcronyms, except the first word of a camelCase name, which is always lower-cased (URLParser → urlParser). Characters with no letter case (Japanese, for example) pass through rather than being transliterated. notes reports names that collide after conversion (first name and first_name both become first_name, which is how a column silently disappears on import), results starting with a digit that cannot be identifiers, and items containing acronyms; items[].detected names the case each input was written in. allFormats expands every item into all eleven cases, listFormats returns just the list of cases with what each is used fortext? or path?, outputPath?, format? (camel default), scope? (lines default / items / whole), splitDigits?, keepAcronyms?, allFormats?, listFormats?, lang? (ja default / en)
csv_convertConverts CSV/TSV into a JSON array and back — the same logic as the browser tool at tools.first-ch.com/csv-json/. For moving data you already have between a spreadsheet and an API: turning an exported table into JSON a request body can carry, or an API response into something Excel opens. With direction omitted it guesses json2csv when the input starts with [ or { and csv2json otherwise. The delimiter is detected by looking at the first 20 lines for the character that appears the same number of times on every line, and can be pinned with delimiter. Column names such as stock.qty are read and written as nested objects, and tags.0 / tags.1 (tags[0] means the same) become an array — the reverse direction flattens by the same rule, so a round trip through CSV restores the original structure (nest: false writes nested values into a single cell as JSON text). Type inference is decided by round trip — a value becomes a number only when converting it back to text is character-for-character identical — so 0123, +1, 1.50 and integers beyond 2^53 (12345678901234567890) stay strings and postcodes, phone numbers, invoice numbers and version strings survive. Reading follows RFC 4180: quoted cells, "" escapes, line breaks inside cells, CRLF and a BOM are all handled, and the output side offers bom and newline for Excel. On the JSON side it accepts an array, a single object, an object wrapping an array such as {"data":[…]}, and JSON Lines. A JSON syntax error comes back as an ok: false result with a line, a column and an excerpt rather than an exception, so the reply itself says where to fix it. notes also reports rows whose column count does not match the header, duplicate header names (kept as name_2), empty headers (named column4), values that would lose digits, cells starting with =, +, - or @ that a spreadsheet may execute as a formula (CSV injection), and objects with a different set of keystext? or path?, outputPath?, direction? (auto default / csv2json / json2csv), delimiter? (auto default / comma / tab / semicolon / pipe), header?, nest?, types?, trim?, emptyNull?, indent? (2 default / 0–8 / tab), newline? (lf default / crlf), quoteAll?, bom?, lang? (ja default / en)
zenkaku_convertConverts letters and digits, katakana, symbols and spaces between their full-width and half-width forms with a direction chosen per kind, and cleans up the whitespace in the same pass — the same logic as the browser tool at tools.first-ch.com/zenkaku/. For normalising Japanese copy supplied by a client, cleaning a file before an import, and tidying form input. Each of alnum / kana / symbol / space takes keep, han (half-width) or zen (full-width); the defaults are the form most Japanese copy is set in — letters, digits, symbols and spaces half-width, katakana full-width (the same as preset: 'ja'). preset offers ja, csv (ja plus the whitespace and invisible-character cleanup), han and zen, and any per-kind option overrides it. Half-width katakana is not one character per glyph, so converting to full-width composes a following voiced mark (ガ → ガ, パ → パ, ヴ → ヴ) and converting the other way splits it into two. Japanese punctuation, brackets, the middle dot and the prolonged sound mark (。 、 「 」 ・ ー) live inside the half-width katakana block (U+FF61–U+FF9F) and are treated as katakana (kana: 'han' turns 「テスト」。 into 「テスト」。; use keep to leave the punctuation full-width). Spaces cover U+3000 ⇄ U+0020 and fold NBSP and the Latin space family to the half-width side. The cleanup is collapseSpaces (a run of spaces becomes its first character), trimLines, blankLines (keep / collapse / remove), removeInvisible (zero-width, BOM, control codes) and composeMarks (NFC, for copy that writes ガ as カ plus a combining U+3099). Line endings (LF/CRLF), tabs, hiragana and kanji are never rewritten. notes reports what is left — half-width katakana, ideographic spaces, invisible characters, combining marks — plus the wave dash 〜 (U+301C) versus the fullwidth tilde ~ (U+FF5E) and platform-dependent characters (① ㈱ Ⅲ), which are reported and never rewritten because which way they should go depends on the destination. This is deliberately not NFKC: ① never becomes 1, and only the kinds you selected are touched. inspect: true converts nothing and returns just the audittext? or path?, outputPath?, preset? (ja / csv / han / zen), alnum?, kana?, symbol?, space? (each keep / han / zen), collapseSpaces?, trimLines?, blankLines? (keep default / collapse / remove), removeInvisible?, composeMarks?, inspect?, lang? (ja default / en)
cidr_calcTurns CIDR notation, a subnet mask, an ACL wildcard mask or a bare address into the network address, broadcast address, usable host range, address and host counts, reverse DNS zone and a binary breakdown — the same logic as the browser tool at tools.first-ch.com/cidr/. For subnet maths while writing server configs, firewall rules and Basic-auth allow lists. IPv4 and IPv6 both work: :: compression, a trailing IPv4 form (::ffff:192.168.0.1), [...] brackets and a %zone suffix are parsed, and output follows RFC 5952. 192.168.1.5 255.255.255.0 and 192.168.1.5/0.0.0.255 (the ACL convention) are accepted in the same field. The exceptions in host counting are built in: a /31 has two usable addresses for point-to-point links (RFC 3021), a /32 is one host, and IPv6 has no broadcast address. When host bits are set in the address you pass, notes returns the block it actually belongs to — the form that belongs in a config file. Octets with a leading zero (192.168.001.1) are refused, because some libraries read them as octal and the same text then means a different address. The address type is matched against the main IANA special-purpose blocks (private, CGNAT, loopback, link-local, documentation, multicast, ULA and more) and a network that extends beyond its reserved range is flagged. split lists the equal subnets of a new prefix length, contains tests addresses for membership, and range reduces ranges such as 10.0.0.5 - 10.0.0.200 (mixed with CIDR blocks and single addresses, one per line or ;-separated) to the fewest blocks that cover them exactly, merging overlaps and adjacencies first. All arithmetic is BigIntcidr? and/or range?, split? (prefix length), contains? (string[]), limit? (1-4096, default 256), lang? (ja default / en)

Documentation truncated — see the full README on GitHub.

Reviews

No reviews yet

Be the first to review this server!