container-manager-mcp 1.1.8__py3-none-any.whl → 1.1.9__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.

Potentially problematic release.


This version of container-manager-mcp might be problematic. Click here for more details.

@@ -5,10 +5,16 @@ import argparse
5
5
  import os
6
6
  import sys
7
7
  import logging
8
- from typing import Optional, List, Dict, Union
9
-
10
- from fastmcp import FastMCP, Context
8
+ from typing import Optional, Dict, List, Union
11
9
  from pydantic import Field
10
+ from fastmcp import FastMCP, Context
11
+ from fastmcp.server.auth.oidc_proxy import OIDCProxy
12
+ from fastmcp.server.auth import OAuthProxy, RemoteAuthProvider
13
+ from fastmcp.server.auth.providers.jwt import JWTVerifier, StaticTokenVerifier
14
+ from fastmcp.server.middleware.logging import LoggingMiddleware
15
+ from fastmcp.server.middleware.timing import TimingMiddleware
16
+ from fastmcp.server.middleware.rate_limiting import RateLimitingMiddleware
17
+ from fastmcp.server.middleware.error_handling import ErrorHandlingMiddleware
12
18
  from container_manager_mcp.container_manager import create_manager
13
19
 
14
20
 
@@ -1556,6 +1562,83 @@ def container_manager_mcp():
1556
1562
  default=8000,
1557
1563
  help="Port number for HTTP transport (default: 8000)",
1558
1564
  )
1565
+ parser.add_argument(
1566
+ "--auth-type",
1567
+ default="none",
1568
+ choices=["none", "static", "jwt", "oauth-proxy", "oidc-proxy", "remote-oauth"],
1569
+ help="Authentication type for MCP server: 'none' (disabled), 'static' (internal), 'jwt' (external token verification), 'oauth-proxy', 'oidc-proxy', 'remote-oauth' (external) (default: none)",
1570
+ )
1571
+ # JWT/Token params
1572
+ parser.add_argument(
1573
+ "--token-jwks-uri", default=None, help="JWKS URI for JWT verification"
1574
+ )
1575
+ parser.add_argument(
1576
+ "--token-issuer", default=None, help="Issuer for JWT verification"
1577
+ )
1578
+ parser.add_argument(
1579
+ "--token-audience", default=None, help="Audience for JWT verification"
1580
+ )
1581
+ # OAuth Proxy params
1582
+ parser.add_argument(
1583
+ "--oauth-upstream-auth-endpoint",
1584
+ default=None,
1585
+ help="Upstream authorization endpoint for OAuth Proxy",
1586
+ )
1587
+ parser.add_argument(
1588
+ "--oauth-upstream-token-endpoint",
1589
+ default=None,
1590
+ help="Upstream token endpoint for OAuth Proxy",
1591
+ )
1592
+ parser.add_argument(
1593
+ "--oauth-upstream-client-id",
1594
+ default=None,
1595
+ help="Upstream client ID for OAuth Proxy",
1596
+ )
1597
+ parser.add_argument(
1598
+ "--oauth-upstream-client-secret",
1599
+ default=None,
1600
+ help="Upstream client secret for OAuth Proxy",
1601
+ )
1602
+ parser.add_argument(
1603
+ "--oauth-base-url", default=None, help="Base URL for OAuth Proxy"
1604
+ )
1605
+ # OIDC Proxy params
1606
+ parser.add_argument(
1607
+ "--oidc-config-url", default=None, help="OIDC configuration URL"
1608
+ )
1609
+ parser.add_argument("--oidc-client-id", default=None, help="OIDC client ID")
1610
+ parser.add_argument("--oidc-client-secret", default=None, help="OIDC client secret")
1611
+ parser.add_argument("--oidc-base-url", default=None, help="Base URL for OIDC Proxy")
1612
+ # Remote OAuth params
1613
+ parser.add_argument(
1614
+ "--remote-auth-servers",
1615
+ default=None,
1616
+ help="Comma-separated list of authorization servers for Remote OAuth",
1617
+ )
1618
+ parser.add_argument(
1619
+ "--remote-base-url", default=None, help="Base URL for Remote OAuth"
1620
+ )
1621
+ # Common
1622
+ parser.add_argument(
1623
+ "--allowed-client-redirect-uris",
1624
+ default=None,
1625
+ help="Comma-separated list of allowed client redirect URIs",
1626
+ )
1627
+ # Eunomia params
1628
+ parser.add_argument(
1629
+ "--eunomia-type",
1630
+ default="none",
1631
+ choices=["none", "embedded", "remote"],
1632
+ help="Eunomia authorization type: 'none' (disabled), 'embedded' (built-in), 'remote' (external) (default: none)",
1633
+ )
1634
+ parser.add_argument(
1635
+ "--eunomia-policy-file",
1636
+ default="mcp_policies.json",
1637
+ help="Policy file for embedded Eunomia (default: mcp_policies.json)",
1638
+ )
1639
+ parser.add_argument(
1640
+ "--eunomia-remote-url", default=None, help="URL for remote Eunomia server"
1641
+ )
1559
1642
 
