Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ GET /self/v1/api/schemas/dependents/{path}
|----------|------|----------|-------------|
| `/*/from` | String | Yes | The absolute URL of the schema that originates the dependency |
| `/*/to` | String | Yes | The absolute URL of the schema being referenced |
| `/*/at` | String | Yes | The JSON Pointer to the schema location where the dependency originates |

=== "404"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -296,9 +298,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down
6 changes: 3 additions & 3 deletions enterprise/e2e/html/hurl/mcp-2025-11-25-resources.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ jsonpath "$.result.resources[23].uri" == "{{base}}/self/v1/schemas/api/schemas/d
jsonpath "$.result.resources[23].name" == "Sourcemeta One Schema Dependents API Response"
jsonpath "$.result.resources[23].description" == "The response format for the schema dependents API endpoint"
jsonpath "$.result.resources[23].mimeType" == "application/schema+json"
jsonpath "$.result.resources[23].size" == 820
jsonpath "$.result.resources[23].size" == 986
jsonpath "$.result.resources[23].annotations.priority" == 0
jsonpath "$.result.resources[24].uri" == "{{base}}/self/v1/schemas/api/schemas/evaluate/request"
jsonpath "$.result.resources[24].name" == "Sourcemeta One Schema Evaluate API Request"
Expand Down Expand Up @@ -665,7 +665,7 @@ jsonpath "$.result.resources[3].uri" == "{{base}}/self/v1/schemas/mcp/tools/call
jsonpath "$.result.resources[3].name" == "Sourcemeta One Schema Dependencies RPC Output"
jsonpath "$.result.resources[3].description" == "Get all direct and indirect dependencies of a schema in the catalog"
jsonpath "$.result.resources[3].mimeType" == "application/schema+json"
jsonpath "$.result.resources[3].size" == 736
jsonpath "$.result.resources[3].size" == 741
jsonpath "$.result.resources[3].annotations.priority" == 0
jsonpath "$.result.resources[4].uri" == "{{base}}/self/v1/schemas/mcp/tools/call/get-schema-dependents/request"
jsonpath "$.result.resources[4].name" == "Sourcemeta One Schema Dependents RPC Input"
Expand All @@ -677,7 +677,7 @@ jsonpath "$.result.resources[5].uri" == "{{base}}/self/v1/schemas/mcp/tools/call
jsonpath "$.result.resources[5].name" == "Sourcemeta One Schema Dependents RPC Output"
jsonpath "$.result.resources[5].description" == "Get all direct and transitive dependents of a schema in the catalog"
jsonpath "$.result.resources[5].mimeType" == "application/schema+json"
jsonpath "$.result.resources[5].size" == 691
jsonpath "$.result.resources[5].size" == 735
jsonpath "$.result.resources[5].annotations.priority" == 0
jsonpath "$.result.resources[6].uri" == "{{base}}/self/v1/schemas/mcp/tools/call/get-schema-health/request"
jsonpath "$.result.resources[6].name" == "Sourcemeta One Schema Health RPC Input"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -131,9 +133,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down
6 changes: 3 additions & 3 deletions enterprise/e2e/path/hurl/mcp-2025-11-25-resources.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jsonpath "$.result.resources[10].uri" == "{{base}}/v1/catalog/self/v1/schemas/ap
jsonpath "$.result.resources[10].name" == "Sourcemeta One Schema Dependents API Response"
jsonpath "$.result.resources[10].description" == "The response format for the schema dependents API endpoint"
jsonpath "$.result.resources[10].mimeType" == "application/schema+json"
jsonpath "$.result.resources[10].size" == 831
jsonpath "$.result.resources[10].size" == 997
jsonpath "$.result.resources[10].annotations.priority" == 0
jsonpath "$.result.resources[11].uri" == "{{base}}/v1/catalog/self/v1/schemas/api/schemas/evaluate/request"
jsonpath "$.result.resources[11].name" == "Sourcemeta One Schema Evaluate API Request"
Expand Down Expand Up @@ -260,7 +260,7 @@ jsonpath "$.result.resources[40].uri" == "{{base}}/v1/catalog/self/v1/schemas/mc
jsonpath "$.result.resources[40].name" == "Sourcemeta One Schema Dependencies RPC Output"
jsonpath "$.result.resources[40].description" == "Get all direct and indirect dependencies of a schema in the catalog"
jsonpath "$.result.resources[40].mimeType" == "application/schema+json"
jsonpath "$.result.resources[40].size" == 747
jsonpath "$.result.resources[40].size" == 752
jsonpath "$.result.resources[40].annotations.priority" == 0
jsonpath "$.result.resources[41].uri" == "{{base}}/v1/catalog/self/v1/schemas/mcp/tools/call/get-schema-dependents/request"
jsonpath "$.result.resources[41].name" == "Sourcemeta One Schema Dependents RPC Input"
Expand All @@ -272,7 +272,7 @@ jsonpath "$.result.resources[42].uri" == "{{base}}/v1/catalog/self/v1/schemas/mc
jsonpath "$.result.resources[42].name" == "Sourcemeta One Schema Dependents RPC Output"
jsonpath "$.result.resources[42].description" == "Get all direct and transitive dependents of a schema in the catalog"
jsonpath "$.result.resources[42].mimeType" == "application/schema+json"
jsonpath "$.result.resources[42].size" == 702
jsonpath "$.result.resources[42].size" == 746
jsonpath "$.result.resources[42].annotations.priority" == 0
jsonpath "$.result.resources[43].uri" == "{{base}}/v1/catalog/self/v1/schemas/mcp/tools/call/get-schema-health/request"
jsonpath "$.result.resources[43].name" == "Sourcemeta One Schema Health RPC Input"
Expand Down
24 changes: 14 additions & 10 deletions src/index/generators.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <queue> // std::queue
#include <set> // std::set
#include <sstream> // std::ostringstream
#include <tuple> // std::tuple
#include <unordered_map> // std::unordered_map
#include <utility> // std::move, std::pair

