codetether 1.2.2__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.
- a2a_server/__init__.py +29 -0
- a2a_server/a2a_agent_card.py +365 -0
- a2a_server/a2a_errors.py +1133 -0
- a2a_server/a2a_executor.py +926 -0
- a2a_server/a2a_router.py +1033 -0
- a2a_server/a2a_types.py +344 -0
- a2a_server/agent_card.py +408 -0
- a2a_server/agents_server.py +271 -0
- a2a_server/auth_api.py +349 -0
- a2a_server/billing_api.py +638 -0
- a2a_server/billing_service.py +712 -0
- a2a_server/billing_webhooks.py +501 -0
- a2a_server/config.py +96 -0
- a2a_server/database.py +2165 -0
- a2a_server/email_inbound.py +398 -0
- a2a_server/email_notifications.py +486 -0
- a2a_server/enhanced_agents.py +919 -0
- a2a_server/enhanced_server.py +160 -0
- a2a_server/hosted_worker.py +1049 -0
- a2a_server/integrated_agents_server.py +347 -0
- a2a_server/keycloak_auth.py +750 -0
- a2a_server/livekit_bridge.py +439 -0
- a2a_server/marketing_tools.py +1364 -0
- a2a_server/mcp_client.py +196 -0
- a2a_server/mcp_http_server.py +2256 -0
- a2a_server/mcp_server.py +191 -0
- a2a_server/message_broker.py +725 -0
- a2a_server/mock_mcp.py +273 -0
- a2a_server/models.py +494 -0
- a2a_server/monitor_api.py +5904 -0
- a2a_server/opencode_bridge.py +1594 -0
- a2a_server/redis_task_manager.py +518 -0
- a2a_server/server.py +726 -0
- a2a_server/task_manager.py +668 -0
- a2a_server/task_queue.py +742 -0
- a2a_server/tenant_api.py +333 -0
- a2a_server/tenant_middleware.py +219 -0
- a2a_server/tenant_service.py +760 -0
- a2a_server/user_auth.py +721 -0
- a2a_server/vault_client.py +576 -0
- a2a_server/worker_sse.py +873 -0
- agent_worker/__init__.py +8 -0
- agent_worker/worker.py +4877 -0
- codetether/__init__.py +10 -0
- codetether/__main__.py +4 -0
- codetether/cli.py +112 -0
- codetether/worker_cli.py +57 -0
- codetether-1.2.2.dist-info/METADATA +570 -0
- codetether-1.2.2.dist-info/RECORD +66 -0
- codetether-1.2.2.dist-info/WHEEL +5 -0
- codetether-1.2.2.dist-info/entry_points.txt +4 -0
- codetether-1.2.2.dist-info/licenses/LICENSE +202 -0
- codetether-1.2.2.dist-info/top_level.txt +5 -0
- codetether_voice_agent/__init__.py +6 -0
- codetether_voice_agent/agent.py +445 -0
- codetether_voice_agent/codetether_mcp.py +345 -0
- codetether_voice_agent/config.py +16 -0
- codetether_voice_agent/functiongemma_caller.py +380 -0
- codetether_voice_agent/session_playback.py +247 -0
- codetether_voice_agent/tools/__init__.py +21 -0
- codetether_voice_agent/tools/definitions.py +135 -0
- codetether_voice_agent/tools/handlers.py +380 -0
- run_server.py +314 -0
- ui/monitor-tailwind.html +1790 -0
- ui/monitor.html +1775 -0
- ui/monitor.js +2662 -0
a2a_server/mcp_server.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server implementation providing tools for A2A agents.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
import json
|
|
10
|
+
import math
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
# Add the parent directory to Python path for imports
|
|
15
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
16
|
+
|
|
17
|
+
from mcp.server import Server
|
|
18
|
+
from mcp.server.stdio import stdio_server
|
|
19
|
+
from mcp.types import TextContent
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MCPToolServer:
|
|
25
|
+
"""MCP server providing tools for A2A agents."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, host: str = "localhost", port: int = 9000):
|
|
28
|
+
self.host = host
|
|
29
|
+
self.port = port
|
|
30
|
+
self.server = Server("a2a-tools")
|
|
31
|
+
self._setup_tools()
|
|
32
|
+
|
|
33
|
+
def _setup_tools(self):
|
|
34
|
+
"""Set up available tools."""
|
|
35
|
+
|
|
36
|
+
@self.server.tool()
|
|
37
|
+
async def calculator(
|
|
38
|
+
operation: str,
|
|
39
|
+
a: float,
|
|
40
|
+
b: Optional[float] = None
|
|
41
|
+
) -> str:
|
|
42
|
+
"""
|
|
43
|
+
Perform mathematical calculations.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
operation: The operation to perform (add, subtract, multiply, divide, square, sqrt)
|
|
47
|
+
a: First number
|
|
48
|
+
b: Second number (optional for unary operations)
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
if operation == "add":
|
|
52
|
+
if b is None:
|
|
53
|
+
return json.dumps({"error": "Addition requires two numbers"})
|
|
54
|
+
result = a + b
|
|
55
|
+
elif operation == "subtract":
|
|
56
|
+
if b is None:
|
|
57
|
+
return json.dumps({"error": "Subtraction requires two numbers"})
|
|
58
|
+
result = a - b
|
|
59
|
+
elif operation == "multiply":
|
|
60
|
+
if b is None:
|
|
61
|
+
return json.dumps({"error": "Multiplication requires two numbers"})
|
|
62
|
+
result = a * b
|
|
63
|
+
elif operation == "divide":
|
|
64
|
+
if b is None:
|
|
65
|
+
return json.dumps({"error": "Division requires two numbers"})
|
|
66
|
+
if b == 0:
|
|
67
|
+
return json.dumps({"error": "Cannot divide by zero"})
|
|
68
|
+
result = a / b
|
|
69
|
+
elif operation == "square":
|
|
70
|
+
result = a ** 2
|
|
71
|
+
elif operation == "sqrt":
|
|
72
|
+
if a < 0:
|
|
73
|
+
return json.dumps({"error": "Cannot take square root of negative number"})
|
|
74
|
+
result = math.sqrt(a)
|
|
75
|
+
else:
|
|
76
|
+
return json.dumps({"error": f"Unknown operation: {operation}"})
|
|
77
|
+
|
|
78
|
+
return json.dumps({"result": result, "operation": operation, "inputs": {"a": a, "b": b}})
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
return json.dumps({"error": f"Calculation error: {str(e)}"})
|
|
82
|
+
|
|
83
|
+
@self.server.tool()
|
|
84
|
+
async def weather_info(location: str) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Get weather information for a location (mock implementation).
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
location: The location to get weather for
|
|
90
|
+
"""
|
|
91
|
+
# Mock weather data
|
|
92
|
+
mock_weather = {
|
|
93
|
+
"location": location,
|
|
94
|
+
"temperature": "22°C",
|
|
95
|
+
"condition": "Partly cloudy",
|
|
96
|
+
"humidity": "65%",
|
|
97
|
+
"wind": "10 km/h SW",
|
|
98
|
+
"timestamp": datetime.now().isoformat()
|
|
99
|
+
}
|
|
100
|
+
return json.dumps(mock_weather)
|
|
101
|
+
|
|
102
|
+
@self.server.tool()
|
|
103
|
+
async def text_analyzer(text: str) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Analyze text and provide statistics.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
text: The text to analyze
|
|
109
|
+
"""
|
|
110
|
+
words = text.split()
|
|
111
|
+
sentences = text.split('.')
|
|
112
|
+
chars = len(text)
|
|
113
|
+
chars_no_spaces = len(text.replace(' ', ''))
|
|
114
|
+
|
|
115
|
+
analysis = {
|
|
116
|
+
"text": text,
|
|
117
|
+
"word_count": len(words),
|
|
118
|
+
"sentence_count": len([s for s in sentences if s.strip()]),
|
|
119
|
+
"character_count": chars,
|
|
120
|
+
"character_count_no_spaces": chars_no_spaces,
|
|
121
|
+
"average_word_length": sum(len(word) for word in words) / len(words) if words else 0,
|
|
122
|
+
"timestamp": datetime.now().isoformat()
|
|
123
|
+
}
|
|
124
|
+
return json.dumps(analysis)
|
|
125
|
+
|
|
126
|
+
@self.server.tool()
|
|
127
|
+
async def memory_store(
|
|
128
|
+
action: str,
|
|
129
|
+
key: Optional[str] = None,
|
|
130
|
+
value: Optional[str] = None
|
|
131
|
+
) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Simple key-value memory store for agents.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
action: Action to perform (store, retrieve, list, delete)
|
|
137
|
+
key: Key for store/retrieve/delete operations
|
|
138
|
+
value: Value for store operation
|
|
139
|
+
"""
|
|
140
|
+
if not hasattr(self, '_memory'):
|
|
141
|
+
self._memory = {}
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
if action == "store":
|
|
145
|
+
if key is None or value is None:
|
|
146
|
+
return json.dumps({"error": "Store action requires both key and value"})
|
|
147
|
+
self._memory[key] = value
|
|
148
|
+
return json.dumps({"action": "store", "key": key, "value": value, "success": True})
|
|
149
|
+
|
|
150
|
+
elif action == "retrieve":
|
|
151
|
+
if key is None:
|
|
152
|
+
return json.dumps({"error": "Retrieve action requires a key"})
|
|
153
|
+
value = self._memory.get(key)
|
|
154
|
+
if value is None:
|
|
155
|
+
return json.dumps({"action": "retrieve", "key": key, "found": False})
|
|
156
|
+
return json.dumps({"action": "retrieve", "key": key, "value": value, "found": True})
|
|
157
|
+
|
|
158
|
+
elif action == "list":
|
|
159
|
+
keys = list(self._memory.keys())
|
|
160
|
+
return json.dumps({"action": "list", "keys": keys, "count": len(keys)})
|
|
161
|
+
|
|
162
|
+
elif action == "delete":
|
|
163
|
+
if key is None:
|
|
164
|
+
return json.dumps({"error": "Delete action requires a key"})
|
|
165
|
+
if key in self._memory:
|
|
166
|
+
del self._memory[key]
|
|
167
|
+
return json.dumps({"action": "delete", "key": key, "success": True})
|
|
168
|
+
return json.dumps({"action": "delete", "key": key, "success": False, "error": "Key not found"})
|
|
169
|
+
|
|
170
|
+
else:
|
|
171
|
+
return json.dumps({"error": f"Unknown action: {action}"})
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
return json.dumps({"error": f"Memory operation error: {str(e)}"})
|
|
175
|
+
|
|
176
|
+
async def run(self):
|
|
177
|
+
"""Run the MCP server."""
|
|
178
|
+
logger.info(f"Starting MCP tool server")
|
|
179
|
+
|
|
180
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
181
|
+
await self.server.run(read_stream, write_stream)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def run_mcp_server():
|
|
185
|
+
"""Run the MCP server."""
|
|
186
|
+
server = MCPToolServer()
|
|
187
|
+
await server.run()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
if __name__ == "__main__":
|
|
191
|
+
asyncio.run(run_mcp_server())
|