1560
1643
  args = parser.parse_args()
1561
1644
 
@@ -1563,6 +1646,133 @@ def container_manager_mcp():
1563
1646
  print(f"Error: Port {args.port} is out of valid range (0-65535).")
1564
1647
  sys.exit(1)
1565
1648
 
1649
+ # Set auth based on type
1650
+ auth = None
1651
+ allowed_uris = (
1652
+ args.allowed_client_redirect_uris.split(",")
1653
+ if args.allowed_client_redirect_uris
1654
+ else None
1655
+ )
1656
+
1657
+ if args.auth_type == "none":
1658
+ auth = None
1659
+ elif args.auth_type == "static":
1660
+ # Internal static tokens (hardcoded example)
1661
+ auth = StaticTokenVerifier(
1662
+ tokens={
1663
+ "test-token": {"client_id": "test-user", "scopes": ["read", "write"]},
1664
+ "admin-token": {"client_id": "admin", "scopes": ["admin"]},
1665
+ }
1666
+ )
1667
+ elif args.auth_type == "jwt":
1668
+ if not (args.token_jwks_uri and args.token_issuer and args.token_audience):
1669
+ print(
1670
+ "Error: jwt requires --token-jwks-uri, --token-issuer, --token-audience"
1671
+ )
1672
+ sys.exit(1)
1673
+ auth = JWTVerifier(
1674
+ jwks_uri=args.token_jwks_uri,
1675
+ issuer=args.token_issuer,
1676
+ audience=args.token_audience,
1677
+ )
1678
+ elif args.auth_type == "oauth-proxy":
1679
+ if not (
1680
+ args.oauth_upstream_auth_endpoint
1681
+ and args.oauth_upstream_token_endpoint
1682
+ and args.oauth_upstream_client_id
1683
+ and args.oauth_upstream_client_secret
1684
+ and args.oauth_base_url
1685
+ and args.token_jwks_uri
1686
+ and args.token_issuer
1687
+ and args.token_audience
1688
+ ):
1689
+ print(
1690
+ "Error: oauth-proxy requires --oauth-upstream-auth-endpoint, --oauth-upstream-token-endpoint, --oauth-upstream-client-id, --oauth-upstream-client-secret, --oauth-base-url, --token-jwks-uri, --token-issuer, --token-audience"
1691
+ )
1692
+ sys.exit(1)
1693
+ token_verifier = JWTVerifier(
1694
+ jwks_uri=args.token_jwks_uri,
1695
+ issuer=args.token_issuer,
1696
+ audience=args.token_audience,
1697
+ )
1698
+ auth = OAuthProxy(
1699
+ upstream_authorization_endpoint=args.oauth_upstream_auth_endpoint,
1700
+ upstream_token_endpoint=args.oauth_upstream_token_endpoint,
1701
+ upstream_client_id=args.oauth_upstream_client_id,
1702
+ upstream_client_secret=args.oauth_upstream_client_secret,
1703
+ token_verifier=token_verifier,
1704
+ base_url=args.oauth_base_url,
1705
+ allowed_client_redirect_uris=allowed_uris,
1706
+ )
1707
+ elif args.auth_type == "oidc-proxy":
1708
+ if not (
1709
+ args.oidc_config_url
1710
+ and args.oidc_client_id
1711
+ and args.oidc_client_secret
1712
+ and args.oidc_base_url
1713
+ ):
1714
+ print(
1715
+ "Error: oidc-proxy requires --oidc-config-url, --oidc-client-id, --oidc-client-secret, --oidc-base-url"
1716
+ )
1717
+ sys.exit(1)
1718
+ auth = OIDCProxy(
1719
+ config_url=args.oidc_config_url,
1720
+ client_id=args.oidc_client_id,
1721
+ client_secret=args.oidc_client_secret,
1722
+ base_url=args.oidc_base_url,
1723
+ allowed_client_redirect_uris=allowed_uris,
1724
+ )
1725
+ elif args.auth_type == "remote-oauth":
1726
+ if not (
1727
+ args.remote_auth_servers
1728
+ and args.remote_base_url
1729
+ and args.token_jwks_uri
1730
+ and args.token_issuer
1731
+ and args.token_audience
1732
+ ):
1733
+ print(
1734
+ "Error: remote-oauth requires --remote-auth-servers, --remote-base-url, --token-jwks-uri, --token-issuer, --token-audience"
1735
+ )
1736
+ sys.exit(1)
1737
+ auth_servers = [url.strip() for url in args.remote_auth_servers.split(",")]
1738
+ token_verifier = JWTVerifier(
1739
+ jwks_uri=args.token_jwks_uri,
1740
+ issuer=args.token_issuer,
1741
+ audience=args.token_audience,
1742
+ )
1743
+ auth = RemoteAuthProvider(
1744
+ token_verifier=token_verifier,
1745
+ authorization_servers=auth_servers,
1746
+ base_url=args.remote_base_url,
1747
+ )
1748
+ mcp.auth = auth
1749
+ if args.eunomia_type != "none":
1750
+ from eunomia_mcp import create_eunomia_middleware
1751
+
1752
+ if args.eunomia_type == "embedded":
1753
+ if not args.eunomia_policy_file:
1754
+ print("Error: embedded Eunomia requires --eunomia-policy-file")
1755
+ sys.exit(1)
1756
+ middleware = create_eunomia_middleware(policy_file=args.eunomia_policy_file)
1757
+ mcp.add_middleware(middleware)
1758
+ elif args.eunomia_type == "remote":
1759
+ if not args.eunomia_remote_url:
1760
+ print("Error: remote Eunomia requires --eunomia-remote-url")
1761
+ sys.exit(1)
1762
+ middleware = create_eunomia_middleware(
1763
+ use_remote_eunomia=args.eunomia_remote_url
1764
+ )
1765
+ mcp.add_middleware(middleware)
1766
+
1767
+ mcp.add_middleware(
1768
+ ErrorHandlingMiddleware(include_traceback=True, transform_errors=True)
1769
+ )
1770
+ mcp.add_middleware(
1771
+ RateLimitingMiddleware(max_requests_per_second=10.0, burst_capacity=20)
1772
+ )
1773
+ mcp.add_middleware(TimingMiddleware())
1774
+ mcp.add_middleware(LoggingMiddleware())
1775
+
1566
1776
  if args.transport == "stdio":