Expand Down Expand Up @@ -313,7 +314,8 @@ struct GENERATE_DEPENDENTS {

using DirectMap =
std::unordered_map<sourcemeta::core::JSON::String,
std::unordered_set<sourcemeta::core::JSON::String>>;
std::set<std::pair<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
DirectMap direct;
for (const auto &dependency : action.dependencies) {
const auto contents_option{
Expand All @@ -322,15 +324,16 @@ struct GENERATE_DEPENDENTS {
const auto &contents{contents_option.value()};
assert(contents.is_array());
for (const auto &entry : contents.as_array()) {
direct[entry.at("to").to_string()].emplace(
entry.at("from").to_string());
direct[entry.at("to").to_string()].emplace(entry.at("from").to_string(),
entry.at("at").to_string());
}
}

using TransitiveMap =
std::unordered_map<sourcemeta::core::JSON::String,
std::set<std::pair<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
using TransitiveMap = std::unordered_map<
sourcemeta::core::JSON::String,
std::set<std::tuple<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
TransitiveMap transitive;
for (const auto &[target, _] : direct) {
auto &edges{transitive[target]};
Expand All @@ -346,8 +349,8 @@ struct GENERATE_DEPENDENTS {
continue;
}

for (const auto &dependent : match->second) {
edges.emplace(dependent, current);
for (const auto &[dependent, at] : match->second) {
edges.emplace(dependent, current, at);
if (visited.emplace(dependent).second) {
queue.emplace(dependent);
}
Expand All @@ -358,10 +361,11 @@ struct GENERATE_DEPENDENTS {
auto result{sourcemeta::core::JSON::make_array()};
const auto match{transitive.find(std::string{action.data})};
if (match != transitive.cend()) {
for (const auto &[from, to] : match->second) {
for (const auto &[from, to, at] : match->second) {
auto object{sourcemeta::core::JSON::make_object()};
object.assign("from", sourcemeta::core::JSON{from});
object.assign("to", sourcemeta::core::JSON{to});
object.assign("at", sourcemeta::core::JSON{at});
result.push_back(std::move(object));
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/self/v1/schemas/api/schemas/dependents/response.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@
[
{
"from": "https://example.com/schemas/user.json",
"to": "https://example.com/schemas/address.json"
"to": "https://example.com/schemas/address.json",
"at": "/properties/address/$ref"
}
]
],
"type": "array",
"items": {
"type": "object",
"required": [ "from", "to" ],
"required": [ "from", "to", "at" ],
"properties": {
"at": {
"x-format-assertion": true,
"type": "string",
"format": "json-pointer"
},
"from": {
"x-format-assertion": true,
"type": "string",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{
"from": "https://example.com/schemas/user.json",
"to": "https://example.com/schemas/address.json",
"at": "/properties/address"
"at": "/properties/address/$ref"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The example value in this file's update is inconsistent with the example in the referenced API schema (api/schemas/dependencies/response.json), which still uses /properties/address. Both describe the same data format for the dependencies endpoint — the MCP tool schema references the API schema for the results property definition — so they should agree on example values.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/self/v1/schemas/mcp/tools/call/get-schema-dependencies/response.json, line 11:

<comment>The example value in this file's update is inconsistent with the example in the referenced API schema (`api/schemas/dependencies/response.json`), which still uses `/properties/address`. Both describe the same data format for the dependencies endpoint — the MCP tool schema references the API schema for the `results` property definition — so they should agree on example values.</comment>

<file context>
@@ -8,7 +8,7 @@
           "from": "https://example.com/schemas/user.json",
           "to": "https://example.com/schemas/address.json",
-          "at": "/properties/address"
+          "at": "/properties/address/$ref"
         }
       ]
</file context>

}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"results": [
{
"from": "https://example.com/schemas/user.json",
"to": "https://example.com/schemas/address.json"
"to": "https://example.com/schemas/address.json",
"at": "/properties/address/$ref"
}
]
}
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/headless/hurl/schemas-dependents.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ header "Last-Modified" exists
jsonpath "$" count == 3
jsonpath "$[0].from" == "{{base}}/test/schemas/bundling-double"
jsonpath "$[0].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[0].at" == "/properties/foo/$ref"
jsonpath "$[1].from" == "{{base}}/test/schemas/with-rebase"
jsonpath "$[1].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[1].at" == "/$ref"
jsonpath "$[2].from" == "{{base}}/test/schemas/with-rebase-same-host"
jsonpath "$[2].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[2].at" == "/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -46,12 +49,16 @@ header "Last-Modified" exists
jsonpath "$" count == 4
jsonpath "$[0].from" == "{{base}}/test/schemas/bundling-double"
jsonpath "$[0].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[0].at" == "/properties/foo/$ref"
jsonpath "$[1].from" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[1].to" == "{{base}}/test/schemas/no-id"
jsonpath "$[1].at" == "/properties/foo/$ref"
jsonpath "$[2].from" == "{{base}}/test/schemas/with-rebase"
jsonpath "$[2].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[2].at" == "/$ref"
jsonpath "$[3].from" == "{{base}}/test/schemas/with-rebase-same-host"
jsonpath "$[3].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[3].at" == "/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down
10 changes: 5 additions & 5 deletions test/e2e/html/hurl/list.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ header "Last-Modified" exists
jsonpath "$.path" == "/"
jsonpath "$.url" == "{{base}}"
jsonpath "$.breadcrumb" count == 0
jsonpath "$.schemas" == 102
jsonpath "$.schemas" == 106
jsonpath "$.entries" count >= 2
jsonpath "$.entries[0].name" == "self"
jsonpath "$.entries[0].title" == "Self"
Expand All @@ -28,7 +28,7 @@ jsonpath "$.entries[1].title" == "Test"
jsonpath "$.entries[1].description" == "A directory full of testing schemas"
jsonpath "$.entries[1].type" == "directory"
jsonpath "$.entries[1].health" == 13
jsonpath "$.entries[1].schemas" == 46
jsonpath "$.entries[1].schemas" == 50
jsonpath "$.entries[1].path" == "/test/"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
Expand Down Expand Up @@ -62,7 +62,7 @@ jsonpath "$.breadcrumb[0].name" == "test"
jsonpath "$.breadcrumb[0].path" == "/test/"
jsonpath "$.description" == "A directory full of testing schemas"
jsonpath "$.title" == "Test"
jsonpath "$.schemas" == 46
jsonpath "$.schemas" == 50
jsonpath "$.entries" count == 13
jsonpath "$.entries[0].name" == "v2.0"
jsonpath "$.entries[0].type" == "directory"
Expand Down Expand Up @@ -123,8 +123,8 @@ jsonpath "$.entries[10].schemas" == 1
jsonpath "$.entries[10].path" == "/test/same/"
jsonpath "$.entries[11].name" == "schemas"
jsonpath "$.entries[11].type" == "directory"
jsonpath "$.entries[11].health" == 7
jsonpath "$.entries[11].schemas" == 25
jsonpath "$.entries[11].health" == 6
jsonpath "$.entries[11].schemas" == 29
jsonpath "$.entries[11].path" == "/test/schemas/"
jsonpath "$.entries[12].name" == "unsafe-alert"
jsonpath "$.entries[12].type" == "directory"
Expand Down
58 changes: 58 additions & 0 deletions test/e2e/html/hurl/schemas-dependencies.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,64 @@ header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

GET {{base}}/self/v1/api/schemas/dependencies/test/schemas/using-meta-draft7
HTTP 200
Content-Type: application/json
Access-Control-Allow-Origin: *
Link: </self/v1/schemas/api/schemas/dependencies/response>; rel="describedby"
[Captures]
last_response: body
schema_path: header "Link" regex "<([^>]+)>"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
header "ETag" exists
header "Last-Modified" exists
jsonpath "$" count == 1
jsonpath "$[0].from" == "{{base}}/test/schemas/using-meta-draft7"
jsonpath "$[0].to" == "{{base}}/test/schemas/custom-meta-draft7"
jsonpath "$[0].at" == "/$schema"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
{{last_response}}
```
HTTP 200
Link: </self/v1/schemas/api/schemas/evaluate/response>; rel="describedby"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

GET {{base}}/self/v1/api/schemas/dependencies/test/schemas/using-meta-2020
HTTP 200
Content-Type: application/json
Access-Control-Allow-Origin: *
Link: </self/v1/schemas/api/schemas/dependencies/response>; rel="describedby"
[Captures]
last_response: body
schema_path: header "Link" regex "<([^>]+)>"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
header "ETag" exists
header "Last-Modified" exists
jsonpath "$" count == 1
jsonpath "$[0].from" == "{{base}}/test/schemas/using-meta-2020"
jsonpath "$[0].to" == "{{base}}/test/schemas/custom-meta-2020"
jsonpath "$[0].at" == "/$schema"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
{{last_response}}
```
HTTP 200
Link: </self/v1/schemas/api/schemas/evaluate/response>; rel="describedby"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

HEAD {{base}}/self/v1/api/schemas/dependencies/test/v2.0/schema
HTTP 200
Content-Type: application/json
Expand Down
Loading
Loading