From dfde88c796a95677ad53af8dece8e6f891af3824 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 10:42:44 +0000 Subject: [PATCH] Become mcp-server, in the package name too The repository was renamed from ai-mcp to mcp-server: `mcp` names a protocol, `mcp-server` names the thing, and somebody scanning the organisation's repository list should not have to click to find out which it is. The package follows - `@abap2ui5/mcp-server`, not `@abap2ui5/mcp`. The timing is the point. RELEASING.md says it itself: the package name is the one thing a release cannot take back. Nothing is published yet, so the name costs four files today and nothing downstream; after the first publish it would cost a deprecation and a second name to explain forever. A repository whose name differs from its only package is exactly the discrepancy the rename was for. lib/repo-dirs.json gains an entry for this server itself. It resolves nothing for its own sake - the file exists so the server can find its NEIGHBOURS - but abap2UI5/vscode-extension looks for a local checkout of this repository by directory name before falling back to npx, and after a rename it would look for the wrong one. Listing both names there is what that file is for: the ecosystem's rename history, in one place. The npx spec stays on `github:abap2UI5/mcp-server` rather than moving to the npm package, because the package does not exist yet. Moving it is the last step of the first release, and RELEASING.md says where. Co-Authored-By: Claude --- .github/workflows/ci.yml | 6 ++-- .github/workflows/release.yml | 6 ++-- AGENTS.md | 8 ++--- CHANGELOG.md | 17 ++++++++-- README.md | 12 +++---- RELEASING.md | 20 +++++------ lib/examples.mjs | 2 +- lib/repo-dirs.json | 62 ++++++++++++++++++++++++++++------- lib/repos.mjs | 2 +- lib/runtime.mjs | 2 +- package.json | 10 +++--- server.mjs | 14 ++++---- 12 files changed, 107 insertions(+), 54 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 449fc9e..85414d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - path: ai-mcp + path: mcp-server - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: '22' @@ -63,6 +63,6 @@ jobs: # less than it appears to is worse than one that fails. - run: git clone --depth 1 https://github.com/abap2UI5/app-template - run: npm ci - working-directory: ai-mcp + working-directory: mcp-server - run: npm test - working-directory: ai-mcp + working-directory: mcp-server diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a2f91a8..b34612d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,8 @@ name: Publish to npm -# Publishes @abap2ui5/mcp to the public npm registry from one version tag. +# Publishes @abap2ui5/mcp-server to the public npm registry from one version tag. # # Why this exists: the server was installable only as `npx --yes -# github:abap2UI5/ai-mcp`, which resolves to whatever main happens to hold. +# github:abap2UI5/mcp-server`, which resolves to whatever main happens to hold. # For a server whose tool NAMES and result SHAPES are a contract with every # agent setup that registers it, "whatever main holds" is the wrong contract - # an agent's config keeps working or stops working depending on the day. @@ -135,7 +135,7 @@ jobs: const list = msgs.find((m) => m.id === 2); const call = msgs.find((m) => m.id === 3); expect(init && init.result.serverInfo.name === "abap2ui5", "the installed server starts and identifies itself"); - expect(init.result.serverInfo.version === require("./node_modules/@abap2ui5/mcp/package.json").version, "it serves the packaged version"); + expect(init.result.serverInfo.version === require("./node_modules/@abap2ui5/mcp-server/package.json").version, "it serves the packaged version"); expect(list && list.result.tools.length > 0, "tools/list answers from the tarball (lib/ came along)"); expect(call && call.result.isError && /checkout not found/.test(call.result.content[0].text), "a missing checkout is an actionable message, not a crash"); diff --git a/AGENTS.md b/AGENTS.md index bb9c4fe..d00d31a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# AGENTS.md — ai-mcp +# AGENTS.md — mcp-server Single source of truth for agents working on the **abap2UI5 MCP server** — the `app_guide → validate_view/screenshot_view → deploy_app → build_backend → @@ -24,7 +24,7 @@ is what an agent's feedback loop is made of. ## The one thing to understand first: this repo cannot work alone -ai-mcp **bundles no content**. Every tool reads live from sibling checkouts, +mcp-server **bundles no content**. Every tool reads live from sibling checkouts, resolved per call in `lib/repos.mjs` (explicit env var, then the `../` sibling of this repo — plus, for abap2UI5, the in-repo `.abap2UI5` clone that samples-controls' `npm run node:setup` creates). A **set env var is @@ -64,7 +64,7 @@ It answers from what it can read, names what it could not under ### The compatibility surface — renames upstream break tools here silently -These upstream file names/shapes are load-bearing for ai-mcp. When one +These upstream file names/shapes are load-bearing for mcp-server. When one changes upstream, this repo must change in the same breath: - samples, samples-controls, samples-stack: the `SAMPLES.md` **row shape** — @@ -114,7 +114,7 @@ changes upstream, this repo must change in the same breath: ## Side effects on sibling repos — expected, not a bug The server **writes into the sibling checkouts**. When you (or another -agent) find these artifacts in a dirty sibling worktree, ai-mcp caused them: +agent) find these artifacts in a dirty sibling worktree, mcp-server caused them: - `/.abaplint-mcp-dev.jsonc` — patched lint config for deployed dev apps (gitignored there). diff --git a/CHANGELOG.md b/CHANGELOG.md index a927a58..1f1c6db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,22 @@ ## Unreleased -Nothing published yet — `@abap2ui5/mcp` has never been on npm. Everything +Nothing published yet — `@abap2ui5/mcp-server` has never been on npm. Everything below is what the first version will carry, and what changed since the server -was only installable as `npx --yes github:abap2UI5/ai-mcp`. +was only installable as `npx --yes github:abap2UI5/mcp-server`. + +- **Renamed: the repository is `mcp-server`, the package is `@abap2ui5/mcp-server`.** + `mcp` names a protocol; `mcp-server` names the thing, which is what somebody + scanning the organisation's repository list needs to read without clicking. + The rename happened before the first publish on purpose: a package name is + the one thing a release cannot take back, and a repository whose name differs + from its only package is a discrepancy nobody has to inherit. + + `lib/repo-dirs.json` — the ecosystem's rename history — now carries an entry + for this server itself, listing `mcp-server` and `ai-mcp`. It resolves + nothing for its own sake, but a consumer that looks for a local checkout by + directory name (abap2UI5/vscode-extension does, before falling back to npx) + would otherwise miss one carrying the previous name. - **`scaffold_app`: the files a new project starts from.** The server could tell an agent how to write a class (`app_guide`) and where to put one so it diff --git a/README.md b/README.md index 7737fb3..bf8d88d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ai-mcp +# mcp-server **The MCP server for abap2UI5** — gives any AI coding agent (Claude Code, Cursor, VS Code Copilot, or any MCP client) the full abap2UI5 development @@ -39,8 +39,8 @@ in the linter checkout. `validate_view`'s property gate needs neither.) ```sh git clone https://github.com/abap2UI5/linter # AI_VIEW_CHECK_HOME -git clone https://github.com/abap2UI5/ai-mcp -cd linter && npm ci && cd ../ai-mcp && npm ci +git clone https://github.com/abap2UI5/mcp-server +cd linter && npm ci && cd ../mcp-server && npm ci ``` The other tools answer with an actionable message naming what is missing @@ -98,7 +98,7 @@ it is what buys an agent the ability to look at what it built. **Claude Code:** ```sh -claude mcp add abap2ui5 -- node /path/to/ai-mcp/server.mjs +claude mcp add abap2ui5 -- node /path/to/mcp-server/server.mjs ``` **Cursor** (`.cursor/mcp.json`), **VS Code** (`.vscode/mcp.json`), **Claude @@ -110,7 +110,7 @@ standard stdio shape: "mcpServers": { "abap2ui5": { "command": "node", - "args": ["/path/to/ai-mcp/server.mjs"], + "args": ["/path/to/mcp-server/server.mjs"], "env": { "AI_VIEW_CHECK_HOME": "/path/to/linter", "A2UI5_HOME": "/path/to/abap2UI5", @@ -122,7 +122,7 @@ standard stdio shape: ``` The three `env` entries are only needed if the checkouts are not siblings of -`ai-mcp`; drop the ones you stopped short of. VS Code wants the same object +`mcp-server`; drop the ones you stopped short of. VS Code wants the same object under a top-level `"servers"` key rather than `"mcpServers"`. The [abap2UI5 VS Code extension](https://github.com/abap2UI5/vscode-extension) diff --git a/RELEASING.md b/RELEASING.md index 214070b..126b179 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,6 +1,6 @@ # Releasing -One tag publishes one package: **`@abap2ui5/mcp`** on the public npm +One tag publishes one package: **`@abap2ui5/mcp-server`** on the public npm registry. Everything mechanical lives in [`.github/workflows/release.yml`](.github/workflows/release.yml); its header comment is the reference. This file is the human checklist. @@ -11,7 +11,7 @@ Merging to `main` is the release for everyone reading the repository. npm is the one channel that needs a deliberate, immutable version, and this server needs it more than most: its **tool names and result shapes are a contract** with every agent configuration that registers it. `npx --yes -github:abap2UI5/ai-mcp` resolves to whatever `main` holds that day, so an +github:abap2UI5/mcp-server` resolves to whatever `main` holds that day, so an agent setup that worked on Monday can behave differently on Tuesday without anyone having decided that. @@ -22,7 +22,7 @@ to the first 72 hours and, for a package others depend on, is worse than the bug it would remove. The everyday correction is a new version. What genuinely cannot be taken back -is the **package name** — `@abap2ui5/mcp` — so that is the one thing worth +is the **package name** — `@abap2ui5/mcp-server` — so that is the one thing worth getting right the first time. ## One-time setup — what a maintainer still has to do by hand @@ -45,7 +45,7 @@ npm publish --access public supported CI and aborts anywhere else. The bootstrap version ships without it; every release the workflow cuts has it.) -Then, on npmjs.com → `@abap2ui5/mcp` → **Settings → Trusted Publisher**, point +Then, on npmjs.com → `@abap2ui5/mcp-server` → **Settings → Trusted Publisher**, point it at this repository and `release.yml`. From the second release on the workflow publishes with no token at all. @@ -53,9 +53,9 @@ Two things follow the first publish, in other repositories, and neither is automatic: - the [VS Code extension](https://github.com/abap2UI5/vscode-extension) - registers this server as `npx --yes github:abap2UI5/ai-mcp` — the whole + registers this server as `npx --yes github:abap2UI5/mcp-server` — the whole reason for publishing is that this resolves to whatever `main` holds that - day, so it should become `npx --yes @abap2ui5/mcp@`; + day, so it should become `npx --yes @abap2ui5/mcp-server@`; - the README's setup section still tells everyone to `git clone` this repository, which stops being necessary for the tools that need no corpus. @@ -109,7 +109,7 @@ Done once, by hand, before there was anything on npm — repeat it if One thing worth knowing before the first `npm publish`: **the install is ~45 MB**, and 19 MB of that is `playwright` + `playwright-core`, which only -`run_app` uses (via a dynamic import). `npx --yes @abap2ui5/mcp` therefore +`run_app` uses (via a dynamic import). `npx --yes @abap2ui5/mcp-server` therefore pays for a browser driver before it validates a single view. Marking the dependency `optional` would not help — npm installs optional dependencies by default — so the fix is the shape `@abap2ui5/linter` arrived at: a separate @@ -132,9 +132,9 @@ after the tag. Worth remembering before cutting one. ## After a release - The [VS Code extension](https://github.com/abap2UI5/vscode-extension) - registers this server via `npx --yes github:abap2UI5/ai-mcp` today. Once a - version is on npm it should point at `@abap2ui5/mcp` instead, which is a + registers this server via `npx --yes github:abap2UI5/mcp-server` today. Once a + version is on npm it should point at `@abap2ui5/mcp-server` instead, which is a change in that repository. - The README's setup section names checkouts. A published package makes - `npx @abap2ui5/mcp` possible for the tools that need no corpus — worth + `npx @abap2ui5/mcp-server` possible for the tools that need no corpus — worth updating there when the first version lands. diff --git a/lib/examples.mjs b/lib/examples.mjs index d305863..eb1a6df 100644 --- a/lib/examples.mjs +++ b/lib/examples.mjs @@ -81,7 +81,7 @@ export function catalogueFiles() { const file = root && path.join(root, 'SAMPLES.md'); if (file && fs.existsSync(file)) found.push({ ...c, root, file }); else if (root) missing.push({ ...c, why: `${c.repo} checkout at ${root} has no SAMPLES.md — update it (git pull)` }); - else missing.push({ ...c, why: `${c.repo} checkout not found — clone ${c.url} as a sibling of ai-mcp, or point ${c.env} at an existing checkout` }); + else missing.push({ ...c, why: `${c.repo} checkout not found — clone ${c.url} as a sibling of mcp-server, or point ${c.env} at an existing checkout` }); } return { found, missing }; } diff --git a/lib/repo-dirs.json b/lib/repo-dirs.json index f586768..3232ca6 100644 --- a/lib/repo-dirs.json +++ b/lib/repo-dirs.json @@ -1,40 +1,80 @@ { - "note": "Directory names each sibling checkout can carry, newest first, plus the env vars that override the guess. THE source of truth for the ecosystem's rename history - lib/repos.mjs resolves from it, and abap2UI5/vscode-extension snapshots it into src/data/repo-dirs.json. Add a name here when a repository is renamed; never keep a second list somewhere else.", + "note": "Directory names each sibling checkout can carry, newest first, plus the env vars that override the guess. THE source of truth for the ecosystem's rename history - lib/repos.mjs resolves from it, and abap2UI5/vscode-extension snapshots it into src/data/repo-dirs.json. Add a name here when a repository is renamed; never keep a second list somewhere else. The `server` entry is this repository itself: it resolves nothing for its own sake, but the extension looks for a local checkout of it by directory name and would miss one carrying the previous name.", "repos": { "corpus": { "repository": "abap2UI5/samples-controls", "why": "The corpus: 416 generated ports of the UI5 demo kit. e2e-build, the capability map, the scope gate, the deploy sandbox and the @openui5 packages the render/boot path serves.", - "dirs": ["samples-controls", "abap2UI5-api", "ai-demokit"], - "env": ["SAMPLES_CONTROLS_HOME", "AI_DEMOKIT_HOME"], + "dirs": [ + "samples-controls", + "abap2UI5-api", + "ai-demokit" + ], + "env": [ + "SAMPLES_CONTROLS_HOME", + "AI_DEMOKIT_HOME" + ], "probe": "scripts/e2e-build.mjs" }, "samples": { "repository": "abap2UI5/samples", "why": "The pattern catalogue: which PATTERN has somebody already built. A different repository from the corpus on purpose - that one answers which CONTROL can be expressed.", - "dirs": ["samples", "abap2UI5-samples"], - "env": ["SAMPLES_HOME"], + "dirs": [ + "samples", + "abap2UI5-samples" + ], + "env": [ + "SAMPLES_HOME" + ], "probe": "SAMPLES.md" }, "samplesStack": { "repository": "abap2UI5/samples-stack", "why": "The third catalogue: apps that need something from the STACK - an OData service, a RAP behavior definition, an APC channel, the Fiori launchpad. They cannot run on a bare abap2UI5 install.", - "dirs": ["samples-stack", "abap2UI5-samples-stack"], - "env": ["SAMPLES_STACK_HOME"], + "dirs": [ + "samples-stack", + "abap2UI5-samples-stack" + ], + "env": [ + "SAMPLES_STACK_HOME" + ], "probe": "SAMPLES.md" }, "appTemplate": { "repository": "abap2UI5/app-template", "why": "The starter project: both gate configs, the CI workflow, the abapGit metadata and one working app class.", - "dirs": ["app-template", "abap2UI5-app-template"], - "env": ["APP_TEMPLATE_HOME"], + "dirs": [ + "app-template", + "abap2UI5-app-template" + ], + "env": [ + "APP_TEMPLATE_HOME" + ], "probe": "abaplint.jsonc" }, "viewCheck": { "repository": "abap2UI5/linter", "why": "The abap2UI5 linter: the property and render gates, imported through its package.json exports map.", - "dirs": ["linter", "abap2UI5-linter", "ai-view-check"], - "env": ["AI_VIEW_CHECK_HOME"], + "dirs": [ + "linter", + "abap2UI5-linter", + "ai-view-check" + ], + "env": [ + "AI_VIEW_CHECK_HOME" + ], "probe": "package.json" + }, + "server": { + "repository": "abap2UI5/mcp-server", + "why": "This server. Listed so a consumer looking for a local checkout of it - the VS Code extension does, before falling back to npx - finds one under either name.", + "dirs": [ + "mcp-server", + "ai-mcp" + ], + "env": [ + "ABAP2UI5_MCP_HOME" + ], + "probe": "server.mjs" } } } diff --git a/lib/repos.mjs b/lib/repos.mjs index 09f1e35..6196330 100644 --- a/lib/repos.mjs +++ b/lib/repos.mjs @@ -1,7 +1,7 @@ /* * repos — locate the sibling checkouts this server orchestrates. * - * ai-mcp is the thin MCP layer; the machinery lives in: + * mcp-server is the thin MCP layer; the machinery lives in: * abap2UI5 the framework (transpiler config, express shim, node/output) * samples-controls the corpus (e2e-build, capabilities map, generation * rules, the src/zz_dev deploy sandbox, @openui5 packages) diff --git a/lib/runtime.mjs b/lib/runtime.mjs index 4ced536..5c4bfe6 100644 --- a/lib/runtime.mjs +++ b/lib/runtime.mjs @@ -388,7 +388,7 @@ export function buildBackend({ onLine, mode = 'auto' } = {}) { }); } if (incremental && !a2) { - return Promise.resolve({ ok: false, code: 1, tail: 'abap2UI5 checkout not found — clone https://github.com/abap2UI5/abap2UI5 as a sibling of ai-mcp (or run `npm run node:setup` in samples-controls), or point A2UI5_HOME at an existing checkout; then run mode:full once' }); + return Promise.resolve({ ok: false, code: 1, tail: 'abap2UI5 checkout not found — clone https://github.com/abap2UI5/abap2UI5 as a sibling of mcp-server (or run `npm run node:setup` in samples-controls), or point A2UI5_HOME at an existing checkout; then run mode:full once' }); } if (incremental && !canIncrement) { return Promise.resolve({ ok: false, code: 1, tail: 'incremental build needs a prior full build (node/downport + node/output missing) — run mode:full first' }); diff --git a/package.json b/package.json index 6a1458a..e0b5bc9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "@abap2ui5/mcp", + "name": "@abap2ui5/mcp-server", "version": "0.1.0", - "description": "MCP server for abap2UI5: capability queries, view validation, deploy, headless run + screenshot — the AI agent dev loop, no SAP system needed.", + "description": "MCP server for abap2UI5: capability queries, view validation, deploy, headless run + screenshot \u2014 the AI agent dev loop, no SAP system needed.", "type": "module", "bin": { "abap2ui5-mcp": "server.mjs" @@ -12,13 +12,13 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/abap2UI5/ai-mcp.git" + "url": "git+https://github.com/abap2UI5/mcp-server.git" }, "license": "MIT", "bugs": { - "url": "https://github.com/abap2UI5/ai-mcp/issues" + "url": "https://github.com/abap2UI5/mcp-server/issues" }, - "homepage": "https://github.com/abap2UI5/ai-mcp#readme", + "homepage": "https://github.com/abap2UI5/mcp-server#readme", "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", "playwright": "^1.61.1" diff --git a/server.mjs b/server.mjs index e60c224..05113d0 100644 --- a/server.mjs +++ b/server.mjs @@ -5,7 +5,7 @@ * * Speaks MCP over stdio. Register it in any MCP client, e.g. Claude Code: * - * claude mcp add abap2ui5 -- node ai-mcp/server.mjs + * claude mcp add abap2ui5 -- node mcp-server/server.mjs * * Tools (each wraps infrastructure this repo already trusts in CI): * capabilities what abap2UI5 can express (CAPABILITIES.md, live-parsed) @@ -407,23 +407,23 @@ function toolError(message) { const SIBLING_REPOS = { 'samples-controls': { resolve: resolveSamplesControls, - hint: 'clone https://github.com/abap2UI5/samples-controls as a sibling of ai-mcp, or point SAMPLES_CONTROLS_HOME at an existing checkout (AI_DEMOKIT_HOME, its former name, is still read)', + hint: 'clone https://github.com/abap2UI5/samples-controls as a sibling of mcp-server, or point SAMPLES_CONTROLS_HOME at an existing checkout (AI_DEMOKIT_HOME, its former name, is still read)', }, abap2UI5: { resolve: resolveA2UI5, - hint: 'clone https://github.com/abap2UI5/abap2UI5 as a sibling of ai-mcp (or run `npm run node:setup` in samples-controls), or point A2UI5_HOME at an existing checkout', + hint: 'clone https://github.com/abap2UI5/abap2UI5 as a sibling of mcp-server (or run `npm run node:setup` in samples-controls), or point A2UI5_HOME at an existing checkout', }, samples: { resolve: resolveSamples, - hint: 'clone https://github.com/abap2UI5/samples as a sibling of ai-mcp, or point SAMPLES_HOME at an existing checkout', + hint: 'clone https://github.com/abap2UI5/samples as a sibling of mcp-server, or point SAMPLES_HOME at an existing checkout', }, linter: { resolve: resolveViewCheck, - hint: 'clone https://github.com/abap2UI5/linter as a sibling of ai-mcp, or point AI_VIEW_CHECK_HOME at an existing checkout', + hint: 'clone https://github.com/abap2UI5/linter as a sibling of mcp-server, or point AI_VIEW_CHECK_HOME at an existing checkout', }, 'app-template': { resolve: resolveAppTemplate, - hint: 'clone https://github.com/abap2UI5/app-template as a sibling of ai-mcp, or point APP_TEMPLATE_HOME at an existing checkout', + hint: 'clone https://github.com/abap2UI5/app-template as a sibling of mcp-server, or point APP_TEMPLATE_HOME at an existing checkout', }, }; @@ -526,7 +526,7 @@ async function handle(name, args = {}, ctx = {}) { const { found, missing } = catalogueFiles(); if (!found.length) { return toolError( - 'no sample catalogue found — clone at least one of them as a sibling of ai-mcp:\n' + 'no sample catalogue found — clone at least one of them as a sibling of mcp-server:\n' + missing.map((m) => ` ${m.repo}: ${m.why}`).join('\n'), ); }