1567
1777
  mcp.run(transport="stdio")
1568
1778
  elif args.transport == "http":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: container-manager-mcp
3
- Version: 1.1.8
3
+ Version: 1.1.9
4
4
  Summary: Container Manager manage Docker, Docker Swarm, and Podman containers as an MCP Server
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -13,7 +13,7 @@ Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: requests>=2.28.1
16
- Requires-Dist: fastmcp>=2.11.3
16
+ Requires-Dist: fastmcp>=2.12.4
17
17
  Requires-Dist: podman>=5.6.0
18
18
  Provides-Extra: podman
19
19
  Requires-Dist: podman>=5.6.0; extra == "podman"
@@ -21,7 +21,7 @@ Provides-Extra: docker
21
21
  Requires-Dist: docker>=7.1.0; extra == "docker"
22
22
  Provides-Extra: all
23
23
  Requires-Dist: requests>=2.28.1; extra == "all"
24
- Requires-Dist: fastmcp>=2.11.3; extra == "all"
24
+ Requires-Dist: fastmcp>=2.12.4; extra == "all"
25
25
  Requires-Dist: docker>=7.1.0; extra == "all"
26
26
  Requires-Dist: podman>=5.6.0; extra == "all"
27
27
  Dynamic: license-file
@@ -48,7 +48,7 @@ Dynamic: license-file
48
48
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/container-manager-mcp)
49
49
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/container-manager-mcp)
50
50
 
