feat(sdk): ship per-tool TypeScript types codegen (#65)#66
Merged
Conversation
Plan for shipping a per-tool TypeScript types codegen from the SDK, exposing createPermissiveCodegenUser() and a umbraco-mcp-generate-types CLI binary so downstream MCPs can emit typed tool registries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Return type is unknown (not UserModel) — proxy doesn't satisfy the UserModel scalar shape; consumers must only pass it to collection.tools(user) and not read .id/.email directly. - JSDoc lists supported array predicates + documents the filter/map/reduce/forEach gap. - Drop the source-file-scan test — its behavioral assertion is covered by the existing "any property access" test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Type-name collision error now identifies both the conflicting tool and the previously-claimed tool, helping users find the duplicate in large collections. - Test now asserts the previous tool name appears in the message. - Add assertions on skipped[0].field and the absent-output-schema fallback registry line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Consolidate node:fs dynamic imports in mainFromCli into a single destructure at the top of the function. - Hoist binPath + existsSync guard into a shared beforeAll for the binary smoke tests so both tests get a clear error when dist is stale. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hifi-phil
commented
Apr 25, 2026
Contributor
Author
There was a problem hiding this comment.
what does this do?
Contributor
Author
There was a problem hiding this comment.
Added a JSDoc file-header explaining the dual role (library + CLI binary). Pushed in dc0c80f.
Per PR review feedback: - Drop the "Generating tool types" section from packages/mcp-server-sdk/README.md. The full docs now live at 17/umbraco-in-ai/mcp/base-mcp/sdk/tool-types.md in the UmbracoDocs repo (separate PR). - Add a JSDoc file-header to generate-tool-types.ts explaining what the file does (it's both a library entry and the CLI binary, which isn't obvious from the shebang). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
When the CLI is invoked through an npm bin shim (e.g. node_modules/.bin/umbraco-mcp-generate-types), process.argv[1] is the shim's symlink path while import.meta.url is the resolved physical path. The strict-equality check meant mainFromCli never ran, so the binary silently no-op'd with exit 0 in every consumer using @umbraco-cms/mcp-dev's postbuild hook. Resolve symlinks via realpathSync before comparing. Caught while wiring the CLI into umbraco-mcp-cms (PR #168 there): the postbuild step ran without output and produced no tool-types.d.ts.
hifi-phil
added a commit
to umbraco/Umbraco-CMS-MCP-Dev
that referenced
this pull request
Apr 26, 2026
The codegen pattern landed upstream in @umbraco-cms/mcp-server-sdk via PR umbraco/Umbraco-MCP-Base#66 (issue #65). Replace the local 157-line script with a postbuild call to the SDK's umbraco-mcp-generate-types CLI. - Drop scripts/generate-tool-types.mjs - Drop json-schema-to-typescript devDep (now provided transitively by SDK) - Bump @umbraco-cms/mcp-server-sdk floor to ^17.0.0-beta.14 - Switch from && chaining to a postbuild hook (per review #3) - Revert version bump to 17.3.0 (release branch handles versioning, per review #2) - Update README import to CmsToolsName (SDK derives the union name as ${registryName}Name) Output is byte-identical to the previous inline script except for the banner comment and the renamed union type. 354 tools, 0 schema fallbacks. Note: requires SDK >= beta.15 to actually run on a fresh checkout (beta.14 ships the CLI but its _isMain check no-ops under bin-shim symlinks; fixed in the SDK PR).
Every freshly scaffolded MCP now runs umbraco-mcp-generate-types as a postbuild step and exposes the generated dist/tool-types.d.ts via a ./tool-types subpath export. This means any other MCP that wants to chain to this server gets compile-time type safety for free, with no manual setup. Verified locally: template build emits a 10-tool McpTemplateTools registry; all 24 template tests still pass. CLAUDE.md notes that the postbuild step + ./tool-types export are optional and can be removed for private/internal MCPs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The SDK's bin (umbraco-mcp-generate-types) points at dist/cli/generate-tool-types.js which doesn't exist when npm ci runs, so npm skips the symlink creation. After Build SDK the file exists but the symlink is still missing, causing the template's postbuild step to fail with "command not found" (exit 127). npm rebuild recreates the bin symlinks based on current state, fixing both Test Suite and CLI eval jobs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The template now has a postbuild step (umbraco-mcp-generate-types) and a ./tool-types subpath export. Update the snapshot in template-structure.test.ts to reflect this. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hifi-phil
added a commit
that referenced
this pull request
Apr 26, 2026
Changes since 17.0.0-beta.14:
- feat(sdk): ship per-tool TypeScript types codegen (#65, #66)
Adds a `umbraco-mcp-generate-types` postbuild step that walks
`dist/collections.js`, runs each tool's input/output Zod schema
through codegen, and writes a typed registry to
`dist/tool-types.d.ts`. Exposed via the `./tool-types` subpath
so downstream MCPs can chain to a built server with full type
safety (`import type { McpTemplateTools } from "@umbraco-cms/mcp-template/tool-types"`).
- fix: normalize trailing slashes in UMBRACO_BASE_URL (#63, #64)
Strips a trailing `/` from `UMBRACO_BASE_URL` before joining
paths, so values like `https://example.com/` no longer produce
`//umbraco/management/api/...` request URLs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #65. Ships a
umbraco-mcp-generate-typesCLI binary and acreatePermissiveCodegenUser()helper from@umbraco-cms/mcp-server-sdkso any downstream MCP can emit a typed tool registry from its built collections.bin:umbraco-mcp-generate-types— walks--collections <path>, runs Zod v4'sz.toJSONSchema()+json-schema-to-typescriptper tool, writes a single.d.tsregistry.createPermissiveCodegenUser()(Proxy-based, no enumeration of section/permission strings).Record<string, unknown>/unknownwhen a schema can't convert.get-documentvsgetDocument) with both offending tool names in the error.Smoke-tested against the local template — wrote a valid
TemplateToolsregistry covering all 10 fixture tools.What's NOT in this PR
Plan
Implementation followed docs/plans/mcp-server-sdk/tool-types-codegen.md (committed as the first commit on the branch). 7 tasks, each TDD where possible, two-stage review per task.
Test plan
npm run build -w packages/mcp-server-sdk— cleannpm run test -w packages/mcp-server-sdk— 491/491 pass (468 parallel + 23 stdio)Public API additions
🤖 Generated with Claude Code