CHAN9IJI commited on
Commit
928aa38
Β·
verified Β·
1 Parent(s): 1c61ef6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -173
app.py CHANGED
@@ -4,6 +4,7 @@ import json
4
  import asyncio
5
  import subprocess
6
  import os
 
7
  from typing import Optional, Dict, Any, List
8
 
9
 
@@ -14,7 +15,7 @@ class MCPContextManager:
14
  self.context = []
15
  self.tools = {}
16
  self.resources = {}
17
- self.mcp_servers = {}
18
 
19
  def add_context(self, role: str, content: str, metadata: Optional[Dict] = None):
20
  """Add context entry following MCP specification"""
@@ -45,13 +46,17 @@ class MCPContextManager:
45
  "content": content
46
  }
47
 
48
- def register_mcp_server(self, server_name: str, config: Dict):
49
- """Register an MCP server configuration"""
50
- self.mcp_servers[server_name] = config
 
 
 
 
51
 
52
  def get_context_window(self, max_tokens: int = 4096) -> List[Dict]:
53
  """Get context window within token limits"""
54
- return self.context[-10:] # Simple implementation
55
 
56
  async def call_tool(self, tool_name: str, arguments: Dict) -> Any:
57
  """Execute a registered tool"""
@@ -77,37 +82,15 @@ class MCPContextManager:
77
  return json.dumps({
78
  "context": self.context,
79
  "tools": self.get_available_tools(),
80
- "resources": list(self.resources.keys()),
81
- "mcp_servers": list(self.mcp_servers.keys())
82
  }, indent=2)
83
 
84
 
85
  # Initialize MCP Manager
86
  mcp_manager = MCPContextManager()
87
 
88
- # Register MCP Servers (from your config)
89
- mcp_manager.register_mcp_server("postgres-full", {
90
- "command": "npx",
91
- "args": [
92
- "-y",
93
- "mcp-postgres-full-access",
94
- "postgresql://neondb_owner:npg_oGg8yphr6FeZ@ep-summer-art-a1jpcb05-pooler.ap-southeast-1.aws.neon.tech/neondb?sslmode=require&channel_binding=require"
95
- ],
96
- "env": {
97
- "TRANSACTION_TIMEOUT_MS": "60000",
98
- "MAX_CONCURRENT_TRANSACTIONS": "5",
99
- "PG_STATEMENT_TIMEOUT_MS": "30000"
100
- }
101
- })
102
-
103
- mcp_manager.register_mcp_server("filesystem", {
104
- "command": "npx",
105
- "args": [
106
- "-y",
107
- "@modelcontextprotocol/server-filesystem",
108
- "C:\\Users\\CHAN\\Documents\\PROJECTS"
109
- ]
110
- })
111
 
112
 
113
  # MCP Tool Handlers
@@ -147,23 +130,28 @@ async def memory_handler(args):
147
 
148
 
149
  async def web_search_handler(args):
150
- """Simulated web search handler"""
151
  query = args.get("query")
152
- return f"Search results for: {query} (MCP tool simulation)"
153
 
154
 
155
  async def git_command_handler(args):
156
  """Git command execution handler"""
157
  command = args.get("command", "")
158
- repo_path = args.get("repo_path", os.getcwd())
159
 
160
  try:
161
  # Security: Only allow specific safe git commands
162
- allowed_commands = ["status", "log", "branch", "diff", "commit", "push", "pull", "add"]
163
  cmd_parts = command.split()
164
 
165
- if not cmd_parts or cmd_parts[0] not in allowed_commands:
166
- return {"error": "Command not allowed or invalid"}
 
 
 
 
 
167
 
168
  # Execute git command
169
  result = subprocess.run(
@@ -178,66 +166,132 @@ async def git_command_handler(args):
178
  "stdout": result.stdout,
179
  "stderr": result.stderr,
180
  "returncode": result.returncode,
181
- "success": result.returncode == 0
 
 
182
  }
183
  except subprocess.TimeoutExpired:
184
- return {"error": "Command timed out"}
 
 
185
  except Exception as e:
186
  return {"error": str(e)}
187
 
188
 
189
  async def postgres_query_handler(args):
190
- """PostgreSQL query handler (simulated - would connect to your Neon DB)"""
191
  query = args.get("query", "")
192
- operation = args.get("operation", "SELECT")
193
 
