dockerhub-api 0.1.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.
Files changed (56) hide show
  1. dockerhub_api-0.1.0/LICENSE +21 -0
  2. dockerhub_api-0.1.0/MANIFEST.in +4 -0
  3. dockerhub_api-0.1.0/PKG-INFO +230 -0
  4. dockerhub_api-0.1.0/README.md +200 -0
  5. dockerhub_api-0.1.0/dockerhub_api/__init__.py +80 -0
  6. dockerhub_api-0.1.0/dockerhub_api/__main__.py +4 -0
  7. dockerhub_api-0.1.0/dockerhub_api/agent_server.py +92 -0
  8. dockerhub_api-0.1.0/dockerhub_api/api/__init__.py +1 -0
  9. dockerhub_api-0.1.0/dockerhub_api/api/api_client_access_tokens.py +77 -0
  10. dockerhub_api-0.1.0/dockerhub_api/api/api_client_audit_logs.py +56 -0
  11. dockerhub_api-0.1.0/dockerhub_api/api/api_client_auth.py +80 -0
  12. dockerhub_api-0.1.0/dockerhub_api/api/api_client_base.py +338 -0
  13. dockerhub_api-0.1.0/dockerhub_api/api/api_client_groups.py +158 -0
  14. dockerhub_api-0.1.0/dockerhub_api/api/api_client_org_access_tokens.py +106 -0
  15. dockerhub_api-0.1.0/dockerhub_api/api/api_client_orgs.py +149 -0
  16. dockerhub_api-0.1.0/dockerhub_api/api/api_client_repositories.py +217 -0
  17. dockerhub_api-0.1.0/dockerhub_api/api/api_client_scim.py +153 -0
  18. dockerhub_api-0.1.0/dockerhub_api/api_client.py +35 -0
  19. dockerhub_api-0.1.0/dockerhub_api/auth.py +252 -0
  20. dockerhub_api-0.1.0/dockerhub_api/dockerhub_input_models.py +756 -0
  21. dockerhub_api-0.1.0/dockerhub_api/dockerhub_response_models.py +344 -0
  22. dockerhub_api-0.1.0/dockerhub_api/main_agent.json +14 -0
  23. dockerhub_api-0.1.0/dockerhub_api/mcp/__init__.py +120 -0
  24. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_admin.py +45 -0
  25. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_audit.py +44 -0
  26. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_auth.py +66 -0
  27. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_org.py +58 -0
  28. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_repos.py +58 -0
  29. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_scim.py +56 -0
  30. dockerhub_api-0.1.0/dockerhub_api/mcp/mcp_teams.py +55 -0
  31. dockerhub_api-0.1.0/dockerhub_api/mcp_config.json +3 -0
  32. dockerhub_api-0.1.0/dockerhub_api/mcp_server.py +109 -0
  33. dockerhub_api-0.1.0/dockerhub_api.egg-info/PKG-INFO +230 -0
  34. dockerhub_api-0.1.0/dockerhub_api.egg-info/SOURCES.txt +54 -0
  35. dockerhub_api-0.1.0/dockerhub_api.egg-info/dependency_links.txt +1 -0
  36. dockerhub_api-0.1.0/dockerhub_api.egg-info/entry_points.txt +3 -0
  37. dockerhub_api-0.1.0/dockerhub_api.egg-info/requires.txt +18 -0
  38. dockerhub_api-0.1.0/dockerhub_api.egg-info/top_level.txt +1 -0
  39. dockerhub_api-0.1.0/pyproject.toml +60 -0
  40. dockerhub_api-0.1.0/requirements.txt +3 -0
  41. dockerhub_api-0.1.0/setup.cfg +4 -0
  42. dockerhub_api-0.1.0/tests/test_api_audit.py +31 -0
  43. dockerhub_api-0.1.0/tests/test_api_org.py +124 -0
  44. dockerhub_api-0.1.0/tests/test_api_repositories.py +149 -0
  45. dockerhub_api-0.1.0/tests/test_api_scim.py +77 -0
  46. dockerhub_api-0.1.0/tests/test_api_teams.py +69 -0
  47. dockerhub_api-0.1.0/tests/test_api_tokens.py +102 -0
  48. dockerhub_api-0.1.0/tests/test_api_wrapper.py +56 -0
  49. dockerhub_api-0.1.0/tests/test_auth.py +214 -0
  50. dockerhub_api-0.1.0/tests/test_concept_parity.py +34 -0
  51. dockerhub_api-0.1.0/tests/test_dockerhub_a2a_validation.py +30 -0
  52. dockerhub_api-0.1.0/tests/test_dockerhub_mcp_validation.py +205 -0
  53. dockerhub_api-0.1.0/tests/test_init_dynamics.py +21 -0
  54. dockerhub_api-0.1.0/tests/test_models.py +115 -0
  55. dockerhub_api-0.1.0/tests/test_rate_limit.py +97 -0
  56. dockerhub_api-0.1.0/tests/test_startup.py +39 -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,4 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include dockerhub_api *.py *.json
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: dockerhub-api
3
+ Version: 0.1.0
4
+ Summary: Docker Hub API + MCP Server + A2A Server
5
+ Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
+ License: MIT
7
+ Classifier: Development Status :: 5 - Production/Stable
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.15,>=3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: agent-utilities>=0.47.0
16
+ Requires-Dist: httpx>=0.27.0
17
+ Requires-Dist: python-dotenv>=1.0.0
18
+ Provides-Extra: mcp
19
+ Requires-Dist: agent-utilities[mcp]>=0.47.0; extra == "mcp"
20
+ Provides-Extra: agent
21
+ Requires-Dist: agent-utilities[agent,logfire]>=0.47.0; extra == "agent"
22
+ Provides-Extra: all
23
+ Requires-Dist: dockerhub-api[agent,logfire,mcp]>=0.1.0; extra == "all"
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
26
+ Requires-Dist: pytest; extra == "test"
27
+ Requires-Dist: pytest-asyncio; extra == "test"
28
+ Requires-Dist: pytest-cov; extra == "test"
29
+ Dynamic: license-file
30
+
31
+ # Dockerhub Api
32
+ ## CLI or API | MCP | Agent
33
+
34
+ ![PyPI - Version](https://img.shields.io/pypi/v/dockerhub-api)
35
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
36
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/dockerhub-api)
37
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/dockerhub-api)
38
+ ![PyPI - License](https://img.shields.io/pypi/l/dockerhub-api)
39
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/dockerhub-api)
40
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/dockerhub-api)
41
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/dockerhub-api)
42
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/dockerhub-api)
43
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/dockerhub-api)
44
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/dockerhub-api)
45
+
46
+ *Version: 0.1.0*
47
+
48
+ > **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
49
+ > interfaces, the integrated A2A agent server, and guidance on the backing
50
+ > Docker Hub platform are maintained in [docs/](docs/index.md).
51
+
52
+ ---
53
+
54
+ ## Table of Contents
55
+
56
+ - [Overview](#overview)
57
+ - [Key Features](#key-features)
58
+ - [Installation](#installation)
59
+ - [Usage](#usage)
60
+ - [Python API / CLI](#python-api--cli)
61
+ - [MCP](#mcp)
62
+ - [Agent (A2A)](#agent-a2a)
63
+ - [Environment Variables](#environment-variables)
64
+ - [Deployment](#deployment)
65
+ - [Safety Model](#safety-model)
66
+ - [Concepts](#concepts)
67
+ - [License](#license)
68
+
69
+ ---
70
+
71
+ ## Overview
72
+
73
+ **Dockerhub Api** is a production-grade Agent and Model Context Protocol (MCP) server
74
+ that wraps the official **Docker Hub API v2** (`https://hub.docker.com`): repositories
75
+ and tags, immutable tags, personal and organization access tokens, organization
76
+ members/settings/invites, teams, audit logs, and SCIM 2.0 provisioning.
77
+
78
+ ---
79
+
80
+ ## Key Features
81
+
82
+ - **Consolidated Action-Routed MCP Tools:** Seven togglable tool modules
83
+ (`hub_auth`, `hub_repos`, `hub_org`, `hub_teams`, `hub_audit`, `hub_scim`,
84
+ `hub_admin`) minimize token overhead in LLM contexts.
85
+ - **JWT Auth Lifecycle:** Short-lived bearer minted from `POST /v2/auth/token`
86
+ (password, PAT `dckr_pat_*`, or org access token), cached and refreshed before
87
+ expiry, with one transparent re-mint on 401.
88
+ - **Rate-Limit Telemetry:** `X-RateLimit-*` headers surfaced in every result;
89
+ HTTP 429 retried with bounded `Retry-After` backoff.
90
+ - **Safety by Default:** Deletes and org-settings writes are gated behind
91
+ `DOCKERHUB_ALLOW_DESTRUCTIVE` (default `False`); secrets are redacted from tool
92
+ results (plaintext tokens appear exactly once — on creation). Repository creation
93
+ stays enabled: it is the primary release-provisioning use case.
94
+ - **Integrated Graph Agent:** Built-in Pydantic AI agent (`dockerhub-agent`) with
95
+ A2A and AG-UI web interfaces.
96
+ - **Native Telemetry & Tracing:** Out-of-the-box OpenTelemetry exports and Langfuse
97
+ tracing via agent-utilities.
98
+
99
+ ---
100
+
101
+ ## Installation
102
+
103
+ ```bash
104
+ pip install dockerhub-api # API client only
105
+ pip install "dockerhub-api[mcp]" # + MCP server
106
+ pip install "dockerhub-api[agent]" # + A2A agent server
107
+ pip install "dockerhub-api[all]" # everything
108
+ ```
109
+
110
+ | Extra | Adds |
111
+ |---|---|
112
+ | `mcp` | FastMCP server (`dockerhub-mcp`) via `agent-utilities[mcp]` |
113
+ | `agent` | Pydantic-AI A2A agent (`dockerhub-agent`) + Logfire via `agent-utilities[agent,logfire]` |
114
+ | `all` | `mcp` + `agent` |
115
+ | `test` | pytest toolchain for development |
116
+
117
+ Or pull the published image:
118
+
119
+ ```bash
120
+ docker pull knucklessg1/dockerhub-api:latest
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Usage
126
+
127
+ ### Python API / CLI
128
+
129
+ ```python
130
+ from dockerhub_api.auth import get_client
131
+
132
+ api = get_client() # reads DOCKERHUB_URL / DOCKER_HUB_USER / DOCKER_HUB_TOKEN
133
+
134
+ repos = api.get_repositories(namespace="acme", ordering="-last_updated")
135
+ api.create_repository(namespace="acme", name="release-images", is_private=True)
136
+ tags = api.get_repository_tags(namespace="acme", repository="release-images")
137
+ print(api.rate_limit) # latest X-RateLimit-* snapshot
138
+ ```
139
+
140
+ Every client method returns a uniform envelope:
141
+ `{"status_code": int, "data": ..., "rate_limit": {"limit", "remaining", "reset"}}`.
142
+
143
+ ### MCP
144
+
145
+ #### Available MCP Tools
146
+
147
+ | Tool Module | Toggle Env Var | Enabled by Default | Description & Nested Actions |
148
+ |---|---|---|---|
149
+ | `hub_auth` | `AUTHTOOL` | True | Token lifecycle: `create_token`, `login` (deprecated), `two_factor_login`, `list_pats`, `create_pat`, `get_pat`, `update_pat`, `delete_pat`, `list_oats`, `create_oat`, `get_oat`, `update_oat`, `delete_oat` |
150
+ | `hub_repos` | `REPOSTOOL` | True | Repositories & tags: `list`, `create`, `get`, `check`, `list_tags`, `check_tags`, `get_tag`, `check_tag`, `set_immutable_tags`, `verify_immutable_tags`, `assign_group` |
151
+ | `hub_org` | `ORGTOOL` | True | Org admin: `get_settings`, `update_settings`, `list_members`, `export_members`, `update_member`, `remove_member`, `list_invites`, `delete_invite`, `resend_invite`, `bulk_invite` |
152
+ | `hub_teams` | `TEAMSTOOL` | True | Teams: `list`, `create`, `get`, `update`, `patch`, `delete`, `list_members`, `add_member`, `remove_member` |
153
+ | `hub_audit` | `AUDITTOOL` | True | Audit trail: `logs`, `actions` |
154
+ | `hub_scim` | `SCIMTOOL` | True | SCIM 2.0: `service_provider_config`, `resource_types`, `resource_type`, `schemas`, `schema`, `list_users`, `get_user`, `create_user`, `update_user` |
155
+ | `hub_admin` | `ADMINTOOL` | True | Diagnostics: `rate_limit`, `whoami` (local JWT introspection) |
156
+
157
+ Run the server:
158
+
159
+ ```bash
160
+ export DOCKER_HUB_USER=youruser
161
+ export DOCKER_HUB_TOKEN=dckr_pat_xxx
162
+ dockerhub-mcp --transport streamable-http --host 0.0.0.0 --port 8000
163
+ ```
164
+
165
+ ### Agent (A2A)
166
+
167
+ ```bash
168
+ dockerhub-agent --mcp-url http://localhost:8000/mcp --web
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Environment Variables
174
+
175
+ | Variable | Default | Purpose |
176
+ |---|---|---|
177
+ | `DOCKERHUB_URL` | `https://hub.docker.com` | Docker Hub API base URL |
178
+ | `DOCKER_HUB_USER` | — | Account identifier (official hub-tool name, primary) |
179
+ | `DOCKER_HUB_TOKEN` | — | Password, PAT `dckr_pat_*`, or org access token (primary) |
180
+ | `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` | — | Legacy fallback aliases for the two above |
181
+ | `DOCKERHUB_JWT` | — | Optional pre-minted bearer (overrides credential exchange) |
182
+ | `DOCKERHUB_SSL_VERIFY` | `True` | TLS certificate verification |
183
+ | `DOCKERHUB_ALLOW_DESTRUCTIVE` | `False` | Enable deletes and org-settings writes |
184
+ | `AUTHTOOL` … `ADMINTOOL` | `True` | Per-module MCP tool toggles (see table above) |
185
+ | `HOST` / `PORT` / `TRANSPORT` | `0.0.0.0` / `8000` / `stdio` | MCP server bind & transport (`stdio`, `streamable-http`, `sse`) |
186
+ | `AUTH_TYPE` | `none` | MCP server auth mode (Docker image) |
187
+ | `MCP_URL` | — | MCP endpoint the A2A agent connects to |
188
+ | `ENABLE_OTEL` | `True` | OpenTelemetry / Langfuse export via agent-utilities |
189
+ | `EUNOMIA_TYPE` / `EUNOMIA_POLICY_FILE` / `EUNOMIA_REMOTE_URL` | `none` / `mcp_policies.json` / — | Eunomia access-governance middleware |
190
+ | `FASTMCP_LOG_LEVEL` / `NO_COLOR` | — | FastMCP logging controls |
191
+
192
+ A complete annotated template lives in [.env.example](.env.example).
193
+
194
+ ---
195
+
196
+ ## Deployment
197
+
198
+ Docker Compose definitions ship in [docker/](docker/):
199
+
200
+ ```bash
201
+ cp .env.example .env # fill in DOCKER_HUB_USER / DOCKER_HUB_TOKEN
202
+ docker compose -f docker/mcp.compose.yml up -d # MCP server only
203
+ docker compose -f docker/agent.compose.yml up -d # MCP server + A2A agent (port 9018)
204
+ ```
205
+
206
+ Both services expose `/health` endpoints; see
207
+ [docs/deployment.md](docs/deployment.md) for transports, Caddy ingress, and
208
+ Technitium DNS guidance.
209
+
210
+ ---
211
+
212
+ ## Safety Model
213
+
214
+ | Operation class | Default | Override |
215
+ |---|---|---|
216
+ | Reads (repos, tags, members, logs, SCIM) | allowed | — |
217
+ | Repository create / immutable-tag config / invites / role updates | allowed | — |
218
+ | Deletes (PATs, OATs, groups, members, invites) | **blocked** | `DOCKERHUB_ALLOW_DESTRUCTIVE=True` |
219
+ | Org-settings writes (`PUT /v2/orgs/{org}/settings`) | **blocked** | `DOCKERHUB_ALLOW_DESTRUCTIVE=True` |
220
+
221
+ ---
222
+
223
+ ## Concepts
224
+
225
+ The concept registry (`CONCEPT:HUB-1.x`) is documented in
226
+ [docs/concepts.md](docs/concepts.md).
227
+
228
+ ## License
229
+
230
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,200 @@
1
+ # Dockerhub Api
2
+ ## CLI or API | MCP | Agent
3
+
4
+ ![PyPI - Version](https://img.shields.io/pypi/v/dockerhub-api)
5
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
6
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/dockerhub-api)
7
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/dockerhub-api)
8
+ ![PyPI - License](https://img.shields.io/pypi/l/dockerhub-api)
9
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/dockerhub-api)
10
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/dockerhub-api)
11
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/dockerhub-api)
12
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/dockerhub-api)
13
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/dockerhub-api)
14
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/dockerhub-api)
15
+
16
+ *Version: 0.1.0*
17
+
18
+ > **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
19
+ > interfaces, the integrated A2A agent server, and guidance on the backing
20
+ > Docker Hub platform are maintained in [docs/](docs/index.md).
21
+
22
+ ---
23
+
24
+ ## Table of Contents
25
+
26
+ - [Overview](#overview)
27
+ - [Key Features](#key-features)
28
+ - [Installation](#installation)
29
+ - [Usage](#usage)
30
+ - [Python API / CLI](#python-api--cli)
31
+ - [MCP](#mcp)
32
+ - [Agent (A2A)](#agent-a2a)
33
+ - [Environment Variables](#environment-variables)
34
+ - [Deployment](#deployment)
35
+ - [Safety Model](#safety-model)
36
+ - [Concepts](#concepts)
37
+ - [License](#license)
38
+
39
+ ---
40
+
41
+ ## Overview
42
+
43
+ **Dockerhub Api** is a production-grade Agent and Model Context Protocol (MCP) server
44
+ that wraps the official **Docker Hub API v2** (`https://hub.docker.com`): repositories
45
+ and tags, immutable tags, personal and organization access tokens, organization
46
+ members/settings/invites, teams, audit logs, and SCIM 2.0 provisioning.
47
+
48
+ ---
49
+
50
+ ## Key Features
51
+
52
+ - **Consolidated Action-Routed MCP Tools:** Seven togglable tool modules
53
+ (`hub_auth`, `hub_repos`, `hub_org`, `hub_teams`, `hub_audit`, `hub_scim`,
54
+ `hub_admin`) minimize token overhead in LLM contexts.
55
+ - **JWT Auth Lifecycle:** Short-lived bearer minted from `POST /v2/auth/token`
56
+ (password, PAT `dckr_pat_*`, or org access token), cached and refreshed before
57
+ expiry, with one transparent re-mint on 401.
58
+ - **Rate-Limit Telemetry:** `X-RateLimit-*` headers surfaced in every result;
59
+ HTTP 429 retried with bounded `Retry-After` backoff.
60
+ - **Safety by Default:** Deletes and org-settings writes are gated behind
61
+ `DOCKERHUB_ALLOW_DESTRUCTIVE` (default `False`); secrets are redacted from tool
62
+ results (plaintext tokens appear exactly once — on creation). Repository creation
63
+ stays enabled: it is the primary release-provisioning use case.
64
+ - **Integrated Graph Agent:** Built-in Pydantic AI agent (`dockerhub-agent`) with
65
+ A2A and AG-UI web interfaces.
66
+ - **Native Telemetry & Tracing:** Out-of-the-box OpenTelemetry exports and Langfuse
67
+ tracing via agent-utilities.
68
+
69
+ ---
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ pip install dockerhub-api # API client only
75
+ pip install "dockerhub-api[mcp]" # + MCP server
76
+ pip install "dockerhub-api[agent]" # + A2A agent server
77
+ pip install "dockerhub-api[all]" # everything
78
+ ```
79
+
80
+ | Extra | Adds |
81
+ |---|---|
82
+ | `mcp` | FastMCP server (`dockerhub-mcp`) via `agent-utilities[mcp]` |
83
+ | `agent` | Pydantic-AI A2A agent (`dockerhub-agent`) + Logfire via `agent-utilities[agent,logfire]` |
84
+ | `all` | `mcp` + `agent` |
85
+ | `test` | pytest toolchain for development |
86
+
87
+ Or pull the published image:
88
+
89
+ ```bash
90
+ docker pull knucklessg1/dockerhub-api:latest
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Usage
96
+
97
+ ### Python API / CLI
98
+
99
+ ```python
100
+ from dockerhub_api.auth import get_client
101
+
102
+ api = get_client() # reads DOCKERHUB_URL / DOCKER_HUB_USER / DOCKER_HUB_TOKEN
103
+
104
+ repos = api.get_repositories(namespace="acme", ordering="-last_updated")
105
+ api.create_repository(namespace="acme", name="release-images", is_private=True)
106
+ tags = api.get_repository_tags(namespace="acme", repository="release-images")
107
+ print(api.rate_limit) # latest X-RateLimit-* snapshot
108
+ ```
109
+
110
+ Every client method returns a uniform envelope:
111
+ `{"status_code": int, "data": ..., "rate_limit": {"limit", "remaining", "reset"}}`.
112
+
113
+ ### MCP
114
+
115
+ #### Available MCP Tools
116
+
117
+ | Tool Module | Toggle Env Var | Enabled by Default | Description & Nested Actions |
118
+ |---|---|---|---|
119
+ | `hub_auth` | `AUTHTOOL` | True | Token lifecycle: `create_token`, `login` (deprecated), `two_factor_login`, `list_pats`, `create_pat`, `get_pat`, `update_pat`, `delete_pat`, `list_oats`, `create_oat`, `get_oat`, `update_oat`, `delete_oat` |
120
+ | `hub_repos` | `REPOSTOOL` | True | Repositories & tags: `list`, `create`, `get`, `check`, `list_tags`, `check_tags`, `get_tag`, `check_tag`, `set_immutable_tags`, `verify_immutable_tags`, `assign_group` |
121
+ | `hub_org` | `ORGTOOL` | True | Org admin: `get_settings`, `update_settings`, `list_members`, `export_members`, `update_member`, `remove_member`, `list_invites`, `delete_invite`, `resend_invite`, `bulk_invite` |
122
+ | `hub_teams` | `TEAMSTOOL` | True | Teams: `list`, `create`, `get`, `update`, `patch`, `delete`, `list_members`, `add_member`, `remove_member` |
123
+ | `hub_audit` | `AUDITTOOL` | True | Audit trail: `logs`, `actions` |
124
+ | `hub_scim` | `SCIMTOOL` | True | SCIM 2.0: `service_provider_config`, `resource_types`, `resource_type`, `schemas`, `schema`, `list_users`, `get_user`, `create_user`, `update_user` |
125
+ | `hub_admin` | `ADMINTOOL` | True | Diagnostics: `rate_limit`, `whoami` (local JWT introspection) |
126
+
127
+ Run the server:
128
+
129
+ ```bash
130
+ export DOCKER_HUB_USER=youruser
131
+ export DOCKER_HUB_TOKEN=dckr_pat_xxx
132
+ dockerhub-mcp --transport streamable-http --host 0.0.0.0 --port 8000
133
+ ```
134
+
135
+ ### Agent (A2A)
136
+
137
+ ```bash
138
+ dockerhub-agent --mcp-url http://localhost:8000/mcp --web
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Environment Variables
144
+
145
+ | Variable | Default | Purpose |
146
+ |---|---|---|
147
+ | `DOCKERHUB_URL` | `https://hub.docker.com` | Docker Hub API base URL |
148
+ | `DOCKER_HUB_USER` | — | Account identifier (official hub-tool name, primary) |
149
+ | `DOCKER_HUB_TOKEN` | — | Password, PAT `dckr_pat_*`, or org access token (primary) |
150
+ | `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` | — | Legacy fallback aliases for the two above |
151
+ | `DOCKERHUB_JWT` | — | Optional pre-minted bearer (overrides credential exchange) |
152
+ | `DOCKERHUB_SSL_VERIFY` | `True` | TLS certificate verification |
153
+ | `DOCKERHUB_ALLOW_DESTRUCTIVE` | `False` | Enable deletes and org-settings writes |
154
+ | `AUTHTOOL` … `ADMINTOOL` | `True` | Per-module MCP tool toggles (see table above) |
155
+ | `HOST` / `PORT` / `TRANSPORT` | `0.0.0.0` / `8000` / `stdio` | MCP server bind & transport (`stdio`, `streamable-http`, `sse`) |
156
+ | `AUTH_TYPE` | `none` | MCP server auth mode (Docker image) |
157
+ | `MCP_URL` | — | MCP endpoint the A2A agent connects to |
158
+ | `ENABLE_OTEL` | `True` | OpenTelemetry / Langfuse export via agent-utilities |
159
+ | `EUNOMIA_TYPE` / `EUNOMIA_POLICY_FILE` / `EUNOMIA_REMOTE_URL` | `none` / `mcp_policies.json` / — | Eunomia access-governance middleware |
160
+ | `FASTMCP_LOG_LEVEL` / `NO_COLOR` | — | FastMCP logging controls |
161
+
162
+ A complete annotated template lives in [.env.example](.env.example).
163
+
164
+ ---
165
+
166
+ ## Deployment
167
+
168
+ Docker Compose definitions ship in [docker/](docker/):
169
+
170
+ ```bash
171
+ cp .env.example .env # fill in DOCKER_HUB_USER / DOCKER_HUB_TOKEN
172
+ docker compose -f docker/mcp.compose.yml up -d # MCP server only
173
+ docker compose -f docker/agent.compose.yml up -d # MCP server + A2A agent (port 9018)
174
+ ```
175
+
176
+ Both services expose `/health` endpoints; see
177
+ [docs/deployment.md](docs/deployment.md) for transports, Caddy ingress, and
178
+ Technitium DNS guidance.
179
+
180
+ ---
181
+
182
+ ## Safety Model
183
+
184
+ | Operation class | Default | Override |
185
+ |---|---|---|
186
+ | Reads (repos, tags, members, logs, SCIM) | allowed | — |
187
+ | Repository create / immutable-tag config / invites / role updates | allowed | — |
188
+ | Deletes (PATs, OATs, groups, members, invites) | **blocked** | `DOCKERHUB_ALLOW_DESTRUCTIVE=True` |
189
+ | Org-settings writes (`PUT /v2/orgs/{org}/settings`) | **blocked** | `DOCKERHUB_ALLOW_DESTRUCTIVE=True` |
190
+
191
+ ---
192
+
193
+ ## Concepts
194
+
195
+ The concept registry (`CONCEPT:HUB-1.x`) is documented in
196
+ [docs/concepts.md](docs/concepts.md).
197
+
198
+ ## License
199
+
200
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python
2
+
3
+ import importlib
4
+ import inspect
5
+ from typing import Any
6
+
7
+ __all__: list[str] = []
8
+
9
+ CORE_MODULES: list[str] = [
10
+ "dockerhub_api.dockerhub_input_models",
11
+ "dockerhub_api.dockerhub_response_models",
12
+ "dockerhub_api.api_client",
13
+ "dockerhub_api.auth",
14
+ ]
15
+
16
+ OPTIONAL_MODULES = {
17
+ "dockerhub_api.agent_server": "agent",
18
+ "dockerhub_api.mcp_server": "mcp",
19
+ }
20
+
21
+
22
+ def _expose_members(module):
23
+ """Expose public classes and functions from a module into globals and __all__."""
24
+ for name, obj in inspect.getmembers(module):
25
+ if (inspect.isclass(obj) or inspect.isfunction(obj)) and not name.startswith(
26
+ "_"
27
+ ):
28
+ globals()[name] = obj
29
+ if name not in __all__:
30
+ __all__.append(name)
31
+
32
+
33
+ # Eagerly import core modules (keeps API wrappers fast & light)
34
+ for module_name in CORE_MODULES:
35
+ if module_name:
36
+ module = importlib.import_module(module_name)
37
+ _expose_members(module)
38
+
39
+ # Dynamic/lazy loading of optional modules (agent_server, mcp_server)
40
+ _loaded_optional_modules: dict[str, Any] = {}
41
+
42
+
43
+ def _import_module_safely(module_name: str):
44
+ """Try to import a module and return it, or None if not available."""
45
+ try:
46
+ return importlib.import_module(module_name)
47
+ except ImportError:
48
+ return None
49
+
50
+
51
+ def __getattr__(name: str) -> Any:
52
+ # Handle availability flags dynamically without eager imports
53
+ if name == "_MCP_AVAILABLE":
54
+ mcp_key = next((k for k in OPTIONAL_MODULES if "mcp_server" in k), None)
55
+ if mcp_key:
56
+ return _import_module_safely(mcp_key) is not None
57
+ return False
58
+ if name == "_AGENT_AVAILABLE":
59
+ agent_key = next((k for k in OPTIONAL_MODULES if "agent_server" in k), None)
60
+ if agent_key:
61
+ return _import_module_safely(agent_key) is not None
62
+ return False
63
+
64
+ # Check optional modules
65
+ for module_name in OPTIONAL_MODULES:
66
+ if module_name not in _loaded_optional_modules:
67
+ module = _import_module_safely(module_name)
68
+ if module is not None:
69
+ _loaded_optional_modules[module_name] = module
70
+ _expose_members(module)
71
+
72
+ module = _loaded_optional_modules.get(module_name)
73
+ if module is not None and hasattr(module, name):
74
+ return getattr(module, name)
75
+
76
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
77
+
78
+
79
+ def __dir__() -> list[str]:
80
+ return sorted(list(globals().keys()) + __all__)
@@ -0,0 +1,4 @@
1
+ from dockerhub_api.agent_server import agent_server
2
+
3
+ if __name__ == "__main__":
4
+ agent_server()
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/python
2
+ """Docker Hub A2A agent server.
3
+
4
+ CONCEPT:HUB-1.6 — A2A agent server. A Pydantic-AI graph agent over the
5
+ Docker Hub MCP tool surface, exposed via agent-utilities'
6
+ ``create_agent_server`` (A2A + AG-UI web interface).
7
+ """
8
+
9
+ import logging
10
+ import os
11
+ import sys
12
+ import warnings
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ logging.basicConfig(
17
+ level=logging.INFO,
18
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
19
+ handlers=[logging.StreamHandler()],
20
+ )
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ DEFAULT_AGENT_NAME = None
25
+ DEFAULT_AGENT_DESCRIPTION = None
26
+ DEFAULT_AGENT_SYSTEM_PROMPT = None
27
+
28
+
29
+ def agent_server():
30
+ from agent_utilities import (
31
+ build_system_prompt_from_workspace,
32
+ create_agent_parser,
33
+ create_agent_server,
34
+ initialize_workspace,
35
+ load_identity,
36
+ )
37
+
38
+ global DEFAULT_AGENT_NAME, DEFAULT_AGENT_DESCRIPTION, DEFAULT_AGENT_SYSTEM_PROMPT
39
+ initialize_workspace()
40
+ meta = load_identity()
41
+ DEFAULT_AGENT_NAME = os.getenv(
42
+ "DEFAULT_AGENT_NAME", meta.get("name", "Dockerhub Api")
43
+ )
44
+ DEFAULT_AGENT_DESCRIPTION = os.getenv(
45
+ "AGENT_DESCRIPTION",
46
+ meta.get(
47
+ "description",
48
+ "AI agent for Docker Hub management.",
49
+ ),
50
+ )
51
+ DEFAULT_AGENT_SYSTEM_PROMPT = os.getenv(
52
+ "AGENT_SYSTEM_PROMPT",
53
+ meta.get("content") or build_system_prompt_from_workspace(),
54
+ )
55
+
56
+ warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
57
+ warnings.filterwarnings("ignore", category=DeprecationWarning, module="fastmcp")
58
+
59
+ print(f"{DEFAULT_AGENT_NAME} v{__version__}", file=sys.stderr)
60
+ parser = create_agent_parser()
61
+ args = parser.parse_args()
62
+
63
+ if args.debug:
64
+ logging.getLogger().setLevel(logging.DEBUG)
65
+ logger.debug("Debug mode enabled")
66
+
67
+ # Start server using the auto-discovery pattern (from mcp_config.json)
68
+ create_agent_server(
69
+ mcp_url=args.mcp_url,
70
+ mcp_config=args.mcp_config or "mcp_config.json",
71
+ host=args.host,
72
+ port=args.port,
73
+ provider=args.provider,
74
+ model_id=args.model_id,
75
+ router_model=args.model_id,
76
+ agent_model=args.model_id,
77
+ base_url=args.base_url,
78
+ api_key=args.api_key,
79
+ custom_skills_directory=args.custom_skills_directory,
80
+ enable_web_ui=args.web,
81
+ enable_otel=args.otel,
82
+ otel_endpoint=args.otel_endpoint,
83
+ otel_headers=args.otel_headers,
84
+ otel_public_key=args.otel_public_key,
85
+ otel_secret_key=args.otel_secret_key,
86
+ otel_protocol=args.otel_protocol,
87
+ debug=args.debug,
88
+ )
89
+
90
+
91
+ if __name__ == "__main__":
92
+ agent_server()
@@ -0,0 +1 @@
1
+ """Per-domain Docker Hub API client mixins."""