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.
@@ -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,4 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include listmonk_api *.md *.json *.yaml *.yml *.py
@@ -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
+ ![PyPI - Version](https://img.shields.io/pypi/v/listmonk-api)
26
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
27
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/listmonk-api)
28
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/listmonk-api)
29
+ ![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/listmonk-api)
30
+ ![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/listmonk-api)
31
+ ![PyPI - License](https://img.shields.io/pypi/l/listmonk-api)
32
+ ![GitHub](https://img.shields.io/github/license/Knuckles-Team/listmonk-api)
33
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/listmonk-api)
34
+ ![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/listmonk-api)
35
+ ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/listmonk-api)
36
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/listmonk-api)
37
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/listmonk-api)
38
+ ![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/listmonk-api)
39
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/listmonk-api)
40
+ ![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/listmonk-api)
41
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/listmonk-api)
42
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/listmonk-api)
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
+ ![GitHub followers](https://img.shields.io/github/followers/Knucklessg1)
293
+ ![GitHub User's stars](https://img.shields.io/github/stars/Knucklessg1)
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
+ ![PyPI - Version](https://img.shields.io/pypi/v/listmonk-api)
5
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
6
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/listmonk-api)
7
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/listmonk-api)
8
+ ![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/listmonk-api)
9
+ ![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/listmonk-api)
10
+ ![PyPI - License](https://img.shields.io/pypi/l/listmonk-api)
11
+ ![GitHub](https://img.shields.io/github/license/Knuckles-Team/listmonk-api)
12
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/listmonk-api)
13
+ ![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/listmonk-api)
14
+ ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/listmonk-api)
15
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/listmonk-api)
16
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/listmonk-api)
17
+ ![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/listmonk-api)
18
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/listmonk-api)
19
+ ![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/listmonk-api)
20
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/listmonk-api)
21
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/listmonk-api)
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
+ ![GitHub followers](https://img.shields.io/github/followers/Knucklessg1)
272
+ ![GitHub User's stars](https://img.shields.io/github/stars/Knucklessg1)
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__)