objectstore-mcp 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 (46) hide show
  1. objectstore_mcp-0.1.0/LICENSE +21 -0
  2. objectstore_mcp-0.1.0/MANIFEST.in +4 -0
  3. objectstore_mcp-0.1.0/PKG-INFO +234 -0
  4. objectstore_mcp-0.1.0/README.md +198 -0
  5. objectstore_mcp-0.1.0/objectstore_mcp/__init__.py +63 -0
  6. objectstore_mcp-0.1.0/objectstore_mcp/__main__.py +4 -0
  7. objectstore_mcp-0.1.0/objectstore_mcp/agent_server.py +73 -0
  8. objectstore_mcp-0.1.0/objectstore_mcp/api/__init__.py +84 -0
  9. objectstore_mcp-0.1.0/objectstore_mcp/api/api_client_azure_blob.py +308 -0
  10. objectstore_mcp-0.1.0/objectstore_mcp/api/api_client_base.py +234 -0
  11. objectstore_mcp-0.1.0/objectstore_mcp/api/api_client_filesystem.py +285 -0
  12. objectstore_mcp-0.1.0/objectstore_mcp/api/api_client_gcs.py +268 -0
  13. objectstore_mcp-0.1.0/objectstore_mcp/api/api_client_s3.py +291 -0
  14. objectstore_mcp-0.1.0/objectstore_mcp/api_client.py +37 -0
  15. objectstore_mcp-0.1.0/objectstore_mcp/auth.py +64 -0
  16. objectstore_mcp-0.1.0/objectstore_mcp/config.py +170 -0
  17. objectstore_mcp-0.1.0/objectstore_mcp/main_agent.json +14 -0
  18. objectstore_mcp-0.1.0/objectstore_mcp/mcp/__init__.py +5 -0
  19. objectstore_mcp-0.1.0/objectstore_mcp/mcp/mcp_objectstore.py +471 -0
  20. objectstore_mcp-0.1.0/objectstore_mcp/mcp_config.json +1 -0
  21. objectstore_mcp-0.1.0/objectstore_mcp/mcp_server.py +61 -0
  22. objectstore_mcp-0.1.0/objectstore_mcp/objectstore_input_models.py +64 -0
  23. objectstore_mcp-0.1.0/objectstore_mcp/objectstore_response_models.py +52 -0
  24. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/PKG-INFO +234 -0
  25. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/SOURCES.txt +44 -0
  26. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/dependency_links.txt +1 -0
  27. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/entry_points.txt +3 -0
  28. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/requires.txt +27 -0
  29. objectstore_mcp-0.1.0/objectstore_mcp.egg-info/top_level.txt +1 -0
  30. objectstore_mcp-0.1.0/pyproject.toml +60 -0
  31. objectstore_mcp-0.1.0/requirements.txt +2 -0
  32. objectstore_mcp-0.1.0/setup.cfg +4 -0
  33. objectstore_mcp-0.1.0/tests/test_api_wrapper.py +33 -0
  34. objectstore_mcp-0.1.0/tests/test_auth.py +22 -0
  35. objectstore_mcp-0.1.0/tests/test_azure_backend.py +169 -0
  36. objectstore_mcp-0.1.0/tests/test_backend_conformance.py +235 -0
  37. objectstore_mcp-0.1.0/tests/test_concept_parity.py +29 -0
  38. objectstore_mcp-0.1.0/tests/test_config.py +121 -0
  39. objectstore_mcp-0.1.0/tests/test_gcs_backend.py +172 -0
  40. objectstore_mcp-0.1.0/tests/test_init_dynamics.py +6 -0
  41. objectstore_mcp-0.1.0/tests/test_objectstore_mcp_validation.py +249 -0
  42. objectstore_mcp-0.1.0/tests/test_optional_dependencies.py +72 -0
  43. objectstore_mcp-0.1.0/tests/test_s3_backend.py +238 -0
  44. objectstore_mcp-0.1.0/tests/test_s3_moto.py +45 -0
  45. objectstore_mcp-0.1.0/tests/test_safety.py +217 -0
  46. objectstore_mcp-0.1.0/tests/test_startup.py +19 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Knuckles-Team
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 objectstore_mcp *.py *.json
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: objectstore-mcp
3
+ Version: 0.1.0
4
+ Summary: Object storage (S3/MinIO/R2, Google Cloud Storage, Azure Blob, local filesystem) API + MCP Server + A2A Server for Agentic AI!
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.15,>=3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: agent-utilities>=0.47.0
16
+ Requires-Dist: python-dotenv>=1.0.0
17
+ Provides-Extra: mcp
18
+ Requires-Dist: agent-utilities[mcp]>=0.47.0; extra == "mcp"
19
+ Provides-Extra: agent
20
+ Requires-Dist: agent-utilities[agent,logfire]>=0.47.0; extra == "agent"
21
+ Provides-Extra: s3
22
+ Requires-Dist: boto3>=1.34.0; extra == "s3"
23
+ Provides-Extra: gcs
24
+ Requires-Dist: google-cloud-storage>=2.16.0; extra == "gcs"
25
+ Provides-Extra: azure
26
+ Requires-Dist: azure-storage-blob>=12.20.0; extra == "azure"
27
+ Provides-Extra: all
28
+ Requires-Dist: objectstore-mcp[agent,azure,gcs,logfire,mcp,s3]>=0.1.0; extra == "all"
29
+ Provides-Extra: test
30
+ Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
31
+ Requires-Dist: pytest; extra == "test"
32
+ Requires-Dist: pytest-asyncio; extra == "test"
33
+ Requires-Dist: pytest-cov; extra == "test"
34
+ Requires-Dist: moto[s3]>=5.0.0; extra == "test"
35
+ Dynamic: license-file
36
+
37
+ # ObjectStore MCP
38
+ ## Multi-Backend Object Storage | MCP Server
39
+
40
+ ![PyPI - Version](https://img.shields.io/pypi/v/objectstore-mcp)
41
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
42
+ ![PyPI - License](https://img.shields.io/pypi/l/objectstore-mcp)
43
+
44
+ The object-storage connector for the agent-utilities fleet: **one MCP tool
45
+ surface over S3 and S3-compatible stores (MinIO, Cloudflare R2), Google Cloud
46
+ Storage, Azure Blob Storage, and a zero-infra local-filesystem backend**.
47
+
48
+ *Version: 0.1.0*
49
+
50
+ > **Documentation** — Installation, deployment, and usage across the API, CLI, and
51
+ > MCP interfaces are maintained in [`docs/`](docs/index.md).
52
+
53
+ ## Table of Contents
54
+
55
+ - [Overview](#overview)
56
+ - [What it provides](#what-it-provides)
57
+ - [Backend × capability matrix](#backend--capability-matrix)
58
+ - [Installation](#installation)
59
+ - [Configuration (environment)](#configuration-environment)
60
+ - [Usage](#usage)
61
+ - [MCP config](#mcp-config)
62
+ - [Docker deployment](#docker-deployment)
63
+ - [Development](#development)
64
+ - [License](#license)
65
+
66
+ ## Overview
67
+
68
+ `objectstore-mcp` wraps heterogeneous object stores behind one typed,
69
+ deterministic MCP tool surface, plus an optional Pydantic-AI A2A agent server
70
+ (`objectstore-agent`). Safety caps, explicit buckets, and dry-run-by-default
71
+ batch deletes are enforced uniformly in the tool layer, regardless of backend.
72
+
73
+ ## What it provides
74
+
75
+ - **A multi-backend store abstraction** (`objectstore_mcp.api`,
76
+ CONCEPT:OBJ-1.0) — every provider implements the same
77
+ `ObjectStoreBackend` protocol, validated by a single conformance test
78
+ suite that runs for real against the filesystem backend.
79
+ - **Three consolidated, action-routed MCP tools** (`objectstore-mcp`
80
+ console script):
81
+
82
+ | Tool | Actions | Description |
83
+ |---|---|---|
84
+ | `objects` | `list` (prefix/delimiter pagination), `head`, `get` (text/base64, size-capped), `put` (text/base64, size-capped), `copy`, `move`, `delete`, `delete_batch` (capped, dry-run by default), `presign`, `metadata_get`, `metadata_set` | Single-object lifecycle and listing on any store |
85
+ | `buckets` | `list`, `create`, `delete` (empty-only, opt-in), `exists`, `info`, `stores` | Bucket/container admin and store registry introspection |
86
+ | `transfer` | `upload`, `download`, `upload_dir`, `download_prefix` (all size/batch-capped) | Local-filesystem ⇄ object-store transfer, single or by prefix |
87
+
88
+ The whole tool set toggles with `OBJECTSTORETOOL`.
89
+
90
+ - **Named multi-store routing** — `OBJECTSTORE_STORES` JSON maps store names
91
+ to `{backend, bucket?, endpoint?, profile?, ...}`; every tool takes an
92
+ optional `store` argument. A zero-infra `local` filesystem store always
93
+ exists, so the server works with no cloud credentials at all.
94
+ - **A safety governor** — size caps on get/put/transfer, list/batch key caps,
95
+ deletes that demand an explicit bucket+key (no wildcards), batch deletes
96
+ that are prefix-scoped, capped, and dry-run by default, and bucket deletes
97
+ that are empty-only and disabled unless explicitly enabled.
98
+
99
+ ## Backend × capability matrix
100
+
101
+ | Capability | filesystem | s3 / minio / r2 | gcs | azure |
102
+ |---|---|---|---|---|
103
+ | buckets (list/create/delete/exists/info) | yes | yes | yes | yes |
104
+ | objects (list/head/get/put/copy/move/delete) | yes | yes | yes | yes |
105
+ | prefix + delimiter listing, pagination | yes | yes | yes | yes |
106
+ | user metadata get/set | yes | yes | yes | yes |
107
+ | presigned URLs | no | yes | yes (needs service-account key) | yes (needs account key) |
108
+ | bucket location | no | yes | yes | no |
109
+
110
+ ## Installation
111
+
112
+ ```bash
113
+ pip install objectstore-mcp # core: local filesystem backend only
114
+ pip install objectstore-mcp[s3] # + boto3 (S3, MinIO, R2)
115
+ pip install objectstore-mcp[gcs] # + google-cloud-storage
116
+ pip install objectstore-mcp[azure] # + azure-storage-blob
117
+ pip install objectstore-mcp[all] # everything (incl. MCP + agent extras)
118
+ ```
119
+
120
+ Or pull the container image:
121
+
122
+ ```bash
123
+ docker pull knucklessg1/objectstore-mcp:latest
124
+ ```
125
+
126
+ ## Configuration (environment)
127
+
128
+ | Var | Default | Meaning |
129
+ |---|---|---|
130
+ | `OBJECTSTORE_STORES` | _(empty)_ | JSON: store name → `{backend, bucket?, endpoint?, profile?, region?, root?, project?, connection_string?}` |
131
+ | `OBJECTSTORE_DEFAULT_STORE` | first configured store, else `local` | Store used when a tool call omits `store` |
132
+ | `OBJECTSTORE_FS_ROOT` | `~/.local/share/objectstore-mcp` | Root of the implicit `local` filesystem store |
133
+ | `OBJECTSTORE_MAX_GET_BYTES` | `10485760` (10 MiB) | Cap on `objects get` |
134
+ | `OBJECTSTORE_MAX_PUT_BYTES` | `10485760` (10 MiB) | Cap on `objects put` |
135
+ | `OBJECTSTORE_MAX_TRANSFER_BYTES` | `104857600` (100 MiB) | Cap per transfer (single or batch total) |
136
+ | `OBJECTSTORE_MAX_BATCH_KEYS` | `100` | Cap on batch delete / dir transfer key counts |
137
+ | `OBJECTSTORE_MAX_LIST_KEYS` | `1000` | Cap on one listing page |
138
+ | `OBJECTSTORE_ALLOW_DELETE` | `true` | Object deletes (delete/delete_batch/move) |
139
+ | `OBJECTSTORE_ALLOW_BUCKET_DELETE` | `false` | Bucket deletes (empty buckets only) |
140
+ | `OBJECTSTORETOOL` | `True` | Register the objectstore tool set |
141
+ | `HOST` / `PORT` / `TRANSPORT` | `0.0.0.0` / `8000` / `stdio` | MCP server bind + transport (`stdio`, `streamable-http`, `sse`) |
142
+ | `AUTH_TYPE` | `none` | MCP auth mode (container image) |
143
+ | `ENABLE_OTEL` | `True` | OTEL/Langfuse telemetry export |
144
+ | `EUNOMIA_TYPE` / `EUNOMIA_POLICY_FILE` | `none` / `mcp_policies.json` | Eunomia access-governance middleware |
145
+ | `DEFAULT_AGENT_NAME` / `AGENT_DESCRIPTION` / `AGENT_SYSTEM_PROMPT` | identity defaults | A2A agent server identity overrides |
146
+ | `MCP_URL` | _(empty)_ | MCP endpoint the A2A agent connects to |
147
+
148
+ Provider credentials resolve through each SDK's own chain — boto3's
149
+ resolution order for S3 (env keys, `~/.aws` profiles via the store's
150
+ `profile`, SSO, instance metadata), `GOOGLE_APPLICATION_CREDENTIALS` /
151
+ Application Default Credentials for GCS, and
152
+ `AZURE_STORAGE_CONNECTION_STRING` for Azure Blob.
153
+
154
+ ### Example store registry
155
+
156
+ ```json
157
+ {
158
+ "media": {"backend": "s3", "bucket": "media-prod", "profile": "prod", "region": "us-east-1"},
159
+ "minio": {"backend": "s3", "endpoint": "http://minio.arpa:9000"},
160
+ "r2": {"backend": "s3", "endpoint": "https://<account>.r2.cloudflarestorage.com"},
161
+ "reports": {"backend": "gcs", "bucket": "acme-reports"},
162
+ "archive": {"backend": "azure", "bucket": "archive"},
163
+ "scratch": {"backend": "filesystem", "root": "~/scratch-store"}
164
+ }
165
+ ```
166
+
167
+ ## Usage
168
+
169
+ ```bash
170
+ objectstore-mcp # stdio
171
+ objectstore-mcp --transport streamable-http --host 0.0.0.0 --port 8000
172
+ ```
173
+
174
+ Example tool calls (any MCP client):
175
+
176
+ ```jsonc
177
+ // Write then read a text object on the zero-infra local store
178
+ {"tool": "buckets", "arguments": {"action": "create", "params_json": "{\"bucket\": \"notes\"}"}}
179
+ {"tool": "objects", "arguments": {"action": "put", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\", \"text\": \"- ship it\"}"}}
180
+ {"tool": "objects", "arguments": {"action": "get", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\"}"}}
181
+
182
+ // Preview then execute a prefix-scoped batch delete on a named S3 store
183
+ {"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\"}"}}
184
+ {"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\", \"dry_run\": false}"}}
185
+ ```
186
+
187
+ ## MCP config
188
+
189
+ ```json
190
+ {
191
+ "mcpServers": {
192
+ "objectstore-mcp": {
193
+ "command": "uv",
194
+ "args": ["run", "objectstore-mcp"],
195
+ "env": {
196
+ "OBJECTSTORE_STORES": "{\"minio\": {\"backend\": \"s3\", \"endpoint\": \"http://minio.arpa:9000\"}}",
197
+ "OBJECTSTORE_DEFAULT_STORE": "local"
198
+ }
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ Run the A2A agent server against a live MCP server:
205
+
206
+ ```bash
207
+ objectstore-agent --mcp-url http://localhost:8000/mcp --host 0.0.0.0 --port 9001
208
+ ```
209
+
210
+ ## Docker deployment
211
+
212
+ ```bash
213
+ docker compose -f docker/mcp.compose.yml up -d # MCP server only
214
+ docker compose -f docker/agent.compose.yml up -d # MCP + A2A agent
215
+ curl -s http://localhost:8000/health # {"status":"OK"}
216
+ ```
217
+
218
+ Both services read configuration from `../.env` (copy
219
+ [`.env.example`](.env.example)); see [`docs/deployment.md`](docs/deployment.md).
220
+
221
+ ## Development
222
+
223
+ ```bash
224
+ pip install -e .[test]
225
+ pytest # full suite (cloud SDKs not required)
226
+ pip install -e .[test-s3] # adds boto3+moto integration tests
227
+ pre-commit run --all-files
228
+ ```
229
+
230
+ See [`docs/`](docs/) for architecture, concepts, and deployment details.
231
+
232
+ ## License
233
+
234
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,198 @@
1
+ # ObjectStore MCP
2
+ ## Multi-Backend Object Storage | MCP Server
3
+
4
+ ![PyPI - Version](https://img.shields.io/pypi/v/objectstore-mcp)
5
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
6
+ ![PyPI - License](https://img.shields.io/pypi/l/objectstore-mcp)
7
+
8
+ The object-storage connector for the agent-utilities fleet: **one MCP tool
9
+ surface over S3 and S3-compatible stores (MinIO, Cloudflare R2), Google Cloud
10
+ Storage, Azure Blob Storage, and a zero-infra local-filesystem backend**.
11
+
12
+ *Version: 0.1.0*
13
+
14
+ > **Documentation** — Installation, deployment, and usage across the API, CLI, and
15
+ > MCP interfaces are maintained in [`docs/`](docs/index.md).
16
+
17
+ ## Table of Contents
18
+
19
+ - [Overview](#overview)
20
+ - [What it provides](#what-it-provides)
21
+ - [Backend × capability matrix](#backend--capability-matrix)
22
+ - [Installation](#installation)
23
+ - [Configuration (environment)](#configuration-environment)
24
+ - [Usage](#usage)
25
+ - [MCP config](#mcp-config)
26
+ - [Docker deployment](#docker-deployment)
27
+ - [Development](#development)
28
+ - [License](#license)
29
+
30
+ ## Overview
31
+
32
+ `objectstore-mcp` wraps heterogeneous object stores behind one typed,
33
+ deterministic MCP tool surface, plus an optional Pydantic-AI A2A agent server
34
+ (`objectstore-agent`). Safety caps, explicit buckets, and dry-run-by-default
35
+ batch deletes are enforced uniformly in the tool layer, regardless of backend.
36
+
37
+ ## What it provides
38
+
39
+ - **A multi-backend store abstraction** (`objectstore_mcp.api`,
40
+ CONCEPT:OBJ-1.0) — every provider implements the same
41
+ `ObjectStoreBackend` protocol, validated by a single conformance test
42
+ suite that runs for real against the filesystem backend.
43
+ - **Three consolidated, action-routed MCP tools** (`objectstore-mcp`
44
+ console script):
45
+
46
+ | Tool | Actions | Description |
47
+ |---|---|---|
48
+ | `objects` | `list` (prefix/delimiter pagination), `head`, `get` (text/base64, size-capped), `put` (text/base64, size-capped), `copy`, `move`, `delete`, `delete_batch` (capped, dry-run by default), `presign`, `metadata_get`, `metadata_set` | Single-object lifecycle and listing on any store |
49
+ | `buckets` | `list`, `create`, `delete` (empty-only, opt-in), `exists`, `info`, `stores` | Bucket/container admin and store registry introspection |
50
+ | `transfer` | `upload`, `download`, `upload_dir`, `download_prefix` (all size/batch-capped) | Local-filesystem ⇄ object-store transfer, single or by prefix |
51
+
52
+ The whole tool set toggles with `OBJECTSTORETOOL`.
53
+
54
+ - **Named multi-store routing** — `OBJECTSTORE_STORES` JSON maps store names
55
+ to `{backend, bucket?, endpoint?, profile?, ...}`; every tool takes an
56
+ optional `store` argument. A zero-infra `local` filesystem store always
57
+ exists, so the server works with no cloud credentials at all.
58
+ - **A safety governor** — size caps on get/put/transfer, list/batch key caps,
59
+ deletes that demand an explicit bucket+key (no wildcards), batch deletes
60
+ that are prefix-scoped, capped, and dry-run by default, and bucket deletes
61
+ that are empty-only and disabled unless explicitly enabled.
62
+
63
+ ## Backend × capability matrix
64
+
65
+ | Capability | filesystem | s3 / minio / r2 | gcs | azure |
66
+ |---|---|---|---|---|
67
+ | buckets (list/create/delete/exists/info) | yes | yes | yes | yes |
68
+ | objects (list/head/get/put/copy/move/delete) | yes | yes | yes | yes |
69
+ | prefix + delimiter listing, pagination | yes | yes | yes | yes |
70
+ | user metadata get/set | yes | yes | yes | yes |
71
+ | presigned URLs | no | yes | yes (needs service-account key) | yes (needs account key) |
72
+ | bucket location | no | yes | yes | no |
73
+
74
+ ## Installation
75
+
76
+ ```bash
77
+ pip install objectstore-mcp # core: local filesystem backend only
78
+ pip install objectstore-mcp[s3] # + boto3 (S3, MinIO, R2)
79
+ pip install objectstore-mcp[gcs] # + google-cloud-storage
80
+ pip install objectstore-mcp[azure] # + azure-storage-blob
81
+ pip install objectstore-mcp[all] # everything (incl. MCP + agent extras)
82
+ ```
83
+
84
+ Or pull the container image:
85
+
86
+ ```bash
87
+ docker pull knucklessg1/objectstore-mcp:latest
88
+ ```
89
+
90
+ ## Configuration (environment)
91
+
92
+ | Var | Default | Meaning |
93
+ |---|---|---|
94
+ | `OBJECTSTORE_STORES` | _(empty)_ | JSON: store name → `{backend, bucket?, endpoint?, profile?, region?, root?, project?, connection_string?}` |
95
+ | `OBJECTSTORE_DEFAULT_STORE` | first configured store, else `local` | Store used when a tool call omits `store` |
96
+ | `OBJECTSTORE_FS_ROOT` | `~/.local/share/objectstore-mcp` | Root of the implicit `local` filesystem store |
97
+ | `OBJECTSTORE_MAX_GET_BYTES` | `10485760` (10 MiB) | Cap on `objects get` |
98
+ | `OBJECTSTORE_MAX_PUT_BYTES` | `10485760` (10 MiB) | Cap on `objects put` |
99
+ | `OBJECTSTORE_MAX_TRANSFER_BYTES` | `104857600` (100 MiB) | Cap per transfer (single or batch total) |
100
+ | `OBJECTSTORE_MAX_BATCH_KEYS` | `100` | Cap on batch delete / dir transfer key counts |
101
+ | `OBJECTSTORE_MAX_LIST_KEYS` | `1000` | Cap on one listing page |
102
+ | `OBJECTSTORE_ALLOW_DELETE` | `true` | Object deletes (delete/delete_batch/move) |
103
+ | `OBJECTSTORE_ALLOW_BUCKET_DELETE` | `false` | Bucket deletes (empty buckets only) |
104
+ | `OBJECTSTORETOOL` | `True` | Register the objectstore tool set |
105
+ | `HOST` / `PORT` / `TRANSPORT` | `0.0.0.0` / `8000` / `stdio` | MCP server bind + transport (`stdio`, `streamable-http`, `sse`) |
106
+ | `AUTH_TYPE` | `none` | MCP auth mode (container image) |
107
+ | `ENABLE_OTEL` | `True` | OTEL/Langfuse telemetry export |
108
+ | `EUNOMIA_TYPE` / `EUNOMIA_POLICY_FILE` | `none` / `mcp_policies.json` | Eunomia access-governance middleware |
109
+ | `DEFAULT_AGENT_NAME` / `AGENT_DESCRIPTION` / `AGENT_SYSTEM_PROMPT` | identity defaults | A2A agent server identity overrides |
110
+ | `MCP_URL` | _(empty)_ | MCP endpoint the A2A agent connects to |
111
+
112
+ Provider credentials resolve through each SDK's own chain — boto3's
113
+ resolution order for S3 (env keys, `~/.aws` profiles via the store's
114
+ `profile`, SSO, instance metadata), `GOOGLE_APPLICATION_CREDENTIALS` /
115
+ Application Default Credentials for GCS, and
116
+ `AZURE_STORAGE_CONNECTION_STRING` for Azure Blob.
117
+
118
+ ### Example store registry
119
+
120
+ ```json
121
+ {
122
+ "media": {"backend": "s3", "bucket": "media-prod", "profile": "prod", "region": "us-east-1"},
123
+ "minio": {"backend": "s3", "endpoint": "http://minio.arpa:9000"},
124
+ "r2": {"backend": "s3", "endpoint": "https://<account>.r2.cloudflarestorage.com"},
125
+ "reports": {"backend": "gcs", "bucket": "acme-reports"},
126
+ "archive": {"backend": "azure", "bucket": "archive"},
127
+ "scratch": {"backend": "filesystem", "root": "~/scratch-store"}
128
+ }
129
+ ```
130
+
131
+ ## Usage
132
+
133
+ ```bash
134
+ objectstore-mcp # stdio
135
+ objectstore-mcp --transport streamable-http --host 0.0.0.0 --port 8000
136
+ ```
137
+
138
+ Example tool calls (any MCP client):
139
+
140
+ ```jsonc
141
+ // Write then read a text object on the zero-infra local store
142
+ {"tool": "buckets", "arguments": {"action": "create", "params_json": "{\"bucket\": \"notes\"}"}}
143
+ {"tool": "objects", "arguments": {"action": "put", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\", \"text\": \"- ship it\"}"}}
144
+ {"tool": "objects", "arguments": {"action": "get", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\"}"}}
145
+
146
+ // Preview then execute a prefix-scoped batch delete on a named S3 store
147
+ {"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\"}"}}
148
+ {"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\", \"dry_run\": false}"}}
149
+ ```
150
+
151
+ ## MCP config
152
+
153
+ ```json
154
+ {
155
+ "mcpServers": {
156
+ "objectstore-mcp": {
157
+ "command": "uv",
158
+ "args": ["run", "objectstore-mcp"],
159
+ "env": {
160
+ "OBJECTSTORE_STORES": "{\"minio\": {\"backend\": \"s3\", \"endpoint\": \"http://minio.arpa:9000\"}}",
161
+ "OBJECTSTORE_DEFAULT_STORE": "local"
162
+ }
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ Run the A2A agent server against a live MCP server:
169
+
170
+ ```bash
171
+ objectstore-agent --mcp-url http://localhost:8000/mcp --host 0.0.0.0 --port 9001
172
+ ```
173
+
174
+ ## Docker deployment
175
+
176
+ ```bash
177
+ docker compose -f docker/mcp.compose.yml up -d # MCP server only
178
+ docker compose -f docker/agent.compose.yml up -d # MCP + A2A agent
179
+ curl -s http://localhost:8000/health # {"status":"OK"}
180
+ ```
181
+
182
+ Both services read configuration from `../.env` (copy
183
+ [`.env.example`](.env.example)); see [`docs/deployment.md`](docs/deployment.md).
184
+
185
+ ## Development
186
+
187
+ ```bash
188
+ pip install -e .[test]
189
+ pytest # full suite (cloud SDKs not required)
190
+ pip install -e .[test-s3] # adds boto3+moto integration tests
191
+ pre-commit run --all-files
192
+ ```
193
+
194
+ See [`docs/`](docs/) for architecture, concepts, and deployment details.
195
+
196
+ ## License
197
+
198
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,63 @@
1
+ """objectstore-mcp — multi-backend object-storage API + MCP Server + A2A Agent.
2
+
3
+ One MCP tool surface (objects/buckets/transfer) over S3 and S3-compatible
4
+ stores (MinIO, Cloudflare R2), Google Cloud Storage, Azure Blob Storage, and
5
+ a zero-infra local-filesystem backend (CONCEPT:OBJ-1.0).
6
+ """
7
+
8
+ import importlib
9
+ import inspect
10
+ from typing import Any
11
+
12
+ __version__ = "0.1.0"
13
+ __all__: list[str] = []
14
+
15
+ CORE_MODULES = ["objectstore_mcp.api_client"]
16
+ OPTIONAL_MODULES = {
17
+ "objectstore_mcp.agent_server": "agent",
18
+ "objectstore_mcp.mcp_server": "mcp",
19
+ }
20
+
21
+
22
+ def _expose_members(module):
23
+ for name, obj in inspect.getmembers(module):
24
+ if (inspect.isclass(obj) or inspect.isfunction(obj)) and not name.startswith(
25
+ "_"
26
+ ):
27
+ globals()[name] = obj
28
+ if name not in __all__:
29
+ __all__.append(name)
30
+
31
+
32
+ for module_name in CORE_MODULES:
33
+ module = importlib.import_module(module_name)
34
+ _expose_members(module)
35
+
36
+ _loaded_optional_modules: dict = {}
37
+
38
+
39
+ def _import_module_safely(module_name: str):
40
+ try:
41
+ return importlib.import_module(module_name)
42
+ except ImportError:
43
+ return None
44
+
45
+
46
+ def __getattr__(name: str) -> Any:
47
+ if name == "_MCP_AVAILABLE":
48
+ mcp_key = next((k for k in OPTIONAL_MODULES if "mcp_server" in k), None)
49
+ return _import_module_safely(mcp_key) is not None if mcp_key else False
50
+ if name == "_AGENT_AVAILABLE":
51
+ agent_key = next((k for k in OPTIONAL_MODULES if "agent_server" in k), None)
52
+ return _import_module_safely(agent_key) is not None if agent_key else False
53
+
54
+ for module_name in OPTIONAL_MODULES:
55
+ if module_name not in _loaded_optional_modules:
56
+ module = _import_module_safely(module_name)
57
+ _loaded_optional_modules[module_name] = module
58
+ if module is not None:
59
+ _expose_members(module)
60
+ module = _loaded_optional_modules[module_name]
61
+ if module is not None and hasattr(module, name):
62
+ return getattr(module, name)
63
+ raise AttributeError(f"module 'objectstore_mcp' has no attribute {name!r}")
@@ -0,0 +1,4 @@
1
+ from objectstore_mcp.agent_server import agent_server
2
+
3
+ if __name__ == "__main__":
4
+ agent_server()
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/python
2
+ import logging
3
+ import os
4
+ import sys
5
+ import warnings
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ logging.basicConfig(
10
+ level=logging.INFO,
11
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
12
+ handlers=[logging.StreamHandler()],
13
+ )
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def agent_server():
18
+ from agent_utilities import (
19
+ build_system_prompt_from_workspace,
20
+ create_agent_parser,
21
+ create_agent_server,
22
+ initialize_workspace,
23
+ load_identity,
24
+ )
25
+
26
+ warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
27
+ warnings.filterwarnings("ignore", category=DeprecationWarning, module="fastmcp")
28
+
29
+ initialize_workspace()
30
+ meta = load_identity()
31
+ agent_name = os.getenv("DEFAULT_AGENT_NAME", meta.get("name", "Objectstore Mcp"))
32
+
33
+ print(f"{agent_name} v{__version__}", file=sys.stderr)
34
+ parser = create_agent_parser()
35
+ args = parser.parse_args()
36
+
37
+ if args.debug:
38
+ logging.getLogger().setLevel(logging.DEBUG)
39
+ logger.debug("Debug mode enabled")
40
+
41
+ create_agent_server(
42
+ mcp_url=args.mcp_url,
43
+ mcp_config=args.mcp_config or "mcp_config.json",
44
+ host=args.host,
45
+ port=args.port,
46
+ provider=args.provider,
47
+ model_id=args.model_id,
48
+ router_model=args.model_id,
49
+ agent_model=args.model_id,
50
+ base_url=args.base_url,
51
+ api_key=args.api_key,
52
+ agent_description=os.getenv(
53
+ "AGENT_DESCRIPTION",
54
+ meta.get("description", "Objectstore Mcp API + MCP Server + A2A Server"),
55
+ ),
56
+ system_prompt=os.getenv(
57
+ "AGENT_SYSTEM_PROMPT",
58
+ meta.get("content") or build_system_prompt_from_workspace(),
59
+ ),
60
+ custom_skills_directory=args.custom_skills_directory,
61
+ enable_web_ui=args.web,
62
+ enable_otel=args.otel,
63
+ otel_endpoint=args.otel_endpoint,
64
+ otel_headers=args.otel_headers,
65
+ otel_public_key=args.otel_public_key,
66
+ otel_secret_key=args.otel_secret_key,
67
+ otel_protocol=args.otel_protocol,
68
+ debug=args.debug,
69
+ )
70
+
71
+
72
+ if __name__ == "__main__":
73
+ agent_server()