51
- *Version: 1.1.8*
51
+ *Version: 1.1.9*
52
52
 
53
53
  Container Manager MCP Server provides a robust interface to manage Docker and Podman containers, networks, volumes, and Docker Swarm services through a FastMCP server, enabling programmatic and remote container management.
54
54
 
@@ -66,12 +66,48 @@ This repository is actively maintained - Contributions are welcome!
66
66
  <details>
67
67
  <summary><b>Usage:</b></summary>
68
68
 
69
- | Short Flag | Long Flag | Description |
70
- |------------|----------------|-----------------------------------------------|
71
- | -h | --help | Display help information |
72
- | -t | --transport | Transport method (stdio or http, default: stdio) |
73
- | -h | --host | Host address for HTTP transport (default: 0.0.0.0) |
74
- | -p | --port | Port for HTTP transport (default: 8000) |
69
+ ### MCP CLI
70
+
71
+ | Short Flag | Long Flag | Description |
72
+ |------------|------------------------------------|-----------------------------------------------------------------------------|
73
+ | -h | --help | Display help information |
74
+ | -t | --transport | Transport method: 'stdio', 'http', or 'sse' [legacy] (default: stdio) |
75
+ | -s | --host | Host address for HTTP transport (default: 0.0.0.0) |
76
+ | -p | --port | Port number for HTTP transport (default: 8000) |
77
+ | | --auth-type | Authentication type: 'none', 'static', 'jwt', 'oauth-proxy', 'oidc-proxy', 'remote-oauth' (default: none) |
78
+ | | --token-jwks-uri | JWKS URI for JWT verification |
79
+ | | --token-issuer | Issuer for JWT verification |
80
+ | | --token-audience | Audience for JWT verification |
81
+ | | --oauth-upstream-auth-endpoint | Upstream authorization endpoint for OAuth Proxy |
82
+ | | --oauth-upstream-token-endpoint | Upstream token endpoint for OAuth Proxy |
83
+ | | --oauth-upstream-client-id | Upstream client ID for OAuth Proxy |
84
+ | | --oauth-upstream-client-secret | Upstream client secret for OAuth Proxy |
85
+ | | --oauth-base-url | Base URL for OAuth Proxy |
86
+ | | --oidc-config-url | OIDC configuration URL |
87
+ | | --oidc-client-id | OIDC client ID |
88
+ | | --oidc-client-secret | OIDC client secret |
89
+ | | --oidc-base-url | Base URL for OIDC Proxy |
90
+ | | --remote-auth-servers | Comma-separated list of authorization servers for Remote OAuth |
91
+ | | --remote-base-url | Base URL for Remote OAuth |
92
+ | | --allowed-client-redirect-uris | Comma-separated list of allowed client redirect URIs |
93
+ | | --eunomia-type | Eunomia authorization type: 'none', 'embedded', 'remote' (default: none) |
94
+ | | --eunomia-policy-file | Policy file for embedded Eunomia (default: mcp_policies.json) |
95
+ | | --eunomia-remote-url | URL for remote Eunomia server |
96
+
97
+
98
+ ### Using as an MCP Server
99
+
100
+ The MCP Server can be run in two modes: `stdio` (for local testing) or `http` (for networked access). To start the server, use the following commands:
101
+
102
+ #### Run in stdio mode (default):
103
+ ```bash
104
+ container-manager-mcp
105
+ ```
106
+
107
+ #### Run in HTTP mode:
108
+ ```bash
109
+ container-manager-mcp --transport "http" --host "0.0.0.0" --port "8000"
110
+ ```
75
111
 
76
112
  ### Available MCP Tools
77
113
  - `get_version`: Retrieve version information of the container runtime
@@ -102,14 +138,95 @@ This repository is actively maintained - Contributions are welcome!
102
138
  - `create_service`: Create a new service in a Docker Swarm
103
139
  - `remove_service`: Remove a service from a Docker Swarm
104
140
 
105
- </details>
141
+ ### Deploy MCP Server as a Service
106
142
 
107
- <details>
108
- <summary><b>Example:</b></summary>
143
+ The ServiceNow MCP server can be deployed using Docker, with configurable authentication, middleware, and Eunomia authorization.
109
144
 
110
- ## Use with AI
145
+ #### Using Docker Run
111
146
 
112
- Configure `mcp.json`
147
+ ```bash
148
+ docker pull knucklessg1/container-manager:latest
149
+
150
+ docker run -d \
151
+ --name container-manager-mcp \
152
+ -p 8004:8004 \
153
+ -e HOST=0.0.0.0 \
154
+ -e PORT=8004 \
155
+ -e TRANSPORT=http \
156
+ -e AUTH_TYPE=none \
157
+ -e EUNOMIA_TYPE=none \
158
+ knucklessg1/container-manager:latest
159
+ ```
160
+
161
+ For advanced authentication (e.g., JWT, OAuth Proxy, OIDC Proxy, Remote OAuth) or Eunomia, add the relevant environment variables:
162
+
163
+ ```bash
164
+ docker run -d \
165
+ --name container-manager-mcp \
166
+ -p 8004:8004 \
167
+ -e HOST=0.0.0.0 \
168
+ -e PORT=8004 \
169
+ -e TRANSPORT=http \
170
+ -e AUTH_TYPE=oidc-proxy \
171
+ -e OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration \
172
+ -e OIDC_CLIENT_ID=your-client-id \
173
+ -e OIDC_CLIENT_SECRET=your-client-secret \
174
+ -e OIDC_BASE_URL=https://your-server.com \
175
+ -e ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/* \
176
+ -e EUNOMIA_TYPE=embedded \
177
+ -e EUNOMIA_POLICY_FILE=/app/mcp_policies.json \
178
+ knucklessg1/container-manager:latest
179
+ ```
180
+
181
+ #### Using Docker Compose
182
+
183
+ Create a `docker-compose.yml` file:
184
+
185
+ ```yaml
186
+ services:
187
+ container-manager-mcp:
188
+ image: knucklessg1/container-manager:latest
189
+ environment:
190
+ - HOST=0.0.0.0
191
+ - PORT=8004
192
+ - TRANSPORT=http
193
+ - AUTH_TYPE=none
194
+ - EUNOMIA_TYPE=none
195
+ ports:
196
+ - 8004:8004
197
+ ```
198
+
199
+ For advanced setups with authentication and Eunomia:
200
+
201
+ ```yaml
202
+ services:
203
+ container-manager-mcp:
204
+ image: knucklessg1/container-manager:latest
205
+ environment:
206
+ - HOST=0.0.0.0
207
+ - PORT=8004
208
+ - TRANSPORT=http
209
+ - AUTH_TYPE=oidc-proxy
210
+ - OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration
211
+ - OIDC_CLIENT_ID=your-client-id
212
+ - OIDC_CLIENT_SECRET=your-client-secret
213
+ - OIDC_BASE_URL=https://your-server.com
214
+ - ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/*
215
+ - EUNOMIA_TYPE=embedded
216
+ - EUNOMIA_POLICY_FILE=/app/mcp_policies.json
217
+ ports:
218
+ - 8004:8004
219
+ volumes:
220
+ - ./mcp_policies.json:/app/mcp_policies.json
221
+ ```
222
+
223
+ Run the service:
224
+
225
+ ```bash
226
+ docker-compose up -d
227
+ ```
228
+
229
+ #### Configure `mcp.json` for AI Integration
113
230
 
