eulerian-marketing-platform 0.2.4__tar.gz → 0.2.6__tar.gz
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-0.2.4 → eulerian_marketing_platform-0.2.6}/PKG-INFO +1 -1
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/pyproject.toml +1 -1
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/setup.cfg +1 -1
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform/__init__.py +1 -1
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform/server.py +74 -51
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/PKG-INFO +1 -1
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/.env.example +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/LICENSE +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/MANIFEST.in +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/README.md +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/requirements.txt +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/SOURCES.txt +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/dependency_links.txt +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/entry_points.txt +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/requires.txt +0 -0
- {eulerian_marketing_platform-0.2.4 → eulerian_marketing_platform-0.2.6}/src/eulerian_marketing_platform.egg-info/top_level.txt +0 -0
|
@@ -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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "eulerian_marketing_platform"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.6"
|
|
8
8
|
description = "MCP server for Eulerian Marketing Platform - enables AI assistants to interact with Eulerian's marketing analytics and campaign management APIs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -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,15 +100,18 @@ def forward_request(request_data: dict) -> dict:
|
|
|
101
100
|
|
|
102
101
|
logger.info(f"<<< RESPONSE: HTTP {response.status_code}")
|
|
103
102
|
|
|
103
|
+
# Handle HTTP 204 No Content (common for notifications)
|
|
104
|
+
if response.status_code == 204:
|
|
105
|
+
logger.info(" HTTP 204 No Content - creating empty success response")
|
|
106
|
+
return {
|
|
107
|
+
"jsonrpc": "2.0",
|
|
108
|
+
"id": request_id,
|
|
109
|
+
"result": {}
|
|
110
|
+
}
|
|
111
|
+
|
|
104
112
|
if response.status_code != 200:
|
|
105
113
|
error_msg = f"HTTP {response.status_code}: {response.reason_phrase}"
|
|
106
114
|
logger.error(f" Error: {response.text[:200]}")
|
|
107
|
-
|
|
108
|
-
# For notifications, don't return error responses
|
|
109
|
-
if is_notification:
|
|
110
|
-
logger.info(" Notification error - no response sent")
|
|
111
|
-
return None
|
|
112
|
-
|
|
113
115
|
return {
|
|
114
116
|
"jsonrpc": "2.0",
|
|
115
117
|
"id": request_id,
|
|
@@ -119,35 +121,77 @@ def forward_request(request_data: dict) -> dict:
|
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
# Parse response
|
|
124
|
+
# Parse response for HTTP 200
|
|
123
125
|
try:
|
|
124
126
|
response_data = response.json()
|
|
125
127
|
logger.debug(f" Response: {json.dumps(response_data)[:200]}...")
|
|
126
128
|
|
|
127
|
-
#
|
|
128
|
-
if
|
|
129
|
-
logger.info("
|
|
130
|
-
|
|
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}")
|
|
131
186
|
|
|
132
187
|
# Validate JSON-RPC response
|
|
133
188
|
if "jsonrpc" not in response_data:
|
|
134
189
|
logger.warning(" WARNING: Missing 'jsonrpc' field")
|
|
135
190
|
|
|
136
|
-
if "result" in response_data:
|
|
137
|
-
logger.info(" Has 'result' field [OK]")
|
|
138
|
-
elif "error" in response_data:
|
|
139
|
-
logger.info(f" Has 'error' field: {response_data['error']}")
|
|
140
|
-
|
|
141
191
|
return response_data
|
|
142
192
|
|
|
143
193
|
except json.JSONDecodeError as e:
|
|
144
194
|
logger.error(f" ERROR: Invalid JSON - {e}")
|
|
145
|
-
|
|
146
|
-
# For notifications, don't return error responses
|
|
147
|
-
if is_notification:
|
|
148
|
-
logger.info(" Notification JSON error - no response sent")
|
|
149
|
-
return None
|
|
150
|
-
|
|
151
195
|
return {
|
|
152
196
|
"jsonrpc": "2.0",
|
|
153
197
|
"id": request_id,
|
|
@@ -159,12 +203,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
159
203
|
|
|
160
204
|
except httpx.TimeoutException:
|
|
161
205
|
logger.error("ERROR: Request timeout")
|
|
162
|
-
|
|
163
|
-
# For notifications, don't return error responses
|
|
164
|
-
if is_notification:
|
|
165
|
-
logger.info(" Notification timeout - no response sent")
|
|
166
|
-
return None
|
|
167
|
-
|
|
168
206
|
return {
|
|
169
207
|
"jsonrpc": "2.0",
|
|
170
208
|
"id": request_id,
|
|
@@ -176,12 +214,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
176
214
|
|
|
177
215
|
except httpx.RequestError as e:
|
|
178
216
|
logger.error(f"ERROR: Request failed - {str(e)}")
|
|
179
|
-
|
|
180
|
-
# For notifications, don't return error responses
|
|
181
|
-
if is_notification:
|
|
182
|
-
logger.info(" Notification request error - no response sent")
|
|
183
|
-
return None
|
|
184
|
-
|
|
185
217
|
return {
|
|
186
218
|
"jsonrpc": "2.0",
|
|
187
219
|
"id": request_id,
|
|
@@ -195,12 +227,6 @@ def forward_request(request_data: dict) -> dict:
|
|
|
195
227
|
logger.error(f"ERROR: Unexpected error - {str(e)}")
|
|
196
228
|
import traceback
|
|
197
229
|
logger.error(f"Traceback: {traceback.format_exc()}")
|
|
198
|
-
|
|
199
|
-
# For notifications, don't return error responses
|
|
200
|
-
if is_notification:
|
|
201
|
-
logger.info(" Notification unexpected error - no response sent")
|
|
202
|
-
return None
|
|
203
|
-
|
|
204
230
|
return {
|
|
205
231
|
"jsonrpc": "2.0",
|
|
206
232
|
"id": request_id,
|
|
@@ -251,15 +277,12 @@ def main() -> None:
|
|
|
251
277
|
# Forward to remote server
|
|
252
278
|
response_data = forward_request(request_data)
|
|
253
279
|
|
|
254
|
-
#
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
else:
|
|
261
|
-
logger.info(" Notification processed (no response sent)")
|
|
262
|
-
|
|
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
|
+
|
|
263
286
|
except json.JSONDecodeError as e:
|
|
264
287
|
logger.error(f"ERROR: Invalid JSON in request - {e}")
|
|
265
288
|
logger.error(f" Problematic line: {line[:200]}")
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|