Skip to content

Commit 8b3487d

Browse files
Restore MCP security guards settings UI
1 parent e6a28ce commit 8b3487d

11 files changed

Lines changed: 1259 additions & 217 deletions

File tree

crates/agentgateway/src/mcp/security/wasm.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@
77

88
use serde::{Deserialize, Serialize};
99
use std::collections::HashMap;
10-
use std::time::{Duration, SystemTime, UNIX_EPOCH};
1110

12-
use super::native::NativeGuard;
13-
use super::{DenyReason, GuardContext, GuardDecision, GuardError, GuardResult, ModifyAction};
14-
15-
#[cfg(feature = "wasm-guards")]
16-
use wasmtime::component::{Component, Linker, Val};
17-
#[cfg(feature = "wasm-guards")]
18-
use wasmtime::{Config, Engine, Store};
1911
#[cfg(feature = "wasm-guards")]
20-
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView};
12+
use {
13+
std::time::{Duration, SystemTime, UNIX_EPOCH},
14+
super::native::NativeGuard,
15+
super::{DenyReason, GuardContext, GuardDecision, GuardResult, ModifyAction},
16+
wasmtime::component::{Component, Linker, Val},
17+
wasmtime::{Config, Engine, Store},
18+
wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView},
19+
};
20+
21+
use super::{GuardError};
2122

2223
/// Configuration for WASM-based guards
2324
#[derive(Debug, Clone, Serialize, Deserialize)]

ui/src/app/playground/page.tsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,13 +485,15 @@ export default function PlaygroundPage() {
485485

486486
await client.connect(transport);
487487
setMcpState((prev) => ({ ...prev, client }));
488-
setConnectionState((prev) => ({ ...prev, isConnected: true }));
489-
toast.success("Connected to MCP endpoint");
490488

491489
setUiState((prev) => ({ ...prev, isLoadingCapabilities: true }));
492490
const listToolsRequest: McpClientRequest = { method: "tools/list", params: {} };
493491
const toolsResponse = await client.request(listToolsRequest, McpListToolsResultSchema);
494492
setMcpState((prev) => ({ ...prev, tools: toolsResponse.tools }));
493+
494+
// Only mark as connected and show success after tools are loaded successfully
495+
setConnectionState((prev) => ({ ...prev, isConnected: true }));
496+
toast.success("Connected to MCP endpoint");
495497
} else if (backendType === "a2a") {
496498
// Connect to A2A endpoint
497499
setConnectionState((prev) => ({ ...prev, connectionType: "a2a" }));
@@ -740,18 +742,44 @@ export default function PlaygroundPage() {
740742
arguments: mcpState.paramValues,
741743
},
742744
};
745+
743746
const result = await mcpState.client.request(request, McpToolResponseSchema);
747+
744748
setMcpState((prev) => ({ ...prev, response: result }));
745749
toast.success(`Tool ${mcpState.selectedTool?.name} executed.`);
746750
} catch (error: any) {
747-
const message = error instanceof McpError ? error.message : "Failed to run tool";
751+
const message =
752+
error instanceof McpError ? error.message : error?.message || "Failed to run tool";
748753
setMcpState((prev) => ({ ...prev, response: { error: message, details: error } }));
749754
toast.error(message);
750755
} finally {
751756
setUiState((prev) => ({ ...prev, isRequestRunning: false }));
752757
}
753758
};
754759

760+
const refreshMcpTools = async () => {
761+
if (!mcpState.client) return;
762+
763+
setUiState((prev) => ({ ...prev, isLoadingCapabilities: true }));
764+
try {
765+
// Call tools/list through the existing gateway connection
766+
// The gateway will re-fetch from all configured MCP targets
767+
const listToolsRequest: McpClientRequest = { method: "tools/list", params: {} };
768+
const toolsResponse = await mcpState.client.request(
769+
listToolsRequest,
770+
McpListToolsResultSchema
771+
);
772+
setMcpState((prev) => ({ ...prev, tools: toolsResponse.tools }));
773+
toast.success(`Refreshed tools list (${toolsResponse.tools.length} tools)`);
774+
} catch (error: any) {
775+
const message =
776+
error instanceof McpError ? error.message : error?.message || "Failed to refresh tools";
777+
toast.error(message);
778+
} finally {
779+
setUiState((prev) => ({ ...prev, isLoadingCapabilities: false }));
780+
}
781+
};
782+
755783
const handleA2aSkillSelect = (skill: AgentSkill) => {
756784
setA2aState((prev) => ({ ...prev, selectedSkill: skill, response: null, message: "" }));
757785
setMcpState((prev) => ({ ...prev, response: null }));
@@ -1436,6 +1464,7 @@ export default function PlaygroundPage() {
14361464
selectedA2aSkillId={a2aState.selectedSkill?.id ?? null}
14371465
onMcpToolSelect={handleMcpToolSelect}
14381466
onA2aSkillSelect={handleA2aSkillSelect}
1467+
onRefreshMcpTools={refreshMcpTools}
14391468
/>
14401469

14411470
<ActionPanel

ui/src/components/backend-config.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export function BackendConfig() {
3535
updateMcpTarget,
3636
parseAndUpdateUrl,
3737
updateMcpStateful,
38+
// Security guard management
39+
addSecurityGuard,
40+
removeSecurityGuard,
41+
updateSecurityGuardField,
3842
} = useBackendFormState();
3943

4044
const {
@@ -145,6 +149,9 @@ export function BackendConfig() {
145149
updateMcpTarget={updateMcpTarget}
146150
parseAndUpdateUrl={parseAndUpdateUrl}
147151
updateMcpStateful={updateMcpStateful}
152+
addSecurityGuard={addSecurityGuard}
153+
removeSecurityGuard={removeSecurityGuard}
154+
updateSecurityGuardField={updateSecurityGuardField}
148155
/>
149156
</div>
150157
);

0 commit comments

Comments
 (0)