Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion webmcp/declarative/getTools-declarative-schema.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
required: ["query"]
};

const tool = await waitForFormToolSchemaToMatch(expected_schema_obj);
const tool = await waitForFormToolSchemaToMatch(JSON.stringify(expected_schema_obj));

assert_equals(tool.name, "search_tool", "Tool name matches");
assert_equals(tool.description, "Search the web", "Tool description matches");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@
const form = document.getElementById('f1');

// Wait for the baseline form schema.
await waitForFormToolSchemaToMatch({"type":"object","properties":{"input_name":{"type":"string"}},"required":[]});
await waitForFormToolSchemaToMatch(`{"type":"object","properties":{"input_name":{"type":"string"}},"required":[]}`);

// Test adding an input
const i = document.createElement('input');
i.type = 'text';
i.name = 'new_input';
i.id = 'new_input';
form.appendChild(i);
await waitForFormToolSchemaToMatch({"type":"object","properties":{"input_name":{"type":"string"},"new_input":{"type":"string"}},"required":[]});
await waitForFormToolSchemaToMatch(`{"type":"object","properties":{"input_name":{"type":"string"},"new_input":{"type":"string"}},"required":[]}`);

// Test removing an input
const newInput = document.getElementById('new_input');
form.removeChild(newInput);
await waitForFormToolSchemaToMatch({"type":"object","properties":{"input_name":{"type":"string"}},"required":[]});
await waitForFormToolSchemaToMatch(`{"type":"object","properties":{"input_name":{"type":"string"}},"required":[]}`);
}, "Test that toolchange event fires when controls are added or removed");
</script>
</body>
4 changes: 2 additions & 2 deletions webmcp/imperative/exposedTo-cross-origin-child.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
assert_true(toolsAreEqual(tool, {
name: 'parent_tool_exposed',
description: 'Parent tool exposed to child',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
inputSchema: JSON.stringify({ type: 'object', properties: { query: { type: 'string' } } }),
origin: self.origin
}), 'Tool details should match');

Expand Down Expand Up @@ -104,7 +104,7 @@
assert_true(toolsAreEqual(tool, {
name: 'iframe_tool_exposed',
description: 'Iframe tool exposed to parent',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
inputSchema: JSON.stringify({ type: 'object', properties: { query: { type: 'string' } } }),
origin: host_info.HTTPS_REMOTE_ORIGIN
}), 'Tool details should match');

Expand Down
4 changes: 2 additions & 2 deletions webmcp/imperative/exposedTo-defaults-same-origin.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
assert_true(toolsAreEqual(tool, {
name: 'parent_tool_default',
description: 'Parent tool with default exposure',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
inputSchema: JSON.stringify({ type: 'object', properties: { query: { type: 'string' } } }),
annotations: { readOnlyHint: true, untrustedContentHint: false },
origin: self.origin
}), 'Tool details should match');
Expand Down Expand Up @@ -90,7 +90,7 @@
assert_true(toolsAreEqual(tool, {
name: 'parent_tool_empty',
description: 'Parent tool with empty exposedTo',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
inputSchema: JSON.stringify({ type: 'object', properties: { query: { type: 'string' } } }),
origin: self.origin
}), 'Tool details should match');

Expand Down
2 changes: 1 addition & 1 deletion webmcp/imperative/exposedTo-multiple-children.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
assert_true(toolsAreEqual(tool, {
name: 'tool_b_to_c',
description: 'Tool B exposed to C',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } },
inputSchema: JSON.stringify({ type: 'object', properties: { query: { type: 'string' } } }),
origin: origin_b
}), 'Tool details should match');

Expand Down
24 changes: 13 additions & 11 deletions webmcp/imperative/getTools-imperative-schema.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,25 @@
assert_equals(registeredTool.description, "Search the web", "Tool description matches registered tool");

assert_true(!!registeredTool.inputSchema, "inputSchema should be non-empty");
assert_equals(registeredTool.inputSchema.type, "object", "Schema should be an object");
const schema = JSON.parse(registeredTool.inputSchema);

