Skip to content
Open
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
5 changes: 5 additions & 0 deletions src/filesystem/__tests__/structured-content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe('structuredContent schema compliance', () => {

// structuredContent.content should be a string (matching outputSchema: { content: z.string() })
const structuredContent = result.structuredContent as { content: unknown };
expect(Object.keys(structuredContent)).toEqual(['content']);
expect(typeof structuredContent.content).toBe('string');

// It should NOT be an array
Expand All @@ -85,6 +86,7 @@ describe('structuredContent schema compliance', () => {

// structuredContent.content should be a string (matching outputSchema: { content: z.string() })
const structuredContent = result.structuredContent as { content: unknown };
expect(Object.keys(structuredContent)).toEqual(['content']);
expect(typeof structuredContent.content).toBe('string');

// It should NOT be an array
Expand Down Expand Up @@ -113,6 +115,7 @@ describe('structuredContent schema compliance', () => {

// structuredContent.content should be a string (matching outputSchema: { content: z.string() })
const structuredContent = result.structuredContent as { content: unknown };
expect(Object.keys(structuredContent)).toEqual(['content']);
expect(typeof structuredContent.content).toBe('string');

// It should NOT be an array
Expand All @@ -133,6 +136,7 @@ describe('structuredContent schema compliance', () => {
expect(result.structuredContent).toBeDefined();

const structuredContent = result.structuredContent as { content: unknown };
expect(Object.keys(structuredContent)).toEqual(['content']);
expect(typeof structuredContent.content).toBe('string');
expect(Array.isArray(structuredContent.content)).toBe(false);
});
Expand All @@ -151,6 +155,7 @@ describe('structuredContent schema compliance', () => {
expect(result.structuredContent).toBeDefined();

const structuredContent = result.structuredContent as { content: unknown };
expect(Object.keys(structuredContent)).toEqual(['content']);
expect(typeof structuredContent.content).toBe('string');
expect(Array.isArray(structuredContent.content)).toBe(false);
});
Expand Down
70 changes: 19 additions & 51 deletions src/filesystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ async function readFileAsBase64Stream(filePath: string): Promise<string> {
});
}

function asTextToolResult(text: string): CallToolResult {
return {
content: [{ type: "text", text }],
structuredContent: { content: text },
};
}

// Tool registrations

// read_file (deprecated) and read_text_file
Expand All @@ -204,10 +211,7 @@ const readTextFileHandler = async (args: z.infer<typeof ReadTextFileArgsSchema>)
content = await readFileContent(validPath);
}

return {
content: [{ type: "text" as const, text: content }],
structuredContent: { content }
};
return asTextToolResult(content);
};

server.registerTool(
Expand Down Expand Up @@ -329,10 +333,7 @@ server.registerTool(
}),
);
const text = results.join("\n---\n");
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -355,10 +356,7 @@ server.registerTool(
const validPath = await validatePath(args.path);
await writeFileContent(validPath, args.content);
const text = `Successfully wrote to ${args.path}`;
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -384,10 +382,7 @@ server.registerTool(
async (args: z.infer<typeof EditFileArgsSchema>) => {
const validPath = await validatePath(args.path);
const result = await applyFileEdits(validPath, args.edits, args.dryRun);
return {
content: [{ type: "text" as const, text: result }],
structuredContent: { content: result }
};
return asTextToolResult(result);
}
);

Expand All @@ -410,10 +405,7 @@ server.registerTool(
const validPath = await validatePath(args.path);
await fs.mkdir(validPath, { recursive: true });
const text = `Successfully created directory ${args.path}`;
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -438,10 +430,7 @@ server.registerTool(
const formatted = entries
.map((entry) => `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`)
.join("\n");
return {
content: [{ type: "text" as const, text: formatted }],
structuredContent: { content: formatted }
};
return asTextToolResult(formatted);
}
);

Expand Down Expand Up @@ -516,11 +505,7 @@ server.registerTool(
];

const text = [...formattedEntries, ...summary].join("\n");
const contentBlock = { type: "text" as const, text };
return {
content: [contentBlock],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand Down Expand Up @@ -586,11 +571,7 @@ server.registerTool(

const treeData = await buildTree(rootPath, args.excludePatterns);
const text = JSON.stringify(treeData, null, 2);
const contentBlock = { type: "text" as const, text };
return {
content: [contentBlock],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -615,11 +596,7 @@ server.registerTool(
const validDestPath = await validatePath(args.destination);
await fs.rename(validSourcePath, validDestPath);
const text = `Successfully moved ${args.source} to ${args.destination}`;
const contentBlock = { type: "text" as const, text };
return {
content: [contentBlock],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -645,10 +622,7 @@ server.registerTool(
const validPath = await validatePath(args.path);
const results = await searchFilesWithValidation(validPath, args.pattern, allowedDirectories, { excludePatterns: args.excludePatterns });
const text = results.length > 0 ? results.join("\n") : "No matches found";
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -673,10 +647,7 @@ server.registerTool(
const text = Object.entries(info)
.map(([key, value]) => `${key}: ${value}`)
.join("\n");
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand All @@ -695,10 +666,7 @@ server.registerTool(
},
async () => {
const text = `Allowed directories:\n${allowedDirectories.join('\n')}`;
return {
content: [{ type: "text" as const, text }],
structuredContent: { content: text }
};
return asTextToolResult(text);
}
);

Expand Down
Loading