Skip to content
This repository was archived by the owner on Oct 27, 2026. It is now read-only.
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
17 changes: 12 additions & 5 deletions components/pages/integrations/filter-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,25 @@ const TOOLKIT_CATEGORIES: readonly ToolkitCategory[] = CATEGORIES.map(
(category) => category.id
);

/**
* The designations the index presents. `community` is still a design-system
* ToolkitType, but no toolkit is assigned it.
*/
export type ListedToolkitType = Exclude<ToolkitType, "community">;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should probably remove community from the design system as well, so we don't need to do this here. We can merge that PR first and update this one if that is ok with you, @samkujovich

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. We're doing it your way. ArcadeAI/monorepo#5987 removes community from design-system (8.0.0) and from the monorepo copy of the docs site; no toolkit uses it since ArcadeAI/monorepo#5732. Once 8.0.0 is on npm, I'll cut this PR down to bumping design-system and deleting the community entries, without the ListedToolkitType plumbing.

~ 🤖 sam-i-am, Sam’s Agent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I approved #5987. You can refactor this one when that one is merged!


// ToolkitType has no runtime export from the design system, so this list is
// hand-maintained. `satisfies` turns a missing or extra entry into a
// compile error the next time the union changes, instead of a silent drop.
const TOOLKIT_TYPE_MEMBERSHIP = {
arcade: true,
arcade_starter: true,
verified: true,
community: true,
auth: true,
} satisfies Record<ToolkitType, true>;
} satisfies Record<ListedToolkitType, true>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We can avoid all these changes by renaming it in the DS.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same fix as the thread above: once ArcadeAI/monorepo#5987 publishes 8.0.0, these changes collapse to plain deletions.

~ 🤖 sam-i-am, Sam’s Agent


const TOOLKIT_TYPES = Object.keys(TOOLKIT_TYPE_MEMBERSHIP) as ToolkitType[];
const TOOLKIT_TYPES = Object.keys(
TOOLKIT_TYPE_MEMBERSHIP
) as ListedToolkitType[];