assert_equals(schema.type, "object", "Schema should be an object");

// 'query' property validation (required string)
assert_true("query" in registeredTool.inputSchema.properties, "Schema should contain 'query' property");
assert_equals(registeredTool.inputSchema.properties.query.type, "string", "Query property type should be string");
assert_equals(registeredTool.inputSchema.properties.query.description, "The search query", "Query property description is correct");
assert_array_equals(registeredTool.inputSchema.required, ["query"], "Query should be a required property");
assert_true("query" in schema.properties, "Schema should contain 'query' property");
assert_equals(schema.properties.query.type, "string", "Query property type should be string");
assert_equals(schema.properties.query.description, "The search query", "Query property description is correct");
assert_array_equals(schema.required, ["query"], "Query should be a required property");

// 'limit' property validation (optional number)
assert_true("limit" in registeredTool.inputSchema.properties, "Schema should contain 'limit' property");
assert_equals(registeredTool.inputSchema.properties.limit.type, "number", "Limit property type should be number");
assert_equals(registeredTool.inputSchema.properties.limit.description, "Max results count", "Limit property description is correct");
assert_true("limit" in schema.properties, "Schema should contain 'limit' property");
assert_equals(schema.properties.limit.type, "number", "Limit property type should be number");
assert_equals(schema.properties.limit.description, "Max results count", "Limit property description is correct");

// 'safe_search' property validation (optional boolean)
assert_true("safe_search" in registeredTool.inputSchema.properties, "Schema should contain 'safe_search' property");
assert_equals(registeredTool.inputSchema.properties.safe_search.type, "boolean", "safe_search property type should be boolean");
assert_equals(registeredTool.inputSchema.properties.safe_search.description, "Enable safe search filtering", "safe_search property description is correct");
assert_true("safe_search" in schema.properties, "Schema should contain 'safe_search' property");
assert_equals(schema.properties.safe_search.type, "boolean", "safe_search property type should be boolean");
assert_equals(schema.properties.safe_search.description, "Enable safe search filtering", "safe_search property description is correct");
}, "Test that getTools() returns the correct inputSchema for an imperative tool");
</script>
</body>
7 changes: 2 additions & 5 deletions webmcp/imperative/resources/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ function toolsAreEqual(actual, expected) {
if (actual.description !== expected.description) {
return `descriptions are unequal: ${actual.description} !== ${expected.description}`;
}
if (JSON.stringify(actual.inputSchema) !==
JSON.stringify(expected.inputSchema)) {
return `inputSchemas are unequal: ${
JSON.stringify(
actual.inputSchema)} !== ${JSON.stringify(expected.inputSchema)}`;
if (actual.inputSchema !== expected.inputSchema) {
return `inputSchemas are unequal: ${actual.inputSchemas} !== ${expected.inputSchemas}`;
}
if (actual.origin !== expected.origin) {
return `origins are unequal: ${actual.origin} !== ${expected.origin}`;
Expand Down
12 changes: 3 additions & 9 deletions webmcp/resources/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,17 @@ async function waitForTool(name) {
});
}

// Wait for the active WebMCP tool's input schema to match the expected schema.
// Wait for the active WebMCP tool's input schema to match the expected schema string.
async function waitForFormToolSchemaToMatch(expected_schema) {
const isMatch = (tool) => {
if (!tool)
return false;
return JSON.stringify(tool.inputSchema) === JSON.stringify(expected_schema);
};

const [tool] = await document.modelContext.getTools();
if (isMatch(tool)) {
if (tool && tool.inputSchema === expected_schema) {
return tool;
}
return new Promise(resolve => {
const ac = new AbortController();
document.modelContext.addEventListener('toolchange', async e => {
const [tool] = await document.modelContext.getTools();
if (isMatch(tool)) {
if (tool && tool.inputSchema === expected_schema) {
resolve(tool);
ac.abort();
}
Expand Down
Loading