1import { describe, expect, it } from "@effect/vitest";
2import { mcpToolPresentation } from "./mcpToolPresentation.ts";
3
4describe("mcpToolPresentation", () => {
5 it("uses supplied names and logos while retaining the server identity", () => {
6 expect(
7 mcpToolPresentation({
8 serverName: "firecrawl-local",
9 toolName: "firecrawl_scrape",
10 title: " Scrape\n page ",
11 serverDisplayName: "Firecrawl",
12 iconUrl: "https://example.com/icon.png",
13 iconUrlDark: "https://example.com/dark.png",
14 }),
15 ).toEqual({
16 title: "Scrape page",
17 toolIcon: {
18 _tag: "themed-logo",
19 logoUrl: "https://example.com/icon.png",
20 logoUrlDark: "https://example.com/dark.png",
21 },
22 toolSource: {
23 key: "mcp:firecrawl-local",
24 name: "Firecrawl",
25 kind: "integration",
26 icon: {
27 _tag: "themed-logo",
28 logoUrl: "https://example.com/icon.png",
29 logoUrlDark: "https://example.com/dark.png",
30 },
31 },
32 });
33 });
34
35 it("uses MCP result source metadata for the tool and its integration", () => {
36 const presentation = mcpToolPresentation({
37 serverName: "firecrawl-local",
38 toolName: "firecrawl_scrape",
39 source: {
40 name: "Firecrawl",
41 logoUrl: "https://example.com/firecrawl.png",
42 logoUrlDark: "https://example.com/firecrawl-dark.png",
43 },
44 });
45 expect(presentation.toolSource?.name).toBe("Firecrawl");
46 expect(presentation.toolIcon).toEqual({
47 _tag: "themed-logo",
48 logoUrl: "https://example.com/firecrawl.png",
49 logoUrlDark: "https://example.com/firecrawl-dark.png",
50 });
51 expect(presentation.toolSource?.icon).toEqual(presentation.toolIcon);
52 });
53
54 it("uses readable fallback names without a guessed logo", () => {
55 expect(mcpToolPresentation({ toolName: "mcp__my_server__get_weather" })).toEqual({
56 title: "get weather",
57 toolSource: { key: "mcp:my_server", name: "my server", kind: "integration" },
58 });
59 expect(mcpToolPresentation({ toolName: "Read" })).toEqual({});
60 expect(mcpToolPresentation({ serverName: "t3-code", toolName: "delegate_task" })).toEqual({});
61 });
62
63 it.each([
64 "javascript:alert(1)",
65 "file:///tmp/logo.png",
66 "not a URL",
67 "https://example.com/" + "x".repeat(4096),
68 ])("ignores an invalid logo %s", (iconUrl) => {
69 expect(
70 mcpToolPresentation({
71 serverName: "weather",
72 toolName: "get_weather",
73 iconUrl,
74 title: "x".repeat(161),
75 }),
76 ).toEqual({
77 title: "get weather",
78 toolSource: { key: "mcp:weather", name: "weather", kind: "integration" },
79 });
80 });
81
82 it("rejects malformed and overlong names", () => {
83 expect(mcpToolPresentation({ serverName: {}, toolName: 1, title: [] })).toEqual({});
84 expect(mcpToolPresentation({ serverName: "x".repeat(161), toolName: "get_weather" })).toEqual(
85 {},
86 );
87 expect(mcpToolPresentation({ title: "Tool title" })).toEqual({ title: "Tool title" });
88 });
89
90 it.each([
91 null,
92 "logo",
93 { logoUrl: "file:///tmp/logo.png" },
94 { logoUrlDark: "https://example.com/dark.png" },
95 ])("ignores source metadata without a valid logo: %j", (source) => {
96 expect(mcpToolPresentation({ serverName: "weather", toolName: "get_weather", source })).toEqual(
97 {
98 title: "get weather",
99 toolSource: { key: "mcp:weather", name: "weather", kind: "integration" },
100 },
101 );
102 });
103});