eulerian-marketing-platform 0.1.2__py3-none-any.whl → 0.2.1__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.
@@ -4,7 +4,7 @@ This package provides a Model Context Protocol (MCP) server that enables
4
4
  AI assistants to interact with Eulerian Marketing Platform APIs.
5
5
  """
6
6
 
7
- __version__ = "0.1.2"
7
+ __version__ = "0.2.1"
8
8
  __author__ = "Eulerian Technologies"
9
9
  __all__ = []
10
10
 
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env python3
2
2
  """Eulerian Marketing Platform MCP Proxy Server.
3
3
 
4
- This server acts as a proxy/bridge between local MCP clients (Claude Desktop, Gemini CLI, etc.)
4
+ This server acts as a transparent proxy between local MCP clients (Claude Desktop, etc.)
5
5
  and a remote Eulerian Marketing Platform MCP server via HTTP.
6
6
 
7
- It uses EMP_API_ENDPOINT and EMP_API_TOKEN environment variables to authenticate
8
- and forward requests to the remote MCP server.
7
+ It forwards ALL MCP requests directly to the remote server, making all remote tools
8
+ and resources available to the client without any intermediary logic.
9
9
  """
10
10
 
11
11
  import os
@@ -14,27 +14,19 @@ import json
14
14
  import logging
15
15
  import tempfile
16
16
  from datetime import datetime
17
- from typing import Any
18
- from pathlib import Path
19
17
  import httpx
20
18
 
21
- from mcp.server.fastmcp import FastMCP
22
- from mcp.server import Server
23
- from mcp.server.stdio import stdio_server
24
- from mcp import types
25
-
26
19
  # Configuration
27
20
  EMP_API_ENDPOINT = os.environ.get("EMP_API_ENDPOINT")
28
21
  EMP_API_TOKEN = os.environ.get("EMP_API_TOKEN")
29
22
 
30
23
  # Logging setup - Use cross-platform temp directory
31
- # Default to system temp directory if EMP_LOG_FILE not set
32
24
  DEFAULT_LOG_FILE = os.path.join(tempfile.gettempdir(), "eulerian-mcp-proxy.log")
33
25
  LOG_FILE = os.environ.get("EMP_LOG_FILE", DEFAULT_LOG_FILE)
34
26
 
35
27
  # Ensure log directory exists
36
28
  log_dir = os.path.dirname(LOG_FILE)
37
- if log_dir: # Only create if there's a directory part
29
+ if log_dir:
38
30
  os.makedirs(log_dir, exist_ok=True)
39
31
 
40
32
  # Configure logging to file and stderr with UTF-8 encoding for cross-platform compatibility
@@ -75,176 +67,175 @@ def validate_config() -> None:
75
67
  sys.exit(1)
76
68
 
77
69
 
78
- class EulerianMCPProxy:
79
- """Proxy that forwards MCP requests to remote Eulerian server."""
70
+ def forward_request(request_data: dict) -> dict:
71
+ """Forward a JSON-RPC request to the remote MCP server.
80
72
 
81
- def __init__(self):
82
- """Initialize the proxy with configuration."""
83
- self.endpoint = EMP_API_ENDPOINT
84
- self.token = EMP_API_TOKEN
85
- self.timeout = float(os.environ.get("EMP_TIMEOUT", "300"))
73
+ Args:
74
+ request_data: The JSON-RPC request to forward
86
75
 
87
- logger.info("=== EULERIAN MCP PROXY START ===")
88
- logger.info(f"Endpoint: {self.endpoint}")
89
- logger.info(f"Token: {self.token[:10] if self.token else 'None'}...")
90
- logger.info(f"Timeout: {self.timeout}s")
76
+ Returns:
77
+ The JSON-RPC response from the remote server
78
+ """
79
+ timeout = float(os.environ.get("EMP_TIMEOUT", "300"))
80
+
81
+ request_id = request_data.get("id")
82
+ method = request_data.get("method")
91
83
 
92
- async def forward_request(self, method: str, params: dict = None) -> dict[str, Any]:
93
- """Forward a JSON-RPC request to the remote MCP server.
84
+ logger.info(f">>> REQUEST: {method} (id: {request_id})")
85
+ logger.debug(f" Full request: {json.dumps(request_data)[:200]}...")
86
+
87
+ try:
88
+ logger.info(f"Forwarding to {EMP_API_ENDPOINT}")
94
89
 
