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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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");
Expand Down
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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 →
Expand All @@ -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 `../<name>`
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
Expand Down Expand Up @@ -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** —
Expand Down Expand Up @@ -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:

- `<samples-controls>/.abaplint-mcp-dev.jsonc` — patched lint config for deployed
dev apps (gitignored there).
Expand Down
17 changes: 15 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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",
Expand All @@ -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)
Expand Down
20 changes: 10 additions & 10 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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.

Expand All @@ -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
Expand All @@ -45,17 +45,17 @@ 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.

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@<version>`;
day, so it should become `npx --yes @abap2ui5/mcp-server@<version>`;
- the README's setup section still tells everyone to `git clone` this
repository, which stops being necessary for the tools that need no corpus.

Expand Down Expand Up @@ -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
Expand All @@ -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.
2 changes: 1 addition & 1 deletion lib/examples.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
}
Expand Down
62 changes: 51 additions & 11 deletions lib/repo-dirs.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
2 changes: 1 addition & 1 deletion lib/repos.mjs
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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"
Expand Down
Loading