apteva 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.y11xqt9m.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/db.ts +93 -19
- package/src/integrations/agentdojo.ts +350 -0
- package/src/openapi.ts +195 -0
- package/src/providers.ts +78 -7
- package/src/routes/api/agent-utils.ts +638 -0
- package/src/routes/api/agents.ts +743 -0
- package/src/routes/api/helpers.ts +12 -0
- package/src/routes/api/integrations.ts +608 -0
- package/src/routes/api/mcp.ts +377 -0
- package/src/routes/api/meta-agent.ts +145 -0
- package/src/routes/api/projects.ts +95 -0
- package/src/routes/api/providers.ts +269 -0
- package/src/routes/api/skills.ts +538 -0
- package/src/routes/api/system.ts +215 -0
- package/src/routes/api/telemetry.ts +142 -0
- package/src/routes/api/users.ts +148 -0
- package/src/routes/api.ts +32 -3474
- package/src/server.ts +1 -1
- package/src/web/components/api/ApiDocsPage.tsx +259 -0
- package/src/web/components/mcp/IntegrationsPanel.tsx +15 -8
- package/src/web/components/mcp/McpPage.tsx +458 -174
- package/src/web/components/settings/SettingsPage.tsx +275 -36
- package/src/web/components/skills/SkillsPage.tsx +330 -1
- package/src/web/components/tasks/TasksPage.tsx +187 -58
- package/src/web/context/TelemetryContext.tsx +14 -1
- package/src/web/hooks/useAgents.ts +9 -0
- package/src/web/types.ts +22 -4
- package/dist/App.mbp9atpm.js +0 -227
|
@@ -273,7 +273,7 @@ export function McpPage() {
|
|
|
273
273
|
|
|
274
274
|
{/* Hosted Services Tab */}
|
|
275
275
|
{activeTab === "hosted" && (
|
|
276
|
-
<HostedServices onServerAdded={fetchServers} />
|
|
276
|
+
<HostedServices onServerAdded={fetchServers} projectId={currentProjectId} />
|
|
277
277
|
)}
|
|
278
278
|
|
|
279
279
|
{/* Browse Registry Tab */}
|
|
@@ -932,8 +932,9 @@ interface ComposioConfig {
|
|
|
932
932
|
createdAt?: string;
|
|
933
933
|
}
|
|
934
934
|
|
|
935
|
-
function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
935
|
+
function HostedServices({ onServerAdded, projectId }: { onServerAdded?: () => void; projectId?: string | null }) {
|
|
936
936
|
const { authFetch } = useAuth();
|
|
937
|
+
const [activeProvider, setActiveProvider] = useState<"composio" | "smithery" | "agentdojo">("composio");
|
|
937
938
|
const [subTab, setSubTab] = useState<"configs" | "connect">("configs");
|
|
938
939
|
const [composioConnected, setComposioConnected] = useState(false);
|
|
939
940
|
const [smitheryConnected, setSmitheryConnected] = useState(false);
|
|
@@ -973,12 +974,22 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
973
974
|
const composio = providers.find((p: any) => p.id === "composio");
|
|
974
975
|
const smithery = providers.find((p: any) => p.id === "smithery");
|
|
975
976
|
const agentdojo = providers.find((p: any) => p.id === "agentdojo");
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
977
|
+
const composioHasKey = composio?.hasKey || false;
|
|
978
|
+
const smitheryHasKey = smithery?.hasKey || false;
|
|
979
|
+
const agentdojoHasKey = agentdojo?.hasKey || false;
|
|
979
980
|
|
|
980
|
-
|
|
981
|
+
setComposioConnected(composioHasKey);
|
|
982
|
+
setSmitheryConnected(smitheryHasKey);
|
|
983
|
+
setAgentDojoConnected(agentdojoHasKey);
|
|
984
|
+
|
|
985
|
+
// Set initial active provider to first connected one
|
|
986
|
+
if (composioHasKey) {
|
|
987
|
+
setActiveProvider("composio");
|
|
981
988
|
fetchComposioConfigs();
|
|
989
|
+
} else if (smitheryHasKey) {
|
|
990
|
+
setActiveProvider("smithery");
|
|
991
|
+
} else if (agentdojoHasKey) {
|
|
992
|
+
setActiveProvider("agentdojo");
|
|
982
993
|
}
|
|
983
994
|
} catch (e) {
|
|
984
995
|
console.error("Failed to fetch providers:", e);
|
|
@@ -989,7 +1000,8 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
989
1000
|
const fetchComposioConfigs = async () => {
|
|
990
1001
|
setLoadingConfigs(true);
|
|
991
1002
|
try {
|
|
992
|
-
const
|
|
1003
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
1004
|
+
const res = await authFetch(`/api/integrations/composio/configs${projectParam}`);
|
|
993
1005
|
const data = await res.json();
|
|
994
1006
|
setComposioConfigs(data.configs || []);
|
|
995
1007
|
} catch (e) {
|
|
@@ -1001,7 +1013,8 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
1001
1013
|
const addComposioConfig = async (configId: string) => {
|
|
1002
1014
|
setAddingConfig(configId);
|
|
1003
1015
|
try {
|
|
1004
|
-
const
|
|
1016
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
1017
|
+
const res = await authFetch(`/api/integrations/composio/configs/${configId}/add${projectParam}`, {
|
|
1005
1018
|
method: "POST",
|
|
1006
1019
|
});
|
|
1007
1020
|
if (res.ok) {
|
|
@@ -1031,6 +1044,7 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
1031
1044
|
}
|
|
1032
1045
|
|
|
1033
1046
|
const hasAnyConnection = composioConnected || smitheryConnected || agentDojoConnected;
|
|
1047
|
+
const connectedCount = [composioConnected, smitheryConnected, agentDojoConnected].filter(Boolean).length;
|
|
1034
1048
|
|
|
1035
1049
|
if (!hasAnyConnection) {
|
|
1036
1050
|
return (
|
|
@@ -1053,210 +1067,255 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
1053
1067
|
<>
|
|
1054
1068
|
{AlertDialog}
|
|
1055
1069
|
<div className="space-y-6">
|
|
1056
|
-
{/*
|
|
1057
|
-
{
|
|
1070
|
+
{/* Provider Tabs - show when multiple providers are connected */}
|
|
1071
|
+
{connectedCount > 1 && (
|
|
1058
1072
|
<div className="flex gap-1 bg-[#0a0a0a] border border-[#222] rounded-lg p-1 w-fit">
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
<
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
}}
|
|
1099
|
-
/>
|
|
1073
|
+
{composioConnected && (
|
|
1074
|
+
<button
|
|
1075
|
+
onClick={() => { setActiveProvider("composio"); setSubTab("configs"); }}
|
|
1076
|
+
className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${
|
|
1077
|
+
activeProvider === "composio"
|
|
1078
|
+
? "bg-[#1a1a1a] text-white"
|
|
1079
|
+
: "text-[#666] hover:text-[#888]"
|
|
1080
|
+
}`}
|
|
1081
|
+
>
|
|
1082
|
+
<span className="w-2 h-2 rounded-full bg-purple-500" />
|
|
1083
|
+
Composio
|
|
1084
|
+
</button>
|
|
1085
|
+
)}
|
|
1086
|
+
{smitheryConnected && (
|
|
1087
|
+
<button
|
|
1088
|
+
onClick={() => setActiveProvider("smithery")}
|
|
1089
|
+
className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${
|
|
1090
|
+
activeProvider === "smithery"
|
|
1091
|
+
? "bg-[#1a1a1a] text-white"
|
|
1092
|
+
: "text-[#666] hover:text-[#888]"
|
|
1093
|
+
}`}
|
|
1094
|
+
>
|
|
1095
|
+
<span className="w-2 h-2 rounded-full bg-blue-500" />
|
|
1096
|
+
Smithery
|
|
1097
|
+
</button>
|
|
1098
|
+
)}
|
|
1099
|
+
{agentDojoConnected && (
|
|
1100
|
+
<button
|
|
1101
|
+
onClick={() => setActiveProvider("agentdojo")}
|
|
1102
|
+
className={`px-4 py-2 rounded text-sm font-medium transition flex items-center gap-2 ${
|
|
1103
|
+
activeProvider === "agentdojo"
|
|
1104
|
+
? "bg-[#1a1a1a] text-white"
|
|
1105
|
+
: "text-[#666] hover:text-[#888]"
|
|
1106
|
+
}`}
|
|
1107
|
+
>
|
|
1108
|
+
<span className="w-2 h-2 rounded-full bg-green-500" />
|
|
1109
|
+
AgentDojo
|
|
1110
|
+
</button>
|
|
1111
|
+
)}
|
|
1100
1112
|
</div>
|
|
1101
1113
|
)}
|
|
1102
1114
|
|
|
1103
|
-
{/*
|
|
1104
|
-
{composioConnected &&
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
<span className="text-xs text-green-400">Connected</span>
|
|
1110
|
-
</div>
|
|
1111
|
-
<div className="flex items-center gap-3">
|
|
1115
|
+
{/* Composio Content */}
|
|
1116
|
+
{composioConnected && (connectedCount === 1 || activeProvider === "composio") && (
|
|
1117
|
+
<>
|
|
1118
|
+
{/* Sub-tabs for Composio */}
|
|
1119
|
+
<div className="flex items-center justify-between">
|
|
1120
|
+
<div className="flex gap-1 bg-[#0a0a0a] border border-[#222] rounded-lg p-1">
|
|
1112
1121
|
<button
|
|
1113
|
-
onClick={
|
|
1114
|
-
|
|
1115
|
-
|
|
1122
|
+
onClick={() => setSubTab("configs")}
|
|
1123
|
+
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
1124
|
+
subTab === "configs"
|
|
1125
|
+
? "bg-[#1a1a1a] text-white"
|
|
1126
|
+
: "text-[#666] hover:text-[#888]"
|
|
1127
|
+
}`}
|
|
1116
1128
|
>
|
|
1117
|
-
|
|
1129
|
+
MCP Configs
|
|
1118
1130
|
</button>
|
|
1119
|
-
<
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1131
|
+
<button
|
|
1132
|
+
onClick={() => setSubTab("connect")}
|
|
1133
|
+
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
1134
|
+
subTab === "connect"
|
|
1135
|
+
? "bg-[#1a1a1a] text-white"
|
|
1136
|
+
: "text-[#666] hover:text-[#888]"
|
|
1137
|
+
}`}
|
|
1124
1138
|
>
|
|
1125
|
-
|
|
1126
|
-
</
|
|
1139
|
+
Connect Apps
|
|
1140
|
+
</button>
|
|
1127
1141
|
</div>
|
|
1142
|
+
{connectedCount === 1 && (
|
|
1143
|
+
<div className="flex items-center gap-2 text-xs text-[#666]">
|
|
1144
|
+
<span className="w-2 h-2 rounded-full bg-purple-500" />
|
|
1145
|
+
Composio
|
|
1146
|
+
<span className="text-green-400">Connected</span>
|
|
1147
|
+
</div>
|
|
1148
|
+
)}
|
|
1128
1149
|
</div>
|
|
1129
1150
|
|
|
1130
|
-
{
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
<p className="text-xs text-[#555] mt-2">
|
|
1136
|
-
First <button onClick={() => setSubTab("connect")} className="text-[#f97316] hover:text-[#fb923c]">connect some apps</button>, then create a config.
|
|
1151
|
+
{/* Connect Apps Tab */}
|
|
1152
|
+
{subTab === "connect" && (
|
|
1153
|
+
<div>
|
|
1154
|
+
<p className="text-sm text-[#666] mb-4">
|
|
1155
|
+
Connect your accounts to enable tools in MCP configs
|
|
1137
1156
|
</p>
|
|
1138
|
-
<
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1157
|
+
<IntegrationsPanel
|
|
1158
|
+
providerId="composio"
|
|
1159
|
+
projectId={projectId}
|
|
1160
|
+
onConnectionComplete={() => {
|
|
1161
|
+
// Refresh configs after connecting an app
|
|
1162
|
+
fetchComposioConfigs();
|
|
1163
|
+
}}
|
|
1164
|
+
/>
|
|
1146
1165
|
</div>
|
|
1147
|
-
)
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1166
|
+
)}
|
|
1167
|
+
|
|
1168
|
+
{/* MCP Configs Tab */}
|
|
1169
|
+
{subTab === "configs" && (
|
|
1170
|
+
<div>
|
|
1171
|
+
<div className="flex items-center justify-between mb-3">
|
|
1172
|
+
<p className="text-sm text-[#666]">
|
|
1173
|
+
Your MCP configs from Composio
|
|
1174
|
+
</p>
|
|
1175
|
+
<div className="flex items-center gap-3">
|
|
1176
|
+
<button
|
|
1177
|
+
onClick={fetchComposioConfigs}
|
|
1178
|
+
disabled={loadingConfigs}
|
|
1179
|
+
className="text-xs text-[#666] hover:text-[#888] transition"
|
|
1158
1180
|
>
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1181
|
+
{loadingConfigs ? "Loading..." : "Refresh"}
|
|
1182
|
+
</button>
|
|
1183
|
+
<a
|
|
1184
|
+
href="https://app.composio.dev/mcp_configs"
|
|
1185
|
+
target="_blank"
|
|
1186
|
+
rel="noopener noreferrer"
|
|
1187
|
+
className="text-xs text-[#666] hover:text-[#f97316] transition"
|
|
1188
|
+
>
|
|
1189
|
+
Create Config →
|
|
1190
|
+
</a>
|
|
1191
|
+
</div>
|
|
1192
|
+
</div>
|
|
1193
|
+
|
|
1194
|
+
{loadingConfigs ? (
|
|
1195
|
+
<div className="text-center py-6 text-[#666]">Loading configs...</div>
|
|
1196
|
+
) : composioConfigs.length === 0 ? (
|
|
1197
|
+
<div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 text-center">
|
|
1198
|
+
<p className="text-sm text-[#666]">No MCP configs found</p>
|
|
1199
|
+
<p className="text-xs text-[#555] mt-2">
|
|
1200
|
+
First <button onClick={() => setSubTab("connect")} className="text-[#f97316] hover:text-[#fb923c]">connect some apps</button>, then create a config.
|
|
1201
|
+
</p>
|
|
1202
|
+
<a
|
|
1203
|
+
href="https://app.composio.dev/mcp_configs"
|
|
1204
|
+
target="_blank"
|
|
1205
|
+
rel="noopener noreferrer"
|
|
1206
|
+
className="text-xs text-[#f97316] hover:text-[#fb923c] mt-2 inline-block"
|
|
1207
|
+
>
|
|
1208
|
+
Create in Composio →
|
|
1209
|
+
</a>
|
|
1210
|
+
</div>
|
|
1211
|
+
) : (
|
|
1212
|
+
<div className="space-y-2">
|
|
1213
|
+
{composioConfigs.map((config) => {
|
|
1214
|
+
const added = isConfigAdded(config.id);
|
|
1215
|
+
const isAdding = addingConfig === config.id;
|
|
1216
|
+
return (
|
|
1217
|
+
<div
|
|
1218
|
+
key={config.id}
|
|
1219
|
+
className={`bg-[#111] border rounded-lg p-3 transition flex items-center justify-between ${
|
|
1220
|
+
added ? "border-green-500/30" : "border-[#1a1a1a] hover:border-[#333]"
|
|
1221
|
+
}`}
|
|
1222
|
+
>
|
|
1223
|
+
<div className="flex-1 min-w-0">
|
|
1224
|
+
<div className="flex items-center gap-2">
|
|
1225
|
+
<span className="font-medium text-sm">{config.name}</span>
|
|
1226
|
+
<span className="text-xs text-[#555]">{config.toolsCount} tools</span>
|
|
1227
|
+
{added && (
|
|
1228
|
+
<span className="text-xs text-green-400">Added</span>
|
|
1229
|
+
)}
|
|
1230
|
+
</div>
|
|
1231
|
+
{config.toolkits.length > 0 && (
|
|
1232
|
+
<div className="flex flex-wrap gap-1 mt-1">
|
|
1233
|
+
{config.toolkits.slice(0, 4).map((toolkit) => (
|
|
1234
|
+
<span
|
|
1235
|
+
key={toolkit}
|
|
1236
|
+
className="text-xs bg-[#1a1a1a] text-[#666] px-1.5 py-0.5 rounded"
|
|
1237
|
+
>
|
|
1238
|
+
{toolkit}
|
|
1239
|
+
</span>
|
|
1240
|
+
))}
|
|
1241
|
+
{config.toolkits.length > 4 && (
|
|
1242
|
+
<span className="text-xs text-[#555]">+{config.toolkits.length - 4}</span>
|
|
1243
|
+
)}
|
|
1244
|
+
</div>
|
|
1245
|
+
)}
|
|
1246
|
+
</div>
|
|
1247
|
+
<div className="flex items-center gap-2 ml-3">
|
|
1248
|
+
{added ? (
|
|
1249
|
+
<span className="text-xs text-[#555] px-2 py-1">In Servers</span>
|
|
1250
|
+
) : (
|
|
1251
|
+
<button
|
|
1252
|
+
onClick={() => addComposioConfig(config.id)}
|
|
1253
|
+
disabled={isAdding}
|
|
1254
|
+
className="text-xs bg-[#f97316] hover:bg-[#fb923c] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50"
|
|
1173
1255
|
>
|
|
1174
|
-
{
|
|
1175
|
-
</
|
|
1176
|
-
))}
|
|
1177
|
-
{config.toolkits.length > 4 && (
|
|
1178
|
-
<span className="text-xs text-[#555]">+{config.toolkits.length - 4}</span>
|
|
1256
|
+
{isAdding ? "Adding..." : "Add"}
|
|
1257
|
+
</button>
|
|
1179
1258
|
)}
|
|
1259
|
+
<a
|
|
1260
|
+
href={`https://app.composio.dev/mcp_configs/${config.id}`}
|
|
1261
|
+
target="_blank"
|
|
1262
|
+
rel="noopener noreferrer"
|
|
1263
|
+
className="text-xs text-[#666] hover:text-[#888] transition"
|
|
1264
|
+
>
|
|
1265
|
+
Edit
|
|
1266
|
+
</a>
|
|
1180
1267
|
</div>
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
) : (
|
|
1187
|
-
<button
|
|
1188
|
-
onClick={() => addComposioConfig(config.id)}
|
|
1189
|
-
disabled={isAdding}
|
|
1190
|
-
className="text-xs bg-[#f97316] hover:bg-[#fb923c] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50"
|
|
1191
|
-
>
|
|
1192
|
-
{isAdding ? "Adding..." : "Add"}
|
|
1193
|
-
</button>
|
|
1194
|
-
)}
|
|
1195
|
-
<a
|
|
1196
|
-
href={`https://app.composio.dev/mcp_configs/${config.id}`}
|
|
1197
|
-
target="_blank"
|
|
1198
|
-
rel="noopener noreferrer"
|
|
1199
|
-
className="text-xs text-[#666] hover:text-[#888] transition"
|
|
1200
|
-
>
|
|
1201
|
-
Edit
|
|
1202
|
-
</a>
|
|
1203
|
-
</div>
|
|
1204
|
-
</div>
|
|
1205
|
-
);
|
|
1206
|
-
})}
|
|
1268
|
+
</div>
|
|
1269
|
+
);
|
|
1270
|
+
})}
|
|
1271
|
+
</div>
|
|
1272
|
+
)}
|
|
1207
1273
|
</div>
|
|
1208
1274
|
)}
|
|
1209
|
-
|
|
1275
|
+
</>
|
|
1210
1276
|
)}
|
|
1211
1277
|
|
|
1212
|
-
{/* Smithery
|
|
1213
|
-
{smitheryConnected && (
|
|
1278
|
+
{/* Smithery Content */}
|
|
1279
|
+
{smitheryConnected && (connectedCount === 1 || activeProvider === "smithery") && (
|
|
1214
1280
|
<div>
|
|
1215
|
-
|
|
1216
|
-
<div className="flex items-center gap-2">
|
|
1217
|
-
<
|
|
1218
|
-
|
|
1281
|
+
{connectedCount === 1 && (
|
|
1282
|
+
<div className="flex items-center gap-2 text-xs text-[#666] mb-4">
|
|
1283
|
+
<span className="w-2 h-2 rounded-full bg-blue-500" />
|
|
1284
|
+
Smithery
|
|
1285
|
+
<span className="text-green-400">Connected</span>
|
|
1219
1286
|
</div>
|
|
1287
|
+
)}
|
|
1288
|
+
<div className="flex items-center justify-between mb-3">
|
|
1289
|
+
<p className="text-sm text-[#666]">
|
|
1290
|
+
Add MCP servers from the Smithery registry
|
|
1291
|
+
</p>
|
|
1220
1292
|
<a
|
|
1221
1293
|
href="https://smithery.ai/servers"
|
|
1222
1294
|
target="_blank"
|
|
1223
1295
|
rel="noopener noreferrer"
|
|
1224
1296
|
className="text-xs text-[#666] hover:text-[#f97316] transition"
|
|
1225
1297
|
>
|
|
1226
|
-
|
|
1298
|
+
Browse Smithery →
|
|
1227
1299
|
</a>
|
|
1228
1300
|
</div>
|
|
1229
1301
|
<div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 text-center">
|
|
1230
1302
|
<p className="text-sm text-[#666]">
|
|
1231
|
-
Smithery servers can be added from the Registry tab.
|
|
1303
|
+
Smithery servers can be added from the <strong>Browse Registry</strong> tab.
|
|
1304
|
+
</p>
|
|
1305
|
+
<p className="text-xs text-[#555] mt-2">
|
|
1306
|
+
Your API key will be used automatically when adding Smithery servers.
|
|
1232
1307
|
</p>
|
|
1233
1308
|
</div>
|
|
1234
1309
|
</div>
|
|
1235
1310
|
)}
|
|
1236
1311
|
|
|
1237
|
-
{/* AgentDojo
|
|
1238
|
-
{agentDojoConnected && (
|
|
1239
|
-
<
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
</div>
|
|
1245
|
-
<a
|
|
1246
|
-
href="https://agentdojo.com/tools"
|
|
1247
|
-
target="_blank"
|
|
1248
|
-
rel="noopener noreferrer"
|
|
1249
|
-
className="text-xs text-[#666] hover:text-[#f97316] transition"
|
|
1250
|
-
>
|
|
1251
|
-
Browse Tools →
|
|
1252
|
-
</a>
|
|
1253
|
-
</div>
|
|
1254
|
-
<div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 text-center">
|
|
1255
|
-
<p className="text-sm text-[#666]">
|
|
1256
|
-
AgentDojo integration coming soon. Browse available tools on their platform.
|
|
1257
|
-
</p>
|
|
1258
|
-
</div>
|
|
1259
|
-
</div>
|
|
1312
|
+
{/* AgentDojo Content */}
|
|
1313
|
+
{agentDojoConnected && (connectedCount === 1 || activeProvider === "agentdojo") && (
|
|
1314
|
+
<AgentDojoContent
|
|
1315
|
+
projectId={projectId}
|
|
1316
|
+
onServerAdded={onServerAdded}
|
|
1317
|
+
showProviderBadge={connectedCount === 1}
|
|
1318
|
+
/>
|
|
1260
1319
|
)}
|
|
1261
1320
|
|
|
1262
1321
|
<div className="p-3 bg-[#0a0a0a] border border-[#222] rounded text-xs text-[#666]">
|
|
@@ -1269,6 +1328,231 @@ function HostedServices({ onServerAdded }: { onServerAdded?: () => void }) {
|
|
|
1269
1328
|
);
|
|
1270
1329
|
}
|
|
1271
1330
|
|
|
1331
|
+
// AgentDojo Content Component
|
|
1332
|
+
interface AgentDojoConfig {
|
|
1333
|
+
id: string;
|
|
1334
|
+
name: string;
|
|
1335
|
+
slug: string;
|
|
1336
|
+
toolkits: string[];
|
|
1337
|
+
toolsCount: number;
|
|
1338
|
+
mcpUrl: string;
|
|
1339
|
+
createdAt?: string;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
function AgentDojoContent({
|
|
1343
|
+
projectId,
|
|
1344
|
+
onServerAdded,
|
|
1345
|
+
showProviderBadge,
|
|
1346
|
+
}: {
|
|
1347
|
+
projectId?: string | null;
|
|
1348
|
+
onServerAdded?: () => void;
|
|
1349
|
+
showProviderBadge?: boolean;
|
|
1350
|
+
}) {
|
|
1351
|
+
const { authFetch } = useAuth();
|
|
1352
|
+
const [subTab, setSubTab] = useState<"configs" | "toolkits">("configs");
|
|
1353
|
+
const [configs, setConfigs] = useState<AgentDojoConfig[]>([]);
|
|
1354
|
+
const [addedServers, setAddedServers] = useState<Set<string>>(new Set());
|
|
1355
|
+
const [loadingConfigs, setLoadingConfigs] = useState(false);
|
|
1356
|
+
const [addingConfig, setAddingConfig] = useState<string | null>(null);
|
|
1357
|
+
const { alert, AlertDialog } = useAlert();
|
|
1358
|
+
|
|
1359
|
+
const fetchConfigs = async () => {
|
|
1360
|
+
setLoadingConfigs(true);
|
|
1361
|
+
try {
|
|
1362
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
1363
|
+
const [configsRes, serversRes] = await Promise.all([
|
|
1364
|
+
authFetch(`/api/integrations/agentdojo/configs${projectParam}`),
|
|
1365
|
+
authFetch("/api/mcp/servers"),
|
|
1366
|
+
]);
|
|
1367
|
+
const configsData = await configsRes.json();
|
|
1368
|
+
const serversData = await serversRes.json();
|
|
1369
|
+
|
|
1370
|
+
setConfigs(configsData.configs || []);
|
|
1371
|
+
|
|
1372
|
+
// Track which configs are already added as local servers
|
|
1373
|
+
const agentdojoServerIds = new Set(
|
|
1374
|
+
(serversData.servers || [])
|
|
1375
|
+
.filter((s: any) => s.source === "agentdojo")
|
|
1376
|
+
.map((s: any) => {
|
|
1377
|
+
// Extract config ID from URL or match by name
|
|
1378
|
+
const match = s.url?.match(/\/mcp\/([^/?]+)/);
|
|
1379
|
+
return match ? match[1] : s.name;
|
|
1380
|
+
})
|
|
1381
|
+
);
|
|
1382
|
+
setAddedServers(agentdojoServerIds);
|
|
1383
|
+
} catch (e) {
|
|
1384
|
+
console.error("Failed to fetch AgentDojo configs:", e);
|
|
1385
|
+
}
|
|
1386
|
+
setLoadingConfigs(false);
|
|
1387
|
+
};
|
|
1388
|
+
|
|
1389
|
+
const addConfig = async (configId: string) => {
|
|
1390
|
+
setAddingConfig(configId);
|
|
1391
|
+
try {
|
|
1392
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
1393
|
+
const res = await authFetch(`/api/integrations/agentdojo/configs/${configId}/add${projectParam}`, {
|
|
1394
|
+
method: "POST",
|
|
1395
|
+
});
|
|
1396
|
+
if (res.ok) {
|
|
1397
|
+
const config = configs.find(c => c.id === configId);
|
|
1398
|
+
setAddedServers(prev => new Set([...prev, config?.slug || configId]));
|
|
1399
|
+
onServerAdded?.();
|
|
1400
|
+
} else {
|
|
1401
|
+
const data = await res.json();
|
|
1402
|
+
await alert(data.error || "Failed to add config", { title: "Error", variant: "error" });
|
|
1403
|
+
}
|
|
1404
|
+
} catch (e) {
|
|
1405
|
+
console.error("Failed to add config:", e);
|
|
1406
|
+
}
|
|
1407
|
+
setAddingConfig(null);
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
const isConfigAdded = (config: AgentDojoConfig) => {
|
|
1411
|
+
return addedServers.has(config.slug) || addedServers.has(config.id) || addedServers.has(config.name);
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
useEffect(() => {
|
|
1415
|
+
fetchConfigs();
|
|
1416
|
+
}, [authFetch, projectId]);
|
|
1417
|
+
|
|
1418
|
+
return (
|
|
1419
|
+
<>
|
|
1420
|
+
{AlertDialog}
|
|
1421
|
+
<div>
|
|
1422
|
+
{showProviderBadge && (
|
|
1423
|
+
<div className="flex items-center gap-2 text-xs text-[#666] mb-4">
|
|
1424
|
+
<span className="w-2 h-2 rounded-full bg-green-500" />
|
|
1425
|
+
AgentDojo
|
|
1426
|
+
<span className="text-green-400">Connected</span>
|
|
1427
|
+
</div>
|
|
1428
|
+
)}
|
|
1429
|
+
|
|
1430
|
+
{/* Sub-tabs */}
|
|
1431
|
+
<div className="flex items-center justify-between mb-4">
|
|
1432
|
+
<div className="flex gap-1 bg-[#0a0a0a] border border-[#222] rounded-lg p-1">
|
|
1433
|
+
<button
|
|
1434
|
+
onClick={() => setSubTab("configs")}
|
|
1435
|
+
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
1436
|
+
subTab === "configs"
|
|
1437
|
+
? "bg-[#1a1a1a] text-white"
|
|
1438
|
+
: "text-[#666] hover:text-[#888]"
|
|
1439
|
+
}`}
|
|
1440
|
+
>
|
|
1441
|
+
MCP Servers
|
|
1442
|
+
</button>
|
|
1443
|
+
<button
|
|
1444
|
+
onClick={() => setSubTab("toolkits")}
|
|
1445
|
+
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
1446
|
+
subTab === "toolkits"
|
|
1447
|
+
? "bg-[#1a1a1a] text-white"
|
|
1448
|
+
: "text-[#666] hover:text-[#888]"
|
|
1449
|
+
}`}
|
|
1450
|
+
>
|
|
1451
|
+
Browse Toolkits
|
|
1452
|
+
</button>
|
|
1453
|
+
</div>
|
|
1454
|
+
</div>
|
|
1455
|
+
|
|
1456
|
+
{/* MCP Servers Tab */}
|
|
1457
|
+
{subTab === "configs" && (
|
|
1458
|
+
<div>
|
|
1459
|
+
<div className="flex items-center justify-between mb-3">
|
|
1460
|
+
<p className="text-sm text-[#666]">
|
|
1461
|
+
Your MCP servers from AgentDojo
|
|
1462
|
+
</p>
|
|
1463
|
+
<button
|
|
1464
|
+
onClick={fetchConfigs}
|
|
1465
|
+
disabled={loadingConfigs}
|
|
1466
|
+
className="text-xs text-[#666] hover:text-[#888] transition"
|
|
1467
|
+
>
|
|
1468
|
+
{loadingConfigs ? "Loading..." : "Refresh"}
|
|
1469
|
+
</button>
|
|
1470
|
+
</div>
|
|
1471
|
+
|
|
1472
|
+
{loadingConfigs ? (
|
|
1473
|
+
<div className="text-center py-6 text-[#666]">Loading servers...</div>
|
|
1474
|
+
) : configs.length === 0 ? (
|
|
1475
|
+
<div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4 text-center">
|
|
1476
|
+
<p className="text-sm text-[#666]">No MCP servers found</p>
|
|
1477
|
+
<p className="text-xs text-[#555] mt-2">
|
|
1478
|
+
<button onClick={() => setSubTab("toolkits")} className="text-[#f97316] hover:text-[#fb923c]">
|
|
1479
|
+
Browse toolkits
|
|
1480
|
+
</button>
|
|
1481
|
+
{" "}to create a new MCP server.
|
|
1482
|
+
</p>
|
|
1483
|
+
</div>
|
|
1484
|
+
) : (
|
|
1485
|
+
<div className="space-y-2">
|
|
1486
|
+
{configs.map((config) => {
|
|
1487
|
+
const added = isConfigAdded(config);
|
|
1488
|
+
const isAdding = addingConfig === config.id;
|
|
1489
|
+
return (
|
|
1490
|
+
<div
|
|
1491
|
+
key={config.id}
|
|
1492
|
+
className={`bg-[#111] border rounded-lg p-3 transition flex items-center justify-between ${
|
|
1493
|
+
added ? "border-green-500/30" : "border-[#1a1a1a] hover:border-[#333]"
|
|
1494
|
+
}`}
|
|
1495
|
+
>
|
|
1496
|
+
<div className="flex-1 min-w-0">
|
|
1497
|
+
<div className="flex items-center gap-2">
|
|
1498
|
+
<span className="font-medium text-sm">{config.name}</span>
|
|
1499
|
+
<span className="text-xs text-[#555]">{config.toolsCount} tools</span>
|
|
1500
|
+
{added && (
|
|
1501
|
+
<span className="text-xs text-green-400">Added</span>
|
|
1502
|
+
)}
|
|
1503
|
+
</div>
|
|
1504
|
+
{config.mcpUrl && (
|
|
1505
|
+
<code className="text-xs text-[#555] mt-1 block truncate">
|
|
1506
|
+
{config.mcpUrl}
|
|
1507
|
+
</code>
|
|
1508
|
+
)}
|
|
1509
|
+
{!config.mcpUrl && config.slug && (
|
|
1510
|
+
<code className="text-xs text-[#555] mt-1 block truncate">
|
|
1511
|
+
{config.slug}
|
|
1512
|
+
</code>
|
|
1513
|
+
)}
|
|
1514
|
+
</div>
|
|
1515
|
+
<div className="flex items-center gap-2 ml-3">
|
|
1516
|
+
{added ? (
|
|
1517
|
+
<span className="text-xs text-[#555] px-2 py-1">In Servers</span>
|
|
1518
|
+
) : (
|
|
1519
|
+
<button
|
|
1520
|
+
onClick={() => addConfig(config.id)}
|
|
1521
|
+
disabled={isAdding}
|
|
1522
|
+
className="text-xs bg-[#f97316] hover:bg-[#fb923c] text-black px-3 py-1 rounded font-medium transition disabled:opacity-50"
|
|
1523
|
+
>
|
|
1524
|
+
{isAdding ? "Adding..." : "Add"}
|
|
1525
|
+
</button>
|
|
1526
|
+
)}
|
|
1527
|
+
</div>
|
|
1528
|
+
</div>
|
|
1529
|
+
);
|
|
1530
|
+
})}
|
|
1531
|
+
</div>
|
|
1532
|
+
)}
|
|
1533
|
+
</div>
|
|
1534
|
+
)}
|
|
1535
|
+
|
|
1536
|
+
{/* Browse Toolkits Tab */}
|
|
1537
|
+
{subTab === "toolkits" && (
|
|
1538
|
+
<div>
|
|
1539
|
+
<p className="text-sm text-[#666] mb-4">
|
|
1540
|
+
Browse available toolkits and create MCP servers
|
|
1541
|
+
</p>
|
|
1542
|
+
<IntegrationsPanel
|
|
1543
|
+
providerId="agentdojo"
|
|
1544
|
+
projectId={projectId}
|
|
1545
|
+
onConnectionComplete={() => {
|
|
1546
|
+
fetchConfigs();
|
|
1547
|
+
}}
|
|
1548
|
+
/>
|
|
1549
|
+
</div>
|
|
1550
|
+
)}
|
|
1551
|
+
</div>
|
|
1552
|
+
</>
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1272
1556
|
// Parse command and extract credential placeholders
|
|
1273
1557
|
function parseCommandForCredentials(cmd: string): {
|
|
1274
1558
|
cleanCommand: string;
|