refactor(api): remove MCP marketplace cache integration
Removed dependencies on MCPCacheRepository and PulseMCPService from MCP routes to simplify installation and listing logic, avoiding reliance on potentially stale cached data and streamlining the codebase. Updated available-for-chat filter to include MCPs without explicit status.
This commit is contained in:
1 parent
4739a13458
commit
f96d4ed696
34 files changed
+260
-3775
No files matched your search
@@ -1,136 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { ChevronDown, ChevronRight } from "lucide-react";
|
||||
|
||||
interface MCPCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
interface MCPCategoryFilterProps {
|
||||
primaryCategories: MCPCategory[];
|
||||
otherCategories: MCPCategory[];
|
||||
selectedCategory: string;
|
||||
onSelectCategory: (categoryId: string) => void;
|
||||
}
|
||||
|
||||
export function MCPCategoryFilter({
|
||||
primaryCategories,
|
||||
otherCategories,
|
||||
selectedCategory,
|
||||
onSelectCategory,
|
||||
}: MCPCategoryFilterProps) {
|
||||
const [showOthers, setShowOthers] = useState(false);
|
||||
|
||||
const getCategoryIcon = (categoryName: string) => {
|
||||
const iconMap: Record<string, string> = {
|
||||
MAP: "🗺️",
|
||||
BROWSER: "🌐",
|
||||
OFFICE: "📄",
|
||||
CODE: "💻",
|
||||
DATABASE: "🗄️",
|
||||
SEARCH: "🔍",
|
||||
PAYMENT: "💳",
|
||||
CHART: "📊",
|
||||
FINANCE: "💰",
|
||||
OTHER: "📦",
|
||||
};
|
||||
return iconMap[categoryName.toUpperCase()] || "📦";
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold text-sm text-[var(--foreground)] mb-3">
|
||||
Categories
|
||||
</h3>
|
||||
|
||||
{/* All Categories */}
|
||||
<button
|
||||
onClick={() => onSelectCategory("all")}
|
||||
className={`w-full flex items-center justify-between px-3 py-2 rounded-md text-sm transition-colors ${
|
||||
selectedCategory === "all"
|
||||
? "mcp-category-active"
|
||||
: "hover:bg-[var(--surface)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
|
||||
}`}
|
||||
>
|
||||
<span className="flex items-center gap-2">📦 All Categories</span>
|
||||
<span className="text-xs bg-[var(--background)] px-2 py-1 rounded-full">
|
||||
{primaryCategories.reduce((sum, cat) => sum + cat.count, 0) +
|
||||
otherCategories.reduce((sum, cat) => sum + cat.count, 0)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Primary Categories */}
|
||||
<div className="space-y-1">
|
||||
<h4 className="text-xs font-medium text-[var(--muted-foreground)] uppercase tracking-wide">
|
||||
Principais
|
||||
</h4>
|
||||
{primaryCategories.map((category) => (
|
||||
<button
|
||||
key={category.id}
|
||||
onClick={() => onSelectCategory(category.id)}
|
||||
className={`w-full flex items-center justify-between px-3 py-2 rounded-md text-sm transition-colors ${
|
||||
selectedCategory === category.id
|
||||
? "mcp-category-active"
|
||||
: "hover:bg-[var(--surface)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
|
||||
}`}
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
{getCategoryIcon(category.name)} {category.name}
|
||||
</span>
|
||||
<span className="text-xs bg-[var(--background)] px-2 py-1 rounded-full">
|
||||
{category.count}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Other Categories */}
|
||||
{otherCategories.length > 0 && (
|
||||
<div className="space-y-1">
|
||||
<button
|
||||
onClick={() => setShowOthers(!showOthers)}
|
||||
className="w-full flex items-center justify-between px-3 py-2 rounded-md text-sm transition-colors hover:bg-[var(--surface)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
{showOthers ? (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
)}
|
||||
<span className="text-xs font-medium uppercase tracking-wide">
|
||||
Outras ({otherCategories.length})
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{showOthers && (
|
||||
<div className="ml-4 space-y-1">
|
||||
{otherCategories.map((category) => (
|
||||
<button
|
||||
key={category.id}
|
||||
onClick={() => onSelectCategory(category.id)}
|
||||
className={`w-full flex items-center justify-between px-3 py-2 rounded-md text-sm transition-colors ${
|
||||
selectedCategory === category.id
|
||||
? "mcp-category-active"
|
||||
: "hover:bg-[var(--surface)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
|
||||
}`}
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
📦 {category.name}
|
||||
</span>
|
||||
<span className="text-xs bg-[var(--background)] px-2 py-1 rounded-full">
|
||||
{category.count}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -154,9 +154,9 @@ export function MCPManualInstallModal({
|
||||
How to use
|
||||
</h3>
|
||||
<p className="text-sm text-blue-700 dark:text-blue-300 mb-3">
|
||||
Paste your MCP server configuration in Claude Desktop format
|
||||
(claude_desktop_config.json). You can install custom MCPs or MCPs
|
||||
not available in the marketplace.
|
||||
Cole a configuração do servidor MCP no formato do Claude Desktop
|
||||
(claude_desktop_config.json). Apenas instalação manual é suportada
|
||||
neste projeto.
|
||||
</p>
|
||||
<button
|
||||
onClick={handlePasteExample}
|
||||
@@ -273,7 +273,7 @@ export function MCPManualInstallModal({
|
||||
{error && (
|
||||
<div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertCircle className="h-5 w-5 text-red-500 flex-shrink-0 mt-0.5" />
|
||||
<AlertCircle className="h-5 w-5 text-red-500 shrink-0 mt-0.5" />
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-red-900 dark:text-red-100">
|
||||
Installation Error
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,74 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Star } from "lucide-react";
|
||||
|
||||
interface MCPRatingStarsProps {
|
||||
rating: number;
|
||||
size?: "sm" | "md" | "lg";
|
||||
showNumber?: boolean;
|
||||
}
|
||||
|
||||
export function MCPRatingStars({
|
||||
rating,
|
||||
size = "sm",
|
||||
showNumber = true,
|
||||
}: MCPRatingStarsProps) {
|
||||
const sizeClasses = {
|
||||
sm: "h-3 w-3",
|
||||
md: "h-4 w-4",
|
||||
lg: "h-5 w-5",
|
||||
};
|
||||
|
||||
const stars = [];
|
||||
const fullStars = Math.floor(rating);
|
||||
const hasHalfStar = rating % 1 >= 0.5;
|
||||
|
||||
// Renderizar estrelas cheias
|
||||
for (let i = 0; i < fullStars; i++) {
|
||||
stars.push(
|
||||
<Star
|
||||
key={i}
|
||||
className={`${sizeClasses[size]} fill-yellow-400 text-yellow-400`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Renderizar meia estrela se necessário
|
||||
if (hasHalfStar) {
|
||||
stars.push(
|
||||
<div key="half" className="relative">
|
||||
<Star className={`${sizeClasses[size]} text-gray-300`} />
|
||||
<div
|
||||
className="absolute inset-0 overflow-hidden"
|
||||
style={{ width: "50%" }}
|
||||
>
|
||||
<Star
|
||||
className={`${sizeClasses[size]} fill-yellow-400 text-yellow-400`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Renderizar estrelas vazias
|
||||
const emptyStars = 5 - Math.ceil(rating);
|
||||
for (let i = 0; i < emptyStars; i++) {
|
||||
stars.push(
|
||||
<Star
|
||||
key={`empty-${i}`}
|
||||
className={`${sizeClasses[size]} text-gray-300`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex">{stars}</div>
|
||||
{showNumber && (
|
||||
<span className="text-sm text-[var(--muted-foreground)] ml-1">
|
||||
{rating.toFixed(1)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { Search } from "lucide-react";
|
||||
|
||||
interface MCPSearchBarProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
onSearch: () => void;
|
||||
}
|
||||
|
||||
export function MCPSearchBar({ value, onChange, onSearch }: MCPSearchBarProps) {
|
||||
const handleKeyPress = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
onSearch();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-[var(--muted-foreground)]" />
|
||||
<input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
onKeyPress={handleKeyPress}
|
||||
placeholder="Search MCPs..."
|
||||
className="w-full pl-10 pr-4 py-2 bg-[var(--surface)] border border-[var(--border)] rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--primary)] focus:border-transparent mcp-search-input"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
Reference in new issue
Block a user