@W-20592464 SCAPI Schemas List and SCAPI Custom APIs Status MCP tools#133
Conversation
Resolved conflicts: - packages/b2c-tooling-sdk/package.json: Kept both ./operations/scapi and ./operations/content exports - packages/b2c-dx-mcp/package.json: Kept yaml dependency from branch Co-authored-by: Cursor <cursoragent@cursor.com>
|
nit: can you add a changeset |
patricksullivansf
left a comment
There was a problem hiding this comment.
Aside:
- Tool Selection
Scenario: Ensure correct tool is used for schemas vs endpoint status.
Rather than part of a tool implementation PR, I think tool selection testing is more reliably to be done as a separate task, ideally with dozens of tools enabled.
| columns: z | ||
| .string() | ||
| .optional() | ||
| .describe( | ||
| 'Comma-separated fields to return, e.g. type,apiName,status,siteId. Valid: type, apiName, apiVersion, cartridgeName, endpointPath, httpMethod, status, siteId, securityScheme, operationId, schemaFile, implementationScript, errorReason, id.', | ||
| ), | ||
| extended: z | ||
| .boolean() | ||
| .optional() | ||
| .describe( | ||
| 'If true, return all available fields (14 fields total). If false or omitted, return default columns only (6 fields: type, apiName, endpointPath, httpMethod, status, siteId). Use extended: true when you need additional details like apiVersion, cartridgeName, securityScheme, operationId, schemaFile, implementationScript, errorReason, or id. Note: If you only need specific fields, use columns parameter instead for more control.', |
There was a problem hiding this comment.
columns and extended seem to do largely the same thing: decide what columns are returned. We could make the LLM have an easier chore by giving them one option instead of two.
There was a problem hiding this comment.
From the convenience and token usage perspective, more thinking and more data means more token. I will simplify it so that agent can get common default or specific columns.
| return createToolAdapter<CustomListInput, CustomListOutput>( | ||
| { | ||
| name: 'scapi_custom_apis_status', | ||
| description: `List Custom SCAPI API endpoints and their registration status (active vs not_registered). Returns individual HTTP endpoints (e.g., GET /hello, POST /items/{id}) with deployment status, one row per endpoint per site. Use this for developer-defined custom APIs only. |
There was a problem hiding this comment.
although i like the extended description, we should keep in mind that tool descriptions eat context tokens for EVERY request, even when not used. Across dozens if tools this can get unwieldy.We might want to ask if the LLM can compress this a bit.
There was a problem hiding this comment.
That's true. Definitely will compact these.
| const DEFAULT_COLUMNS = ['type', 'apiName', 'endpointPath', 'httpMethod', 'status', 'siteId'] as const; | ||
| const ALL_COLUMN_KEYS = [ |
There was a problem hiding this comment.
weird to me these aren't defined at the SDK level.
There was a problem hiding this comment.
I do not need these. Removed them.
| const {apiFamily, apiName, apiVersion, expandAll, status} = args; | ||
|
|
||
| // Warn if status filter was provided (it's ignored in fetch mode) | ||
| const warning = status |
There was a problem hiding this comment.
for my info, what does the LLM typically do when it gets this warning mixed into the response?
There was a problem hiding this comment.
It usually do nothing to it. We have description on when to send status and I do not see agent send it by mistake. This is extra info.
|
|
||
| **Requirements:** Instance must have shortCode, tenantId, and OAuth with sfcc.scapi-schemas scope.`, | ||
| toolsets: ['PWAV3', 'SCAPI', 'STOREFRONTNEXT'], | ||
| isGA: true, |
There was a problem hiding this comment.
do we really want to go straight to GA?
There was a problem hiding this comment.
Oops, I will update this. Thanks!
| .enum(['current', 'deprecated']) | ||
| .optional() | ||
| .describe( | ||
| 'Filter by schema status. "current" returns only active schemas, "deprecated" returns deprecated ones. Only works in discovery mode.', |
There was a problem hiding this comment.
which is better, default, etc? or does the LLM do a good job of guessing?
There was a problem hiding this comment.
Agent does a good job but I can improve it by setting a default.
| .boolean() | ||
| .optional() | ||
| .describe( | ||
| 'Include full OpenAPI schemas. Requires all three identifiers (apiFamily, apiName, apiVersion). Default false (returns metadata only). WARNING: Slower and increases response size.', |
There was a problem hiding this comment.
love this performance call out.
|
|
||
| describe('handler', () => { | ||
| it('should return endpoints and total when API returns data', async () => { | ||
| mockGet.resolves({ |
There was a problem hiding this comment.
I would rather MCP tests didn't include the SDK, but there are arguments either way.
pro to mocking API response - guarantees integration from API response to MCP output is verified.
con makes the MCP tests brittle and sensitive to SDK implementation, instead of relying on SDK to enforce it's contract with consumers to adapt and hide API changes.
There was a problem hiding this comment.
I agree. If you can mock the SDK the better. We have good test coverage there. Coverage here should be on MCP linnes
There was a problem hiding this comment.
Since its mono repo and its very easy to detect SDK changes. I will refactor the test to focus on MCP side test only. Thanks!
Yes, agent makes decision on which tool to use and the section just to see if the agent use both tools correctly. I will update the section. Thanks. |
|
Both tools description is compacted to save token when agent uses it. Also removed redundant |
There was a problem hiding this comment.
I guess we can address that later. This is the first one we have in MCP. We probably need to add them all.
There was a problem hiding this comment.
You can add them later, and you can add multiple at once. it just might not tag it to the original PR
There was a problem hiding this comment.
@patricksullivansf changeset is updated. Please check.
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
This PR defines the
scapi_custom_apis_statusMCP tool to get the status of Custom API endpoints (which are active, which failed to register). Remote only—no local cartridge scan or schema retrieval. Requires OAuth (sfcc.custom-apis scope). For listing/fetching SCAPI schemas (standard APIs), usescapi_schemas_list.Test coverage script is enabled.
Two SCAPI Tools (Scope of This PR)
The MCP exposes two SCAPI-related tools. This PR and doc cover only the second one:
scapi_schemas_listapiFamily: "custom"for custom APIs.scapi_custom_apis_status(this PR)Test Plan
Prerequisites
pnpm --filter @salesforce/b2c-dx-mcp run builddw.json, env vars, or CLI argsMCP configuration example:
{ "mcpServers": { "b2c-dx": { "command": "/path/to/packages/b2c-dx-mcp/bin/dev.js", "args": [ "--working-directory", "/path/to/your-cartridge-or-storefront-project", "--toolsets", "SCAPI", "--allow-non-ga-tools" ] } } }Test Cases
1. Basic Functionality
Scenario: List custom APIs with default parameters.
Test: Prompt "What custom APIs are in this project?" or "List custom SCAPI endpoints."
Expected Behavior:
2. Status Filtering
Scenario: Filter endpoints by deployment status.
Test: Prompt "Show me only active custom APIs" or "Which custom APIs failed to deploy?"
Expected Behavior:
status: "active": Returns only active endpoints (remote-sourced endpoints havestatus: "active"; local-only may still appear as"not_registered")status: "not_registered": Returns only non-registered endpoints (includes local-only and failed remote registrations)3. Schema Inclusion
Scenario: Include full OpenAPI schemas in response.
Test: Prompt "Get custom APIs with full OpenAPI schemas" or "List custom APIs and include their schema definitions."
Expected Behavior:
includeSchemas: trueschemafield with OpenAPI YAML contentschemasRetrievedcountwebdavErrormay be set; local schemas still included4. Error Handling
Scenario: Handle missing credentials and empty results gracefully.
Test Cases:
remoteErrorset,remoteCount: 0localCount: 0total: 0, appropriate error messageExpected Behavior:
remoteErrorormessagefieldspnpm test)pnpm run format)