Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
},
"metadata": {
"description": "Claude Code plugins for the Umbraco MCP Toolkit - professional skills for building MCP servers, testing, and API integration",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"homepage": "https://github.com/umbraco/Umbraco-MCP-Base"
},
"plugins": [
{
"name": "umbraco-mcp-skills",
"source": "./plugins",
"description": "Professional skills for building Umbraco MCP servers - tool creation, testing, API patterns, and eval testing",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"category": "development",
"author": {
"name": "Phil W",
Expand All @@ -35,7 +35,7 @@
"name": "umbraco-mcp-server",
"source": "./plugins-server",
"description": "Skills for CLI operation of Umbraco MCP servers - CLI setup, tool filtering, introspection, and runtime modes",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"category": "operations",
"author": {
"name": "Phil W",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ jobs:
run: npm ci

- name: Build
run: npm run build && npm run build -w packages/create-mcp-server
run: npm run build && npm run build -w packages/hosted-mcp && npm run build -w packages/create-mcp-server

- name: Run CLI E2E tests
run: npm run test:e2e -w packages/create-mcp-server
Expand Down
29 changes: 23 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,36 @@ All packages are versioned together and published from the `main` branch via Azu

### Release process

1. Create a release branch from `dev`: `release/<version>` (e.g. `release/17.0.0-beta.5`)
2. Bump the version in **all** package.json files and `marketplace.json`:
1. Create a release branch from `dev`: `release/<version>` (e.g. `release/17.0.0-beta.9`)
2. Bump the version in **all** files (use find-and-replace for the old version string):
- `package.json` (root)
- `packages/mcp-server-sdk/package.json`
- `packages/hosted-mcp/package.json`
- `packages/create-mcp-server/package.json`
- `template/package.json`
- `plugins/package.json`
- `.claude-plugin/marketplace.json` (both `metadata.version` and `plugins[0].version`)
- `plugins/.claude-plugin/plugin.json`
- `.claude-plugin/marketplace.json` (`metadata.version` and each `plugins[].version`)
3. Run `npm install --package-lock-only` to update `package-lock.json`
4. Commit, push, and create a PR from the release branch into `main`
5. The CI pipeline publishes packages when the PR is merged to `main`
6. Manually create a GitHub Release tagged `v<version>` from the merge commit
4. Verify no stale versions: `grep -r "beta.OLD" package.json packages/*/package.json template/package.json plugins/package.json plugins/.claude-plugin/plugin.json .claude-plugin/marketplace.json`
5. Commit, push, and create a PR from the release branch into `main`
6. CI runs all tests including LLM evals and skill E2E (release PRs only)
7. Merge when all checks pass — Azure Pipelines publishes packages to npm
8. Create a GitHub Release tagged `v<version>` from the merge commit
9. Merge `main` back into `dev` via PR (to sync version numbers)

### Post-release: merge main to dev

After a release is published, main has the version bump commit that dev doesn't. Create a PR to merge main back:

```bash
git checkout dev && git pull
git checkout -b chore/merge-main-to-dev
git merge origin/main --no-edit
# Resolve any conflicts (take dev's version for code, main's for versions)
git push -u origin chore/merge-main-to-dev
gh pr create --base dev --title "Merge main into dev after <version> release"
```

### Version scheme

Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "umbraco-mcp-server-sdk-monorepo",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"private": true,
"description": "Umbraco MCP Server SDK monorepo",
"workspaces": [
Expand Down
2 changes: 1 addition & 1 deletion packages/create-mcp-server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/create-umbraco-mcp-server",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"type": "module",
"description": "Create a new Umbraco MCP server project",
"bin": {
Expand Down
15 changes: 7 additions & 8 deletions packages/create-mcp-server/src/discover/generate-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@ export interface GenerateResult {
export function generateClient(projectDir: string): GenerateResult {
try {
// Ensure dependencies are installed (Orval needs to be available)
if (!fs.existsSync(path.join(projectDir, "node_modules"))) {
execSync("npm install", {
cwd: projectDir,
stdio: "inherit",
timeout: 120_000,
});
}
// Always run install — node_modules may exist but be incomplete
execSync("npm install", {
cwd: projectDir,
stdio: "inherit",
timeout: 120_000,
});

execSync("npm run generate", {
cwd: projectDir,
stdio: "inherit",
timeout: 60_000,
timeout: 180_000,
env: {
...process.env,
NODE_TLS_REJECT_UNAUTHORIZED: "0",
Expand Down
37 changes: 35 additions & 2 deletions packages/create-mcp-server/tests/e2e/cli-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ describeOrSkip("CLI full E2E", () => {
);
expect(pkg.name).toBe("test-project");

// Rewrite SDK/hosted deps to use monorepo file: references
// (the scaffold writes the current package version which may not be published yet)
const monorepoRoot = path.resolve(__dirname, "../../../..");
if (pkg.dependencies?.["@umbraco-cms/mcp-server-sdk"]) {
pkg.dependencies["@umbraco-cms/mcp-server-sdk"] = `file:${path.join(monorepoRoot, "packages/mcp-server-sdk")}`;
}
if (pkg.dependencies?.["@umbraco-cms/mcp-hosted"]) {
pkg.dependencies["@umbraco-cms/mcp-hosted"] = `file:${path.join(monorepoRoot, "packages/hosted-mcp")}`;
}
fs.writeFileSync(path.join(projectDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");

console.log("[E2E] Step 1 passed: project scaffolded");
});

Expand Down Expand Up @@ -609,7 +620,13 @@ describeOrSkip("CLI full E2E", () => {
// ── Step 9: TypeScript compile on scaffolded project ────────────────────
test("Step 9: scaffolded project TypeScript compiles cleanly", () => {
console.log("[E2E] Running TypeScript compile check...");
execFileSync("npm", ["run", "compile"], {
// Exclude worker.ts and client-fetch.ts — they import from @umbraco-cms/mcp-hosted
// which via file: refs causes duplicate @modelcontextprotocol/sdk types.
// Worker compilation is verified by Step 12 (wrangler build + start).
const tsconfig = JSON.parse(fs.readFileSync(path.join(projectDir, "tsconfig.json"), "utf-8"));
tsconfig.exclude = [...(tsconfig.exclude || []), "src/worker.ts", "src/umbraco-api/api/client-fetch.ts"];
fs.writeFileSync(path.join(projectDir, "tsconfig.e2e.json"), JSON.stringify(tsconfig, null, 2));
execFileSync("npx", ["tsc", "--noEmit", "-p", "tsconfig.e2e.json"], {
cwd: projectDir,
encoding: "utf-8",
timeout: 60_000,
Expand Down Expand Up @@ -887,6 +904,18 @@ describeOrSkip("CLI container mode E2E", () => {
expect(fs.existsSync(path.join(projectDir, "package.json"))).toBe(true);
expect(fs.existsSync(path.join(projectDir, "src/index.ts"))).toBe(true);
expect(fs.existsSync(path.join(projectDir, "src/config/mcp-servers.ts"))).toBe(true);

// Rewrite deps to monorepo file: references (same as main E2E)
const monorepoRoot = path.resolve(__dirname, "../../../..");
const pkg = JSON.parse(fs.readFileSync(path.join(projectDir, "package.json"), "utf-8"));
if (pkg.dependencies?.["@umbraco-cms/mcp-server-sdk"]) {
pkg.dependencies["@umbraco-cms/mcp-server-sdk"] = `file:${path.join(monorepoRoot, "packages/mcp-server-sdk")}`;
}
if (pkg.dependencies?.["@umbraco-cms/mcp-hosted"]) {
pkg.dependencies["@umbraco-cms/mcp-hosted"] = `file:${path.join(monorepoRoot, "packages/hosted-mcp")}`;
}
fs.writeFileSync(path.join(projectDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");

console.log("[Container E2E] Step 1 passed: project scaffolded");
});

Expand Down Expand Up @@ -956,7 +985,11 @@ describeOrSkip("CLI container mode E2E", () => {
});

console.log("[Container E2E] Running TypeScript compile...");
execFileSync("npm", ["run", "compile"], {
// Exclude worker.ts — file: refs cause duplicate type issues (see Step 9)
const tsconfig = JSON.parse(fs.readFileSync(path.join(projectDir, "tsconfig.json"), "utf-8"));
tsconfig.exclude = [...(tsconfig.exclude || []), "src/worker.ts"];
fs.writeFileSync(path.join(projectDir, "tsconfig.e2e.json"), JSON.stringify(tsconfig, null, 2));
execFileSync("npx", ["tsc", "--noEmit", "-p", "tsconfig.e2e.json"], {
cwd: projectDir,
encoding: "utf-8",
timeout: 60_000,
Expand Down
18 changes: 11 additions & 7 deletions packages/create-mcp-server/tests/e2e/skill-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,17 @@ Build tools ONLY for the "${targetCollection}" group from .discover.json. Build
expect(collectionDir).toBeDefined();
targetCollection = collectionDir!;

// Verify compile passes
execFileSync("npm", ["run", "compile"], {
cwd: projectDir,
encoding: "utf-8",
timeout: 60_000,
stdio: "pipe",
});
// Verify compile passes (exclude worker.ts — file: refs cause type duplication)
const tsconfigPath = path.join(projectDir, "tsconfig.json");
if (fs.existsSync(path.join(projectDir, "tsconfig.e2e.json"))) {
execFileSync("npx", ["tsc", "--noEmit", "-p", "tsconfig.e2e.json"], {
cwd: projectDir, encoding: "utf-8", timeout: 60_000, stdio: "pipe",
});
} else {
execFileSync("npm", ["run", "compile"], {
cwd: projectDir, encoding: "utf-8", timeout: 60_000, stdio: "pipe",
});
}

console.log(`[Skill E2E] Step 1 passed: ${targetCollection} tools compile`);
}, 600_000);
Expand Down
2 changes: 1 addition & 1 deletion packages/hosted-mcp/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/mcp-hosted",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"description": "Hosted MCP server infrastructure for Umbraco on Cloudflare Workers",
"type": "module",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp-server-sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/mcp-server-sdk",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"type": "module",
"description": "Umbraco-specific MCP infrastructure and patterns for building MCP servers",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion plugins/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "umbraco-mcp-skills",
"version": "17.0.0-beta.4",
"version": "17.0.0-beta.9",
"description": "Skills for building Umbraco MCP servers - tool creation, testing, API patterns, and eval testing",
"author": {
"name": "Phil W",
Expand Down
2 changes: 1 addition & 1 deletion plugins/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/mcp-skills",
"version": "17.0.0-beta.6",
"version": "17.0.0-beta.9",
"private": true,
"type": "module",
"description": "Skills and agents for building Umbraco MCP servers",
Expand Down
2 changes: 1 addition & 1 deletion template/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umbraco-cms/mcp-template",
"version": "17.0.0-beta.8",
"version": "17.0.0-beta.9",
"type": "module",
"description": "MCP server for my Umbraco add-on",
"main": "dist/index.js",
Expand Down
Loading