mcp-gen
OpenAPI v3 또는 Swagger 2.0 스펙에서 TypeScript, Python, Go로 MCP 서버를 생성합니다. 각 라우트는 타입이 지정된 도구가 되며, 커스텀 코드를 보존하는 증분 재생성을 지원합니다.
문서
MCP-Generator
Also available in: Português (Versão em Português)
Generate MCP servers from OpenAPI specs.
Status:
@christopher_dondici/mcp-gen2.3.5 is the latest published version on npm. See release notes (PT-BR).
mcp-gen turns an OpenAPI v3 or Swagger 2.0 spec into an MCP server in TypeScript, Python, or Go. It maps each route to a tool, generates typed models (including enums, oneOf/anyOf), and keeps custom code when you regenerate.
What's new in 2.3.5
(Patch release — no breaking changes.)
- Operation allowlist
METHOD pathnow matches case-insensitively (get /pets=GET /pets). - Filters that match zero tools emit a
Filters matched 0 of N toolswarning suggesting--dry-run. - Go incremental regeneration uses the Go default stub (
handler not implemented); untouched stubs are no longer preserved as custom. - Non-JSON request bodies and response examples fall back to the first content-type when
application/jsonis absent (coversmultipart/form-dataandurlencodedfrom Swagger 2.0formDataconversion). - Local verification: 19 Jest suites / 244 tests, CLI exit-code smoke 3/3, TypeScript/Python/Go generated-server smokes,
npm audit --omit=devclean.
What's new in 2.3.4
(Patch release — no breaking changes.)
ip-address10.4.0 → 10.7.2 through the SDK transitive chain (express-rate-limit^10.2.0), sonpm audit --omit=devis clean again.- New
tests/scaffold-lockfile.test.tsguard: scaffoldpackage.json.hbsranges against thepackage-lock.json.hbssnapshot, plus anip-addressfloor above 10.5.0 in both project and scaffold lockfiles. - Dev-only
js-yamlfinding stays documented inSECURITY.md, with no broad Jest upgrade on the 2.3.x line. - Local verification: 19 Jest suites / 238 tests, CLI exit-code smoke 3/3, TypeScript/Python/Go generated-server smokes,
npm audit --omit=devclean.
What's new in 2.3.3
(Patch release — no breaking changes.)
- Missing
--env-filepaths now fail with an explicit error instead of being silently ignored. - The interactive
initflow shows Go next steps (go mod tidy && go run .) instead of suggestingpip install. - Placeholder links in generated READMEs and SECURITY docs replaced with the official repository links.
distis cleaned before every build, so stale artifacts can't leak into builds or tarballs.- Local verification: 18 Jest suites / 234 tests, CLI exit-code smoke 3/3, TypeScript/Python/Go generated-server smokes,
npm audit --omit=devclean.
What's new in 2.3.2
(Patch release — no breaking changes.)
js-yamlandopenapi-typesare now direct dependencies instead of transitive ones; YAML spec scanning in security-lint uses a typed import.- Registry URL validation is covered by real tests: non-HTTPS, unknown and removed keys fail without calling
fetch. - Trailing
/**path globs also match the base path, so/pets/**includes/pets. - Incremental markers gained a Go default-stub pattern plus round-trip coverage for
<generated:handlers:name>guards alongside the legacy@@mcp-genmarkers. - New Go compilation smoke (
npm run test:generated:go): the Petstore Go scaffold runsgo mod tidy+go build, also gated in CI with Go 1.22. - Local verification: 17 Jest suites / 232 tests, CLI exit-code smoke 3/3, TypeScript and Go generated-server smokes,
npm audit --omit=devclean.
What's new in 2.3.1
(Patch release — no breaking changes.)
- Generated TypeScript projects include
package-lock.json, so their CI and Dockernpm cicommands work from a fresh checkout. --forcenow takes precedence when combined with--incremental, discarding preserved handlers as documented.watch --oncereturns exit code 1 on fetch, parse, or generation failures and uses Commander's async action flow.- ESLint is installed locally with a minimal TypeScript flat config and runs in both CI and release.
- Local verification: 16 Jest suites / 214 tests, CLI exit-code smoke, TypeScript and Python generated-server smoke, and
npm pack --dry-run.
What's new in 2.3.0
(Fase 2 — anchor: unlocks the registry, no breaking changes.)
- Swagger 2.0 support: v2 specs are converted to v3 internally on ingest (
host/basePath/schemes→servers,definitions→components.schemas, body/formData →requestBody,securityDefinitions→securitySchemes).validate+generateaccept v2 files (seeexamples/swagger-v2-petstore.json). - Registry re-enabled:
slack,kubernetes,digitaloceanare back (v2, converted on the fly); onlyazurestays removed (it was a types fragment, not a full spec). - Scale benchmark:
examples/large-scale.json(180 ops, 10 tags) proves180 → 10 toolswith--group-by tag(also10withpath-prefix). See Benchmark.
What's new in 2.2.0 (previous)
(Fase 1 — solid base, no breaking changes.)
generate --dry-runlists tools/models/groups/files without writing anything;--jsonprints a machine-readable summary (Codex-friendly, no chalk noise).watchaccepts the same filter/group flags asgenerate, and the interactive mode asks for filters and grouping.watch --onceexits after the first generation on file inputs too.validate(andgenerate) warn per affected schema whenallOf$refs are skipped or inlineoneOf/anyOfvariants are dropped (partial support is no longer silent).- OSS hygiene: CONTRIBUTING updated,
MCP_GEN_ALLOW_PLUGINSdocumented in Plugins.
What's new in 2.1.5 (previous)
(Fase 0, PR #4 — P0 fixes on top of 2.1.4.)
- TypeScript client serializes query params (
queryNames+URLSearchParams);get_pets({ limit: 5 })calls/pets?limit=5. - Python server passes query and headers (
_build_query/_build_headers,kwargs["params"]) in--httpmode, including grouped tools. - Go
--httpmode wired to the realAPIClient(__client.do(...),q.Encode(),PathEscape), no morenot yet wiredstubs. - Registry is v3-only (
stripe,github,openai,petstore,twilio,shopify); removed keys fail with guidance and unknown keys listKnown keys; v2 specs fail withOnly OpenAPI v3.
What's new in 2.1.4 (previous)
(The v2.1.3 tag was superseded before reaching npm; everything below shipped in 2.1.4, plus a fix for the generated auth middleware on specs without securitySchemes.)
- Path filtering with globs:
--path-prefix "/users/**",--include-paths,--exclude-paths; inline--operation-allowlist op1,op2(file still supported). - Aggregation with
--group-by tag | path-prefix: one logical tool per tag or path segment, routing internally byaction(operation name + method). - Name dedup: collisions fall back to method suffix, then short path hash.
- Incremental guards:
<generated:handlers>regions plus per-tool@@mcp-genmarkers, 3-way merge on--incremental,--forceto overwrite. - Separate auth middleware (
src/auth.ts,auth.py,auth.go) generated fromsecuritySchemes, andhandlers.custom.*files that are never overwritten without--force.
Quick start
With Git, Node.js 20+ and npm 9+ installed, run:
git clone https://github.com/ChristopherDond/MCP-Generator.git
cd MCP-Generator
npm ci
npm run build
node dist/cli/index.js --version
Generate a server from a local spec:
node dist/cli/index.js generate -i examples/petstore.yaml -l typescript -o ./my-server
Validate a spec without generating files:
node dist/cli/index.js validate -i examples/petstore.yaml
Run these commands from the repository root on main. The build and packaging fixes are part of 2.1.2. Generation writes a scaffold; it does not install dependencies, build, or start the generated server.
Run the interactive CLI if you prefer prompts:
npm run dev
What it does
sequenceDiagram
participant User
participant CLI
participant Parser
participant Generator
participant Output
User->>CLI: mcp-gen generate --input api.yaml --lang go
CLI->>Parser: validate and parse OpenAPI v3 / Swagger 2.0 (JSON or YAML)
Parser->>Generator: internal AST (tools, models, examples)
Generator->>Output: render Handlebars templates
Output-->>User: TypeScript, Python, or Go MCP server project
Each route becomes an MCP tool with:
- typed input from parameters (path, query, header, cookie, body) and request bodies
- example responses from the spec
- enum / oneOf / anyOf / discriminator schema support
- real HTTP client mode (
--http) that calls the actual API - scaffolded authContext checks for scoped metadata and credential-like argument keys; review before deployment
- optional incremental code preservation
Requirements
- Node.js 20+
- npm 9+ (the source quick start uses the repository lockfile)
- Git to clone the repository
- (Optional) Python 3.8+ for Python projects
- (Optional) Go 1.22+ for Go projects
Local installation and command shorthand
Install the latest release with npm install -g @christopher_dondici/mcp-gen@2.3.4. To work from source, use the build in Quick start.
Throughout this README, mcp-gen is shorthand for node dist/cli/index.js from the repository root. For example, mcp-gen validate -i examples/petstore.yaml means node dist/cli/index.js validate -i examples/petstore.yaml.
Optionally, run npm link from the repository root after building to make the mcp-gen command point to your local checkout. This changes npm's global links; it does not download a published @christopher_dondici/mcp-gen package. The npm package name changed because mcp-gen was rejected for similarity to mcpgen; the command remains mcp-gen.
To install a locally produced tarball without publishing:
npm install ./christopher_dondici-mcp-gen-2.3.4.tgz
./node_modules/.bin/mcp-gen --version
./node_modules/.bin/mcp-gen validate -i node_modules/@christopher_dondici/mcp-gen/examples/petstore.yaml
CLI
Commands
mcp-gen generateormcp-gen gcreates a server from a spec.mcp-gen validateormcp-gen vchecks a spec with detailed warnings (name collisions, missing examples, unsupported schemas).mcp-gen initdownloads a known public spec and can generate a project.mcp-gen watchwatches a file or URL and regenerates on changes.
Generate
mcp-gen generate -i ./api/openapi.yaml -l typescript -o ./my-server
mcp-gen generate -i ./api/openapi.yaml -l python -o ./my-server
mcp-gen generate -i ./api/openapi.yaml -l go -o ./my-server
Useful flags:
--force,-foverwrites existing files, ignoring preserved handlers and custom files (skips 3-way merge). It wins when combined with--incremental.--incrementalkeeps code between@@mcp-gen:startand@@mcp-gen:end(also<generated:handlers:name>). Uses 3-way merge: base stub vs your custom code vs new template.--httpgenerates handlers that call the real API over HTTP instead of returning example stubs.--env-file <path>embeds TOKEN/BASE_URL from a .env-style file into the generated client.--name <name>sets the server name.--server-version <version>sets the server version.--plugin <path>loads a plugin module or folder (can be repeated).--include-tags <a,b>only includes tools with one of these tags.--exclude-tags <a,b>excludes tools with these tags.--path-prefix <glob>only includes paths matching a prefix or glob (/users,/users/**,/pets/*).--include-paths <globs>comma-separated path globs to include.--exclude-paths <globs>comma-separated path globs to exclude.--operation-allowlist <ops>comma-separatedoperationId, tool name, orMETHOD /pathlist, or a path to an allowlist file (JSON array or line/comma separated).--group-by <mode>aggregates to one logical tool per group:tagorpath-prefix. Each group routes byaction(operation name) internally.--dry-runlists tools/models/groups/files that would be generated without writing anything.--jsonprints the generation summary as machine-readable JSON (pairs with--dry-runfor scripting).
Filtering examples
mcp-gen generate -i api.yaml -o ./out --include-tags pets,orders
mcp-gen generate -i api.yaml -o ./out --exclude-tags admin
mcp-gen generate -i api.yaml -o ./out --path-prefix "/users/**"
mcp-gen generate -i api.yaml -o ./out --include-paths "/users/**,/orders/*" --exclude-paths "/users/internal/*"
mcp-gen generate -i api.yaml -o ./out --operation-allowlist listPets,createPet
mcp-gen generate -i api.yaml -o ./out --operation-allowlist ./allow.json
mcp-gen generate -i api.yaml -o ./out --include-tags pets --group-by tag
Grouping
--group-by tag emits one tool per tag (plus untagged), e.g. 200 operations across 8 tags become ~8 tools. --group-by path-prefix emits one tool per first path segment (/users/** becomes users_group). Each grouped tool takes a required action enum (member operation names) and routes internally by METHOD + path. Member params are unioned as optional.
Benchmark
Measured on examples/large-scale.json (180 ops across 10 tags, 2 models):
| Mode | Tools |
|---|---|
| no grouping | 180 |
--group-by tag | 10 |
--group-by path-prefix | 10 |
180 → 10 tools — grouping cuts the surface by 18x on this fixture. Covered by tests/scale.test.ts.
Tool name dedup
Tool names come from METHOD + path (GET /pets/{id} becomes get_pets_petid). operationId is stored for allowlist matching. On collision the generator suffixes with the method first, then with a short path hash, instead of emitting duplicate tools.
Auth middleware
Generated projects include a separate auth layer built from securitySchemes:
- TypeScript:
src/auth.ts - Python:
auth.py - Go:
auth.go
Put business logic in guards; keep auth and schema validation in the middleware so you do not need a guard for auth.
How not to overwrite your edits
Generated handlers are wrapped in two markers:
// <generated:handlers>
// @@mcp-gen:start:get_pets
// ... your code here ...
// @@mcp-gen:end:get_pets
// </generated:handlers>
Rules:
- Edit only between
@@mcp-gen:start:<tool>and@@mcp-gen:end:<tool>(or<generated:handlers:<tool>>). That body is preserved on regen. - Put reusable business logic in
src/handlers.custom.ts(TS),handlers_custom.py(Python), orhandlers_custom.go(Go). That file is created once and never overwritten unless you pass--force. - Re-run with
generate --incremental. The generator does a 3-way merge (fresh stub vs your custom body vs new template) and reportspreservedhandlers plusMerged ... custom handlers preserved. Pass--forceto ignore preservation and overwrite everything; force also wins if both flags are present.
Validate (v2.1+)
mcp-gen validate -i ./api/openapi.yaml
Outputs a rich report:
Spec is valid
Tools: 12 Models: 8 Base URL: https://api.example.com
2 warning(s):
⚠ Tool name collision resolved: "get_users" appears 2x (unique suffixes added)
⚠ 3 tool(s) have no example response: get_users_id, delete_user, patch_user
Security and lint (v2.1.1)
node dist/cli/index.js security -p ./my-server
node dist/cli/index.js security -p ./my-server --fail-on-warn
Scans generated files for credential-like patterns, authorization-related identifiers, naming, descriptions, and incremental markers. --json prints a JSON report, but the CLI also prints a header; stdout is not a pure JSON document. Errors cause exit code 1; --fail-on-warn also fails on warnings. This is static analysis, not a security guarantee.
Init
init uses the built-in registry:
mcp-gen init --from list
mcp-gen init --from stripe
mcp-gen init --from stripe --generate -o ./stripe-mcp
Available registry keys:
| Key | Description |
|---|---|
stripe | Stripe Payment API |
github | GitHub REST API |
openai | OpenAI API |
petstore | Swagger Petstore example |
twilio | Twilio Communications API |
shopify | Shopify Admin API |
slack | Slack Web API (Swagger 2.0, converted) |
kubernetes | Kubernetes API (Swagger 2.0, converted) |
digitalocean | DigitalOcean API (Swagger 2.0, converted) |
OpenAPI v3 and Swagger 2.0 are supported (v2 is converted to v3 on ingest). Only azure stays removed — it pointed at a types fragment, not a full spec.
Watch
mcp-gen watch -i ./api/openapi.yaml -o ./my-server
mcp-gen watch -i https://example.com/spec.json --interval 60000
For URL inputs, --interval <ms> controls the polling interval. --once runs one generation immediately and exits. Fetch, parse, or generation failures return exit code 1 instead of a false success.
watch accepts the same filtering flags as generate (--include-tags, --exclude-tags, --path-prefix, --include-paths, --exclude-paths, --operation-allowlist, --group-by), plus --http, --force/--incremental:
mcp-gen watch -i ./api/openapi.yaml -o ./my-server --include-tags pets --group-by tag --once
Plugins
Plugins can override templates and register extra Handlebars helpers.
Basic structure:
templates/typescript/...,templates/python/..., ortemplates/go/...for.hbstemplate overridesindex.jsthat exportsregisterHandlebars(handlebars)for custom helpers
Example:
mcp-gen generate -i ./api/openapi.yaml --plugin ./my-plugin
mcp-gen watch -i ./api/openapi.yaml --plugin ./my-plugin
Plugin templates override core templates when they use the same path under templates/<lang>/.
Plugin code execution gate: template overrides always apply, but a plugin's JS module (
registerHandlebars) is only loaded whenMCP_GEN_ALLOW_PLUGINS=trueis set. Without it,--pluginonly provides template overrides. Never enable the variable with untrusted plugins — see SECURITY.md.
Generated project structure
TypeScript:
my-server/
├── src/
│ ├── server.ts # MCP server — tool definitions + handlers
│ ├── auth.ts # Auth/validation middleware from securitySchemes
│ ├── handlers.custom.ts # Your code — never overwritten without --force
│ ├── models.ts # TypeScript interfaces from OpenAPI schemas (enums, unions)
│ └── client.ts # HTTP client (used in --http mode)
├── .github/
│ └── workflows/
│ └── ci.yml
├── Dockerfile
├── package.json
├── package-lock.json
├── tsconfig.json
└── README.md
Python:
my-server/
├── server.py # FastMCP server — tool definitions + handlers
├── auth.py # Auth/validation middleware from securitySchemes
├── handlers_custom.py # Your code — never overwritten without --force
├── models.py # Pydantic models from OpenAPI schemas (enums, unions)
├── requirements.txt
├── .github/
│ └── workflows/
│ └── ci.yml
├── Dockerfile
└── README.md
Go (new in v2.1):
my-server/
├── main.go # MCP server using mark3labs/mcp-go
├── auth.go # Auth/validation middleware from securitySchemes
├── handlers_custom.go # Your code — never overwritten without --force
├── models.go # Go types from OpenAPI schemas (enums, unions)
├── client.go # HTTP client (used in --http mode)
├── go.mod
├── .github/
│ └── workflows/
│ └── ci.yml
├── Dockerfile
└── README.md
Connect to Claude Desktop
TypeScript:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/to/my-server/dist/server.js"]
}
}
}
Python:
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/absolute/path/to/my-server/server.py"]
}
}
}
Go:
{
"mcpServers": {
"my-server": {
"command": "go",
"args": ["run", "/absolute/path/to/my-server/main.go"]
}
}
}
Restart Claude Desktop. Your API tools appear automatically.
Security & authContext Contract
The generated tools expect scoped authorization metadata (not raw credentials):
{
"tokenId": "tok_abc123",
"principal": "user:42",
"expiresAt": "2026-05-11T14:00:00Z",
"allowedTools": ["get_orders"],
"endpointAllowlist": ["GET /orders"],
"spendLimitUsd": 5,
"spendUsedUsd": 1.2,
"revoked": false,
"requestId": "req_01J..."
}
The scaffold blocks arguments like token, authorization, api_key, client_secret, password, secret by default.
Quick example (env var):
# Linux / macOS
export TOKEN=your_api_key_here
# Windows (PowerShell)
$env:TOKEN='your_api_key_here'
For advanced integrations and management, consider Cohesivity.ai as a backend for auth, storage, and revocation policies.
Implement handlers
Generated files return spec examples by default. Replace stubs with real logic.
TypeScript (src/server.ts):
case "get_users_id": {
// @@mcp-gen:start:get_users_id
const user = await db.users.findById(args.id);
return { content: [{ type: "text", text: JSON.stringify(user) }] };
// @@mcp-gen:end:get_users_id
}
Python (server.py):
@mcp.tool()
async def get_users_id(id: float, auth_context: dict | None = None) -> Any:
# @@mcp-gen:start:get_users_id
user = await db.users.find_by_id(id)
return user
# @@mcp-gen:end:get_users_id
Go (main.go):
s.AddTool(get_users_idTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// @@mcp-gen:start:get_users_id
return jsonSerialize(jsonExample(`{"id": 1, "name": "Alice"}`))
// @@mcp-gen:end:get_users_id
})
Code between @@mcp-gen:start and @@mcp-gen:end markers is preserved when you re-run generate --incremental (see How not to overwrite your edits).
Programmatic API (Library Mode)
With the package installed from npm, import the scoped package as shown below. From the repository root after building, use "./dist/index.js" instead.
import { generate, validateSpec, parseOpenAPI } from "@christopher_dondici/mcp-gen";
const result = await generate({
input: "./api/openapi.yaml",
lang: "typescript",
out: "./my-server",
force: true,
incremental: false,
http: false,
});
const validation = await validateSpec("./api/openapi.yaml");
console.log(validation.tools, validation.models, validation.warnings);
Development
npm run lint
npx tsc --noEmit
npm test
npm run test:cli
npm run test:generated
npm run test:generated:py
# TypeScript example
node dist/cli/index.js generate --input examples/petstore.json --out /tmp/ts-test --force
# Python example
node dist/cli/index.js generate --input examples/petstore.yaml --lang python --out /tmp/py-test --force
# Go example
node dist/cli/index.js generate --input examples/petstore.json --lang go --out /tmp/go-test --force
# HTTP mode (real API calls)
node dist/cli/index.js generate --input examples/petstore.json --lang typescript --out /tmp/ts-http --force --http
# Incremental example
node dist/cli/index.js generate --input examples/petstore.json --out /tmp/ts-test --incremental
Roadmap
| Stage | Status | Scope |
|---|---|---|
| Existing features | Implemented | CLI, OpenAPI v3 parser, TypeScript/Python generation, incremental generation, interactive mode, spec registry, plugins |
| v2.1.0 | Tagged | Go target, HTTP mode, enums, header/cookie params, library API, rich validate |
| v2.1.1 | Tagged | Static security/lint scanning and Go server template checks; TypeScript/Python templates unchanged from v2.1.0 |
| v2.1.2 | Released on npm | Portable template copy, lockfile, package allowlist, prepack build, corrected release workflow, CI tarball smoke test, dependency updates |
| v2.1.3 | Tagged only, superseded (never published to npm) | Feature branch content, replaced by 2.1.4 before publication |
| v2.1.4 | Released on npm | Path glob filters, inline operation allowlist, group-by tag/path-prefix with action routing, method/hash dedup, <generated:handlers> guards with 3-way merge, separate auth middleware, never-overwritten handlers.custom.*, auth template fix for specs without securitySchemes |
| v2.1.5 | Released on npm | Fase 0 P0 fixes (PR #4): TS query serialization, Python query/headers, Go HTTP wiring, v3-only registry with guidance |
| v2.2.0 | Released on npm | Fase 1: generate --dry-run + --json summary, filter/group flags on watch (+ interactive prompts, --once file fix), per-schema partial-support warnings in validate/generate, CONTRIBUTING + MCP_GEN_ALLOW_PLUGINS docs |
| v2.3.5 | Released on npm (latest) | Case-insensitive allowlist METHOD, zero-filter warning with --dry-run hint, Go stub pattern on incremental regen, non-JSON body/example fallback |
| v2.3.4 | Released on npm (latest) | ip-address 10.4.0 → 10.7.2 via SDK chain, scaffold lockfile snapshot guard, dev-only js-yaml stays documented |
| v2.3.3 | Released on npm (latest) | Explicit missing --env-file error, Go next steps in interactive init, placeholder links replaced, dist cleaned before build |
| v2.3.2 | Released on npm | Direct js-yaml/openapi-types deps, real registry validation tests, trailing /** matches base path, Go stub pattern + guard round-trip, Go build smoke in CI |
| v2.3.1 | Released on npm | TypeScript scaffold lockfile, force-over-incremental precedence, reliable watch --once exit codes, reproducible lint gate |
| v2.3.0 | Released on npm | Fase 2: Swagger 2.0 → v3 conversion on ingest, slack/kubernetes/digitalocean back in the registry, examples/large-scale.json benchmark (180 → 10 tools) |
| Distribution | Verified for 2.3.4 | Registry installation works via npm install -g @christopher_dondici/mcp-gen; pip publication is not established. Python is a generation target, not a pip installation path for this CLI |
| Future | Planned | Streaming/resources/prompts, more registries |
Known limitations
- Swagger 2.0 is converted to OpenAPI 3.0.3 on ingest (body/formData →
requestBody,definitions→components.schemas); exotic v2 constructs may lose fidelity oneOf/anyOf/discriminatorschemas generate union types but no runtime validation- Security/lint scanning uses static text patterns and can produce false positives or miss issues. A passing report does not guarantee security or verify runtime authorization, revocation, spending, or audit logging
- Generated authorization checks are scaffolding, not a complete security backend; review and test them before deployment
- Streaming/resources/prompts are not implemented
The copy-templates fix included in 2.1.2 uses Node.js fs.cpSync on Windows, Linux, and macOS; it no longer requires cp or xcopy. CI currently runs on Ubuntu only.
License
MIT © 2026 - Christopher D.