eulerian-marketing-platform 0.2.5__py3-none-any.whl → 0.2.6__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.
- eulerian_marketing_platform/__init__.py +1 -1
- eulerian_marketing_platform/server.py +72 -65
- {eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/METADATA +1 -1
- eulerian_marketing_platform-0.2.6.dist-info/RECORD +8 -0
- eulerian_marketing_platform-0.2.5.dist-info/RECORD +0 -8
- {eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/LICENSE +0 -0
- {eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/WHEEL +0 -0
- {eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/entry_points.txt +0 -0
- {eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/top_level.txt +0 -0
|
@@ -74,13 +74,12 @@ def forward_request(request_data: dict) -> dict:
|
|
|
74
74
|
request_data: The JSON-RPC request to forward
|
|
75
75
|
|
|
76
76
|
Returns:
|
|
77
|
-
The JSON-RPC response from the remote server
|
|
77
|
+
The JSON-RPC response from the remote server
|
|
78
78
|
"""
|
|
79
79
|
timeout = float(os.environ.get("EMP_TIMEOUT", "300"))
|
|
80
80
|
|
|
81
81
|
request_id = request_data.get("id")
|
|
82
82
|
method = request_data.get("method")
|
|
83
|
-
is_notification = request_id is None
|
|
84
83
|
|
|
85
84
|
logger.info(f">>> REQUEST: {method} (id: {request_id})")
|
|
86
85
|
logger.debug(f" Full request: {json.dumps(request_data)[:200]}...")
|
|
@@ -101,30 +100,18 @@ def forward_request(request_data: dict) -> dict:
|
|
|
101
100
|
|
|
102
101
|
logger.info(f"<<< RESPONSE: HTTP {response.status_code}")
|
|
103
102
|
|
|
104
|
-
# Handle HTTP 204 No Content (
|
|
103
|
+
# Handle HTTP 204 No Content (common for notifications)
|
|
105
104
|
if response.status_code == 204:
|
|
106
|
-
logger.info(" HTTP 204 No Content -
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# For regular requests, 204 is unusual but we'll treat it as success with empty result
|
|
113
|
-
return {
|
|
114
|
-
"jsonrpc": "2.0",
|
|
115
|
-
"id": request_id,
|
|
116
|
-
"result": None
|
|
117
|
-
}
|
|
105
|
+
logger.info(" HTTP 204 No Content - creating empty success response")
|
|
106
|
+
return {
|
|
107
|
+
"jsonrpc": "2.0",
|
|
108
|
+
"id": request_id,
|
|
109
|
+
"result": {}
|
|
110
|
+
}
|
|
118
111
|
|
|
119
112
|
if response.status_code != 200:
|
|
120
113
|
error_msg = f"HTTP {response.status_code}: {response.reason_phrase}"
|
|
121
114
|
logger.error(f" Error: {response.text[:200]}")
|
|
122
|
-
|
|
123
|
-
# For notifications, don't return error responses
|
|
124
|
-
if is_notification:
|
|
125
|
-
logger.info(" Notification error - no response sent")
|
|
126
|
-
return None
|
|
127
|
-
|
|
128
115
|
return {
|
|
129
116
|
"jsonrpc": "2.0",
|
|
130
117
|
"id": request_id,
|
|
@@ -134,36 +121,77 @@ def forward_request(request_data: dict) -> dict:
|
|
|
134
121
|
}
|
|
135
122
|
}
|
|
136
123
|
|
|
137
|
-
# Parse response
|
|
124
|
+
# Parse response for HTTP 200
|
|
138
125
|
try:
|
|
139
126
|
response_data = response.json()
|
|
140
127
|
logger.debug(f" Response: {json.dumps(response_data)[:200]}...")
|
|
141
128
|
|
|
142
|
-
#
|
|
143
|
-
if
|
|
144
|
-
logger.info(
|
|
145
|
-
|
|
146
|
-
|
|
129
|
+
# Add detailed logging for different MCP methods
|
|
130
|
+
if "result" in response_data:
|
|
131
|
+
logger.info(" Has 'result' field [OK]")
|
|
132
|
+
|
|
133
|
+
result = response_data.get("result", {})
|
|
134
|
+
|
|
135
|
+
if method == "initialize":
|
|
136
|
+
logger.info(f" Initialize result: protocolVersion={result.get('protocolVersion')}")
|
|
137
|
+
capabilities = result.get("capabilities", {})
|
|
138
|
+
logger.info(f" Server capabilities: {list(capabilities.keys())}")
|
|
139
|
+
server_info = result.get("serverInfo", {})
|
|
140
|
+
logger.info(f" Server info: name={server_info.get('name')}, version={server_info.get('version')}")
|
|
141
|
+
|
|
142
|
+
elif method == "tools/list":
|
|
143
|
+
tools = result.get("tools", [])
|
|
144
|
+
logger.info(f" Tools available: {len(tools)} tools")
|
|
145
|
+
for i, tool in enumerate(tools):
|
|
146
|
+
tool_name = tool.get("name", "unnamed")
|
|
147
|
+
tool_desc = tool.get("description", "no description")[:50]
|
|
148
|
+
logger.info(f" Tool {i+1}: {tool_name} - {tool_desc}")
|
|
149
|
+
# Log input schema info
|
|
150
|
+
input_schema = tool.get("inputSchema", {})
|
|
151
|
+
if "properties" in input_schema:
|
|
152
|
+
props = list(input_schema["properties"].keys())[:3]
|
|
153
|
+
logger.info(f" Input properties: {props}")
|
|
154
|
+
|
|
155
|
+
elif method == "resources/list":
|
|
156
|
+
resources = result.get("resources", [])
|
|
157
|
+
logger.info(f" Resources available: {len(resources)} resources")
|
|
158
|
+
for i, resource in enumerate(resources[:3]):
|
|
159
|
+
res_uri = resource.get("uri", "no uri")
|
|
160
|
+
res_name = resource.get("name", "unnamed")
|
|
161
|
+
logger.info(f" Resource {i+1}: {res_name} ({res_uri})")
|
|
162
|
+
if len(resources) > 3:
|
|
163
|
+
logger.info(f" ... and {len(resources) - 3} more resources")
|
|
164
|
+
|
|
165
|
+
elif method.startswith("tools/call"):
|
|
166
|
+
logger.info(f" Tool call result keys: {list(result.keys())}")
|
|
167
|
+
if "content" in result:
|
|
168
|
+
content = result["content"]
|
|
169
|
+
if isinstance(content, list) and len(content) > 0:
|
|
170
|
+
logger.info(f" Tool returned {len(content)} content items")
|
|
171
|
+
first_item = content[0]
|
|
172
|
+
if isinstance(first_item, dict):
|
|
173
|
+
logger.info(f" First content type: {first_item.get('type', 'unknown')}")
|
|
174
|
+
elif isinstance(content, str):
|
|
175
|
+
logger.info(f" Tool returned string content: {len(content)} chars")
|
|
176
|
+
|
|
177
|
+
else:
|
|
178
|
+
# Generic logging for unknown methods
|
|
179
|
+
logger.info(f" Method '{method}' result keys: {list(result.keys())}")
|
|
180
|
+
|
|
181
|
+
elif "error" in response_data:
|
|
182
|
+
error = response_data["error"]
|
|
183
|
+
error_code = error.get("code", "no code")
|
|
184
|
+
error_message = error.get("message", "no message")
|
|
185
|
+
logger.info(f" Has 'error' field: code={error_code}, message={error_message}")
|
|
147
186
|
|
|
148
187
|
# Validate JSON-RPC response
|
|
149
188
|
if "jsonrpc" not in response_data:
|
|
150
189
|
logger.warning(" WARNING: Missing 'jsonrpc' field")
|
|
151
190
|
|
|
152
|
-
if "result" in response_data:
|
|
153
|
-
logger.info(" Has 'result' field [OK]")
|
|
154
|
-
elif "error" in response_data:
|
|
155
|
-
logger.info(f" Has 'error' field: {response_data['error']}")
|
|
156
|
-
|
|
157
191
|
return response_data
|
|
158
192
|
|
|
159
193
|
except json.JSONDecodeError as e:
|
|
160
194
|
logger.error(f" ERROR: Invalid JSON - {e}")
|
|
161
|
-
|
|
162
|
-
# For notifications, don't return error responses
|
|
163
|
-
if is_notification:
|
|
164
|
-
logger.info(" Notification JSON error - no response sent")
|
|
165
|
-
return None
|
|
166
|
-
|
|
167
195
|
return {
|
|
168
196
|
"jsonrpc": "2.0",
|
|
169
197
|
"id": request_id,
|
|
@@ -175,12 +203,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
175
203
|
|
|
176
204
|
except httpx.TimeoutException:
|
|
177
205
|
logger.error("ERROR: Request timeout")
|
|
178
|
-
|
|
179
|
-
# For notifications, don't return error responses
|
|
180
|
-
if is_notification:
|
|
181
|
-
logger.info(" Notification timeout - no response sent")
|
|
182
|
-
return None
|
|
183
|
-
|
|
184
206
|
return {
|
|
185
207
|
"jsonrpc": "2.0",
|
|
186
208
|
"id": request_id,
|
|
@@ -192,12 +214,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
192
214
|
|
|
193
215
|
except httpx.RequestError as e:
|
|
194
216
|
logger.error(f"ERROR: Request failed - {str(e)}")
|
|
195
|
-
|
|
196
|
-
# For notifications, don't return error responses
|
|
197
|
-
if is_notification:
|
|
198
|
-
logger.info(" Notification request error - no response sent")
|
|
199
|
-
return None
|
|
200
|
-
|
|
201
217
|
return {
|
|
202
218
|
"jsonrpc": "2.0",
|
|
203
219
|
"id": request_id,
|
|
@@ -211,12 +227,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
211
227
|
logger.error(f"ERROR: Unexpected error - {str(e)}")
|
|
212
228
|
import traceback
|
|
213
229
|
logger.error(f"Traceback: {traceback.format_exc()}")
|
|
214
|
-
|
|
215
|
-
# For notifications, don't return error responses
|
|
216
|
-
if is_notification:
|
|
217
|
-
logger.info(" Notification unexpected error - no response sent")
|
|
218
|
-
return None
|
|
219
|
-
|
|
220
230
|
return {
|
|
221
231
|
"jsonrpc": "2.0",
|
|
222
232
|
"id": request_id,
|
|
@@ -267,15 +277,12 @@ def main() -> None:
|
|
|
267
277
|
# Forward to remote server
|
|
268
278
|
response_data = forward_request(request_data)
|
|
269
279
|
|
|
270
|
-
#
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
else:
|
|
277
|
-
logger.info(" Notification processed (no response sent)")
|
|
278
|
-
|
|
280
|
+
# Always send response back to Claude Desktop (MCP requires this)
|
|
281
|
+
response_json = json.dumps(response_data)
|
|
282
|
+
print(response_json, flush=True)
|
|
283
|
+
sys.stdout.flush()
|
|
284
|
+
logger.info(" Response forwarded [OK]")
|
|
285
|
+
|
|
279
286
|
except json.JSONDecodeError as e:
|
|
280
287
|
logger.error(f"ERROR: Invalid JSON in request - {e}")
|
|
281
288
|
logger.error(f" Problematic line: {line[:200]}")
|
{eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eulerian-marketing-platform
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: MCP server for Eulerian Marketing Platform - enables AI assistants to interact with Eulerian's marketing analytics and campaign management APIs
|
|
5
5
|
Author-email: Eulerian Technologies <mathieu@eulerian.com>
|
|
6
6
|
License: MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
eulerian_marketing_platform/__init__.py,sha256=Rchunx1TsnHjirVTZtfMlg6LHXlQupKPi-tYLVZTI00,428
|
|
2
|
+
eulerian_marketing_platform/server.py,sha256=GBuksSr38MWXKNR36mbHaMz8589eElGM6qGt2-zOJdw,13321
|
|
3
|
+
eulerian_marketing_platform-0.2.6.dist-info/LICENSE,sha256=eIqBqE_fRsqQJ8F-2v0e-8WzZqdshsCqnzmqLAWrNHU,1078
|
|
4
|
+
eulerian_marketing_platform-0.2.6.dist-info/METADATA,sha256=VR6nemyIP3yUTR_bbLV1V9K5e48M9WVO3zOssc1jIpM,12169
|
|
5
|
+
eulerian_marketing_platform-0.2.6.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
|
6
|
+
eulerian_marketing_platform-0.2.6.dist-info/entry_points.txt,sha256=rrPZptATSS9PUtH9gzCYq0WuP6eahkF-DkdUP1FaYfk,88
|
|
7
|
+
eulerian_marketing_platform-0.2.6.dist-info/top_level.txt,sha256=nidh3T6fw-mLjUqZwQ8AiMScS4usuH0WXW4ZgG4HYCo,28
|
|
8
|
+
eulerian_marketing_platform-0.2.6.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
eulerian_marketing_platform/__init__.py,sha256=Vy3v2bzqOBm-2QuGgb87QkLjojhqRDvzRTeNPqVMaOE,428
|
|
2
|
-
eulerian_marketing_platform/server.py,sha256=3Iz8fZCug6DnvI1pd3o5Ilbvcu61Zb9KpnLXYjZs0Yk,12119
|
|
3
|
-
eulerian_marketing_platform-0.2.5.dist-info/LICENSE,sha256=eIqBqE_fRsqQJ8F-2v0e-8WzZqdshsCqnzmqLAWrNHU,1078
|
|
4
|
-
eulerian_marketing_platform-0.2.5.dist-info/METADATA,sha256=lmDkaF4qVTcsHgM3Yw20d7xCjPRw8M-eVlD1eerYkTU,12169
|
|
5
|
-
eulerian_marketing_platform-0.2.5.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
|
6
|
-
eulerian_marketing_platform-0.2.5.dist-info/entry_points.txt,sha256=rrPZptATSS9PUtH9gzCYq0WuP6eahkF-DkdUP1FaYfk,88
|
|
7
|
-
eulerian_marketing_platform-0.2.5.dist-info/top_level.txt,sha256=nidh3T6fw-mLjUqZwQ8AiMScS4usuH0WXW4ZgG4HYCo,28
|
|
8
|
-
eulerian_marketing_platform-0.2.5.dist-info/RECORD,,
|
{eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/LICENSE
RENAMED
|
File without changes
|
{eulerian_marketing_platform-0.2.5.dist-info → eulerian_marketing_platform-0.2.6.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|