kite-agent 0.1.0__py3-none-any.whl
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.
- kite/__init__.py +46 -0
- kite/ab_testing.py +384 -0
- kite/agent.py +556 -0
- kite/agents/__init__.py +3 -0
- kite/agents/plan_execute.py +191 -0
- kite/agents/react_agent.py +509 -0
- kite/agents/reflective_agent.py +90 -0
- kite/agents/rewoo.py +119 -0
- kite/agents/tot.py +151 -0
- kite/conversation.py +125 -0
- kite/core.py +974 -0
- kite/data_loaders.py +111 -0
- kite/embedding_providers.py +372 -0
- kite/llm_providers.py +1278 -0
- kite/memory/__init__.py +6 -0
- kite/memory/advanced_rag.py +333 -0
- kite/memory/graph_rag.py +719 -0
- kite/memory/session_memory.py +423 -0
- kite/memory/vector_memory.py +579 -0
- kite/monitoring.py +611 -0
- kite/observers.py +107 -0
- kite/optimization/__init__.py +9 -0
- kite/optimization/resource_router.py +80 -0
- kite/persistence.py +42 -0
- kite/pipeline/__init__.py +5 -0
- kite/pipeline/deterministic_pipeline.py +323 -0
- kite/pipeline/reactive_pipeline.py +171 -0
- kite/pipeline_manager.py +15 -0
- kite/routing/__init__.py +6 -0
- kite/routing/aggregator_router.py +325 -0
- kite/routing/llm_router.py +149 -0
- kite/routing/semantic_router.py +228 -0
- kite/safety/__init__.py +6 -0
- kite/safety/circuit_breaker.py +360 -0
- kite/safety/guardrails.py +82 -0
- kite/safety/idempotency_manager.py +304 -0
- kite/safety/kill_switch.py +75 -0
- kite/tool.py +183 -0
- kite/tool_registry.py +87 -0
- kite/tools/__init__.py +21 -0
- kite/tools/code_execution.py +53 -0
- kite/tools/contrib/__init__.py +19 -0
- kite/tools/contrib/calculator.py +26 -0
- kite/tools/contrib/datetime_utils.py +20 -0
- kite/tools/contrib/linkedin.py +428 -0
- kite/tools/contrib/web_search.py +30 -0
- kite/tools/mcp/__init__.py +31 -0
- kite/tools/mcp/database_mcp.py +267 -0
- kite/tools/mcp/gdrive_mcp_server.py +503 -0
- kite/tools/mcp/gmail_mcp_server.py +601 -0
- kite/tools/mcp/postgres_mcp_server.py +490 -0
- kite/tools/mcp/slack_mcp_server.py +538 -0
- kite/tools/mcp/stripe_mcp_server.py +219 -0
- kite/tools/search.py +90 -0
- kite/tools/system_tools.py +54 -0
- kite/tools_manager.py +27 -0
- kite_agent-0.1.0.dist-info/METADATA +621 -0
- kite_agent-0.1.0.dist-info/RECORD +61 -0
- kite_agent-0.1.0.dist-info/WHEEL +5 -0
- kite_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
- kite_agent-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Google Drive MCP Server Implementation
|
|
3
|
+
Based on Chapter 4: MCP (Model Context Protocol)
|
|
4
|
+
|
|
5
|
+
Allows AI agents to interact with Google Drive.
|
|
6
|
+
|
|
7
|
+
Tools provided:
|
|
8
|
+
- search_files: Search for files
|
|
9
|
+
- read_file: Read file content
|
|
10
|
+
- list_folder: List folder contents
|
|
11
|
+
- get_file_metadata: Get file details
|
|
12
|
+
|
|
13
|
+
Run: python gdrive_mcp_server.py
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import json
|
|
18
|
+
from typing import Dict, List, Optional, Any
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from dotenv import load_dotenv
|
|
22
|
+
|
|
23
|
+
load_dotenv()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# CONFIGURATION
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class GDriveConfig:
|
|
32
|
+
"""Configuration for Google Drive MCP server."""
|
|
33
|
+
credentials_path: str = ""
|
|
34
|
+
|
|
35
|
+
# Safety limits
|
|
36
|
+
max_file_size_mb: int = 10
|
|
37
|
+
max_search_results: int = 50
|
|
38
|
+
rate_limit_per_minute: int = 100
|
|
39
|
+
|
|
40
|
+
# Allowed operations
|
|
41
|
+
enable_read: bool = True
|
|
42
|
+
enable_search: bool = True
|
|
43
|
+
enable_list: bool = True
|
|
44
|
+
|
|
45
|
+
# File type restrictions
|
|
46
|
+
allowed_mime_types: Optional[List[str]] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ============================================================================
|
|
50
|
+
# GOOGLE DRIVE MCP SERVER
|
|
51
|
+
# ============================================================================
|
|
52
|
+
|
|
53
|
+
class GoogleDriveMCPServer:
|
|
54
|
+
"""
|
|
55
|
+
MCP Server for Google Drive integration.
|
|
56
|
+
|
|
57
|
+
Provides tools for AI agents to search and read Google Drive files.
|
|
58
|
+
|
|
59
|
+
Requires: google-api-python-client, google-auth-httplib2, google-auth-oauthlib
|
|
60
|
+
Install: pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
|
|
61
|
+
|
|
62
|
+
Setup:
|
|
63
|
+
1. Enable Google Drive API in Google Cloud Console
|
|
64
|
+
2. Download credentials.json
|
|
65
|
+
3. Run authentication flow to get token
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
from googleapiclient.discovery import build
|
|
69
|
+
from google.oauth2.credentials import Credentials
|
|
70
|
+
|
|
71
|
+
config = GDriveConfig(credentials_path='~/.gdrive_credentials.json')
|
|
72
|
+
server = GoogleDriveMCPServer(config)
|
|
73
|
+
|
|
74
|
+
# Search files
|
|
75
|
+
results = server.search_files("Q4 strategy")
|
|
76
|
+
|
|
77
|
+
# Read file
|
|
78
|
+
content = server.read_file("file1")
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, config: GDriveConfig = None, credentials_path: str = "", **kwargs):
|
|
82
|
+
self.config = config or GDriveConfig()
|
|
83
|
+
if credentials_path:
|
|
84
|
+
self.config.credentials_path = credentials_path
|
|
85
|
+
|
|
86
|
+
# Initialize Drive client (requires Google API client)
|
|
87
|
+
try:
|
|
88
|
+
from googleapiclient.discovery import build
|
|
89
|
+
from google.oauth2.credentials import Credentials
|
|
90
|
+
from google.auth.transport.requests import Request
|
|
91
|
+
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
92
|
+
import os
|
|
93
|
+
import pickle
|
|
94
|
+
|
|
95
|
+
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
|
|
96
|
+
|
|
97
|
+
creds = None
|
|
98
|
+
token_path = os.path.expanduser('~/.gdrive_token.pickle')
|
|
99
|
+
|
|
100
|
+
# Load existing token
|
|
101
|
+
if os.path.exists(token_path):
|
|
102
|
+
with open(token_path, 'rb') as token:
|
|
103
|
+
creds = pickle.load(token)
|
|
104
|
+
|
|
105
|
+
# Refresh or get new credentials
|
|
106
|
+
if not creds or not creds.valid:
|
|
107
|
+
if creds and creds.expired and creds.refresh_token:
|
|
108
|
+
creds.refresh(Request())
|
|
109
|
+
elif self.config.credentials_path and os.path.exists(self.config.credentials_path):
|
|
110
|
+
flow = InstalledAppFlow.from_client_secrets_file(
|
|
111
|
+
self.config.credentials_path, SCOPES)
|
|
112
|
+
creds = flow.run_local_server(port=0)
|
|
113
|
+
else:
|
|
114
|
+
raise Exception("Google Drive credentials not found. Please provide credentials_path")
|
|
115
|
+
|
|
116
|
+
# Save token
|
|
117
|
+
with open(token_path, 'wb') as token:
|
|
118
|
+
pickle.dump(creds, token)
|
|
119
|
+
|
|
120
|
+
self.drive = build('drive', 'v3', credentials=creds)
|
|
121
|
+
|
|
122
|
+
except ImportError:
|
|
123
|
+
raise ImportError(
|
|
124
|
+
"Google API client is required for GoogleDriveMCPServer. "
|
|
125
|
+
"Install with: pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib"
|
|
126
|
+
)
|
|
127
|
+
except Exception as e:
|
|
128
|
+
raise Exception(f"Failed to initialize Google Drive client: {e}")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Rate limiting
|
|
132
|
+
self.request_count = 0
|
|
133
|
+
self.window_start = datetime.now()
|
|
134
|
+
|
|
135
|
+
print(f"[OK] Google Drive MCP Server initialized")
|
|
136
|
+
print(f" Rate limit: {self.config.rate_limit_per_minute}/min")
|
|
137
|
+
print(f" Max file size: {self.config.max_file_size_mb}MB")
|
|
138
|
+
|
|
139
|
+
def _check_rate_limit(self) -> bool:
|
|
140
|
+
"""Check rate limit."""
|
|
141
|
+
now = datetime.now()
|
|
142
|
+
|
|
143
|
+
if (now - self.window_start).seconds >= 60:
|
|
144
|
+
self.request_count = 0
|
|
145
|
+
self.window_start = now
|
|
146
|
+
|
|
147
|
+
if self.request_count >= self.config.rate_limit_per_minute:
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
self.request_count += 1
|
|
151
|
+
return True
|
|
152
|
+
|
|
153
|
+
def _is_mime_type_allowed(self, mime_type: str) -> bool:
|
|
154
|
+
"""Check if MIME type is allowed."""
|
|
155
|
+
if self.config.allowed_mime_types is None:
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
return mime_type in self.config.allowed_mime_types
|
|
159
|
+
|
|
160
|
+
def search_files(
|
|
161
|
+
self,
|
|
162
|
+
query: str,
|
|
163
|
+
max_results: int = 10
|
|
164
|
+
) -> Dict[str, Any]:
|
|
165
|
+
"""
|
|
166
|
+
Search for files in Google Drive.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
query: Search query
|
|
170
|
+
max_results: Maximum results to return
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Search results
|
|
174
|
+
"""
|
|
175
|
+
print(f"\n Searching Drive: {query}")
|
|
176
|
+
|
|
177
|
+
if not self.config.enable_search:
|
|
178
|
+
return {
|
|
179
|
+
"success": False,
|
|
180
|
+
"error": "Search is disabled"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if not self._check_rate_limit():
|
|
184
|
+
return {
|
|
185
|
+
"success": False,
|
|
186
|
+
"error": "Rate limit exceeded"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
results = self.drive.files_list(
|
|
191
|
+
q=query,
|
|
192
|
+
pageSize=min(max_results, self.config.max_search_results)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
files = results.get("files", [])
|
|
196
|
+
|
|
197
|
+
# Filter by allowed MIME types
|
|
198
|
+
filtered_files = []
|
|
199
|
+
for file in files:
|
|
200
|
+
if self._is_mime_type_allowed(file.get("mimeType", "")):
|
|
201
|
+
filtered_files.append({
|
|
202
|
+
"id": file["id"],
|
|
203
|
+
"name": file["name"],
|
|
204
|
+
"mimeType": file["mimeType"],
|
|
205
|
+
"size": file.get("size", 0),
|
|
206
|
+
"modifiedTime": file.get("modifiedTime"),
|
|
207
|
+
"owners": file.get("owners", [])
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
print(f" [OK] Found {len(filtered_files)} files")
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
"success": True,
|
|
214
|
+
"query": query,
|
|
215
|
+
"files": filtered_files,
|
|
216
|
+
"count": len(filtered_files)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
except Exception as e:
|
|
220
|
+
print(f" Error: {e}")
|
|
221
|
+
return {
|
|
222
|
+
"success": False,
|
|
223
|
+
"error": str(e)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
def read_file(self, file_id: str) -> Dict[str, Any]:
|
|
227
|
+
"""
|
|
228
|
+
Read file content from Google Drive.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
file_id: Google Drive file ID
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
File content
|
|
235
|
+
"""
|
|
236
|
+
print(f"\n Reading file: {file_id}")
|
|
237
|
+
|
|
238
|
+
if not self.config.enable_read:
|
|
239
|
+
return {
|
|
240
|
+
"success": False,
|
|
241
|
+
"error": "Read is disabled"
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if not self._check_rate_limit():
|
|
245
|
+
return {
|
|
246
|
+
"success": False,
|
|
247
|
+
"error": "Rate limit exceeded"
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
# Get file metadata first
|
|
252
|
+
metadata = self.drive.files_get(fileId=file_id)
|
|
253
|
+
|
|
254
|
+
# Check MIME type
|
|
255
|
+
if not self._is_mime_type_allowed(metadata.get("mimeType", "")):
|
|
256
|
+
return {
|
|
257
|
+
"success": False,
|
|
258
|
+
"error": f"MIME type not allowed: {metadata.get('mimeType')}"
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# Check file size
|
|
262
|
+
size_mb = metadata.get("size", 0) / (1024 * 1024)
|
|
263
|
+
if size_mb > self.config.max_file_size_mb:
|
|
264
|
+
return {
|
|
265
|
+
"success": False,
|
|
266
|
+
"error": f"File too large: {size_mb:.1f}MB > {self.config.max_file_size_mb}MB"
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# Read content
|
|
270
|
+
content = self.drive.files_get_media(fileId=file_id)
|
|
271
|
+
|
|
272
|
+
print(f" [OK] Read {len(content)} characters")
|
|
273
|
+
|
|
274
|
+
return {
|
|
275
|
+
"success": True,
|
|
276
|
+
"file_id": file_id,
|
|
277
|
+
"name": metadata.get("name"),
|
|
278
|
+
"content": content,
|
|
279
|
+
"metadata": {
|
|
280
|
+
"mimeType": metadata.get("mimeType"),
|
|
281
|
+
"size": metadata.get("size"),
|
|
282
|
+
"modifiedTime": metadata.get("modifiedTime"),
|
|
283
|
+
"owners": metadata.get("owners", [])
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
except Exception as e:
|
|
288
|
+
print(f" Error: {e}")
|
|
289
|
+
return {
|
|
290
|
+
"success": False,
|
|
291
|
+
"error": str(e)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
def get_file_metadata(self, file_id: str) -> Dict[str, Any]:
|
|
295
|
+
"""
|
|
296
|
+
Get file metadata without reading content.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
file_id: Google Drive file ID
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
File metadata
|
|
303
|
+
"""
|
|
304
|
+
print(f"\n[CHART] Getting metadata: {file_id}")
|
|
305
|
+
|
|
306
|
+
if not self._check_rate_limit():
|
|
307
|
+
return {
|
|
308
|
+
"success": False,
|
|
309
|
+
"error": "Rate limit exceeded"
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try:
|
|
313
|
+
metadata = self.drive.files_get(fileId=file_id)
|
|
314
|
+
|
|
315
|
+
print(f" [OK] Retrieved metadata for: {metadata.get('name')}")
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
"success": True,
|
|
319
|
+
"file_id": file_id,
|
|
320
|
+
"metadata": {
|
|
321
|
+
"name": metadata.get("name"),
|
|
322
|
+
"mimeType": metadata.get("mimeType"),
|
|
323
|
+
"size": metadata.get("size"),
|
|
324
|
+
"createdTime": metadata.get("createdTime"),
|
|
325
|
+
"modifiedTime": metadata.get("modifiedTime"),
|
|
326
|
+
"owners": metadata.get("owners", []),
|
|
327
|
+
"parents": metadata.get("parents", [])
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
except Exception as e:
|
|
332
|
+
print(f" Error: {e}")
|
|
333
|
+
return {
|
|
334
|
+
"success": False,
|
|
335
|
+
"error": str(e)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
def get_tool_definitions(self) -> List[Dict]:
|
|
339
|
+
"""Get MCP tool definitions for AI agents."""
|
|
340
|
+
tools = []
|
|
341
|
+
|
|
342
|
+
if self.config.enable_search:
|
|
343
|
+
tools.append({
|
|
344
|
+
"name": "gdrive_search_files",
|
|
345
|
+
"description": "Search for files in Google Drive by keyword or content",
|
|
346
|
+
"input_schema": {
|
|
347
|
+
"type": "object",
|
|
348
|
+
"properties": {
|
|
349
|
+
"query": {
|
|
350
|
+
"type": "string",
|
|
351
|
+
"description": "Search query (keywords, file names, content)"
|
|
352
|
+
},
|
|
353
|
+
"max_results": {
|
|
354
|
+
"type": "integer",
|
|
355
|
+
"description": "Maximum number of results",
|
|
356
|
+
"default": 10
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"required": ["query"]
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
if self.config.enable_read:
|
|
364
|
+
tools.append({
|
|
365
|
+
"name": "gdrive_read_file",
|
|
366
|
+
"description": "Read the content of a Google Drive file",
|
|
367
|
+
"input_schema": {
|
|
368
|
+
"type": "object",
|
|
369
|
+
"properties": {
|
|
370
|
+
"file_id": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"description": "Google Drive file ID"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"required": ["file_id"]
|
|
376
|
+
}
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
tools.append({
|
|
380
|
+
"name": "gdrive_get_metadata",
|
|
381
|
+
"description": "Get metadata about a Google Drive file without reading its content",
|
|
382
|
+
"input_schema": {
|
|
383
|
+
"type": "object",
|
|
384
|
+
"properties": {
|
|
385
|
+
"file_id": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"description": "Google Drive file ID"
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
"required": ["file_id"]
|
|
391
|
+
}
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
return tools
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# ============================================================================
|
|
398
|
+
# DEMO
|
|
399
|
+
# ============================================================================
|
|
400
|
+
|
|
401
|
+
def demo():
|
|
402
|
+
print("=" * 70)
|
|
403
|
+
print("GOOGLE DRIVE MCP SERVER DEMO")
|
|
404
|
+
print("=" * 70)
|
|
405
|
+
print("\nBased on Chapter 4: Model Context Protocol")
|
|
406
|
+
print("Allows AI agents to search and read Google Drive files\n")
|
|
407
|
+
print("=" * 70)
|
|
408
|
+
|
|
409
|
+
# Initialize server
|
|
410
|
+
config = GDriveConfig(
|
|
411
|
+
max_file_size_mb=10,
|
|
412
|
+
enable_read=True,
|
|
413
|
+
enable_search=True
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
server = GDriveMCPServer(config)
|
|
417
|
+
|
|
418
|
+
# Demo 1: Search files
|
|
419
|
+
print(f"\n{'='*70}")
|
|
420
|
+
print("DEMO 1: Search for files")
|
|
421
|
+
print('='*70)
|
|
422
|
+
|
|
423
|
+
result = server.search_files("Project Zeus")
|
|
424
|
+
if result["success"]:
|
|
425
|
+
print(f"\nFound {result['count']} files matching '{result['query']}':")
|
|
426
|
+
for file in result["files"]:
|
|
427
|
+
print(f"\n {file['name']}")
|
|
428
|
+
print(f" ID: {file['id']}")
|
|
429
|
+
print(f" Type: {file['mimeType']}")
|
|
430
|
+
print(f" Modified: {file.get('modifiedTime', 'N/A')}")
|
|
431
|
+
|
|
432
|
+
# Demo 2: Read file content
|
|
433
|
+
print(f"\n{'='*70}")
|
|
434
|
+
print("DEMO 2: Read file content")
|
|
435
|
+
print('='*70)
|
|
436
|
+
|
|
437
|
+
result = server.read_file("file1")
|
|
438
|
+
if result["success"]:
|
|
439
|
+
print(f"\n File: {result['name']}")
|
|
440
|
+
print(f" Size: {result['metadata']['size']} bytes")
|
|
441
|
+
print(f"\n Content preview:")
|
|
442
|
+
print(" " + " " * 66)
|
|
443
|
+
preview = result['content'][:300] + "..." if len(result['content']) > 300 else result['content']
|
|
444
|
+
for line in preview.split('\n'):
|
|
445
|
+
print(f" {line}")
|
|
446
|
+
print(" " + " " * 66)
|
|
447
|
+
|
|
448
|
+
# Demo 3: Get metadata only
|
|
449
|
+
print(f"\n{'='*70}")
|
|
450
|
+
print("DEMO 3: Get file metadata")
|
|
451
|
+
print('='*70)
|
|
452
|
+
|
|
453
|
+
result = server.get_file_metadata("file2")
|
|
454
|
+
if result["success"]:
|
|
455
|
+
meta = result["metadata"]
|
|
456
|
+
print(f"\n[CHART] Metadata for: {meta['name']}")
|
|
457
|
+
print(f" Type: {meta['mimeType']}")
|
|
458
|
+
print(f" Size: {meta['size']} bytes")
|
|
459
|
+
print(f" Created: {meta['createdTime']}")
|
|
460
|
+
print(f" Modified: {meta['modifiedTime']}")
|
|
461
|
+
print(f" Owners: {', '.join(o['displayName'] for o in meta['owners'])}")
|
|
462
|
+
|
|
463
|
+
# Show tool definitions
|
|
464
|
+
print(f"\n{'='*70}")
|
|
465
|
+
print("MCP TOOL DEFINITIONS")
|
|
466
|
+
print('='*70)
|
|
467
|
+
|
|
468
|
+
tools = server.get_tool_definitions()
|
|
469
|
+
print(f"\nAvailable tools: {len(tools)}")
|
|
470
|
+
for tool in tools:
|
|
471
|
+
print(f"\n {tool['name']}")
|
|
472
|
+
print(f" {tool['description']}")
|
|
473
|
+
|
|
474
|
+
print("\n" + "="*70)
|
|
475
|
+
print("USAGE WITH AI AGENT")
|
|
476
|
+
print("="*70)
|
|
477
|
+
print("""
|
|
478
|
+
# In your agent code:
|
|
479
|
+
from gdrive_mcp_server import GDriveMCPServer, GDriveConfig
|
|
480
|
+
|
|
481
|
+
# Initialize
|
|
482
|
+
server = GDriveMCPServer(GDriveConfig())
|
|
483
|
+
|
|
484
|
+
# Get tools for agent
|
|
485
|
+
tools = server.get_tool_definitions()
|
|
486
|
+
|
|
487
|
+
# When agent calls tool:
|
|
488
|
+
if tool_name == "gdrive_search_files":
|
|
489
|
+
result = server.search_files(args["query"])
|
|
490
|
+
elif tool_name == "gdrive_read_file":
|
|
491
|
+
result = server.read_file(args["file_id"])
|
|
492
|
+
elif tool_name == "gdrive_get_metadata":
|
|
493
|
+
result = server.get_file_metadata(args["file_id"])
|
|
494
|
+
|
|
495
|
+
# Agent can now:
|
|
496
|
+
# - Search: "Find our Q4 strategy document"
|
|
497
|
+
# - Read: "What does the AlphaCorp agreement say about IP?"
|
|
498
|
+
# - Analyze: "Summarize all engineering documents from last month"
|
|
499
|
+
""")
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
if __name__ == "__main__":
|
|
503
|
+
demo()
|