Skip to content

feat(#4813): add MCP registry server mapping common library plugin - mcp-registry-server-mapping - #4823

Open
fullsend-ai-coder[bot] wants to merge 10 commits into
mainfrom
agent/4813-mcp-registry-server-mapping
Open

fullsend-ai-coder[bot] wants to merge 10 commits into
mainfrom
agent/4813-mcp-registry-server-mapping

Conversation

@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

Add the generated report.api.md for the new mcp-registry-server-mapping package and fix missing @public release tags on DEFAULT_PREFIX and RepositoryUrlResult. Escape @ in TSDoc comment to resolve api-extractor warnings.

Assisted-by: claude-opus-4-6

Co-Authored-By: Claude Opus 4.6 [email protected]


Closes #4813

Post-script verification

  • Branch is not main/master (agent/4813-mcp-registry-server-mapping)
  • Secret scan passed (gitleaks — 5d966c40591070c960f164a16412193061b48104..HEAD)
  • Pre-commit hooks passed (authoritative run on runner)
  • Tests ran inside sandbox

fullsend-ai-coder Bot and others added 2 commits September 16, 2026 15:06
Implement the direct field mapping transform from MCP Registry
server.json to Backstage mcp-server API entity (Groups 1-2 from
tasks.md). This is the first half of the mcp-registry-server-mapping
capability; annotation projection (Group 3) lands in #4795.

New package: @red-hat-developer-hub/backstage-plugin-mcp-registry-
server-mapping (common-library role).

What changed:
- mapServerToEntity(): pure, deterministic transform producing a
  valid API entity with spec.type: mcp-server, spec.remotes[], no
  spec.definition
- Identity derivation (D4): metadata.name from sanitized
  prefix__name__version with stable hash suffix when sanitization
  mutates or length exceeds 63 chars
- D11 URL scheme policy: allowlist absolute http/https only on all
  emitted URL fields; no host classification or DNS resolution
- D8 placeholder remote: type "undefined" with websiteUrl when no
  valid remotes; actionable error when websiteUrl also unavailable
- SCM-aware repository URL combination (D10): github/gitlab/
  bitbucket/azure-devops subfolder templates with HEAD ref
- Caller defaults: prefix (mcp.registry), owner (unknown),
  lifecycle (production) with override support
- Hand-off contract: consumed paths and reserved annotation keys
  supplied for the annotation projection sibling
- mapping-reference.md: field-mapping table, annotation key rules,
  caller defaults, D11 policy documentation

89 tests covering entity shape, identity, remotes, repository URL
combination, D11 URL policy, determinism, validation, and hand-off.

Closes #4813

Assisted-by: claude-opus-4-6
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add the generated report.api.md for the new
mcp-registry-server-mapping package and fix
missing @public release tags on DEFAULT_PREFIX
and RepositoryUrlResult. Escape @ in TSDoc
comment to resolve api-extractor warnings.

Closes #4813

Assisted-by: claude-opus-4-6

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@fullsend-ai-coder fullsend-ai-coder Bot added the ready-for-review Agent PR ready for human review label Sep 16, 2026
@fullsend-ai-coder
fullsend-ai-coder Bot requested review from a team and gabemontero as code owners September 16, 2026 15:24
@rhdh-gh-app

rhdh-gh-app Bot commented Sep 16, 2026

Copy link
Copy Markdown

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-mcp-registry-server-mapping-common workspaces/ai-integrations/plugins/mcp-registry-server-mapping-common minor v0.1.0

@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.52381% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 63.36%. Comparing base (5d966c4) to head (d883866).
⚠️ Report is 15 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4823      +/-   ##
==========================================
+ Coverage   63.28%   63.36%   +0.07%     
==========================================
  Files        2675     2679       +4     
  Lines      106507   106738     +231     
  Branches    29819    29893      +74     
==========================================
+ Hits        67401    67631     +230     
+ Misses      37326    37318       -8     
- Partials     1780     1789       +9     
Flag Coverage Δ *Carryforward flag
adoption-insights 84.77% <ø> (ø) Carriedforward from 5aa4e8d
ai-integrations 82.56% <99.52%> (+3.06%) ⬆️
app-defaults 54.82% <ø> (ø) Carriedforward from 5aa4e8d
augment 46.67% <ø> (ø) Carriedforward from 5aa4e8d
boost 84.97% <ø> (ø) Carriedforward from 5aa4e8d
bulk-import 73.12% <ø> (ø) Carriedforward from 5aa4e8d
cost-management 13.53% <ø> (ø) Carriedforward from 5aa4e8d
dcm 73.47% <ø> (ø) Carriedforward from 5aa4e8d
e2e-adoption-insights 60.00% <ø> (ø) Carriedforward from 5aa4e8d
e2e-extensions 62.31% <ø> (ø) Carriedforward from 5aa4e8d
e2e-global-header 49.71% <ø> (ø) Carriedforward from 5aa4e8d
e2e-homepage 61.11% <ø> (ø) Carriedforward from 5aa4e8d
e2e-intelligent-assistant 46.01% <ø> (ø) Carriedforward from 5aa4e8d
e2e-orchestrator 49.49% <ø> (ø) Carriedforward from 5aa4e8d
e2e-orchestrator-plugin 49.48% <ø> (ø) Carriedforward from 5aa4e8d
e2e-quickstart 55.21% <ø> (ø) Carriedforward from 5aa4e8d
e2e-scorecard 50.05% <ø> (ø) Carriedforward from 5aa4e8d
e2e-theme 16.36% <ø> (ø) Carriedforward from 5aa4e8d
extensions 58.30% <ø> (ø) Carriedforward from 5aa4e8d
global-floating-action-button 71.18% <ø> (ø) Carriedforward from 5aa4e8d
global-header 67.88% <ø> (ø) Carriedforward from 5aa4e8d
homepage 48.39% <ø> (ø) Carriedforward from 5aa4e8d
install-dynamic-plugins 71.77% <ø> (ø) Carriedforward from 5aa4e8d
intelligent-assistant 77.99% <ø> (ø) Carriedforward from 5aa4e8d
konflux 91.98% <ø> (ø) Carriedforward from 5aa4e8d
lightspeed 69.02% <ø> (ø) Carriedforward from 5aa4e8d
mcp-integrations 84.46% <ø> (ø) Carriedforward from 5aa4e8d
orchestrator 77.32% <ø> (ø) Carriedforward from 5aa4e8d
quickstart 63.74% <ø> (ø) Carriedforward from 5aa4e8d
sandbox 79.56% <ø> (ø) Carriedforward from 5aa4e8d
scorecard 88.44% <ø> (ø) Carriedforward from 5aa4e8d
theme 87.91% <ø> (ø) Carriedforward from 5aa4e8d
translations 5.12% <ø> (ø) Carriedforward from 5aa4e8d
x2a 78.44% <ø> (ø) Carriedforward from 5aa4e8d

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5d966c4...d883866. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:25 PM UTC · Completed 3:40 PM UTC

Commit: a3e20d7 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $6.26

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [logic-error] workspaces/ai-integrations/plugins/mcp-registry-server-mapping-common/src/repository.ts:92computeRepositoryUrl does not trim whitespace from repository.url before using it, unlike every other URL emit path in the codebase (remote.url.trim() in mapRemotes, doc.websiteUrl.trim() in buildLinks). If repository.url has surrounding whitespace, it would pass isAllowedUrl() (which trims internally) but produce untrimmed URLs in combinedUrl, originalUrl, the Source Code link, backstage.io/source-location, and the repository.url annotation. The D11 spec states "Trim leading/trailing whitespace" as step 1.
    Remediation: Add .trim() to the assignment of originalUrl in computeRepositoryUrl.

  • [path-traversal] workspaces/ai-integrations/plugins/mcp-registry-server-mapping-common/src/repository.ts:87normalizeSubfolder strips leading/trailing slashes and whitespace but does not reject .. path traversal segments. A subfolder value containing .. segments is concatenated into the combined URL for all SCM types, written into metadata.links[].url and backstage.io/source-location. The traversal is limited to the same host but could redirect the Source Code link to an unintended repository path. types.ts states "Must be a clean relative path" but this invariant is not enforced.
    Remediation: Add validation to reject or strip .. path segments (e.g., if (segments.some(s => s === '..')) return undefined;).

Low

  • [edge-case] workspaces/ai-integrations/plugins/mcp-registry-server-mapping-common/src/repository.ts:60normalizeBase operates on the raw URL string rather than parsed URL components. The .git suffix stripping and trailing-slash removal would not work correctly if the repository URL contained query parameters or fragment identifiers. While uncommon for repository.url, the string-based approach could produce incorrect combined URLs in such edge cases.

Labels: PR implements MCP registry server mapping in the ai-integrations workspace.

Previous run

Review — request-changes

PR: #4823 — feat(#4813): add MCP registry server mapping common library plugin
Reviewed at: 5aa4e8d

[!NOTE]
Prior review provenance: unverifiable-wrong-app — the prior review comment was created by a different GitHub App than expected. Severity anchoring from the prior review was skipped for this run.

Summary

This PR adds a well-structured common library plugin (mcp-registry-server-mapping-common) that implements a deterministic transform from MCP Registry server.json documents to Backstage mcp-server API entities. The implementation covers identity derivation, URL scheme gating (D11), remote mapping with D8 placeholder behavior, SCM-aware repository URL combination, and a clean hand-off contract for the annotation-projection sibling.

The code quality is high, the test suite is thorough (identity, URL policy, mapping, remotes, repository combination), and the design aligns well with the authorized scope from issue #4813. However, one blocking issue and several medium-severity concerns need to be addressed before merge.


Blocking

1. node:crypto import incompatible with common-library role (high)

File: plugins/mcp-registry-server-mapping-common/src/identity.ts:17

The identity.ts module imports createHash from node:crypto, a Node.js-only API. The package.json declares backstage.role: "common-library", which in Backstage conventions signals that the package can be consumed from both frontend (browser) and backend (Node.js) contexts. The node:crypto module is unavailable in browsers. No other common-library in this workspace uses node: imports (verified against ai-experience-common, catalog-model-ai-model-server, catalog-model-ai-resource-agent). All 5 code-reviewing sub-agents independently flagged this issue.

Fix: Either change the role to "node-library" in package.json (since the downstream consumer is the backend-only mcp-registry-provider), or replace node:crypto with a platform-agnostic hash function (e.g., FNV-1a — cryptographic strength is not needed for an 8-hex-char disambiguation suffix).


Medium

2. URLs stored with untrimmed whitespace

File: plugins/mcp-registry-server-mapping-common/src/mapServerToEntity.ts

isAllowedUrl() trims whitespace internally before parsing, but the calling code in buildLinks() and mapRemotes() stores the original untrimmed value. The D11 spec prescribes trimming as step 1, implying the trimmed value should be what gets stored.

Fix: Trim URL values before storing them in links, annotations, and spec.remotes, or refactor isAllowedUrl to return the trimmed URL string.

3. Misleading error when type-invalid remotes are filtered

File: plugins/mcp-registry-server-mapping-common/src/mapServerToEntity.ts:73

When all declared remotes have valid URLs but empty/undefined type fields, mapRemotes() filters them all out and may throw "no valid remotes and no valid websiteUrl" — giving the operator no clue that fixing the type fields would resolve the problem. The test suite covers the websiteUrl-present path but not the websiteUrl-absent path for type-invalid remotes.

Fix: Add a distinct error message noting that remotes were filtered due to invalid types. Add a test for the type-invalid-remotes-with-no-websiteUrl path.

4. Alpha API re-exports create backward-compatibility hazard

File: plugins/mcp-registry-server-mapping-common/src/index.ts:14

The package re-exports McpServerApiEntity and McpServerRemote from @backstage/catalog-model/alpha. The /alpha entrypoint signals these types may change without a major version bump. Consumers transitively depend on these unstable types. No other common-library in this workspace re-exports types from external packages.

Consider: Removing the re-exports and letting consumers import directly from @backstage/catalog-model/alpha, or at minimum documenting the alpha dependency prominently.

5. Overly broad public API surface for initial release

File: plugins/mcp-registry-server-mapping-common/src/index.ts:27

The package exports 12 functions/constants and 9 interfaces/types as @public API for a 0.1.0 initial release. Functions like sanitizeSegment, trackConsumedRemotePaths, and buildLinks appear to be internal building blocks rather than general-purpose consumer API. Every public export becomes a backward-compatibility commitment.

Consider: Narrowing the public API to the primary consumer surface (mapServerToEntity, types, defaults) and moving sibling-only exports behind a separate entrypoint or marking them @alpha.


Low

# Finding File
6 pluginId mismatch: set to mcp-registry-provider but directory is mcp-registry-server-mapping-common package.json:21
7 Spec says "while" for boundary normalization but code uses single "if" (functionally equivalent) identity.ts:84
8 normalizeBase doesn't re-strip trailing / after .git removal (double-slash edge case) repository.ts:53
9 Subfolder path segments not URL-encoded for non-Azure SCMs (limited impact) repository.ts:126
10 Missing co-located repository.test.ts; sibling plugins use one-module-one-test pattern repository.ts
11 LinksResult and McpRegistryRemote properties lack JSDoc (undocumented in report.api.md) types.ts:33
12 No test for empty title: '' edge case (consumed but not emitted, D12 relevance) mapServerToEntity.test.ts
Previous run (2)

Review — request-changes

Summary

This PR implements a new @red-hat-developer-hub/backstage-plugin-mcp-registry-server-mapping common library plugin that deterministically transforms MCP Registry server.json documents into Backstage mcp-server API entities. The implementation is well-structured with comprehensive tests (identity derivation, URL scheme policy, main mapping, repository URL combination) and a clear separation of concerns.

One blocking issue: the PR includes an out-of-scope change to the root package.json that removes the repository URL, which must be reverted. Several medium-severity findings about runtime validation and API contract documentation also require attention.


Findings

🔴 High

1. Root package.json scope creep — repository URL removed · package.json

The root package.json repository field was changed from a URL string to an object that omits the required url property:

-  "repository": "[email protected]:redhat-developer/rhdh-plugins.git",
+  "repository": {
+    "type": "git",
+    "directory": "."
+  },

Per npm's spec, the object form requires a url field. The new plugin's own package.json correctly includes url, making this inconsistent. This change is unrelated to issue #4813 and affects the entire monorepo. Tools that read repository.url (npm repo, GitHub dependency graph, Renovate/Dependabot) will lose the URL.

Remediation: Revert this change entirely, or add the url field to the object.


🟡 Medium

2. Missing runtime validation for remote.type · mapServerToEntity.ts

McpServerRemote declares type as a required string, but input comes from untrusted JSON where type could be undefined or null at runtime. The code checks remote.url before use but uses remote.type directly without validation. A malformed remote entry missing type would produce type: undefined in the entity, violating the McpServerEntityRemote contract.

Remediation: Add a runtime check: typeof remote.type === 'string' && remote.type.length > 0.

3. Consumed-path tracking asymmetry · mapServerToEntity.ts

websiteUrl is added to consumedPaths regardless of D11 outcome (preventing the projection sibling from re-projecting refused URLs), but remotes[].url is only consumed when D11 passes. This creates an implicit contract: the projection sibling must independently enforce D11 for remote URLs but not for websiteUrl. If the sibling relies solely on consumed-path tracking, refused remote URLs would leak into annotations.

Remediation: Either consume refused remote URLs symmetrically, or document the asymmetry in McpServerMappingResult.consumedPaths JSDoc.

4. McpServerApiEntity omits spec.definition — undocumented deviation · types.ts

The standard Backstage ApiEntity requires spec.definition: string. This entity type intentionally omits it (tests assert not.toHaveProperty('definition')), but the deviation is undocumented. Downstream code casting to the standard ApiEntity type, or catalog validators enforcing spec.definition, will reject these entities.

Remediation: Document why spec.definition is omitted (MCP servers define APIs through remotes, not an inline definition string). Consider adding definition?: string or a sentinel value for standard ApiEntity compatibility.


🔵 Low

5. Subfolder path traversal in display URLs · repository.ts

The subfolder value is normalized (leading/trailing slashes stripped) but not validated for .. segments. A subfolder like ../../etc produces misleading browse URLs. For Azure DevOps, & in subfolder breaks the query parameter format. Risk is limited to misleading display links (no server-side path traversal).

6. Missing test for consumed paths with refused remote URLs · mapServerToEntity.test.ts

No test verifies consumed-path behavior when a remote URL is refused by D11. A test with mixed valid/refused remotes would lock in the asymmetric contract and prevent regressions.

7. Missing test for sanitizeSegment('') · identity.test.ts

No test covers direct invocation of the exported sanitizeSegment function with an empty string input. The empty-string behavior should be documented by a test.


What looks good

  • URL scheme policy (D11): Correct use of WHATWG URL constructor with no base URL; proper scheme comparison against http: and https: with trailing colon.
  • Identity derivation: deriveMetadataName truncation logic is verified correct — result never exceeds 63 characters, always starts/ends with alphanumeric.
  • Determinism: Annotation keys are sorted, consumed paths are sorted, tests verify byte-identical output for identical inputs.
  • Test coverage: Comprehensive test suite covering entity shape, identity, caller defaults, required field validation, remotes (D8), descriptive metadata, repository URL combination (GitHub/GitLab/Bitbucket/Azure DevOps/fallback), determinism, and hand-off contract.
  • Package structure: Consistent with sibling common-library packages — license headers, eslint config, export patterns, naming conventions, backstage.role, sideEffects: false all match established patterns.
  • Security posture: Pure function with no I/O; D11 URL allowlist is sound; no secrets, no auth, no network access.

Labels: PR implements a new feature plugin for MCP registry server mapping in the ai-integrations workspace.

fullsend-ai-review[bot]

This comment was marked as outdated.

@michael-valdron michael-valdron left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

/fs-fix Change PR title to have correct feat(#4813) prefix and adjust title to reflect more on the feature changes and less on the first fix commit.

@michael-valdron michael-valdron changed the title fix(#4813): add API report and fix TSDoc release tags feat(#4813): add MCP registry server mapping common library plugin - mcp-registry-server-mapping Sep 16, 2026
@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix Revert the root package.json change entirely, or add the url field to the repository object.

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 4:07 PM UTC · Completed 4:11 PM UTC

Commit: a3e20d7 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $0.57

Restore the repository URL that was dropped when converting the
repository field from a string to an object in the root package.json.

Addresses review feedback on #4823
@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix address review comments

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 4:39 PM UTC · Completed 4:54 PM UTC

Commit: 6ae5b8d · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $2.54

- Revert root package.json scope-creep (unrelated repository field change)
- Add runtime validation for remote.type (non-empty string check)
- Consume refused remote URLs symmetrically in consumedPaths
- Apply encodeURIComponent per segment for Azure DevOps subfolder paths
- Add tests for all three code changes

Addresses review feedback on #4823

Assisted-by: claude-opus-4-6
@michael-valdron
michael-valdron removed request for a team September 16, 2026 16:59
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (agent timed out after 20m0s without completing (timeout: 20m0s)) · Started 9:06 PM UTC · Completed 9:28 PM UTC

Commit: d061659 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@michael-valdron

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (agent timed out after 20m0s without completing (timeout: 20m0s)) · Started 9:46 PM UTC · Completed 10:08 PM UTC

Commit: d061659 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix address review comments

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 10:10 PM UTC · Completed 10:32 PM UTC

Commit: d061659 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $6.70

- Extract annotation key sort to separate statement (sonarcloud S2871)
- Update McpServerDocument and McpServerRepository JSDoc to match
  draft server.json schema descriptions with @see references
- Update mapping-reference.md: add entity type section, consumed path
  tracking section, and runtime validation notes for remote.type
- Handle potentially undefined entity.metadata.annotations in tests
- Export LinksResult type and fix ae-forgotten-export API warning
- Fix ae-unresolved-link in McpRegistryRemote JSDoc
- Regenerate report.api.md

Addresses review feedback on #4823

Assisted-by: claude-opus-4-6
@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix Resolve the following comments:

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ❌ Failure (agent timed out after 25m0s without completing (timeout: 25m0s)) · Started 10:47 PM UTC · Completed 11:22 PM UTC

Commit: 6c2fe69 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix rather than importing McpServerApiEntity and McpServerRemote in types.ts then exporting to other modules, just do the same imports across all modules, re-generate report.api.md to check for changes afterwords, if there are changes include in commit

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 11:27 PM UTC · Completed 11:39 PM UTC

Commit: 6c2fe69 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $1.24

…odule

Remove re-exports of McpServerApiEntity and McpServerRemote from types.ts.
Each module now imports these types directly from
@backstage/catalog-model/alpha. Regenerated report.api.md to reflect the
updated import structure.

Addresses review feedback on #4823

Assisted-by: claude-opus-4-6
@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix Resolve the following comments:

  • Any reference to DXX design codes (e.g. D11) in the source comments should be followed by a link to the openspec design.md section that is being referenced.
  • feat(#4813): add MCP registry server mapping common library plugin - mcp-registry-server-mapping #4823 (comment) - remove any "Step X:" from comments (e.g. "// Step 7: Sort annotation keys for determinism" should become "// Sort annotation keys for determinism"), this is good product code practice
  • After addressing the above re-generate report.api.md to check for changes, if there are changes include in commit

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 11:50 PM UTC · Completed 12:07 AM UTC

Commit: a3fab73 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $3.41

- Add openspec/changes/mcp-registry-server-mapping/design.md § DXX links
  to all DXX design code references in source comments across
  mapServerToEntity.ts, identity.ts, urlPolicy.ts, and repository.ts
- Remove "Step X:" prefixes from all inline comments in
  mapServerToEntity.ts per code style feedback
- report.api.md unchanged (comment-only edits, no API surface change)

Addresses review feedback on #4823

Assisted-by: claude-opus-4-6
@michael-valdron

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:17 AM UTC · Completed 12:33 AM UTC

Commit: 5aa4e8d · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $9.61

fullsend-ai-review[bot]

This comment was marked as outdated.

@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix address review comments

@fullsend-ai-coder

fullsend-ai-coder Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Fix · ❌ Terminated · Started 12:40 AM UTC · Ended 1:02 AM UTC

Commit: 5aa4e8d · View workflow run →

- Change backstage.role from common-library to node-library to resolve
  node:crypto import incompatibility (blocking finding)
- Trim URLs before storing in mapRemotes and buildLinks to prevent
  untrimmed whitespace in emitted entity values
- Add actionable error message when remotes are filtered due to invalid
  type fields, with a test for the type-invalid-no-websiteUrl path
- Remove re-exports of McpServerApiEntity and McpServerRemote from
  index.ts; consumers should import directly from
  @backstage/catalog-model/alpha
- Re-strip trailing / after .git removal in normalizeBase to prevent
  double-slash edge case
- Add JSDoc to LinksResult and McpRegistryRemote properties
- Add co-located repository.test.ts with comprehensive coverage
- Add tests for sanitizeSegment('') and empty title edge cases
- Update report.api.md to reflect API surface changes

Addresses review feedback on #4823

Assisted-by: claude-opus-4-6
@gabemontero

Copy link
Copy Markdown
Contributor

/fs-fix Resolve the following comments:

  • Any reference to DXX design codes (e.g. D11) in the source comments should be followed by a link to the openspec design.md section that is being referenced.
  • feat(#4813): add MCP registry server mapping common library plugin - mcp-registry-server-mapping #4823 (comment) - remove any "Step X:" from comments (e.g. "// Step 7: Sort annotation keys for determinism" should become "// Sort annotation keys for determinism"), this is good product code practice
  • After addressing the above re-generate report.api.md to check for changes, if there are changes include in commit

@michael-valdron the fs-fix prompt needs to be on a single line

@fullsend-ai-coder

Copy link
Copy Markdown
Contributor Author

🤖 Finished Fix · ✅ Success · Started 12:40 AM UTC · Completed 1:02 AM UTC

Commit: 5aa4e8d · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $6.13

@sonarqubecloud

Copy link
Copy Markdown

@michael-valdron

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 1:11 AM UTC · Ended 1:30 AM UTC

Commit: d883866 · View workflow run →

@michael-valdron

Copy link
Copy Markdown
Member

/fs-fix Resolve the following comments:

  • Any reference to DXX design codes (e.g. D11) in the source comments should be followed by a link to the openspec design.md section that is being referenced.
  • feat(#4813): add MCP registry server mapping common library plugin - mcp-registry-server-mapping #4823 (comment) - remove any "Step X:" from comments (e.g. "// Step 7: Sort annotation keys for determinism" should become "// Sort annotation keys for determinism"), this is good product code practice
  • After addressing the above re-generate report.api.md to check for changes, if there are changes include in commit

@michael-valdron the fs-fix prompt needs to be on a single line

@gabemontero I was beginning to notice this as I was iterating over the fixes, espially when I broke up the one that timed out, thanks for clarify!

I'll make sure my upcoming fs-fix prompts will keep it in the same line (single phrase/sentence/paragraph). I'm also trying @johnmcollier's suggestion to just do "address review comments" over previous fs-review feedback, seems effective most of the time but sometimes still requires me to specify the feedback (human reviews mostly).

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

return undefined;
}

const originalUrl = repository.url;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] logic-error

computeRepositoryUrl does not trim whitespace from repository.url before using it, unlike every other URL emit path in the codebase (remote.url.trim() in mapRemotes, doc.websiteUrl.trim() in buildLinks). If repository.url has surrounding whitespace, it would pass isAllowedUrl() (which trims internally) but produce untrimmed URLs in combinedUrl, originalUrl, the Source Code link, backstage.io/source-location, and the repository.url annotation. The D11 spec states 'Trim leading/trailing whitespace' as step 1.

Suggested fix: Add .trim() to the assignment of originalUrl in computeRepositoryUrl: const originalUrl = repository.url.trim();

*/
export function computeRepositoryUrl(
repository: McpServerRepository,
): RepositoryUrlResult | undefined {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] path-traversal

normalizeSubfolder strips leading/trailing slashes and whitespace but does not reject '..' path traversal segments. A subfolder value containing '..' segments is concatenated into the combined URL for all SCM types, written into metadata.links[].url and backstage.io/source-location. The traversal is limited to the same host but could redirect the Source Code link to an unintended repository path. types.ts states 'Must be a clean relative path' but this invariant is not enforced.

Suggested fix: Add validation to reject or strip '..' path segments (e.g., if (segments.some(s => s === '..')) return undefined;)


return base;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] edge-case

normalizeBase operates on the raw URL string rather than parsed URL components. The .git suffix stripping and trailing-slash removal would not work correctly if the repository URL contained query parameters or fragment identifiers. While uncommon for repository.url, the string-based approach could produce incorrect combined URLs in such edge cases.

@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:11 AM UTC · Completed 1:30 AM UTC

Commit: d883866 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $5.57

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ai-integrations): implement MCP registry server mapping common library plugin - 1 / 2 (mcp-registry-server-mapping)

2 participants