Configuration

wrangler.toml (the whole file)

name = "plot-mcp-worker"
main = "src/index.ts"
compatibility_date = "2026-04-22"
workers_dev = true

[[routes]]
pattern = "your-worker.your-domain.com/*"
zone_name = "your-domain.com"

[[kv_namespaces]]
binding = "SHORT_LINKS"
id = "YOUR_KV_NAMESPACE_ID"
preview_id = "YOUR_KV_PREVIEW_NAMESPACE_ID"

[build]
command = ""

[[rules]]
type = "Data"
globs = ["**/*.ttf"]
fallthrough = true

KV namespace SHORT_LINKS

Binding name SHORT_LINKS. Three uses:

  1. Short link records — key short:{8-char-token}, JSON value {path, payload}, TTL 30 days
  2. Fonts (critical) — key font:arial-unicode-cn-gb2312 (TTF bytes), key font:arial-sans (TTF bytes), no TTL
  3. Anything else? — no, those are the only two namespaces referenced in src/index.ts and src/render.ts

Font upload (one-time setup)

loadFonts in src/render.ts L79-97 fetches both fonts from KV on first PNG render. If either is missing, it throws No CJK font loaded from KV (...). The fonts must be uploaded as raw arrayBuffer:

wrangler kv:key put --binding=SHORT_LINKS   "font:arial-unicode-cn-gb2312"   --path=./fonts/ArialUnicodeCN.ttf

wrangler kv:key put --binding=SHORT_LINKS   "font:arial-sans"   --path=./fonts/ArialSans.ttf

The first font (CJK) is also parsed with opentype.js and used by pathifyCjkText to convert CJK glyphs and math unicode (π, ², ³, ∫, √, etc.) to SVG paths before resvg renders them. Without this, Chinese labels and math symbols render as .

The [[rules]] for .ttf

Wrangler's default behavior tries to bundle TTF files into the worker script, which fails for large fonts. The rule { type = "Data", globs = ["**/*.ttf"], fallthrough = true } tells wrangler: treat .ttf files as data (separate asset) and fall through to the next matching rule. This is what lets the fonts live in KV instead of being inlined into the worker bundle.

Constants (from src/constants.ts)

ConstantValueUsed for
SERVER_NAME"plot-mcp-worker"health/init response
SERVER_VERSION"0.4.14"health/init response (differs from package.json)
SHORT_LINK_PATH_PREFIX"/s/"Short URL path prefix
SHORT_LINK_TOKEN_LENGTH8Token length
SHORT_LINK_TTL_SECONDS2592000 (30 days)KV TTL for short link records
MIN_POINTS / MAX_POINTS10 / 20000Series point count clamp
DEFAULT_POINTS1000When caller doesn't specify
MAX_EXPR_LENGTH400Truncate math expressions
MAX_TITLE_LENGTH120Truncate titles
MAX_LABEL_LENGTH80Truncate labels
MAX_SERIES12Max series per plot
MAX_FORCE_ITEMS16Max forces per body
MAX_FORCE_BODIES8Max bodies in one scene
MAX_CIRCUIT_COMPONENTS24Max components per circuit
MAX_3D_SURFACES6Max surfaces in 3D scene
DEFAULT_WIDTH / DEFAULT_HEIGHT1200 / 720SVG/PNG canvas size
DEFAULT_FONT_FAMILY"ArialUnicodeCN"Used for resvg font lookup
DEFAULT_PALETTE8 colors (blue/red/green/amber/purple/cyan/orange/pink)Series auto-color when caller omits color

TypeScript config (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "Bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": ["@cloudflare/workers-types"]
  },
  "include": ["src/**/*.ts"]
}

ES2022 + strict mode. skipLibCheck skips checking @cloudflare/workers-types. Wrangler's Bundler resolution mode means you don't need to declare explicit import paths for the npm dependencies.