listmonk-api 0.6.0__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.
- listmonk_api-0.6.0/LICENSE +21 -0
- listmonk_api-0.6.0/MANIFEST.in +4 -0
- listmonk_api-0.6.0/PKG-INFO +303 -0
- listmonk_api-0.6.0/README.md +282 -0
- listmonk_api-0.6.0/listmonk_api/__init__.py +83 -0
- listmonk_api-0.6.0/listmonk_api/__main__.py +6 -0
- listmonk_api-0.6.0/listmonk_api/agent_server.py +85 -0
- listmonk_api-0.6.0/listmonk_api/api_client.py +300 -0
- listmonk_api-0.6.0/listmonk_api/auth.py +36 -0
- listmonk_api-0.6.0/listmonk_api/listmonk_api.py +734 -0
- listmonk_api-0.6.0/listmonk_api/main_agent.json +10 -0
- listmonk_api-0.6.0/listmonk_api/mcp_config.json +3 -0
- listmonk_api-0.6.0/listmonk_api/mcp_server.py +444 -0
- listmonk_api-0.6.0/listmonk_api/models.py +75 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/PKG-INFO +303 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/SOURCES.txt +22 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/dependency_links.txt +1 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/entry_points.txt +3 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/requires.txt +7 -0
- listmonk_api-0.6.0/listmonk_api.egg-info/top_level.txt +6 -0
- listmonk_api-0.6.0/pyproject.toml +44 -0
- listmonk_api-0.6.0/requirements.txt +1 -0
- listmonk_api-0.6.0/setup.cfg +4 -0
- listmonk_api-0.6.0/tests/test_mcp_server.py +11 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Audel Rouhi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: listmonk-api
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Agent package for Listmonk
|
|
5
|
+
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: agent-utilities[mcp]>=0.16.0
|
|
16
|
+
Provides-Extra: agent
|
|
17
|
+
Requires-Dist: agent-utilities[agent,logfire]>=0.16.0; extra == "agent"
|
|
18
|
+
Provides-Extra: all
|
|
19
|
+
Requires-Dist: agent-utilities[agent,logfire,mcp]>=0.16.0; extra == "all"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Listmonk Api
|
|
23
|
+
## CLI or API | MCP | Agent
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+

|
|
27
|
+

|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+

|
|
40
|
+

|
|
41
|
+