export const PARAM_CATEGORY = "category";
export const PARAM_TYPE = "type";
Expand All @@ -38,7 +45,7 @@ export function isLabel(value: string): value is Label {

export type FilterState = {
selectedCategory: ToolkitCategory;
selectedType: ToolkitType | "all";
selectedType: ListedToolkitType | "all";
filterByPro: boolean;
filterByByoc: boolean;
searchQuery: string;
Expand All @@ -52,7 +59,7 @@ export const DEFAULT_FILTER_STATE: FilterState = {
searchQuery: "",
};

export function isToolkitType(value: string): value is ToolkitType {
export function isToolkitType(value: string): value is ListedToolkitType {
return (TOOLKIT_TYPES as readonly string[]).includes(value);
}

Expand Down
33 changes: 15 additions & 18 deletions components/pages/integrations/filters-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import {
DropdownMenuTrigger,
Input,
Separator,
type ToolkitType,
} from "@arcadeai/design-system";
import { Check, Filter, FolderOpen, Layers, Search, X } from "lucide-react";
import type React from "react";
import { TYPE_CONFIG } from "./type-config";
import { LISTED_TYPE_CONFIG, TYPE_CONFIG } from "./type-config";
import { useFilters } from "./use-filters";

type FiltersBarProps = {
Expand Down Expand Up @@ -138,21 +137,19 @@ export function FiltersBar({ resultsCount }: FiltersBarProps) {
)}
All Types
</DropdownMenuItem>
{Object.entries(TYPE_CONFIG).map(
([key, { label, icon: Icon }]) => (
<DropdownMenuItem
key={key}
onClick={() => setSelectedType(key as ToolkitType)}
>
{selectedType === key ? (
<Check className="mr-2 h-3.5 w-3.5" />
) : (
<Icon className="mr-2 h-3.5 w-3.5" />
)}
{label}
</DropdownMenuItem>
)
)}
{LISTED_TYPE_CONFIG.map(([key, { label, icon: Icon }]) => (
<DropdownMenuItem
key={key}
onClick={() => setSelectedType(key)}
>
{selectedType === key ? (
<Check className="mr-2 h-3.5 w-3.5" />
) : (
<Icon className="mr-2 h-3.5 w-3.5" />
)}
{label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>

Expand Down Expand Up @@ -254,7 +251,7 @@ export function FiltersBar({ resultsCount }: FiltersBarProps) {
)}
{selectedType !== "all" && (
<Badge className="gap-1" variant="secondary">
{TYPE_CONFIG[selectedType as ToolkitType].label}
{TYPE_CONFIG[selectedType].label}
<button
aria-label="Remove type filter"
className="hover:opacity-70"
Expand Down
39 changes: 17 additions & 22 deletions components/pages/integrations/toolkits-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "@/lib/integration-index";
import { FiltersBar } from "./filters-bar";
import { ToolCard } from "./tool-card";
import { TYPE_CONFIG, TYPE_DESCRIPTIONS } from "./type-config";
import { LISTED_TYPE_CONFIG, TYPE_DESCRIPTIONS } from "./type-config";
import { useFilters } from "./use-filters";
import { useToolkitFilters } from "./use-toolkit-filters";

Expand Down Expand Up @@ -64,30 +64,25 @@ export default function ToolkitsClient({ toolkits }: ToolkitsClientProps) {
MCP Servers
</h1>
<p className="text-gray-600 text-sm leading-relaxed sm:text-base dark:text-gray-400">
There are 5 designations for Arcade MCP Servers:
There are {LISTED_TYPE_CONFIG.length} designations for Arcade MCP
Servers:
</p>
<div className="grid grid-cols-1 gap-3 sm:gap-4 md:grid-cols-2 lg:grid-cols-3">
{Object.entries(TYPE_CONFIG).map(
([key, { label, icon: Icon, color }]) => (
<div className="flex items-start space-x-3" key={key}>
<div className="mt-1">
<Icon className={cn("h-5 w-5", color)} />
</div>
<div>
<h2 className="font-semibold text-gray-800 text-sm sm:text-base dark:text-gray-200">
{label}
</h2>
<p className="mt-1 text-gray-600 text-xs leading-relaxed sm:text-sm dark:text-gray-400">
{
TYPE_DESCRIPTIONS[
key as keyof typeof TYPE_DESCRIPTIONS
]
}
</p>
</div>
{LISTED_TYPE_CONFIG.map(([key, { label, icon: Icon, color }]) => (
<div className="flex items-start space-x-3" key={key}>
<div className="mt-1">
<Icon className={cn("h-5 w-5", color)} />
</div>
)
)}
<div>
<h2 className="font-semibold text-gray-800 text-sm sm:text-base dark:text-gray-200">
{label}
</h2>
<p className="mt-1 text-gray-600 text-xs leading-relaxed sm:text-sm dark:text-gray-400">
{TYPE_DESCRIPTIONS[key]}
</p>
</div>
</div>
))}
</div>

{/* Don't see what you need? Two paths to fix that. */}
Expand Down
14 changes: 9 additions & 5 deletions components/pages/integrations/type-config.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ToolkitType } from "@arcadeai/design-system";
import { BadgeCheck, CheckCircle, Key, Terminal, Users } from "lucide-react";
import type React from "react";
import { isToolkitType, type ListedToolkitType } from "./filter-params";

export const TYPE_CONFIG: Record<
ToolkitType,
Expand Down Expand Up @@ -33,6 +34,12 @@ export const TYPE_CONFIG: Record<
},
};

/** The designations the index lists. No toolkit is assigned `community`. */
export const LISTED_TYPE_CONFIG = Object.entries(TYPE_CONFIG).filter(
(entry): entry is [ListedToolkitType, (typeof TYPE_CONFIG)[ToolkitType]] =>
isToolkitType(entry[0])
);

export const TOOL_CARD_TYPE_CONFIG: Record<
ToolkitType,
{ className: string; label: string; icon: React.ElementType; color: string }
Expand Down Expand Up @@ -74,7 +81,7 @@ export const TOOL_CARD_TYPE_CONFIG: Record<
},
};

export const TYPE_DESCRIPTIONS: Record<ToolkitType, React.ReactNode> = {
export const TYPE_DESCRIPTIONS: Record<ListedToolkitType, React.ReactNode> = {
arcade: (
<>
Official MCP Servers hand-crafted by Arcade that are ready for use and
Expand All @@ -101,9 +108,6 @@ export const TYPE_DESCRIPTIONS: Record<ToolkitType, React.ReactNode> = {
.
</>
),
verified:
"Community-created MCP Servers, thoroughly tested and verified by Arcade.",
community:
"Created and maintained by the Arcade community, offering a wide range of MCP Servers.",
verified: "MCP Servers built outside Arcade, tested and verified by Arcade.",
auth: "Auth integrations allow you to develop custom tools that connect your agent APIs and services.",
};
5 changes: 3 additions & 2 deletions components/pages/integrations/use-filters.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"use client";

import type { ToolkitCategory, ToolkitType } from "@arcadeai/design-system";
import type { ToolkitCategory } from "@arcadeai/design-system";
import { usePathname, useSearchParams } from "next/navigation";
import { useCallback, useMemo } from "react";
import {
DEFAULT_FILTER_STATE,
type FilterState,
type ListedToolkitType,
parseFiltersFromParams,
serializeFiltersToParams,
} from "./filter-params";
Expand Down Expand Up @@ -61,7 +62,7 @@ export function useFilters() {
);

const setSelectedType = useCallback(
(type: ToolkitType | "all") => {
(type: ListedToolkitType | "all") => {
writeState({ ...state, selectedType: type });
},
[state, writeState]
Expand Down
4 changes: 2 additions & 2 deletions tests/filter-params.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ describe("isToolkitType", () => {
expect(isToolkitType("arcade")).toBe(true);
expect(isToolkitType("arcade_starter")).toBe(true);
expect(isToolkitType("verified")).toBe(true);
expect(isToolkitType("community")).toBe(true);
expect(isToolkitType("auth")).toBe(true);
});

test("rejects unknown values", () => {
expect(isToolkitType("bogus")).toBe(false);
expect(isToolkitType("community")).toBe(false);
expect(isToolkitType("ARCADE")).toBe(false);
expect(isToolkitType("")).toBe(false);
});
Expand Down Expand Up @@ -269,7 +269,7 @@ describe("round-trip", () => {
test("serialize then parse produces equivalent filters", () => {
const state: FilterState = {
selectedCategory: "social",
selectedType: "community",
selectedType: "auth",
filterByPro: true,
filterByByoc: false,
searchQuery: "twitter",
Expand Down
Loading