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
27 changes: 20 additions & 7 deletions client/src/components/ToolsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
generateDefaultValue,
isPropertyRequired,
normalizeUnionType,
resolveRef,
} from "@/utils/schemaUtils";
import {
CompatibilityCallToolResult,
Expand Down Expand Up @@ -90,14 +91,21 @@ const ToolsTab = ({
useEffect(() => {
const params = Object.entries(
selectedTool?.inputSchema.properties ?? [],
).map(([key, value]) => [
key,
generateDefaultValue(
).map(([key, value]) => {
// First resolve any $ref references
const resolvedValue = resolveRef(
value as JsonSchemaType,
key,
selectedTool?.inputSchema as JsonSchemaType,
),
]);
);
return [
key,
generateDefaultValue(
resolvedValue,
key,
selectedTool?.inputSchema as JsonSchemaType,
),
];
});
setParams(Object.fromEntries(params));

// Reset validation errors when switching tools
Expand Down Expand Up @@ -154,7 +162,12 @@ const ToolsTab = ({
</p>
{Object.entries(selectedTool.inputSchema.properties ?? []).map(
([key, value]) => {
const prop = normalizeUnionType(value as JsonSchemaType);
// First resolve any $ref references
const resolvedValue = resolveRef(
value as JsonSchemaType,
selectedTool.inputSchema as JsonSchemaType,
);
const prop = normalizeUnionType(resolvedValue);
const inputSchema =
selectedTool.inputSchema as JsonSchemaType;
const required = isPropertyRequired(key, inputSchema);
Expand Down
1 change: 1 addition & 0 deletions client/src/utils/jsonUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type JsonSchemaType = {
const?: JsonValue;
oneOf?: (JsonSchemaType | JsonSchemaConst)[];
anyOf?: (JsonSchemaType | JsonSchemaConst)[];
$ref?: string;
};

export type JsonObject = { [key: string]: JsonValue };
Expand Down
44 changes: 44 additions & 0 deletions client/src/utils/schemaUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,50 @@ export function isPropertyRequired(
return schema.required?.includes(propertyName) ?? false;
}

/**
* Resolves $ref references in JSON schema
* @param schema The schema that may contain $ref
* @param rootSchema The root schema to resolve references against
* @returns The resolved schema without $ref
*/
export function resolveRef(
schema: JsonSchemaType,
rootSchema: JsonSchemaType,
): JsonSchemaType {
if (!("$ref" in schema) || !schema.$ref) {
return schema;
}

const ref = schema.$ref;

// Handle simple #/properties/name references
if (ref.startsWith("#/")) {
const path = ref.substring(2).split("/");
let current: unknown = rootSchema;

for (const segment of path) {
if (
current &&
typeof current === "object" &&
current !== null &&
segment in current
) {
current = (current as Record<string, unknown>)[segment];
} else {
// If reference cannot be resolved, return the original schema
console.warn(`Could not resolve $ref: ${ref}`);
return schema;
}
}

return current as JsonSchemaType;
}

// For other types of references, return the original schema
console.warn(`Unsupported $ref format: ${ref}`);
return schema;
}

/**
* Normalizes union types (like string|null from FastMCP) to simple types for form rendering
* @param schema The JSON schema to normalize
Expand Down