|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
*Version: 0.6.0*
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Overview
|
|
49
|
+
|
|
50
|
+
**Listmonk Api** is a production-grade Agent and Model Context Protocol (MCP) server designed to interface directly with Python Listmonk API Wrapper.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Key Features
|
|
55
|
+
|
|
56
|
+
- **Consolidated Action-Routed MCP Tools:** Minimizes token overhead and eliminates tool bloat in LLM contexts by grouping methods into optimized, togglable tool modules.
|
|
57
|
+
- **Enterprise-Grade Security:** Comprehensive support for Eunomia policies, OIDC token delegation, and granular execution context tracking.
|
|
58
|
+
- **Integrated Graph Agent:** Built-in Pydantic AI agent supporting the Agent Control Protocol (ACP) and standard Web interfaces (AG-UI).
|
|
59
|
+
- **Native Telemetry & Tracing:** Out-of-the-box OpenTelemetry exports and native Langfuse tracing.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## CLI or API
|
|
64
|
+
|
|
65
|
+
This agent wraps the Python Listmonk API Wrapper API. You can interact with it programmatically or via its integrated execution entrypoints.
|
|
66
|
+
|
|
67
|
+
Detailed instructions on how to use the underlying API wrappers, extended schema bindings, and developer SDK references are maintained in [docs/index.md](docs/index.md).
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## MCP
|
|
72
|
+
|
|
73
|
+
This server utilizes dynamic Action-Routed tools to optimize token overhead and maximize IDE compatibility.
|
|
74
|
+
|
|
75
|
+
### Available MCP Tools
|
|
76
|
+
| Tool Module | Toggle Env Var | Enabled by Default | Description & Nested Methods |
|
|
77
|
+
|-------------|----------------|--------------------|------------------------------|
|
|
78
|
+
| **Subscribers** | `SUBSCRIBERSTOOL` | `True` | Manage listmonk subscribers. Action-routed methods. |
|
|
79
|
+
| **Lists** | `LISTSTOOL` | `True` | Manage listmonk lists. Action-routed methods. |
|
|
80
|
+
| **Imports** | `IMPORTSTOOL` | `True` | Manage listmonk imports. Action-routed methods. |
|
|
81
|
+
| **Campaigns** | `CAMPAIGNSTOOL` | `True` | Manage listmonk campaigns. Action-routed methods. |
|
|
82
|
+
| **Media** | `MEDIATOOL` | `True` | Manage listmonk media. Action-routed methods. |
|
|
83
|
+
| **Templates** | `TEMPLATESTOOL` | `True` | Manage listmonk templates. Action-routed methods. |
|
|
84
|
+
| **Tx** | `TXTOOL` | `True` | Manage listmonk transactional messages. Action-routed methods. |
|
|
85
|
+
|
|
86
|
+
Detailed tool schemas, parameter shapes, and validation constraints are preserved in [docs/mcp.md](docs/mcp.md).
|
|
87
|
+
|
|
88
|
+
### MCP Configuration Examples
|
|
89
|
+
|
|
90
|
+
#### stdio Transport (Recommended for local IDEs e.g., Cursor, Claude Desktop)
|
|
91
|
+
Configure your IDE's `mcp.json` to launch the MCP server via `uvx`:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"listmonk-api": {
|
|
97
|
+
"command": "uvx",
|
|
98
|
+
"args": [
|
|
99
|
+
"--from",
|
|
100
|
+
"listmonk-api",
|
|
101
|
+
"listmonk-mcp"
|
|
102
|
+
],
|
|
103
|
+
"env": {
|
|
104
|
+
"LISTMONK_URL": "your_listmonk_url_here",
|
|
105
|
+
"LISTMONK_USERNAME": "your_listmonk_username_here",
|
|
106
|
+
"LISTMONK_PASSWORD": "your_listmonk_password_here"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Streamable-HTTP Transport (Recommended for production deployments)
|
|
114
|
+
Configure your client's `mcp.json` to launch the Streamable-HTTP server via `uvx` with explicit host and port definition:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"listmonk-api": {
|
|
120
|
+
"command": "uvx",
|
|
121
|
+
"args": [
|
|
122
|
+
"--from",
|
|
123
|
+
"listmonk-api",
|
|
124
|
+
"listmonk-mcp"
|
|
125
|
+
],
|
|
126
|
+
"env": {
|
|
127
|
+
"TRANSPORT": "streamable-http",
|
|
128
|
+
"HOST": "0.0.0.0",
|
|
129
|
+
"PORT": "8000",
|
|
130
|
+
"LISTMONK_URL": "your_listmonk_url_here",
|
|
131
|
+
"LISTMONK_USERNAME": "your_listmonk_username_here",
|
|
132
|
+
"LISTMONK_PASSWORD": "your_listmonk_password_here"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Alternatively, connect to a pre-deployed remote or local Streamable-HTTP instance:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"mcpServers": {
|
|
144
|
+
"listmonk-api": {
|
|
145
|
+
"url": "http://localhost:8000/listmonk-api/mcp"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Deploying the Streamable-HTTP server via Docker:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
docker run -d \
|
|
155
|
+
--name listmonk-api-mcp \
|
|
156
|
+
-p 8000:8000 \
|
|
157
|
+
-e TRANSPORT=streamable-http \
|
|
158
|
+
-e PORT=8000 \
|
|
159
|
+
-e LISTMONK_URL="your_listmonk_url_here" \
|
|
160
|
+
-e LISTMONK_USERNAME="your_listmonk_username_here" \
|
|
161
|
+
-e LISTMONK_PASSWORD="your_listmonk_password_here" \
|
|
162
|
+
knucklessg1/listmonk-api:latest
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Agent
|
|
168
|
+
|
|
169
|
+
This repository features a fully integrated Pydantic AI Graph Agent. It communicates over the **Agent Control Protocol (ACP)** and interacts seamlessly with the **Agent Web UI (AG-UI)** and Terminal interface.
|
|
170
|
+
|
|
171
|
+
### Running the Agent CLI
|
|
172
|
+
To start the interactive command-line agent:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Set credentials
|
|
176
|
+
export LISTMONK_URL="your_listmonk_url_here"
|
|
177
|
+
export LISTMONK_USERNAME="your_listmonk_username_here"
|
|
178
|
+
export LISTMONK_PASSWORD="your_listmonk_password_here"
|
|
179
|
+
|
|
180
|
+
# Run the agent server
|
|
181
|
+
listmonk-agent --provider openai --model-id gpt-4o
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Docker Compose Orchestration
|
|
185
|
+
The following `docker/agent.compose.yml` configures the Agent, Web UI, and Terminal Interface together:
|
|
186
|
+
|
|
187
|
+
```yaml
|
|
188
|
+
version: '3.8'
|
|
189
|
+
|
|
190
|
+
services:
|
|
191
|
+
listmonk-api-mcp:
|
|
192
|
+
image: knucklessg1/listmonk-api:latest
|
|
193
|
+
container_name: listmonk-api-mcp
|
|
194
|
+
hostname: listmonk-api-mcp
|
|
195
|
+
restart: always
|
|
196
|
+
env_file:
|
|
197
|
+
- ../.env
|
|
198
|
+
environment:
|
|
199
|
+
- PYTHONUNBUFFERED=1
|
|
200
|
+
- HOST=0.0.0.0
|
|
201
|
+
- PORT=8000
|
|
202
|
+
- TRANSPORT=streamable-http
|
|
203
|
+
ports:
|
|
204
|
+
- "8000:8000"
|
|
205
|
+
healthcheck:
|
|
206
|
+
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
|
|
207
|
+
interval: 30s
|
|
208
|
+
timeout: 10s
|
|
209
|
+
retries: 3
|
|
210
|
+
start_period: 10s
|
|
211
|
+
logging:
|
|
212
|
+
driver: json-file
|
|
213
|
+
options:
|
|
214
|
+
max-size: "10m"
|
|
215
|
+
max-file: "3"
|
|
216
|
+
|
|
217
|
+
listmonk-api-agent:
|
|
218
|
+
image: knucklessg1/listmonk-api:latest
|
|
219
|
+
container_name: listmonk-api-agent
|
|
220
|
+
hostname: listmonk-api-agent
|
|
221
|
+
restart: always
|
|
222
|
+
depends_on:
|
|
223
|
+
- listmonk-api-mcp
|
|
224
|
+
env_file:
|
|
225
|
+
- ../.env
|
|
226
|
+
command: [ "listmonk-agent" ]
|
|
227
|
+
environment:
|
|
228
|
+
- PYTHONUNBUFFERED=1
|
|
229
|
+
- HOST=0.0.0.0
|
|
230
|
+
- PORT=9004
|
|
231
|
+
- MCP_URL=http://listmonk-api-mcp:8000/mcp
|
|
232
|
+
- PROVIDER=${PROVIDER:-openai}
|
|
233
|
+
- MODEL_ID=${MODEL_ID:-gpt-4o}
|
|
234
|
+
- ENABLE_WEB_UI=True
|
|
235
|
+
- ENABLE_OTEL=True
|
|
236
|
+
ports:
|
|
237
|
+
- "9004:9004"
|
|
238
|
+
healthcheck:
|
|
239
|
+
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:9004/health')"]
|
|
240
|
+
interval: 30s
|
|
241
|
+
timeout: 10s
|
|
242
|
+
retries: 3
|
|
243
|
+
start_period: 10s
|
|
244
|
+
logging:
|
|
245
|
+
driver: json-file
|
|
246
|
+
options:
|
|
247
|
+
max-size: "10m"
|
|
248
|
+
max-file: "3"
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Detailed graph node architecture explanations, custom skill configurations, and agentic trace guides are available in [docs/agent.md](docs/agent.md).
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Security & Governance
|
|
257
|
+
|
|
258
|
+
Built directly upon the enterprise-ready [`agent-utilities`](https://github.com/Knuckles-Team/agent-utilities) core, standard security parameters are fully supported:
|
|
259
|
+
|
|
260
|
+
### Access Control & Policy Enforcement
|
|
261
|
+
- **Eunomia Policies:** Fine-grained, policy-driven tool authorization. Supports `none`, local `embedded` (`mcp_policies.json`), or centralized `remote` modes.
|
|
262
|
+
- **OIDC Token Delegation:** Compliant with RFC 8693 token exchange for flowing authenticating user credentials from Web UI / ACP → Agent → MCP.
|
|
263
|
+
- **Scoped Credentials:** Execution context runs restricted to the specific caller identity.
|
|
264
|
+
|
|
265
|
+
### Runtime Security Grid
|
|
266
|
+
| Feature | Functionality | Enablement |
|
|
267
|
+
|---------|---------------|------------|
|
|
268
|
+
| **Tool Guard** | Sensitivity inspection with human-in-the-loop validation | Enabled by default |
|
|
269
|
+
| **Prompt Injection Defense** | Input scanning, repetition monitoring, and recursive loop blocks | Enabled by default |
|
|
270
|
+
| **Context Safety Guard** | Stuck-loop detectors and contextual overflow preemptive alerts | Enabled by default |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Installation
|
|
275
|
+
|
|
276
|
+
Install the Python package locally:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Using uv (highly recommended)
|
|
280
|
+
uv pip install listmonk-api[all]
|
|
281
|
+
|
|
282
|
+
# Using standard pip
|
|
283
|
+
python -m pip install listmonk-api[all]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Repository Owners
|
|
289
|
+
|
|
290
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
291
|
+
|
|
292
|
+

|
|
293
|
+

|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Contribute
|
|
298
|
+
|
|
299
|
+
Contributions are welcome! Please ensure code quality by executing local checks before submitting pull requests:
|
|
300
|
+
- Format code using `ruff format .`
|
|
301
|
+
- Lint code using `ruff check .`
|
|
302
|
+
- Validate type-safety with `mypy .`
|
|
303
|
+
- Execute test suites using `pytest`
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# Listmonk Api
|
|
2
|
+
## CLI or API | MCP | Agent
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+

|
|
16
|
+

|
|
17
|
+

|
|
18
|
+

|
|
19
|
+

|
|
20
|
+

|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
*Version: 0.6.0*
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
**Listmonk Api** is a production-grade Agent and Model Context Protocol (MCP) server designed to interface directly with Python Listmonk API Wrapper.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Key Features
|
|
34
|
+
|
|
35
|
+
- **Consolidated Action-Routed MCP Tools:** Minimizes token overhead and eliminates tool bloat in LLM contexts by grouping methods into optimized, togglable tool modules.
|
|
36
|
+
- **Enterprise-Grade Security:** Comprehensive support for Eunomia policies, OIDC token delegation, and granular execution context tracking.
|
|
37
|
+
- **Integrated Graph Agent:** Built-in Pydantic AI agent supporting the Agent Control Protocol (ACP) and standard Web interfaces (AG-UI).
|
|
38
|
+
- **Native Telemetry & Tracing:** Out-of-the-box OpenTelemetry exports and native Langfuse tracing.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## CLI or API
|
|
43
|
+
|
|
44
|
+
This agent wraps the Python Listmonk API Wrapper API. You can interact with it programmatically or via its integrated execution entrypoints.
|
|
45
|
+
|
|
46
|
+
Detailed instructions on how to use the underlying API wrappers, extended schema bindings, and developer SDK references are maintained in [docs/index.md](docs/index.md).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## MCP
|
|
51
|
+
|
|
52
|
+
This server utilizes dynamic Action-Routed tools to optimize token overhead and maximize IDE compatibility.
|
|
53
|
+
|
|
54
|
+
### Available MCP Tools
|
|
55
|
+
| Tool Module | Toggle Env Var | Enabled by Default | Description & Nested Methods |
|
|
56
|
+
|-------------|----------------|--------------------|------------------------------|
|
|
57
|
+
| **Subscribers** | `SUBSCRIBERSTOOL` | `True` | Manage listmonk subscribers. Action-routed methods. |
|
|
58
|
+
| **Lists** | `LISTSTOOL` | `True` | Manage listmonk lists. Action-routed methods. |
|
|
59
|
+
| **Imports** | `IMPORTSTOOL` | `True` | Manage listmonk imports. Action-routed methods. |
|
|
60
|
+
| **Campaigns** | `CAMPAIGNSTOOL` | `True` | Manage listmonk campaigns. Action-routed methods. |
|
|
61
|
+
| **Media** | `MEDIATOOL` | `True` | Manage listmonk media. Action-routed methods. |
|
|
62
|
+
| **Templates** | `TEMPLATESTOOL` | `True` | Manage listmonk templates. Action-routed methods. |
|
|
63
|
+
| **Tx** | `TXTOOL` | `True` | Manage listmonk transactional messages. Action-routed methods. |
|
|
64
|
+
|
|
65
|
+
Detailed tool schemas, parameter shapes, and validation constraints are preserved in [docs/mcp.md](docs/mcp.md).
|
|
66
|
+
|
|
67
|
+
### MCP Configuration Examples
|
|
68
|
+
|
|
69
|
+
#### stdio Transport (Recommended for local IDEs e.g., Cursor, Claude Desktop)
|
|
70
|
+
Configure your IDE's `mcp.json` to launch the MCP server via `uvx`:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"listmonk-api": {
|
|
76
|
+
"command": "uvx",
|
|
77
|
+
"args": [
|
|
78
|
+
"--from",
|
|
79
|
+
"listmonk-api",
|
|
80
|
+
"listmonk-mcp"
|
|
81
|
+
],
|
|
82
|
+
"env": {
|
|
83
|
+
"LISTMONK_URL": "your_listmonk_url_here",
|
|
84
|
+
"LISTMONK_USERNAME": "your_listmonk_username_here",
|
|
85
|
+
"LISTMONK_PASSWORD": "your_listmonk_password_here"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Streamable-HTTP Transport (Recommended for production deployments)
|
|
93
|
+
Configure your client's `mcp.json` to launch the Streamable-HTTP server via `uvx` with explicit host and port definition:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"listmonk-api": {
|
|
99
|
+
"command": "uvx",
|
|
100
|
+
"args": [
|
|
101
|
+
"--from",
|
|
102
|
+
"listmonk-api",
|
|
103
|
+
"listmonk-mcp"
|
|
104
|
+
],
|
|
105
|
+
"env": {
|
|
106
|
+
"TRANSPORT": "streamable-http",
|
|
107
|
+
"HOST": "0.0.0.0",
|
|
108
|
+
"PORT": "8000",
|
|
109
|
+
"LISTMONK_URL": "your_listmonk_url_here",
|
|
110
|
+
"LISTMONK_USERNAME": "your_listmonk_username_here",
|
|
111
|
+
"LISTMONK_PASSWORD": "your_listmonk_password_here"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Alternatively, connect to a pre-deployed remote or local Streamable-HTTP instance:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"listmonk-api": {
|
|
124
|
+
"url": "http://localhost:8000/listmonk-api/mcp"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Deploying the Streamable-HTTP server via Docker:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
docker run -d \
|
|
134
|
+
--name listmonk-api-mcp \
|
|
135
|
+
-p 8000:8000 \
|
|
136
|
+
-e TRANSPORT=streamable-http \
|
|
137
|
+
-e PORT=8000 \
|
|
138
|
+
-e LISTMONK_URL="your_listmonk_url_here" \
|
|
139
|
+
-e LISTMONK_USERNAME="your_listmonk_username_here" \
|
|
140
|
+
-e LISTMONK_PASSWORD="your_listmonk_password_here" \
|
|
141
|
+
knucklessg1/listmonk-api:latest
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Agent
|
|
147
|
+
|
|
148
|
+
This repository features a fully integrated Pydantic AI Graph Agent. It communicates over the **Agent Control Protocol (ACP)** and interacts seamlessly with the **Agent Web UI (AG-UI)** and Terminal interface.
|
|
149
|
+
|
|
150
|
+
### Running the Agent CLI
|
|
151
|
+
To start the interactive command-line agent:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Set credentials
|
|
155
|
+
export LISTMONK_URL="your_listmonk_url_here"
|
|
156
|
+
export LISTMONK_USERNAME="your_listmonk_username_here"
|
|
157
|
+
export LISTMONK_PASSWORD="your_listmonk_password_here"
|
|
158
|
+
|
|
159
|
+
# Run the agent server
|
|
160
|
+
listmonk-agent --provider openai --model-id gpt-4o
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Docker Compose Orchestration
|
|
164
|
+
The following `docker/agent.compose.yml` configures the Agent, Web UI, and Terminal Interface together:
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
version: '3.8'
|
|
168
|
+
|
|
169
|
+
services:
|
|
170
|
+
listmonk-api-mcp:
|
|
171
|
+
image: knucklessg1/listmonk-api:latest
|
|
172
|
+
container_name: listmonk-api-mcp
|
|
173
|
+
hostname: listmonk-api-mcp
|
|
174
|
+
restart: always
|
|
175
|
+
env_file:
|
|
176
|
+
- ../.env
|
|
177
|
+
environment:
|
|
178
|
+
- PYTHONUNBUFFERED=1
|
|
179
|
+
- HOST=0.0.0.0
|
|
180
|
+
- PORT=8000
|
|
181
|
+
- TRANSPORT=streamable-http
|
|
182
|
+
ports:
|
|
183
|
+
- "8000:8000"
|
|
184
|
+
healthcheck:
|
|
185
|
+
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
|
|
186
|
+
interval: 30s
|
|
187
|
+
timeout: 10s
|
|
188
|
+
retries: 3
|
|
189
|
+
start_period: 10s
|
|
190
|
+
logging:
|
|
191
|
+
driver: json-file
|
|
192
|
+
options:
|
|
193
|
+
max-size: "10m"
|
|
194
|
+
max-file: "3"
|
|
195
|
+
|
|
196
|
+
listmonk-api-agent:
|
|
197
|
+
image: knucklessg1/listmonk-api:latest
|
|
198
|
+
container_name: listmonk-api-agent
|
|
199
|
+
hostname: listmonk-api-agent
|
|
200
|
+
restart: always
|
|
201
|
+
depends_on:
|
|
202
|
+
- listmonk-api-mcp
|
|
203
|
+
env_file:
|
|
204
|
+
- ../.env
|
|
205
|
+
command: [ "listmonk-agent" ]
|
|
206
|
+
environment:
|
|
207
|
+
- PYTHONUNBUFFERED=1
|
|
208
|
+
- HOST=0.0.0.0
|
|
209
|
+
- PORT=9004
|
|
210
|
+
- MCP_URL=http://listmonk-api-mcp:8000/mcp
|
|
211
|
+
- PROVIDER=${PROVIDER:-openai}
|
|
212
|
+
- MODEL_ID=${MODEL_ID:-gpt-4o}
|
|
213
|
+
- ENABLE_WEB_UI=True
|
|
214
|
+
- ENABLE_OTEL=True
|
|
215
|
+
ports:
|
|
216
|
+
- "9004:9004"
|
|
217
|
+
healthcheck:
|
|
218
|
+
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:9004/health')"]
|
|
219
|
+
interval: 30s
|
|
220
|
+
timeout: 10s
|
|
221
|
+
retries: 3
|
|
222
|
+
start_period: 10s
|
|
223
|
+
logging:
|
|
224
|
+
driver: json-file
|
|
225
|
+
options:
|
|
226
|
+
max-size: "10m"
|
|
227
|
+
max-file: "3"
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Detailed graph node architecture explanations, custom skill configurations, and agentic trace guides are available in [docs/agent.md](docs/agent.md).
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Security & Governance
|
|
236
|
+
|
|
237
|
+
Built directly upon the enterprise-ready [`agent-utilities`](https://github.com/Knuckles-Team/agent-utilities) core, standard security parameters are fully supported:
|
|
238
|
+
|
|
239
|
+
### Access Control & Policy Enforcement
|
|
240
|
+
- **Eunomia Policies:** Fine-grained, policy-driven tool authorization. Supports `none`, local `embedded` (`mcp_policies.json`), or centralized `remote` modes.
|
|
241
|
+
- **OIDC Token Delegation:** Compliant with RFC 8693 token exchange for flowing authenticating user credentials from Web UI / ACP → Agent → MCP.
|
|
242
|
+
- **Scoped Credentials:** Execution context runs restricted to the specific caller identity.
|
|
243
|
+
|
|
244
|
+
### Runtime Security Grid
|
|
245
|
+
| Feature | Functionality | Enablement |
|
|
246
|
+
|---------|---------------|------------|
|
|
247
|
+
| **Tool Guard** | Sensitivity inspection with human-in-the-loop validation | Enabled by default |
|
|
248
|
+
| **Prompt Injection Defense** | Input scanning, repetition monitoring, and recursive loop blocks | Enabled by default |
|
|
249
|
+
| **Context Safety Guard** | Stuck-loop detectors and contextual overflow preemptive alerts | Enabled by default |
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Installation
|
|
254
|
+
|
|
255
|
+
Install the Python package locally:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Using uv (highly recommended)
|
|
259
|
+
uv pip install listmonk-api[all]
|
|
260
|
+
|
|
261
|
+
# Using standard pip
|
|
262
|
+
python -m pip install listmonk-api[all]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Repository Owners
|
|
268
|
+
|
|
269
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
270
|
+
|
|
271
|
+

|
|
272
|
+

|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Contribute
|
|
277
|
+
|
|
278
|
+
Contributions are welcome! Please ensure code quality by executing local checks before submitting pull requests:
|
|
279
|
+
- Format code using `ruff format .`
|
|
280
|
+
- Lint code using `ruff check .`
|
|
281
|
+
- Validate type-safety with `mypy .`
|
|
282
|
+
- Execute test suites using `pytest`
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
from typing import Any
|
|
6
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
# Suppress RequestsDependencyWarning due to chardet 6.x / requests 2.32.x mismatch
|
|
9
|
+
# Centralized here to ensure it runs before any sub-package imports
|
|
10
|
+
warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
|
|
11
|
+
|
|
12
|
+
__all__: list[str] = []
|
|
13
|
+
|
|
14
|
+
CORE_MODULES: list[str] = [
|
|
15
|
+
"listmonk_api.api_client",
|
|
16
|
+
"listmonk_api.models",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
OPTIONAL_MODULES = {
|
|
20
|
+
"listmonk_api.agent_server": "agent_server",
|
|
21
|
+
"listmonk_api.mcp_server": "mcp_server",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _expose_members(module):
|
|
26
|
+
"""Expose public classes and functions from a module into globals and __all__."""
|
|
27
|
+
for name, obj in inspect.getmembers(module):
|
|
28
|
+
if (inspect.isclass(obj) or inspect.isfunction(obj)) and not name.startswith(
|
|
29
|
+
"_"
|
|
30
|
+
):
|
|
31
|
+
globals()[name] = obj
|
|
32
|
+
if name not in __all__:
|
|
33
|
+
__all__.append(name)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Eagerly import core modules (keeps API wrappers fast & light)
|
|
37
|
+
for module_name in CORE_MODULES:
|
|
38
|
+
if module_name:
|
|
39
|
+
module = importlib.import_module(module_name)
|
|
40
|
+
_expose_members(module)
|
|
41
|
+
|
|
42
|
+
# Dynamic/lazy loading of optional modules (agent_server, mcp_server)
|
|
43
|
+
_loaded_optional_modules = {}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _import_module_safely(module_name: str):
|
|
47
|
+
"""Try to import a module and return it, or None if not available."""
|
|
48
|
+
try:
|
|
49
|
+
return importlib.import_module(module_name)
|
|
50
|
+
except ImportError:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def __getattr__(name: str) -> Any:
|
|
55
|
+
# Handle availability flags dynamically without eager imports
|
|
56
|
+
if name == "_MCP_AVAILABLE":
|
|
57
|
+
mcp_key = next((k for k in OPTIONAL_MODULES if "mcp_server" in k), None)
|
|
58
|
+
if mcp_key:
|
|
59
|
+
return _import_module_safely(mcp_key) is not None
|
|
60
|
+
return False
|
|
61
|
+
if name == "_AGENT_AVAILABLE":
|
|
62
|
+
agent_key = next((k for k in OPTIONAL_MODULES if "agent_server" in k), None)
|
|
63
|
+
if agent_key:
|
|
64
|
+
return _import_module_safely(agent_key) is not None
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
# Check optional modules
|
|
68
|
+
for module_name in OPTIONAL_MODULES:
|
|
69
|
+
if module_name not in _loaded_optional_modules:
|
|
70
|
+
module = _import_module_safely(module_name)
|
|
71
|
+
if module is not None:
|
|
72
|
+
_loaded_optional_modules[module_name] = module
|
|
73
|
+
_expose_members(module)
|
|
74
|
+
|
|
75
|
+
module = _loaded_optional_modules.get(module_name)
|
|
76
|
+
if module is not None and hasattr(module, name):
|
|
77
|
+
return getattr(module, name)
|
|
78
|
+
|
|
79
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def __dir__() -> list[str]:
|
|
83
|
+
return sorted(list(globals().keys()) + __all__)
|