use bundleId to dynamically match module-wide tool manifest requests
All checks were successful
Deploy Tools / deploy (push) Successful in 7m42s

This commit is contained in:
jade
2026-08-18 21:01:01 +09:00
parent 762681f1ce
commit e200dbd5b8
2 changed files with 35 additions and 1 deletions

View File

@@ -43,12 +43,17 @@ public class ToolManifestService {
}
public ToolManifestResponse currentManifest() {
return currentManifest(null);
}
public ToolManifestResponse currentManifest(String categoryKey) {
String bundleId = properties.getManifest() == null ? null : properties.getManifest().getBundleId();
if (bundleId == null || bundleId.isBlank()) {
throw new IllegalStateException("mcp.manifest.bundle-id must be configured");
}
List<ToolManifestItem> tools = toolSupplier.get().stream()
.filter(tool -> isMatchCategory(categoryKey, tool.getCategoryKey(), bundleId))
.map(this::toManifestItem)
.sorted(Comparator.comparing(ToolManifestItem::name))
.toList();
@@ -56,6 +61,24 @@ public class ToolManifestService {
return new ToolManifestResponse(bundleId, revision(bundleId, tools), tools);
}
private boolean isMatchCategory(String requestedCategory, String toolCategory, String bundleId) {
if (requestedCategory == null) {
return true;
}
if (requestedCategory.equalsIgnoreCase(toolCategory)) {
return true;
}
// Return all tools in this module if the requested category matches the module's bundle ID
if (bundleId != null &&
(bundleId.equalsIgnoreCase(requestedCategory) ||
bundleId.equalsIgnoreCase("was-" + requestedCategory))) {
return true;
}
return false;
}
private ToolManifestItem toManifestItem(ToolMetadata tool) {
String title = tool.getDisplayName() == null || tool.getDisplayName().isBlank()
? tool.getName() : tool.getDisplayName();

View File

@@ -8,6 +8,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
/** Read-only Tool Service manifest endpoint for MCP background discovery. */
@RestController
@@ -22,7 +23,17 @@ public class ToolManifestController {
@GetMapping(value = "/tool-manifest", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ToolManifestResponse> getManifest(
@RequestHeader(value = HttpHeaders.IF_NONE_MATCH, required = false) String ifNoneMatch) {
ToolManifestResponse manifest = toolManifestService.currentManifest();
return handleManifest(toolManifestService.currentManifest(), ifNoneMatch);
}
@GetMapping(value = "/tool-manifest/{categoryKey}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ToolManifestResponse> getManifestByCategory(
@PathVariable("categoryKey") String categoryKey,
@RequestHeader(value = HttpHeaders.IF_NONE_MATCH, required = false) String ifNoneMatch) {
return handleManifest(toolManifestService.currentManifest(categoryKey), ifNoneMatch);
}
private ResponseEntity<ToolManifestResponse> handleManifest(ToolManifestResponse manifest, String ifNoneMatch) {
String eTag = '"' + manifest.revision() + '"';
if (eTag.equals(ifNoneMatch)) {
return ResponseEntity.status(304).eTag(eTag).build();