Skip to content

@W-20592464 SCAPI Schemas List and SCAPI Custom APIs Status MCP tools#133

Merged
yhsieh1 merged 29 commits into
mainfrom
t/commerce/W-20592464
Feb 13, 2026
Merged

@W-20592464 SCAPI Schemas List and SCAPI Custom APIs Status MCP tools#133
yhsieh1 merged 29 commits into
mainfrom
t/commerce/W-20592464

Conversation

@yhsieh1

@yhsieh1 yhsieh1 commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR defines the scapi_custom_apis_status MCP 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), use scapi_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:

Tool Purpose When to use
scapi_schemas_list List or fetch SCAPI schemas (both standard and custom). Two modes: discovery (metadata) and fetch (full OpenAPI schema). Use apiFamily: "custom" for custom APIs. "What SCAPI APIs are available?", "Show me shopper-products schema", "List custom API definitions", filtering by apiFamily / apiName / apiVersion.
scapi_custom_apis_status (this PR) Get registration status of Custom API endpoints (active / not_registered). Remote only. "What's the status of my custom API endpoints?", "Which endpoints are active?"

Test Plan

Prerequisites

  • MCP server built: pnpm --filter @salesforce/b2c-dx-mcp run build
  • MCP server running with a toolset that includes the tool (e.g. SCAPI, PWAV3, or STOREFRONTNEXT)
  • For remote tests: Valid OAuth configured (tenantId, shortCode, sfcc.custom-apis scope), e.g. via dw.json, env vars, or CLI args
  • MCP configured in Claude Desktop or Cursor

MCP 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:

  • Tool returns merged remote + local endpoints (if OAuth configured)

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:

  • With status: "active": Returns only active endpoints (remote-sourced endpoints have status: "active"; local-only may still appear as "not_registered")
  • With status: "not_registered": Returns only non-registered endpoints (includes local-only and failed remote registrations)
  • Filtering applies correctly to merged results

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:

  • Tool called with includeSchemas: true
  • Each endpoint includes schema field with OpenAPI YAML content
  • Response includes schemasRetrieved count
  • Large schemas are capped appropriately; invalid YAML skipped without breaking response
  • If WebDAV fails for remote: webdavError may be set; local schemas still included

4. Error Handling

Scenario: Handle missing credentials and empty results gracefully.

Test Cases:

  • No OAuth: Working directory with local cartridges → returns local endpoints only, remoteError set, remoteCount: 0
  • No local APIs: OAuth configured, no local schemas → returns remote endpoints only, localCount: 0
  • No APIs at all: No OAuth, no local schemas → empty result with total: 0, appropriate error message

Expected Behavior:

  • No crashes on missing credentials or empty results
  • Clear error messages via remoteError or message fields
  • Tool handles all edge cases gracefully

  • Tests pass (pnpm test)
  • Code is formatted (pnpm run format)

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>
@clavery

clavery commented Feb 11, 2026

Copy link
Copy Markdown
Collaborator

nit: can you add a changeset

@patricksullivansf patricksullivansf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside:

  1. 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.

Comment on lines +194 to +204
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.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@yhsieh1 yhsieh1 Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true. Definitely will compact these.

Comment on lines +29 to +30
const DEFAULT_COLUMNS = ['type', 'apiName', 'endpointPath', 'httpMethod', 'status', 'siteId'] as const;
const ALL_COLUMN_KEYS = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird to me these aren't defined at the SDK level.

@yhsieh1 yhsieh1 Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my info, what does the LLM typically do when it gets this warning mixed into the response?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really want to go straight to GA?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which is better, default, etc? or does the LLM do a good job of guessing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love this performance call out.

Comment thread packages/b2c-dx-mcp/src/services.ts

describe('handler', () => {
it('should return endpoints and total when API returns data', async () => {
mockGet.resolves({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. If you can mock the SDK the better. We have good test coverage there. Coverage here should be on MCP linnes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

@yhsieh1

yhsieh1 commented Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

Aside:

  1. 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.

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.

@yhsieh1

yhsieh1 commented Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

Both tools description is compacted to save token when agent uses it. Also removed redundant extended option to avoid agent thinks too much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm. i didn't include this in my #110 and #114. should i have? should we address those here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can address that later. This is the first one we have in MCP. We probably need to add them all.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add them later, and you can add multiple at once. it just might not tag it to the original PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patricksullivansf changeset is updated. Please check.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment thread packages/b2c-tooling-sdk/src/schemas/security-schemes.ts
@yhsieh1 yhsieh1 requested a review from clavery February 12, 2026 19:19
Co-authored-by: Cursor <cursoragent@cursor.com>
clavery
clavery previously approved these changes Feb 13, 2026
clavery
clavery previously approved these changes Feb 13, 2026
clavery
clavery previously approved these changes Feb 13, 2026
@yhsieh1 yhsieh1 requested a review from clavery February 13, 2026 15:18
@yhsieh1 yhsieh1 enabled auto-merge (squash) February 13, 2026 17:21
@yhsieh1 yhsieh1 merged commit 1485923 into main Feb 13, 2026
3 checks passed
@yhsieh1 yhsieh1 deleted the t/commerce/W-20592464 branch February 13, 2026 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants