Skip to content
Open
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
4 changes: 3 additions & 1 deletion .agents/skills/mcp-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ For packaging and protocol details, read [the catalog contract](../../../package
Native skill changes use an agent-plugin changeset; the MCP's bundled
`workspace:*` dependency automatically triggers an MCP patch release. Keep it in
`dependencies` and `bundledDependencies`, not `devDependencies`. MCP-specific
skills and collection changes need an MCP changeset.
skills and collection changes need an MCP changeset. Every bundled skill needs a
short `skill://index` line in `packages/b2c-dx-mcp/skills/index-summaries.json`;
add one when you add a skill (a test enforces this).

## Tools and context

Expand Down
5 changes: 5 additions & 0 deletions .changeset/b2c-cap-skill-mcp-cap-dev.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@salesforce/b2c-agent-plugins': patch
---

The `b2c-cap` skill now points MCP users to the bundled `cap-dev` authoring skills.
5 changes: 5 additions & 0 deletions .changeset/guidance-index-summaries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@salesforce/b2c-tooling-sdk': minor
---

`bundleGuidance` accepts `indexSummaries`, short per-skill lines used only in the `skill://index` listing; skill descriptions and search are unchanged.
5 changes: 5 additions & 0 deletions .changeset/mcp-bundle-cap-dev-skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@salesforce/b2c-dx-mcp': minor
---

The MCP now includes the `cap-dev` Commerce App Package authoring skills (scaffold, generate IMPEX, validate, package, and submit), so you don't need to install them separately.
3 changes: 2 additions & 1 deletion docs/guide/agent-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ B2C skills give your AI assistant guidance for B2C Commerce development,
operations, CLI workflows, and Storefront Next projects.

**The [B2C MCP](../mcp/) gives your assistant access to guidance from the `b2c`,
`b2c-cli`, `b2c-ops`, and `storefront-next` collections** through its
`b2c-cli`, `b2c-ops`, and `storefront-next` collections, plus the
[`cap-dev`](./commerce-apps) Commerce App Package authoring skills,** through its
[`skills_read` tool](../mcp/toolsets#documentation). Your assistant can find and read
that guidance as needed, without a separate skills installation. You can also
install these collections directly in your assistant, alongside the MCP or on their own.
Expand Down
2 changes: 2 additions & 0 deletions docs/guide/commerce-apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ If you build CAPs with an AI coding agent, install the agent skills so it unders

`b2c-cli` and `b2c` ship in the [B2C Developer Tooling marketplace](/guide/agent-skills); `cap-dev` ships separately from the [`SalesforceCommerceCloud/commerce-apps`](https://github.com/SalesforceCommerceCloud/commerce-apps) registry repository.

If you use the [B2C MCP](/mcp/), you don't need to install these separately: it includes all three, including a copy of the `cap-dev` skills that is refreshed in each MCP release. Install the `cap-dev` plugin directly for changes made in the commerce-apps repository since the last MCP release.

### Claude Code

```bash
Expand Down
15 changes: 11 additions & 4 deletions packages/b2c-dx-mcp/docs/skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ under `references/`.

This package's `skills/collections.json` selects entire plugin collections by their existing name in
the repository's `skills/plugins.json`; it does not duplicate the per-skill inventory. Collections
can instead name a package-relative directory for MCP-only skills. `isGA`
can instead name a package-relative directory for MCP-only skills. The `cap-dev` collection is a
directory collection of skills vendored from the public commerce-apps repository; see
[`vendor/cap-dev/README.md`](../vendor/cap-dev/README.md) for how to refresh it. `isGA`
is internal collection metadata; MCP includes every selected collection regardless of it.
`workspaces` only influences ranking. Discovery responses expose only collection
IDs and titles; `isGA` and `workspaces` are absent from the MCP output schema. Neither native
Expand All @@ -20,15 +22,20 @@ skill installation nor `--docs-topics` defines the skill catalog.
chosen by the top-level `featuredResources` IDs in `skills/collections.json`. Featuring
an entry controls listing only. All available skills and references are readable
through the resource template and `skills_read`, grouped into `b2c`, `b2c-cli`,
`b2c-ops`, `storefront-next`, and `mcp`. Every tool discovery/read result includes a URI. MCP resources are always registered.
`b2c-ops`, `storefront-next`, `cap-dev`, and `mcp`. Every tool discovery/read result includes a URI. MCP resources are always registered.
When `skills_read` is omitted from an individual tool selection, the index and
resource template expose only the `mcp` collection; all other collections are
excluded from discovery and direct reads.

The index is generated from the filtered manifest at read time: collection,
skill ID, entrypoint URI, and a description of at most 120 code points per entry.
skill ID, entrypoint URI, and a short summary per entry. Summaries come from
`skills/index-summaries.json` (at most 100 code points, keyed by entry ID) and are
used only in the index; skill descriptions, `skills_read` results, the skills
extension, and search keep the full `description`. An entry without a summary
falls back to its description truncated to 120 code points; a test requires
every bundled skill to have one, so add a summary when you add a skill.
It includes no skill bodies or reference inventory. Current bundled index content
stays below 16 KiB; the runtime resource ceiling is 64 KiB. It is not another
stays below 24 KiB; the runtime resource ceiling is 64 KiB. It is not another
authored skill and does not increase the skill count. Clients can discover files
through the index or tool search without template argument completion.
Passing the index URI to `skills_read` returns its normal paginated catalog
Expand Down
1 change: 1 addition & 0 deletions packages/b2c-dx-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"prepack": "pnpm run generate:guidance && node scripts/prepare-sdk-bundle.mjs && oclif manifest",
"postpack": "shx rm -f oclif.manifest.json",
"generate:guidance": "tsx --conditions=development scripts/generate-guidance.ts",
"sync:cap-dev-skills": "node scripts/sync-cap-dev-skills.mjs",
"prepare:guidance-test": "node scripts/prepare-guidance-test.mjs"
},
"dependencies": {
Expand Down
6 changes: 6 additions & 0 deletions packages/b2c-dx-mcp/scripts/generate-guidance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ const config = JSON.parse(readFileSync(join(packageRoot, 'skills/collections.jso
collections: GuidanceCollectionSource[];
};
if (config.version !== 1) throw new Error('Unsupported guidance collections manifest');
// Short skill://index lines; skill descriptions and search are unaffected.
const indexSummaries = JSON.parse(readFileSync(join(packageRoot, 'skills/index-summaries.json'), 'utf8')) as Record<
string,
string
>;
const result = bundleGuidance({
repoRoot,
baseDirectory: packageRoot,
collections: config.collections,
featuredResources: config.featuredResources,
indexSummaries,
destination: join(packageRoot, 'content/guidance'),
});
process.stdout.write(`Bundled ${result.entries} guidance entries and ${result.files} Markdown files.\n`);
91 changes: 91 additions & 0 deletions packages/b2c-dx-mcp/scripts/sync-cap-dev-skills.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2025, Salesforce, Inc.
* SPDX-License-Identifier: Apache-2
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
*/

/**
* Vendors the `cap-dev` (Commerce App Package development) skills from the
* public commerce-apps repository into `vendor/cap-dev/skills`, which
* `generate:guidance` bundles as the `cap-dev` collection.
*
* The skills are authored upstream; never edit the vendored copy. Refresh with:
*
* pnpm --filter @salesforce/b2c-dx-mcp run sync:cap-dev-skills [-- --ref <branch|tag|sha>]
*
* Only Markdown is vendored (the guidance bundle serves Markdown only). Links
* from a skill into the upstream `shared/` folder are rewritten to a copy inside
* that skill, because bundled skills must be self-contained.
*/
import {execFileSync} from 'node:child_process';
import {cpSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync} from 'node:fs';
import {tmpdir} from 'node:os';
import {dirname, join, posix, resolve} from 'node:path';
import {fileURLToPath} from 'node:url';

const REPO = 'SalesforceCommerceCloud/commerce-apps';
const SKILLS_PATH = '.claude/skills';
const SHARED = 'shared';

const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const vendorRoot = join(packageRoot, 'vendor/cap-dev');
const refIndex = process.argv.indexOf('--ref');
const ref = refIndex === -1 ? 'main' : process.argv[refIndex + 1];
if (!ref) throw new Error('--ref requires a branch, tag, or commit');

function git(cwd, ...args) {
return execFileSync('git', args, {cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit']}).trim();
}

function markdownFiles(root, prefix = '') {
const files = [];
for (const item of readdirSync(root, {withFileTypes: true})) {
if (item.name === 'evals' || item.name.startsWith('.')) continue;
const path = prefix ? `${prefix}/${item.name}` : item.name;
if (item.isDirectory()) files.push(...markdownFiles(join(root, item.name), path));
else if (item.isFile() && item.name.endsWith('.md')) files.push(path);
}
return files;
}

const checkout = mkdtempSync(join(tmpdir(), 'cap-dev-skills-'));
try {
git(checkout, 'init', '--quiet');
git(checkout, 'remote', 'add', 'origin', `https://github.com/${REPO}.git`);
git(checkout, 'fetch', '--quiet', '--depth', '1', 'origin', ref);
git(checkout, 'checkout', '--quiet', 'FETCH_HEAD');
const sha = git(checkout, 'rev-parse', 'HEAD');
const committedAt = git(checkout, 'show', '-s', '--format=%cI', 'HEAD');
const source = join(checkout, SKILLS_PATH);

const destination = join(vendorRoot, 'skills');
rmSync(destination, {recursive: true, force: true});
const skills = readdirSync(source, {withFileTypes: true})
.filter((item) => item.isDirectory() && item.name !== SHARED && !item.name.startsWith('.'))
.map((item) => item.name)
.sort();
for (const skill of skills) {
for (const file of markdownFiles(join(source, skill))) {
let content = readFileSync(join(source, skill, file), 'utf8');
content = content.replaceAll(/\]\(([^)\s#]+)(#[^)\s]*)?\)/g, (match, target, anchor = '') => {
if (/^[a-z][a-z0-9+.-]*:/i.test(target)) return match;
const resolved = posix.normalize(posix.join(skill, posix.dirname(file), target));
if (!resolved.startsWith(`${SHARED}/`)) return match;
const copy = `references/${resolved.slice(SHARED.length + 1)}`;
mkdirSync(dirname(join(destination, skill, copy)), {recursive: true});
cpSync(join(source, resolved), join(destination, skill, copy));
return `](${posix.relative(posix.dirname(file), copy)}${anchor})`;
});
mkdirSync(dirname(join(destination, skill, file)), {recursive: true});
writeFileSync(join(destination, skill, file), content);
}
}

writeFileSync(
join(vendorRoot, 'source.json'),
`${JSON.stringify({repository: REPO, path: SKILLS_PATH, ref, sha, committedAt}, null, 2)}\n`,
);
process.stdout.write(`Vendored ${skills.length} cap-dev skills from ${REPO}@${sha.slice(0, 12)} (${ref}).\n`);
} finally {
rmSync(checkout, {recursive: true, force: true});
}
4 changes: 2 additions & 2 deletions packages/b2c-dx-mcp/skills/b2c-mcp-server/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Read only the skill that matches the task; each links its own references.
Every skill and reference file is readable as an MCP resource
(`skill://<collection>/<skill>/<file>`) or with `skills_read({uri})`.
Collections: `b2c` (platform/cartridges), `b2c-cli` (CLI), `b2c-ops`
(operator/admin runbooks), `storefront-next` (storefronts), `mcp` (server/tool
workflows). Search with `skills_read({query, collection})` or browse `skill://index`.
(operator/admin runbooks), `storefront-next` (storefronts), `cap-dev` (authoring
Commerce App Packages), `mcp` (server/tool workflows). Search with `skills_read({query, collection})` or browse `skill://index`.

## Server configuration and tool availability

Expand Down
6 changes: 6 additions & 0 deletions packages/b2c-dx-mcp/skills/collections.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
"isGA": true,
"workspaces": ["storefront-next"]
},
{
"id": "cap-dev",
"title": "Commerce App Package Development",
"directory": "vendor/cap-dev/skills",
"isGA": true
},
{
"id": "mcp",
"title": "MCP Workflows",
Expand Down
Loading
Loading