114
231
  ```json
115
232
  {
@@ -133,25 +250,6 @@ Configure `mcp.json`
133
250
  }
134
251
  }
135
252
  ```
136
-
137
- ### Deploy MCP Server as a container
138
- ```bash
139
- docker pull knucklessg1/container-manager:latest
140
- ```
141
-
142
- Modify the `compose.yml`
143
-
144
- ```compose
145
- services:
146
- container-manager-mcp:
147
- image: knucklessg1/container-manager:latest
148
- environment:
149
- - HOST=0.0.0.0
150
- - PORT=8015
151
- ports:
152
- - 8015:8015
153
- ```
154
-
155
253
  </details>
156
254
 
157
255
  <details>
@@ -0,0 +1,10 @@
1
+ container_manager_mcp/__init__.py,sha256=Ms3YyGmXg_n_khL1yrD5KKxmTCGJqNhTpg-IGEuboag,860
2
+ container_manager_mcp/__main__.py,sha256=4bpregRyaWJBXOg9_h_F4xcHcX6bPVLL48V2EuwNGBs,168
3
+ container_manager_mcp/container_manager.py,sha256=D8Bleeop3nIlYb5JBkEmhNG6utnJ8JJPuN6bHTmPAto,90354
4
+ container_manager_mcp/container_manager_mcp.py,sha256=Oz1e6Ew9Oxe1Q0HxWiqi0J2034OHCZ18Pt08_eUJxxQ,63726
5
+ container_manager_mcp-1.1.9.dist-info/licenses/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
6
+ container_manager_mcp-1.1.9.dist-info/METADATA,sha256=sQyTPcGryx69g-SyEH5YIfaaCbx9x8C1SNKbwWj-8pk,13491
7
+ container_manager_mcp-1.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ container_manager_mcp-1.1.9.dist-info/entry_points.txt,sha256=n7fE9uXdRktmjvZwyaiQkY0Dd7tMN6AKiHav0ZQdE2I,186
9
+ container_manager_mcp-1.1.9.dist-info/top_level.txt,sha256=B7QQLOd9mBdu0lsPKqyu4T8-zUtbqKzQJbMbtAzoozU,22
10
+ container_manager_mcp-1.1.9.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- container_manager_mcp/__init__.py,sha256=Ms3YyGmXg_n_khL1yrD5KKxmTCGJqNhTpg-IGEuboag,860
2
- container_manager_mcp/__main__.py,sha256=4bpregRyaWJBXOg9_h_F4xcHcX6bPVLL48V2EuwNGBs,168
3
- container_manager_mcp/container_manager.py,sha256=D8Bleeop3nIlYb5JBkEmhNG6utnJ8JJPuN6bHTmPAto,90354
4
- container_manager_mcp/container_manager_mcp.py,sha256=m45h93-1S2qM8TUNQYP43V5HUgV1QJeyW8b9Fj9hiLQ,55392
5
- container_manager_mcp-1.1.8.dist-info/licenses/LICENSE,sha256=Z1xmcrPHBnGCETO_LLQJUeaSNBSnuptcDVTt4kaPUOE,1060
6
- container_manager_mcp-1.1.8.dist-info/METADATA,sha256=nELaXAksLMpoI-MtM3iafTgc9FWltXhTUCoD9slaUMk,8452
7
- container_manager_mcp-1.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- container_manager_mcp-1.1.8.dist-info/entry_points.txt,sha256=n7fE9uXdRktmjvZwyaiQkY0Dd7tMN6AKiHav0ZQdE2I,186
9
- container_manager_mcp-1.1.8.dist-info/top_level.txt,sha256=B7QQLOd9mBdu0lsPKqyu4T8-zUtbqKzQJbMbtAzoozU,22
10
- container_manager_mcp-1.1.8.dist-info/RECORD,,