194
- # Note: In production, this would actually connect to your Neon PostgreSQL
195
- # using the connection string from mcp_servers
196
- return {
197
- "message": f"Would execute {operation} query: {query}",
198
- "note": "Connect to: postgresql://neondb_owner@ep-summer-art-a1jpcb05-pooler.ap-southeast-1.aws.neon.tech/neondb",
199
- "status": "simulated"
200
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
 
203
  async def filesystem_handler(args):
204
  """Filesystem operations handler"""
205
- operation = args.get("operation") # read, write, list, search
206
  path = args.get("path", "")
207
  content = args.get("content", "")
208
 
209
  base_path = r"C:\Users\CHAN\Documents\PROJECTS"
210
- full_path = os.path.join(base_path, path)
 
 
 
 
 
 
 
211
 
212
  try:
213
  if operation == "read":
214
- if os.path.exists(full_path):
215
  with open(full_path, 'r', encoding='utf-8') as f:
216
- return {"content": f.read(), "success": True}
217
  return {"error": "File not found", "success": False}
218
 
219
  elif operation == "list":
220
- if os.path.exists(full_path):
221
- items = os.listdir(full_path)
222
- return {"items": items, "success": True}
 
 
 
 
 
 
 
223
  return {"error": "Directory not found", "success": False}
224
 
225
  elif operation == "write":
226
  with open(full_path, 'w', encoding='utf-8') as f:
227
  f.write(content)
228
- return {"message": "File written successfully", "success": True}
229
 
230
  elif operation == "search":
231
  pattern = args.get("pattern", "")
232
  results = []
233
- for root, dirs, files in os.walk(full_path if os.path.isdir(full_path) else base_path):
 
 
234
  for file in files:
235
  if pattern.lower() in file.lower():
236
  results.append(os.path.join(root, file))
 
 
 
237
  return {"results": results, "count": len(results), "success": True}
238
 
239
- return {"error": "Invalid operation", "success": False}
240
 
 
 
241
  except Exception as e:
242
  return {"error": str(e), "success": False}
243
 
@@ -245,13 +299,13 @@ async def filesystem_handler(args):
245
  # Register all tools with MCP manager
246
  mcp_manager.register_tool(
247
  name="calculator",
248
- description="Perform basic arithmetic operations",
249
  parameters={
250
  "type": "object",
251
  "properties": {
252
  "operation": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"]},
253
- "a": {"type": "number"},
254
- "b": {"type": "number"}
255
  },
256
  "required": ["operation", "a", "b"]
257
  },
@@ -260,13 +314,13 @@ mcp_manager.register_tool(
260
 
261
  mcp_manager.register_tool(
262
  name="memory",
263
- description="Store and retrieve information in memory",
264
  parameters={
265
  "type": "object",
266
  "properties": {
267
  "action": {"type": "string", "enum": ["store", "retrieve"]},
268
- "key": {"type": "string"},
269
- "value": {"type": "string"}
270
  },
271
  "required": ["action", "key"]
272
  },
@@ -279,7 +333,7 @@ mcp_manager.register_tool(
279
  parameters={
280
  "type": "object",
281
  "properties": {
282
- "query": {"type": "string"}
283
  },
284
  "required": ["query"]
285
  },
@@ -288,12 +342,12 @@ mcp_manager.register_tool(
288
 
289
  mcp_manager.register_tool(
290
  name="git",
291
- description="Execute git commands (status, log, commit, push, pull, add, branch, diff)",
292
  parameters={
293
  "type": "object",
294
  "properties": {
295
- "command": {"type": "string", "description": "Git command (e.g., 'status', 'commit -am \"message\"', 'push')"},
296
- "repo_path": {"type": "string", "description": "Repository path (optional)"}
297
  },
298
  "required": ["command"]
299
  },
@@ -302,12 +356,11 @@ mcp_manager.register_tool(
302
 
303
  mcp_manager.register_tool(
304
  name="postgres",
305
- description="Execute PostgreSQL queries on Neon database",
306
  parameters={
307
  "type": "object",
308
  "properties": {
309
- "query": {"type": "string"},
310
- "operation": {"type": "string", "enum": ["SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "ALTER"]}
311
  },
312
  "required": ["query"]
313
  },
@@ -316,14 +369,14 @@ mcp_manager.register_tool(
316
 
317
  mcp_manager.register_tool(
318
  name="filesystem",
319
- description="Perform filesystem operations (read, write, list, search)",
320
  parameters={
321
  "type": "object",
322
  "properties": {
323
- "operation": {"type": "string", "enum": ["read", "write", "list", "search"]},
324
- "path": {"type": "string"},
325
- "content": {"type": "string"},
326
- "pattern": {"type": "string"}
327
  },
328
  "required": ["operation", "path"]
329
  },
@@ -341,20 +394,15 @@ def respond(
341
  enable_mcp,
342
  hf_token: gr.OAuthToken,
343
  ):
344
- """
345
- Enhanced respond function with MCP support
346
- """
347
- # Add message to MCP context if enabled
348
  if enable_mcp:
349
  mcp_manager.add_context("user", message)
350
 
351
  client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
352
 
353
- # Build messages with MCP context
354
  messages = [{"role": "system", "content": system_message}]
355
 
356
  if enable_mcp:
357
- # Add MCP tools information to system message
358
  tools_info = "\n\nAvailable MCP Tools:\n" + json.dumps(mcp_manager.get_available_tools(), indent=2)
359
  messages[0]["content"] += tools_info
360
 
@@ -378,7 +426,6 @@ def respond(
378
  response += token
379
  yield response
380
 
381
- # Add response to MCP context if enabled
382
  if enable_mcp:
383
  mcp_manager.add_context("assistant", response)
384
 
@@ -386,9 +433,11 @@ def respond(
386
  def call_mcp_tool(tool_name: str, arguments_json: str):
387
  """Interface for calling MCP tools from UI"""
388
  try:
389
- arguments = json.loads(arguments_json) if arguments_json else {}
390
  result = asyncio.run(mcp_manager.call_tool(tool_name, arguments))
391
  return json.dumps({"success": True, "result": result}, indent=2)
 
 
392
  except Exception as e:
393
  return json.dumps({"success": False, "error": str(e)}, indent=2)
394
 
@@ -404,39 +453,40 @@ def get_mcp_tools_list():
404
  return json.dumps(tools, indent=2)
405
 
406
 
407
- def get_mcp_servers():
408
- """Get configured MCP servers"""
409
- return json.dumps(mcp_manager.mcp_servers, indent=2)
 
 
 
 
 
 
 
 
 
410
 
411
 
412
- """
413
- Enhanced Gradio interface with Model Context Protocol (MCP) support
414
- """
415
  chatbot = gr.ChatInterface(
416
  respond,
417
  type="messages",
418
  additional_inputs=[
419
  gr.Textbox(
420
- value="You are a powerful AI assistant with MCP tools including: Git operations, PostgreSQL database access (Neon), filesystem operations, calculator, memory, and web search.",
421
  label="System message",
422
  lines=3
423
  ),
424
  gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
425
  gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
426
- gr.Slider(
427
- minimum=0.1,
428
- maximum=1.0,
429
- value=0.95,
430
- step=0.05,
431
- label="Top-p (nucleus sampling)",
432
- ),
433
- gr.Checkbox(value=True, label="Enable MCP (Model Context Protocol)"),
434
  ],
435
  )
436
 
437
- with gr.Blocks(title="AI Chat with Full MCP Support") as demo:
438
- gr.Markdown("# πŸ€– AI Chatbot with Full Model Context Protocol (MCP)")
439
- gr.Markdown("✨ Connected to PostgreSQL (Neon), Filesystem, Git, and more!")
440
 
441
  with gr.Tabs():
442
  with gr.Tab("πŸ’¬ Chat"):
@@ -445,38 +495,47 @@ with gr.Blocks(title="AI Chat with Full MCP Support") as demo:
445
  chatbot.render()
446
 
447
  with gr.Tab("πŸ› οΈ MCP Tools"):
448
- gr.Markdown("### Available MCP Tools")
449
- tools_display = gr.Code(language="json", label="Registered Tools")
450
- refresh_tools_btn = gr.Button("πŸ”„ Refresh Tools List")
451
-
452
  gr.Markdown("### 🎯 Quick Actions")
 
453
  with gr.Row():
454
  with gr.Column():
455
- gr.Markdown("**Git Commands**")
456
- git_cmd = gr.Textbox(label="Git Command", placeholder="status")
457
- git_btn = gr.Button("Execute Git")
458
 
459
  with gr.Column():
460
- gr.Markdown("**Filesystem**")
461
- fs_operation = gr.Dropdown(["list", "read", "search"], label="Operation")
462
- fs_path = gr.Textbox(label="Path", placeholder="PROJECTS")
463
- fs_btn = gr.Button("Execute FS")
464
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  gr.Markdown("### πŸ”§ Custom Tool Call")
 
 
466
  with gr.Row():
467
- tool_name_input = gr.Textbox(label="Tool Name", placeholder="calculator")
468
  tool_args_input = gr.Code(
469
  label="Arguments (JSON)",
470
- value='{"operation": "add", "a": 5, "b": 3}',
471
  language="json",
472
  lines=5
473
  )
474
- call_tool_btn = gr.Button("▢️ Call Tool")
475
- tool_result = gr.Code(language="json", label="Tool Result", lines=10)
476
 
477
  # Event handlers
478
- refresh_tools_btn.click(fn=get_mcp_tools_list, outputs=tools_display)
479
-
480
  git_btn.click(
481
  fn=lambda cmd: call_mcp_tool("git", json.dumps({"command": cmd})),
482
  inputs=[git_cmd],
@@ -489,91 +548,77 @@ with gr.Blocks(title="AI Chat with Full MCP Support") as demo:
489
  outputs=tool_result
490
  )
491
 
 
 
 
 
 
 
 
 
 
 
 
492
  call_tool_btn.click(
493
  fn=call_mcp_tool,
494
  inputs=[tool_name_input, tool_args_input],
495
  outputs=tool_result
496
  )
497
 
498
- with gr.Tab("🌐 MCP Servers"):
499
- gr.Markdown("### Configured MCP Servers")
500
- servers_display = gr.Code(language="json", label="MCP Server Configuration")
501
- refresh_servers_btn = gr.Button("πŸ”„ Refresh Servers")
502
-
503
- refresh_servers_btn.click(fn=get_mcp_servers, outputs=servers_display)
504
-
505
- gr.Markdown("""
506
- #### Connected Servers:
507
- - **postgres-full**: Neon PostgreSQL Database
508
- - **filesystem**: Local file system access (C:\\Users\\CHAN\\Documents\\PROJECTS)
509
- """)
510
-
511
  with gr.Tab("πŸ“‹ MCP Context"):
512
  gr.Markdown("### Export MCP Context")
513
- gr.Markdown("View and export the current context window managed by MCP")
514
  export_btn = gr.Button("πŸ“₯ Export Context")
515
  context_display = gr.Code(language="json", label="MCP Context", lines=15)
516
 
517
  export_btn.click(fn=export_mcp_context, outputs=context_display)
518
 
519
- with gr.Tab("ℹ️ About MCP"):
520
  gr.Markdown("""
521
- ### Model Context Protocol (MCP)
522
 
523
- This AI assistant is powered by MCP with full access to:
 
 
 
524
 
525
- #### πŸ—„οΈ Database Access
526
- - **PostgreSQL (Neon)**: Full database operations
527
- - Connection: `ep-summer-art-a1jpcb05-pooler.ap-southeast-1.aws.neon.tech`
528
 
529
- #### πŸ“ Filesystem Access
530
- - **Root**: `C:\\Users\\CHAN\\Documents\\PROJECTS`
531
- - Operations: read, write, list, search
 
 
 
 
532
 
533
- #### πŸ”§ Available Tools:
534
- 1. **Git**: Execute git commands (status, commit, push, pull, etc.)
535
- 2. **PostgreSQL**: Query and manage your Neon database
536
- 3. **Filesystem**: Read/write files, list directories, search
537
- 4. **Calculator**: Perform arithmetic operations
538
- 5. **Memory**: Store and retrieve session data
539
- 6. **Web Search**: Search for information
540
 
541
- #### πŸ“– Example Commands:
 
 
 
542
 
543
- **Git:**
544
  ```json
545
- {
546
- "tool": "git",
547
- "arguments": {
548
- "command": "status"
549
- }
550
- }
551
  ```
552
 
553
- **Filesystem:**
554
  ```json
555
- {
556
- "tool": "filesystem",
557
- "arguments": {
558
- "operation": "list",
559
- "path": "PROJECTS"
560
- }
561
- }
562
  ```
563
 
564
- **PostgreSQL:**
565
  ```json
566
- {
567
- "tool": "postgres",
568
- "arguments": {
569
- "query": "SELECT * FROM users LIMIT 10",
570
- "operation": "SELECT"
571
- }
572
- }
573
  ```
574
  """)
575
 
576
 
577
  if __name__ == "__main__":
578
  demo.launch()
579
-
 
4
  import asyncio
5
  import subprocess
6
  import os
7
+ import psycopg2
8
  from typing import Optional, Dict, Any, List
9
 
10
 
 
15
  self.context = []
16
  self.tools = {}
17
  self.resources = {}
18
+ self.db_connection = None
19
 
20
  def add_context(self, role: str, content: str, metadata: Optional[Dict] = None):
21
  """Add context entry following MCP specification"""
 
46
  "content": content
47
  }
48
 
49
+ def connect_postgres(self, connection_string: str):
50
+ """Connect to PostgreSQL database"""
51
+ try:
52
+ self.db_connection = psycopg2.connect(connection_string)
53
+ return {"success": True, "message": "Connected to PostgreSQL"}
54
+ except Exception as e:
55
+ return {"success": False, "error": str(e)}
56
 
57
  def get_context_window(self, max_tokens: int = 4096) -> List[Dict]:
58
  """Get context window within token limits"""
59
+ return self.context[-10:]
60
 
61
  async def call_tool(self, tool_name: str, arguments: Dict) -> Any:
62
  """Execute a registered tool"""
 
82
  return json.dumps({
83
  "context": self.context,
84
  "tools": self.get_available_tools(),
85
+ "resources": list(self.resources.keys())
 
86
  }, indent=2)
87
 
88
 
89
  # Initialize MCP Manager
90
  mcp_manager = MCPContextManager()
91
 
92
+ # PostgreSQL Connection String (from your config)
93
+ POSTGRES_CONNECTION_STRING = "postgresql://neondb_owner:npg_oGg8yphr6FeZ@ep-summer-art-a1jpcb05-pooler.ap-southeast-1.aws.neon.tech/neondb?sslmode=require"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
 
96
  # MCP Tool Handlers
 
130
 
131
 
132
  async def web_search_handler(args):
133
+ """Web search handler"""
134
  query = args.get("query")
135
+ return f"Search results for: {query} (Integrated search coming soon)"
136
 
137
 
138
  async def git_command_handler(args):
139
  """Git command execution handler"""
140
  command = args.get("command", "")
141
+ repo_path = args.get("repo_path", r"C:\Users\CHAN\Documents\PROJECTS\PROJECTS\MODEL\SQL")
142
 
143
  try:
144
  # Security: Only allow specific safe git commands
145
+ allowed_commands = ["status", "log", "branch", "diff", "add", "commit", "push", "pull", "fetch"]
146
  cmd_parts = command.split()
147
 
148
+ if not cmd_parts:
149
+ return {"error": "No command provided"}
150
+
151
+ # Check if first word is an allowed command
152
+ base_cmd = cmd_parts[0]
153
+ if base_cmd not in allowed_commands:
154
+ return {"error": f"Command '{base_cmd}' not allowed. Allowed: {', '.join(allowed_commands)}"}
155
 
156
  # Execute git command
157
  result = subprocess.run(
 
166
  "stdout": result.stdout,
167
  "stderr": result.stderr,
168
  "returncode": result.returncode,
169
+ "success": result.returncode == 0,
170
+ "command": f"git {command}",
171
+ "repo": repo_path
172
  }
173
  except subprocess.TimeoutExpired:
174
+ return {"error": "Command timed out (30s limit)"}
175
+ except FileNotFoundError:
176
+ return {"error": "Git not found. Make sure git is installed."}
177
  except Exception as e:
178
  return {"error": str(e)}
179
 
180
 
181
  async def postgres_query_handler(args):
182
+ """PostgreSQL query handler - Direct connection to Neon DB"""
183
  query = args.get("query", "")
 
184
 
185
+ if not query:
186
+ return {"error": "No query provided"}
187
+
188
+ try:
189
+ # Connect to database
190
+ conn = psycopg2.connect(POSTGRES_CONNECTION_STRING)
191
+ cursor = conn.cursor()
192
+
193
+ # Execute query
194
+ cursor.execute(query)
195
+
196
+ # Check if it's a SELECT query
197
+ if query.strip().upper().startswith("SELECT"):
198
+ results = cursor.fetchall()
199
+ columns = [desc[0] for desc in cursor.description]
200
+
201
+ return {
202
+ "success": True,
203
+ "columns": columns,
204
+ "rows": results,
205
+ "row_count": len(results),
206
+ "data": [dict(zip(columns, row)) for row in results]
207
+ }
208
+ else:
209
+ # For INSERT, UPDATE, DELETE, etc.
210
+ conn.commit()
211
+ return {
212
+ "success": True,
213
+ "message": "Query executed successfully",
214
+ "rows_affected": cursor.rowcount
215
+ }
216
+
217
+ except psycopg2.Error as e:
218
+ return {
219
+ "success": False,
220
+ "error": str(e),
221
+ "error_type": "PostgreSQL Error"
222
+ }
223
+ except Exception as e:
224
+ return {
225
+ "success": False,
226
+ "error": str(e),
227
+ "error_type": "General Error"
228
+ }
229
+ finally:
230
+ if 'cursor' in locals():
231
+ cursor.close()
232
+ if 'conn' in locals():
233
+ conn.close()
234
 
235
 
236
  async def filesystem_handler(args):
237
  """Filesystem operations handler"""
238
+ operation = args.get("operation")
239
  path = args.get("path", "")
240
  content = args.get("content", "")
241
 
242
  base_path = r"C:\Users\CHAN\Documents\PROJECTS"
243
+
244
+ # Security: Ensure path is within base_path
245
+ if path:
246
+ full_path = os.path.normpath(os.path.join(base_path, path))
247
+ if not full_path.startswith(base_path):
248
+ return {"error": "Access denied: Path outside allowed directory", "success": False}
249
+ else:
250
+ full_path = base_path
251
 
252
  try:
253
  if operation == "read":
254
+ if os.path.exists(full_path) and os.path.isfile(full_path):
255
  with open(full_path, 'r', encoding='utf-8') as f:
256
+ return {"content": f.read(), "path": full_path, "success": True}
257
  return {"error": "File not found", "success": False}
258
 
259
  elif operation == "list":
260
+ if os.path.exists(full_path) and os.path.isdir(full_path):
261
+ items = []
262
+ for item in os.listdir(full_path):
263
+ item_path = os.path.join(full_path, item)
264
+ items.append({
265
+ "name": item,
266
+ "type": "directory" if os.path.isdir(item_path) else "file",
267
+ "size": os.path.getsize(item_path) if os.path.isfile(item_path) else None
268
+ })
269
+ return {"items": items, "count": len(items), "path": full_path, "success": True}
270
  return {"error": "Directory not found", "success": False}
271
 
272
  elif operation == "write":
273
  with open(full_path, 'w', encoding='utf-8') as f:
274
  f.write(content)
275
+ return {"message": "File written successfully", "path": full_path, "success": True}
276
 
277
  elif operation == "search":
278
  pattern = args.get("pattern", "")
279
  results = []
280
+ search_path = full_path if os.path.isdir(full_path) else base_path
281
+
282
+ for root, dirs, files in os.walk(search_path):
283
  for file in files:
284
  if pattern.lower() in file.lower():
285
  results.append(os.path.join(root, file))
286
+ if len(results) >= 50: # Limit results
287
+ break
288
+
289
  return {"results": results, "count": len(results), "success": True}
290
 
291
+ return {"error": "Invalid operation. Use: read, write, list, or search", "success": False}
292
 
293
+ except PermissionError:
294
+ return {"error": "Permission denied", "success": False}
295
  except Exception as e:
296
  return {"error": str(e), "success": False}
297
 
 
299
  # Register all tools with MCP manager
300
  mcp_manager.register_tool(
301
  name="calculator",
302
+ description="Perform basic arithmetic operations (add, subtract, multiply, divide)",
303
  parameters={
304
  "type": "object",
305
  "properties": {
306
  "operation": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"]},
307
+ "a": {"type": "number", "description": "First number"},
308
+ "b": {"type": "number", "description": "Second number"}
309
  },
310
  "required": ["operation", "a", "b"]
311
  },
 
314
 
315
  mcp_manager.register_tool(
316
  name="memory",
317
+ description="Store and retrieve information in session memory",
318
  parameters={
319
  "type": "object",
320
  "properties": {
321
  "action": {"type": "string", "enum": ["store", "retrieve"]},
322
+ "key": {"type": "string", "description": "Memory key"},
323
+ "value": {"type": "string", "description": "Value to store (required for 'store')"}
324
  },
325
  "required": ["action", "key"]
326
  },
 
333
  parameters={
334
  "type": "object",
335
  "properties": {
336
+ "query": {"type": "string", "description": "Search query"}
337
  },
338
  "required": ["query"]
339
  },
 
342
 
343
  mcp_manager.register_tool(
344
  name="git",
345
+ description="Execute git commands (status, log, commit, push, pull, add, branch, diff, fetch). Example: 'status' or 'commit -am \"message\"'",
346
  parameters={
347
  "type": "object",
348
  "properties": {
349
+ "command": {"type": "string", "description": "Git command (without 'git' prefix)"},
350
+ "repo_path": {"type": "string", "description": "Repository path (optional, defaults to MODEL/SQL)"}
351
  },
352
  "required": ["command"]
353
  },
 
356
 
357
  mcp_manager.register_tool(
358
  name="postgres",
359
+ description="Execute PostgreSQL queries on Neon database. Supports SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, etc.",
360
  parameters={
361
  "type": "object",
362
  "properties": {
363
+ "query": {"type": "string", "description": "SQL query to execute"}
 
364
  },
365
  "required": ["query"]
366
  },
 
369
 
370
  mcp_manager.register_tool(
371
  name="filesystem",
372
+ description="Perform filesystem operations within C:\\Users\\CHAN\\Documents\\PROJECTS",
373
  parameters={
374
  "type": "object",
375
  "properties": {
376
+ "operation": {"type": "string", "enum": ["read", "write", "list", "search"], "description": "Operation to perform"},
377
+ "path": {"type": "string", "description": "Relative path from PROJECTS folder"},
378
+ "content": {"type": "string", "description": "Content for write operation"},
379
+ "pattern": {"type": "string", "description": "Search pattern (for search operation)"}
380
  },
381
  "required": ["operation", "path"]
382
  },
 
394
  enable_mcp,
395
  hf_token: gr.OAuthToken,
396
  ):
397
+ """Enhanced respond function with MCP support"""
 
 
 
398
  if enable_mcp:
399
  mcp_manager.add_context("user", message)
400
 
401
  client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
402
 
 
403
  messages = [{"role": "system", "content": system_message}]
404
 
405
  if enable_mcp:
 
406
  tools_info = "\n\nAvailable MCP Tools:\n" + json.dumps(mcp_manager.get_available_tools(), indent=2)
407
  messages[0]["content"] += tools_info
408
 
 
426
  response += token
427
  yield response
428
 
 
429
  if enable_mcp:
430
  mcp_manager.add_context("assistant", response)
431
 
 
433
  def call_mcp_tool(tool_name: str, arguments_json: str):
434
  """Interface for calling MCP tools from UI"""
435
  try:
436
+ arguments = json.loads(arguments_json) if arguments_json.strip() else {}
437
  result = asyncio.run(mcp_manager.call_tool(tool_name, arguments))
438
  return json.dumps({"success": True, "result": result}, indent=2)
439
+ except json.JSONDecodeError as e:
440
+ return json.dumps({"success": False, "error": f"Invalid JSON: {str(e)}"}, indent=2)
441
  except Exception as e:
442
  return json.dumps({"success": False, "error": str(e)}, indent=2)
443
 
 
453
  return json.dumps(tools, indent=2)
454
 
455
 
456
+ def test_postgres_connection():
457
+ """Test PostgreSQL connection"""
458
+ try:
459
+ conn = psycopg2.connect(POSTGRES_CONNECTION_STRING)
460
+ cursor = conn.cursor()
461
+ cursor.execute("SELECT version();")
462
+ version = cursor.fetchone()[0]
463
+ cursor.close()
464
+ conn.close()
465
+ return json.dumps({"success": True, "message": "Connected!", "version": version}, indent=2)
466
+ except Exception as e:
467
+ return json.dumps({"success": False, "error": str(e)}, indent=2)
468
 
469
 
470
+ # Gradio Interface
 
 
471
  chatbot = gr.ChatInterface(
472
  respond,
473
  type="messages",
474
  additional_inputs=[
475
  gr.Textbox(
476
+ value="You are a powerful AI assistant with MCP tools: Git, PostgreSQL (Neon), Filesystem, Calculator, Memory, Web Search.",
477
  label="System message",
478
  lines=3
479
  ),
480
  gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
481
  gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
482
+ gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p"),
483
+ gr.Checkbox(value=True, label="Enable MCP"),
 
 
 
 
 
 
484
  ],
485
  )
486
 
487
+ with gr.Blocks(title="AI Chat with Full MCP") as demo:
488
+ gr.Markdown("# πŸ€– AI Chatbot with Full MCP Support")
489
+ gr.Markdown("✨ PostgreSQL (Neon) β€’ Git β€’ Filesystem β€’ Calculator β€’ Memory β€’ Web Search")
490
 
491
  with gr.Tabs():
492
  with gr.Tab("πŸ’¬ Chat"):
 
495
  chatbot.render()
496
 
497
  with gr.Tab("πŸ› οΈ MCP Tools"):
 
 
 
 
498
  gr.Markdown("### 🎯 Quick Actions")
499
+
500
  with gr.Row():
501
  with gr.Column():
502
+ gr.Markdown("**πŸ”§ Git Commands**")
503
+ git_cmd = gr.Textbox(label="Command", placeholder="status", value="status")
504
+ git_btn = gr.Button("Execute Git", variant="primary")
505
 
506
  with gr.Column():
507
+ gr.Markdown("**πŸ“ Filesystem**")
508
+ fs_operation = gr.Dropdown(["list", "read", "search"], label="Operation", value="list")
509
+ fs_path = gr.Textbox(label="Path", placeholder="PROJECTS", value="")
510
+ fs_btn = gr.Button("Execute FS", variant="primary")
511
 
512
+ with gr.Row():
513
+ with gr.Column():
514
+ gr.Markdown("**πŸ—„οΈ PostgreSQL**")
515
+ pg_query = gr.Textbox(label="SQL Query", placeholder="SELECT * FROM users LIMIT 5", lines=2)
516
+ pg_btn = gr.Button("Execute SQL", variant="primary")
517
+
518
+ with gr.Column():
519
+ gr.Markdown("**πŸ”Œ Test Connection**")
520
+ test_pg_btn = gr.Button("Test PostgreSQL Connection")
521
+
522
+ tool_result = gr.Code(language="json", label="πŸ“Š Result", lines=15)
523
+
524
+ gr.Markdown("---")
525
  gr.Markdown("### πŸ”§ Custom Tool Call")
526
+ gr.Markdown("**Available Tools:** calculator, memory, web_search, git, postgres, filesystem")
527
+
528
  with gr.Row():
529
+ tool_name_input = gr.Textbox(label="Tool Name", placeholder="calculator", value="calculator")
530
  tool_args_input = gr.Code(
531
  label="Arguments (JSON)",
532
+ value='{"operation": "add", "a": 10, "b": 5}',
533
  language="json",
534
  lines=5
535
  )
536
+ call_tool_btn = gr.Button("▢️ Call Tool", variant="secondary")
 
537
 
538
  # Event handlers
 
 
539
  git_btn.click(
540
  fn=lambda cmd: call_mcp_tool("git", json.dumps({"command": cmd})),
541
  inputs=[git_cmd],
 
548
  outputs=tool_result
549
  )
550
 
551
+ pg_btn.click(
552
+ fn=lambda query: call_mcp_tool("postgres", json.dumps({"query": query})),
553
+ inputs=[pg_query],
554
+ outputs=tool_result
555
+ )
556
+
557
+ test_pg_btn.click(
558
+ fn=test_postgres_connection,
559
+ outputs=tool_result
560
+ )
561
+
562
  call_tool_btn.click(
563
  fn=call_mcp_tool,
564
  inputs=[tool_name_input, tool_args_input],
565
  outputs=tool_result
566
  )
567
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  with gr.Tab("πŸ“‹ MCP Context"):
569
  gr.Markdown("### Export MCP Context")
 
570
  export_btn = gr.Button("πŸ“₯ Export Context")
571
  context_display = gr.Code(language="json", label="MCP Context", lines=15)
572
 
573
  export_btn.click(fn=export_mcp_context, outputs=context_display)
574
 
575
+ with gr.Tab("ℹ️ About"):
576
  gr.Markdown("""
577
+ ### Model Context Protocol (MCP) - Full Integration
578
 
579
+ #### πŸ—„οΈ Database: PostgreSQL (Neon)
580
+ - **Host:** ep-summer-art-a1jpcb05-pooler.ap-southeast-1.aws.neon.tech
581
+ - **Database:** neondb
582
+ - **Direct Connection:** βœ… Active
583
 
584
+ #### πŸ“ Filesystem
585
+ - **Root:** C:\\Users\\CHAN\\Documents\\PROJECTS
586
+ - **Operations:** read, write, list, search
587
 
588
+ #### πŸ”§ Tools (6):
589
+ 1. **Git** - Version control operations
590
+ 2. **PostgreSQL** - Database queries
591
+ 3. **Filesystem** - File operations
592
+ 4. **Calculator** - Math operations
593
+ 5. **Memory** - Session storage
594
+ 6. **Web Search** - Information retrieval
595
 
596
+ #### πŸ“– Examples:
 
 
 
 
 
 
597
 
598
+ **Git Status:**
599
+ ```json
600
+ {"command": "status"}
601
+ ```
602
 
603
+ **Git Commit & Push:**
604
  ```json
605
+ {"command": "commit -am 'Update'"}
606
+ ```
607
+ Then: ```json
608
+ {"command": "push"}
 
 
609
  ```
610
 
611
+ **PostgreSQL Query:**
612
  ```json
613
+ {"query": "SELECT * FROM information_schema.tables LIMIT 5"}
 
 
 
 
 
 
614
  ```
615
 
616
+ **List Files:**
617
  ```json
618
+ {"operation": "list", "path": "PROJECTS"}
 
 
 
 
 
 
619
  ```
620
  """)
621
 
622
 
623
  if __name__ == "__main__":
624
  demo.launch()