95
- Args:
96
- method: The JSON-RPC method name
97
- params: The parameters for the method
98
-
99
- Returns:
100
- The response from the remote server
101
-
102
- Raises:
103
- Exception: If the request fails
104
- """
105
- request_data = {
106
- "jsonrpc": "2.0",
107
- "id": 1,
108
- "method": method,
109
- }
110
- if params:
111
- request_data["params"] = params
90
+ # Use httpx for sync HTTP request
91
+ with httpx.Client(timeout=timeout) as client:
92
+ response = client.post(
93
+ EMP_API_ENDPOINT,
94
+ headers={
95
+ "Content-Type": "application/json",
96
+ "Authorization": f"Bearer {EMP_API_TOKEN}"
97
+ },
98
+ json=request_data
99
+ )
100
+
101
+ logger.info(f"<<< RESPONSE: HTTP {response.status_code}")
112
102
 
113
- logger.info(f">>> REQUEST: {method}")
114
- logger.debug(f" Full request: {json.dumps(request_data)[:200]}...")
103
+ if response.status_code != 200:
104
+ error_msg = f"HTTP {response.status_code}: {response.reason_phrase}"
105
+ logger.error(f" Error: {response.text[:200]}")
106
+
107
+ return {
108
+ "jsonrpc": "2.0",
109
+ "id": request_id,
110
+ "error": {
111
+ "code": -32000,
112
+ "message": error_msg
113
+ }
114
+ }
115
115
 
116
+ # Parse response
116
117
  try:
117
- async with httpx.AsyncClient() as client:
118
- logger.info(f"Forwarding to {self.endpoint}")
119
- response = await client.post(
120
- self.endpoint,
121
- headers={
122
- "Content-Type": "application/json",
123
- "Authorization": f"Bearer {self.token}"
124
- },
125
- json=request_data,
126
- timeout=self.timeout
127
- )
128
-
129
- logger.info(f"<<< RESPONSE: HTTP {response.status_code}")
130
-
131
- if response.status_code != 200:
132
- error_msg = f"HTTP {response.status_code}: {response.reason_phrase}"
133
- logger.error(f" Error: {response.text[:200]}")
134
- raise Exception(error_msg)
135
-
136
- response_data = response.json()
137
- logger.debug(f" Response: {json.dumps(response_data)[:200]}...")
138
-
139
- # Validate JSON-RPC response
140
- if "jsonrpc" not in response_data:
141
- logger.warning(" WARNING: Missing 'jsonrpc' field")
142
-
143
- if "result" in response_data:
144
- logger.info(" Has 'result' field [OK]")
145
- return response_data["result"]
146
- elif "error" in response_data:
147
- logger.error(f" Has 'error' field: {response_data['error']}")
148
- raise Exception(f"Remote error: {response_data['error']}")
149
- else:
150
- logger.warning(" No 'result' or 'error' field")
151
- return response_data
152
-
153
- except httpx.TimeoutException:
154
- logger.error("ERROR: Request timeout")
155
- raise Exception("Request timeout")
156
- except httpx.RequestError as e:
157
- logger.error(f"ERROR: Request failed - {str(e)}")
158
- raise Exception(f"Request failed: {str(e)}")
118
+ response_data = response.json()
119
+ logger.debug(f" Response: {json.dumps(response_data)[:200]}...")
120
+
121
+ # Validate JSON-RPC response
122
+ if "jsonrpc" not in response_data:
123
+ logger.warning(" WARNING: Missing 'jsonrpc' field")
124
+
125
+ if "result" in response_data:
126
+ logger.info(" Has 'result' field [OK]")
127
+ elif "error" in response_data:
128
+ logger.info(f" Has 'error' field: {response_data['error']}")
129
+
130
+ return response_data
131
+
159
132
  except json.JSONDecodeError as e:
160
- logger.error(f"ERROR: Invalid JSON response - {str(e)}")
161
- raise Exception(f"Invalid JSON response: {str(e)}")
162
-
163
-
164
- # Dynamically fetch and register tools from remote server
165
- # (Tools are registered in main() to avoid running on import)
166
-
167
-
168
- def main() -> None:
169
- """Entry point for the MCP proxy server."""
170
- # Validate configuration before starting
171
- validate_config()
172
-
173
- # Create proxy and server instances (moved here to avoid running on import)
174
- global proxy, mcp
175
- proxy = EulerianMCPProxy()
176
- mcp = FastMCP("eulerian-marketing-platform")
177
-
178
- # Register tools
179
- @mcp.tool()
180
- async def list_remote_tools() -> dict[str, Any]:
181
- """List all available tools from the remote Eulerian MCP server."""
182
- try:
183
- result = await proxy.forward_request("tools/list")
184
- return result
185
- except Exception as e:
186
- logger.error(f"Failed to list tools: {str(e)}")
187
- return {"error": str(e), "tools": []}
133
+ logger.error(f" ERROR: Invalid JSON - {e}")
134
+ return {
135
+ "jsonrpc": "2.0",
136
+ "id": request_id,
137
+ "error": {
138
+ "code": -32700,
139
+ "message": f"Invalid JSON: {str(e)}"
140
+ }
141
+ }
188
142
 
189
- @mcp.tool()
190
- async def call_eulerian_tool(tool_name: str, arguments: dict[str, Any] = None) -> dict[str, Any]:
191
- """Call a tool on the remote Eulerian MCP server."""
192
- if arguments is None:
193
- arguments = {}
194
- try:
195
- params = {"name": tool_name, "arguments": arguments}
196
- result = await proxy.forward_request("tools/call", params)
197
- return result
198
- except Exception as e:
199
- logger.error(f"Failed to call tool '{tool_name}': {str(e)}")
200
- return {"error": str(e), "tool": tool_name}
143
+ except httpx.TimeoutException:
144
+ logger.error("ERROR: Request timeout")
145
+ return {
146
+ "jsonrpc": "2.0",
147
+ "id": request_id,
148
+ "error": {
149
+ "code": -32000,
150
+ "message": "Request timeout"
151
+ }
152
+ }
201
153
 
202
- @mcp.tool()
203
- async def get_eulerian_resources() -> dict[str, Any]:
204
- """List all available resources from the remote Eulerian MCP server."""
205
- try:
206
- result = await proxy.forward_request("resources/list")
207
- return result
208
- except Exception as e:
209
- logger.error(f"Failed to list resources: {str(e)}")
210
- return {"error": str(e), "resources": []}
154
+ except httpx.RequestError as e:
155
+ logger.error(f"ERROR: Request failed - {str(e)}")
156
+ return {
157
+ "jsonrpc": "2.0",
158
+ "id": request_id,
159
+ "error": {
160
+ "code": -32000,
161
+ "message": f"Request failed: {str(e)}"
162
+ }
163
+ }
211
164
 
212
- @mcp.tool()
213
- async def read_eulerian_resource(uri: str) -> dict[str, Any]:
214
- """Read a specific resource from the remote Eulerian MCP server."""
215
- try:
216
- params = {"uri": uri}
217
- result = await proxy.forward_request("resources/read", params)
218
- return result
219
- except Exception as e:
220
- logger.error(f"Failed to read resource '{uri}': {str(e)}")
221
- return {"error": str(e), "uri": uri}
165
+ except Exception as e:
166
+ logger.error(f"ERROR: Unexpected error - {str(e)}")
167
+ import traceback
168
+ logger.error(f"Traceback: {traceback.format_exc()}")
169
+ return {
170
+ "jsonrpc": "2.0",
171
+ "id": request_id,
172
+ "error": {
173
+ "code": -32000,
174
+ "message": f"Error: {str(e)}"
175
+ }
176
+ }
177
+
178
+
179
+ def main() -> None:
180
+ """Entry point for the MCP proxy server.
222
181
 
