diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f1bf9ef..e444eb3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,10 +4,12 @@ import { deleteGraphConfig, getGraphConfig, getGraphDefaultConfig, + getMcpToolConfig, listAvailableGraphs, listGraphConfigs, listPipelines, stopPipeline, + updateMcpToolConfig, upsertGraphConfig, } from "./api/frontApis"; import type { @@ -37,6 +39,8 @@ type LaunchCredentials = { authKeyMasked: string; }; +type ActiveTab = "agents" | "mcp"; + const DEFAULT_ENTRY_POINT = "fastapi_server/server_dashscope.py"; const DEFAULT_LLM_NAME = "qwen-plus"; const DEFAULT_PORT = 8100; @@ -118,6 +122,7 @@ function toEditable( } export default function App() { + const [activeTab, setActiveTab] = useState("agents"); const [graphs, setGraphs] = useState([]); const [configItems, setConfigItems] = useState([]); const [running, setRunning] = useState([]); @@ -126,6 +131,9 @@ export default function App() { const [editor, setEditor] = useState(null); const [statusMessage, setStatusMessage] = useState(""); const [launchCredentials, setLaunchCredentials] = useState(null); + const [mcpConfigPath, setMcpConfigPath] = useState(""); + const [mcpConfigRaw, setMcpConfigRaw] = useState(""); + const [mcpToolKeys, setMcpToolKeys] = useState([]); const [busy, setBusy] = useState(false); const configKeySet = useMemo( @@ -208,6 +216,16 @@ export default function App() { } }, [selectedId, configKeySet]); + useEffect(() => { + if (activeTab !== "mcp") { + return; + } + if (mcpConfigRaw) { + return; + } + reloadMcpConfig().catch(() => undefined); + }, [activeTab]); + async function selectExisting(item: GraphConfigListItem): Promise { const id = makeAgentKey(item.pipeline_id, item.prompt_set_id); setSelectedId(id); @@ -321,6 +339,37 @@ export default function App() { } } + async function reloadMcpConfig(): Promise { + setBusy(true); + setStatusMessage("Loading MCP config..."); + try { + const resp = await getMcpToolConfig(); + setMcpConfigPath(resp.path || ""); + setMcpConfigRaw(resp.raw_content || ""); + setMcpToolKeys(resp.tool_keys || []); + setStatusMessage("MCP config loaded."); + } catch (error) { + setStatusMessage((error as Error).message); + } finally { + setBusy(false); + } + } + + async function saveMcpConfig(): Promise { + setBusy(true); + setStatusMessage("Saving MCP config..."); + try { + const resp = await updateMcpToolConfig({ raw_content: mcpConfigRaw }); + setMcpConfigPath(resp.path || ""); + setMcpToolKeys(resp.tool_keys || []); + setStatusMessage("MCP config saved."); + } catch (error) { + setStatusMessage((error as Error).message); + } finally { + setBusy(false); + } + } + async function saveConfig(): Promise { if (!editor) { return; @@ -507,243 +556,303 @@ export default function App() { } } + const showSidebar = activeTab === "agents"; + return ( -
- +
+
+ {rows.map((row) => ( + + ))} + {rows.length === 0 ?

No agents configured yet.

: null} +
+ + ) : null}
-

Agent Configuration

-
- - - -
{statusMessage ?

{statusMessage}

: null} - {launchCredentials ? ( -
-

Access Credentials (shown once)

-
- URL:{" "} - - {launchCredentials.url} - - + + +
-
- {launchCredentials.authType} key: {launchCredentials.authKey} - -
-
- Header: {authHeaderValue} - -
-

- Stored after launch as masked value: {launchCredentials.authKeyMasked} -

-
- ) : null} - {!editor ? ( -
-

Select an agent from the left or create a new one.

-
- ) : ( -
- - - {graphArchImage && ( -
-

Graph Architecture

-
- {`${editor.graphId} + {launchCredentials ? ( +
+

Access Credentials (shown once)

+
+ URL:{" "} + + {launchCredentials.url} + +
+
+ {launchCredentials.authType} key: {launchCredentials.authKey} + +
+
+ Header: {authHeaderValue} + +
+

+ Stored after launch as masked value: {launchCredentials.authKeyMasked} +

- )} + ) : null} - + {!editor ? ( +
+

Select an agent from the left or create a new one.

+
+ ) : ( +
+ - - - - - - - - - - -
-

Prompts

- {Object.keys(editor.prompts).length === 0 ? ( -

No prompt keys returned from backend.

- ) : ( - Object.entries(editor.prompts).map(([key, value]) => ( -