Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import httpx
|
3 |
+
import json
|
4 |
+
import os
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
|
7 |
+
# Load environment variables from .env file
|
8 |
+
load_dotenv()
|
9 |
+
|
10 |
+
MODAL_MCP_ENDPOINT = os.getenv("MODAL_MCP_ENDPOINT", "YOUR_MODAL_MCP_ENDPOINT_HERE")
|
11 |
+
BANDIT_TOOL_NAME = "bandit"
|
12 |
+
|
13 |
+
async def call_bandit_tool_on_modal(tool_parameters_json: str):
|
14 |
+
if MODAL_MCP_ENDPOINT == "YOUR_MODAL_MCP_ENDPOINT_HERE" or not MODAL_MCP_ENDPOINT:
|
15 |
+
return {"error": "MODAL_MCP_ENDPOINT is not set. Please create a .env file in the 'mcp_deploy' directory with MODAL_MCP_ENDPOINT='your_url' or set it as an environment variable."}
|
16 |
+
|
17 |
+
try:
|
18 |
+
tool_parameters = json.loads(tool_parameters_json)
|
19 |
+
except json.JSONDecodeError as e:
|
20 |
+
return {"error": "Invalid JSON format for tool parameters.", "details": str(e)}
|
21 |
+
|
22 |
+
# Ensure 'code' parameter is present, as Bandit expects it.
|
23 |
+
if "code" not in tool_parameters:
|
24 |
+
return {"error": "Missing 'code' parameter in JSON. Bandit requires a 'code' field with the Python code string to analyze."}
|
25 |
+
|
26 |
+
payload = {
|
27 |
+
"tool_name": BANDIT_TOOL_NAME,
|
28 |
+
"tool_params": tool_parameters,
|
29 |
+
"agent_id": "gradio-bandit-ui",
|
30 |
+
"session_id": "default_session"
|
31 |
+
}
|
32 |
+
|
33 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
34 |
+
try:
|
35 |
+
print(f"Calling MCP tool: {BANDIT_TOOL_NAME} at {MODAL_MCP_ENDPOINT} with params: {tool_parameters}")
|
36 |
+
response = await client.post(MODAL_MCP_ENDPOINT, json=payload)
|
37 |
+
response.raise_for_status()
|
38 |
+
print(response.json())
|
39 |
+
|
40 |
+
# Handle Modal's [response_dict, status_code] tuple format
|
41 |
+
raw_response_data = response.json()
|
42 |
+
if isinstance(raw_response_data, list) and len(raw_response_data) > 0 and isinstance(raw_response_data[0], dict):
|
43 |
+
actual_response = raw_response_data[0]
|
44 |
+
elif isinstance(raw_response_data, dict):
|
45 |
+
actual_response = raw_response_data
|
46 |
+
else:
|
47 |
+
return {"error": "Unexpected response format from MCP server", "details": raw_response_data}
|
48 |
+
return actual_response
|
49 |
+
|
50 |
+
except httpx.HTTPStatusError as e:
|
51 |
+
error_message = f"HTTP error: {e.response.status_code}"
|
52 |
+
try:
|
53 |
+
error_details = e.response.json()
|
54 |
+
error_message += f" - {json.dumps(error_details)}"
|
55 |
+
except json.JSONDecodeError:
|
56 |
+
error_message += f" - {e.response.text}"
|
57 |
+
return {"error": error_message}
|
58 |
+
except httpx.RequestError as e:
|
59 |
+
return {"error": f"Request error for {e.request.url!r}: {str(e)}"}
|
60 |
+
except Exception as e:
|
61 |
+
return {"error": f"An unexpected error occurred: {str(e)}"}
|
62 |
+
|
63 |
+
|
64 |
+
# Define Gradio inputs and outputs
|
65 |
+
tool_params_input = gr.Textbox(
|
66 |
+
label="Bandit Parameters (JSON string with 'code' field)",
|
67 |
+
placeholder='e.g., {\"code\": \"import os\nprint(os.listdir(\".\"))\"}',
|
68 |
+
lines=10,
|
69 |
+
info="Enter parameters as a valid JSON string. Must include a 'code' field containing the Python code to analyze."
|
70 |
+
)
|
71 |
+
output_display = gr.JSON(label="Bandit Analysis Output")
|
72 |
+
|
73 |
+
# Example for Bandit tool
|
74 |
+
bandit_example_code = """import subprocess\n\n# Example of a potential security risk with subprocess\nsubprocess.call("ls -l", shell=True)"""
|
75 |
+
bandit_example_params = json.dumps({"code": bandit_example_code}, indent=2)
|
76 |
+
|
77 |
+
# Create the Gradio interface
|
78 |
+
iface = gr.Interface(
|
79 |
+
fn=call_bandit_tool_on_modal,
|
80 |
+
inputs=[tool_params_input],
|
81 |
+
outputs=output_display,
|
82 |
+
title="Bandit Security Scanner Interface (via Modal MCP)",
|
83 |
+
description="""Interface with the Bandit security scanner tool hosted on Modal via the MCP server.
|
84 |
+
Provide Python code within a JSON structure under the 'code' key.
|
85 |
+
Ensure `MODAL_MCP_ENDPOINT` is correctly set in a .env file in the `mcp_deploy` directory or as an environment variable.
|
86 |
+
The endpoint should point to your Modal function that handles MCP tool execution (e.g., /execute_tool).""",
|
87 |
+
examples=[
|
88 |
+
[bandit_example_params]
|
89 |
+
],
|
90 |
+
allow_flagging="never"
|
91 |
+
)
|
92 |
+
|
93 |
+
if __name__ == "__main__":
|
94 |
+
print(f"Attempting to use Modal Endpoint for Bandit: {MODAL_MCP_ENDPOINT}")
|
95 |
+
if MODAL_MCP_ENDPOINT == "YOUR_MODAL_MCP_ENDPOINT_HERE" or not MODAL_MCP_ENDPOINT:
|
96 |
+
print("\nWARNING: MODAL_MCP_ENDPOINT is not configured. The app will show an error on submit.")
|
97 |
+
print("Please create a .env file in the 'mcp_deploy' directory with:")
|
98 |
+
print("MODAL_MCP_ENDPOINT=\"your_actual_modal_mcp_endpoint_url\"\n")
|
99 |
+
iface.launch(server_name="0.0.0.0") # mcp_server=True removed as it's not needed for this direct app
|