223
- @mcp.tool()
224
- async def get_server_info() -> dict[str, Any]:
225
- """Get information about the remote Eulerian MCP server."""
226
- try:
227
- result = await proxy.forward_request("initialize", {
228
- "protocolVersion": "2024-11-05",
229
- "capabilities": {},
230
- "clientInfo": {"name": "eulerian-mcp-proxy", "version": "0.1.1"}
231
- })
232
- return result
233
- except Exception as e:
234
- logger.error(f"Failed to get server info: {str(e)}")
235
- return {"error": str(e)}
182
+ Runs a transparent stdio proxy that forwards all JSON-RPC requests
183
+ to the remote Eulerian MCP server.
184
+ """
185
+ # Validate configuration
186
+ validate_config()
236
187
 
237
- logger.info("Starting Eulerian MCP Proxy Server...")
238
- logger.info("Available tools:")
239
- logger.info(" - list_remote_tools: List all tools from remote server")
240
- logger.info(" - call_eulerian_tool: Call any remote tool")
241
- logger.info(" - get_eulerian_resources: List available resources")
242
- logger.info(" - read_eulerian_resource: Read a specific resource")
243
- logger.info(" - get_server_info: Get remote server information")
188
+ logger.info("=== EULERIAN MCP PROXY START ===")
189
+ logger.info(f"Endpoint: {EMP_API_ENDPOINT}")
190
+ logger.info(f"Token: {EMP_API_TOKEN[:10] if EMP_API_TOKEN else 'None'}...")
191
+ logger.info(f"Timeout: {float(os.environ.get('EMP_TIMEOUT', '300'))}s")
192
+ logger.info("Starting stdio proxy - all remote tools will be available")
244
193
 
245
- # Run the server in stdio mode (default for MCP)
246
194
  try:
247
- mcp.run()
195
+ # Read from stdin line by line
196
+ for line in sys.stdin:
197
+ line = line.strip()
198
+ if not line:
199
+ continue
200
+
201
+ try:
202
+ # Parse request
203
+ request_data = json.loads(line)
204
+
205
+ # Forward to remote server
206
+ response_data = forward_request(request_data)
207
+
208
+ # Send response to stdout
209
+ response_json = json.dumps(response_data)
210
+ print(response_json, flush=True)
211
+ logger.info(" Response forwarded [OK]")
212
+
213
+ except json.JSONDecodeError as e:
214
+ logger.error(f"ERROR: Invalid JSON in request - {e}")
215
+ error_response = {
216
+ "jsonrpc": "2.0",
217
+ "id": None,
218
+ "error": {
219
+ "code": -32700,
220
+ "message": f"Parse error: {str(e)}"
221
+ }
222
+ }
223
+ print(json.dumps(error_response), flush=True)
224
+
225
+ except Exception as e:
226
+ logger.error(f"ERROR: Unexpected error processing request - {str(e)}")
227
+ import traceback
228
+ logger.error(f"Traceback: {traceback.format_exc()}")
229
+ error_response = {
230
+ "jsonrpc": "2.0",
231
+ "id": None,
232
+ "error": {
233
+ "code": -32000,
234
+ "message": f"Error: {str(e)}"
235
+ }
236
+ }
237
+ print(json.dumps(error_response), flush=True)
238
+
248
239
  except KeyboardInterrupt:
249
240
  logger.info("Server stopped by user")
250
241
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eulerian-marketing-platform
3
- Version: 0.1.2
3
+ Version: 0.2.1
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
@@ -24,7 +24,6 @@ Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
26
  Requires-Dist: httpx (>=0.25.0)
27
- Requires-Dist: mcp (>=1.2.0)
28
27
  Provides-Extra: deployment
29
28
  Requires-Dist: uv (>=0.5.0) ; extra == 'deployment'
30
29
  Provides-Extra: dev
@@ -37,7 +36,7 @@ Requires-Dist: ruff (>=0.1.0) ; extra == 'dev'
37
36
 
38
37
  # Eulerian Marketing Platform MCP Server
39
38
 
40
- A Model Context Protocol (MCP) **proxy server** that bridges AI assistants (Claude Desktop, Gemini CLI, Mistral AI) to a remote Eulerian Marketing Platform MCP server. This proxy handles authentication, request forwarding, and provides a local MCP interface to your remote Eulerian instance.
39
+ A Model Context Protocol (MCP) **proxy server** that bridges AI assistants (Claude Desktop, Gemini CLI, etc ...) to a remote Eulerian Marketing Platform MCP server. This proxy handles authentication, request forwarding, and provides a local MCP interface to your remote Eulerian instance.
41
40
 
42
41
  ## How It Works
43
42
 
@@ -62,12 +61,11 @@ The proxy:
62
61
  - **🔌 Proxy Architecture**: Bridges local MCP clients to remote Eulerian MCP server via HTTP
63
62
  - **🔐 Secure Authentication**: Uses Bearer token authentication for remote server access
64
63
  - **🌐 Cross-platform support**: Works on Windows, Linux, and macOS
65
- - **🤖 Multiple AI clients**: Compatible with Claude Desktop, Gemini CLI, and Mistral AI
64
+ - **🤖 Multiple AI clients**: Compatible with Claude Desktop and Gemini CLI
66
65
  - **📝 Comprehensive Logging**: Logs all requests/responses for debugging
67
66
  - **⚡ Async HTTP**: Non-blocking requests using httpx for better performance
68
67
  - **🛠️ Tool Discovery**: Automatically discovers and exposes remote tools
69
68
  - **⏱️ Configurable Timeouts**: Adjustable request timeouts
70
- - **🔍 Easy Installation**: Deploy with a single command using `uvx`
71
69
 
72
70
  ## Prerequisites
73
71
 
@@ -77,63 +75,18 @@ The proxy:
77
75
  - One of the following AI clients:
78
76
  - Claude Desktop (Windows, macOS, Linux)
79
77
  - Gemini CLI
80
- - Mistral AI Le Chat (requires remote deployment)
81
78
 
82
79
  ## Available Tools
83
80
 
84
- The proxy exposes the following tools to AI assistants:
85
-
86
- 1. **`list_remote_tools()`** - Discover all tools available on the remote Eulerian server
87
- 2. **`call_eulerian_tool(tool_name, arguments)`** - Call any remote tool with arguments
88
- 3. **`get_eulerian_resources()`** - List available resources (data sources)
89
- 4. **`read_eulerian_resource(uri)`** - Read a specific resource by URI
90
- 5. **`get_server_info()`** - Get remote server version and capabilities
91
-
92
- For detailed information on how these tools work, see [FASTMCP_PROXY_GUIDE.md](FASTMCP_PROXY_GUIDE.md).
81
+ All API Endpoints supported by the [Eulerian API](https://doc.api.eulerian.com) can be queried through the current MCP.
93
82
 
94
83
  ## Installation
95
84
 
96
- ### Prerequisites Check
97
-
98
- Before installing, verify you have `uvx` installed. This is the recommended way to run the MCP server.
99
-
100
- **Check if uvx is installed:**
101
- ```bash
102
- uvx --version
103
- ```
104
-
105
- **If not installed, see [UVX_DEPLOYMENT_GUIDE.md](UVX_DEPLOYMENT_GUIDE.md) for detailed installation instructions.**
106
-
107
- **Quick install (Linux/macOS):**
108
- ```bash
109
- # Run the included script
110
- chmod +x install-uvx.sh
111
- ./install-uvx.sh
112
-
113
- # Or install manually
114
- curl -LsSf https://astral.sh/uv/install.sh | sh
115
- ```
116
-
117
- **Quick install (Windows PowerShell - Run as Administrator):**
118
- ```powershell
119
- # Run the included script
120
- .\install-uvx.ps1
121
-
122
- # Or install manually
123
- powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
124
- ```
125
-
126
- ---
127
-
128
85
  ### Quick Start (Recommended)
129
86
 
130
- The easiest way to use this MCP server is with `uvx`, which automatically handles dependencies without requiring a separate installation:
131
-
132
- ```bash
133
- # No installation needed! Just configure your AI client (see below)
134
- ```
87
+ The easiest way to use this MCP server is with `pip`.
135
88
 
136
- ### Alternative: Install via pip
89
+ ### Install via pip
137
90
 
138
91
  If you prefer to install the package globally:
139
92
 
@@ -154,8 +107,8 @@ pip install -e .
154
107
  ### Required Environment Variables
155
108
 
156
109
  - `EMP_API_ENDPOINT`: Your remote Eulerian Marketing Platform MCP server URL (HTTP endpoint)
157
- - Example: `https://your-eulerian-instance.com/api/mcp`
158
- - `EMP_API_TOKEN`: Your authentication token for the remote server
110
+ - Example: `https://dem.api.eulerian.com/mcp`
111
+ - `EMP_API_TOKEN`: Your authentication token for the remote server, it is the one linked to your Eulerian account.
159
112
 
160
113
  ### Optional Environment Variables
161
114
 
@@ -197,23 +150,6 @@ Claude Desktop supports local MCP servers via stdio transport.
197
150
 
198
151
  3. **Add the server configuration**:
199
152
 
200
- ```json
201
- {
202
- "mcpServers": {
203
- "eulerian-marketing-platform": {
204
- "command": "uvx",
205
- "args": ["eulerian-marketing-platform"],
206
- "env": {
207
- "EMP_API_ENDPOINT": "https://your-eulerian-instance.com/mcp",
208
- "EMP_API_TOKEN": "your_authentication_token_here"
209
- }
210
- }
211
- }
212
- }
213
- ```
214
-
215
- **Alternative: If using pip installation**:
216
-
217
153
  ```json
218
154
  {
219
155
  "mcpServers": {
@@ -244,7 +180,6 @@ Claude Desktop supports local MCP servers via stdio transport.
244
180
 
245
181
  **Linux**:
246
182
  - The config directory may not exist initially - create it with: `mkdir -p ~/.config/Claude`
247
- - Ensure `uvx` is installed: `pip install uv`
248
183
 
249
184
  **macOS**:
250
185
  - Access the config via Finder: `Cmd + Shift + G` → `~/Library/Application Support/Claude/`
@@ -285,8 +220,8 @@ nano ~/.gemini/settings.json
285
220
  {
286
221
  "mcpServers": {
287
222
  "eulerian-marketing-platform": {
288
- "command": "uvx",
289
- "args": ["eulerian-marketing-platform"],
223
+ "command": "python",
224
+ "args": ["-m", "eulerian_marketing_platform.server"],
290
225
  "env": {
291
226
  "EMP_API_ENDPOINT": "https://your-eulerian-instance.com/mcp",
292
227
  "EMP_API_TOKEN": "your_authentication_token_here"
@@ -317,102 +252,6 @@ gemini
317
252
 
318
253
  ---
319
254
 
320
- ### 3. Mistral AI (Le Chat)
321
-
322
- Mistral's Le Chat web interface supports MCP servers through **Custom Connectors**, but they must be deployed as **remote servers** with HTTP/SSE transport.
323
-
324
- #### Important Limitations
325
-
326
- - ❌ **Local stdio servers are NOT supported** by Mistral Le Chat
327
- - ✅ **Only remote HTTP/SSE servers** are supported
328
- - 📡 Your server must be publicly accessible via HTTPS
329
-
330
- #### Deployment Options
331
-
332
- You'll need to deploy your MCP server to a cloud platform. Popular options include:
333
-
334
- - **Render** (https://render.com)
335
- - **Railway** (https://railway.app)
336
- - **Fly.io** (https://fly.io)
337
- - **AWS Lambda** (with API Gateway)
338
- - **Google Cloud Run**
339
- - **Azure Container Instances**
340
-
341
- #### Server Modification for Remote Deployment
342
-
343
- Modify the `server.py` to support HTTP/SSE transport:
344
-
345
- ```python
346
- # In your server.py main() function
347
- def main() -> None:
348
- """Entry point for the MCP server."""
349
- validate_config()
350
-
351
- # For remote deployment (Mistral AI)
352
- import sys
353
- if "--remote" in sys.argv:
354
- mcp.run(transport="sse", port=8000)
355
- else:
356
- # Default stdio for local clients
357
- mcp.run()
358
- ```
359
-
360
- #### Example: Deploy to Render
361
-
362
- 1. **Create a `render.yaml` file**:
363
-
364
- ```yaml
365
- services:
366
- - type: web
367
- name: eulerian-mcp-server
368
- env: python
369
- buildCommand: pip install -e .
370
- startCommand: python -m eulerian_marketing_platform.server --remote
371
- envVars:
372
- - key: EMP_API_ENDPOINT
373
- sync: false
374
- - key: EMP_API_TOKEN
375
- sync: false
376
- ```
377
-
378
- 2. **Push to GitHub and connect to Render**
379
-
380
- 3. **Set environment variables in Render dashboard**
381
-
382
- #### Setup in Mistral Le Chat
383
-
384
- 1. **Open Le Chat** (https://chat.mistral.ai)
385
-
386
- 2. **Navigate to Connectors**:
387
- - Click the sidebar toggle
388
- - Go to `Intelligence` → `Connectors`
389
- - Click `+ Add Connector`
390
- - Select `Add custom connector`
391
-
392
- 3. **Configure the connector**:
393
- - **Name**: Eulerian Marketing Platform
394
- - **URL**: `https://your-deployed-server.render.com/mcp`
395
- - **Description**: Access to Eulerian Marketing Platform analytics and campaigns
396
- - **Authentication**:
397
- - Select `API Token Authentication` if your deployment requires it
398
- - Or `No Authentication` if your server handles auth via environment variables
399
-
400
- 4. **Connect and test**:
401
- - Click `Connect`
402
- - Once connected, enable it in a chat session
403
- - Ask: "What Eulerian Marketing Platform capabilities do you have?"
404
-
405
- #### Security Recommendations for Remote Deployment
406
-
407
- - ✅ Always use HTTPS (not HTTP)
408
- - ✅ Implement rate limiting
409
- - ✅ Add request origin validation
410
- - ✅ Use environment variables for secrets (never hardcode)
411
- - ✅ Monitor server logs for unusual activity
412
- - ✅ Consider adding IP allowlisting if possible
413
-
414
- ---
415
-
416
255
  ## Usage Examples
417
256
 
418
257
  Once configured with any client, you can interact with your remote Eulerian Marketing Platform:
@@ -421,17 +260,14 @@ Once configured with any client, you can interact with your remote Eulerian Mark
421
260
  User: "What tools are available from Eulerian?"
422
261
  → Proxy calls list_remote_tools() and returns all available tools
423
262
 
424
- User: "Call the get_campaigns tool"
425
- → Proxy forwards to remote server and returns campaign data
263
+ User: "Call the update_goal tool"
264
+ → Proxy forwards to remote server and update goal settings
426
265
 
427
266
  User: "Show me campaign details for CAMP-12345"
428
267
  → Claude uses call_eulerian_tool() to fetch specific campaign
429
268
 
430
269
  User: "What resources are available?"
431
270
  → Proxy lists all available data sources
432
-
433
- User: "Read the configuration at eulerian://config/settings"
434
- → Proxy fetches and returns the configuration
435
271
  ```
436
272
 
437
273
  The AI assistant will automatically use the appropriate proxy tools to fulfill your requests.
@@ -481,13 +317,6 @@ You'll see detailed logging of:
481
317
  - Verify the settings.json is valid JSON
482
318
  - Restart Gemini CLI
483
319
 
484
- #### Mistral connector fails to connect
485
- - **Solution**:
486
- - Verify your server is publicly accessible via `curl https://your-server.com/mcp`
487
- - Check server logs for errors
488
- - Ensure you're using HTTPS (not HTTP)
489
- - Verify the `/mcp` endpoint path is correct
490
-
491
320
  ### Debug Mode
492
321
 
493
322
  For detailed debugging:
@@ -556,9 +385,14 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
556
385
 
557
386
  ## Changelog
558
387
 
388
+ ### 0.2.0
389
+ - Move to full Proxy mode
390
+ - Remove instructions for uvx deployment
391
+ - Remove instructions for Mistral integration (too complex)
392
+
559
393
  ### 0.1.0 (Initial Release)
560
394
  - Initial MCP server implementation
561
- - Support for Claude Desktop, Gemini CLI, and Mistral AI
395
+ - Support for Claude Desktop, Gemini CLI
562
396
  - Cross-platform support (Windows, Linux, macOS)
563
397
  - Environment-based configuration
564
398
 
@@ -0,0 +1,8 @@
1
+ eulerian_marketing_platform/__init__.py,sha256=HibL07V6VMhqFcQSFGJm8ogUu9Qcfl2SSenCfdKtBFY,428
2
+ eulerian_marketing_platform/server.py,sha256=y1vy-LvSjG18dvDv65hO875s_7vogbb5bdNwTetKKcU,8335
3
+ eulerian_marketing_platform-0.2.1.dist-info/LICENSE,sha256=eIqBqE_fRsqQJ8F-2v0e-8WzZqdshsCqnzmqLAWrNHU,1078
4
+ eulerian_marketing_platform-0.2.1.dist-info/METADATA,sha256=WDzHWUPBn0P6MC3PhFXOx70BRGa2xGHIdwoycImLCaA,12111
5
+ eulerian_marketing_platform-0.2.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
6
+ eulerian_marketing_platform-0.2.1.dist-info/entry_points.txt,sha256=rrPZptATSS9PUtH9gzCYq0WuP6eahkF-DkdUP1FaYfk,88
7
+ eulerian_marketing_platform-0.2.1.dist-info/top_level.txt,sha256=nidh3T6fw-mLjUqZwQ8AiMScS4usuH0WXW4ZgG4HYCo,28
8
+ eulerian_marketing_platform-0.2.1.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- eulerian_marketing_platform/__init__.py,sha256=osuJ8iP6O20ElZXPoZlOQ7sNbZ93kgMz3we8mm_B2-Y,428
2
- eulerian_marketing_platform/server.py,sha256=bUVn_b05ZritTtNflldCxoFn8YwyrQBqrcbQZ5ceZAg,9810
3
- eulerian_marketing_platform-0.1.2.dist-info/LICENSE,sha256=eIqBqE_fRsqQJ8F-2v0e-8WzZqdshsCqnzmqLAWrNHU,1078
4
- eulerian_marketing_platform-0.1.2.dist-info/METADATA,sha256=gfE3v09r1B4dd8Vi_snjgd9JQDWaHplKnZMsp1ML-34,16957
5
- eulerian_marketing_platform-0.1.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
6
- eulerian_marketing_platform-0.1.2.dist-info/entry_points.txt,sha256=rrPZptATSS9PUtH9gzCYq0WuP6eahkF-DkdUP1FaYfk,88
7
- eulerian_marketing_platform-0.1.2.dist-info/top_level.txt,sha256=nidh3T6fw-mLjUqZwQ8AiMScS4usuH0WXW4ZgG4HYCo,28
8
- eulerian_marketing_platform-0.1.2.dist-info/RECORD,,