ObjectStore MCP
Multi-Backend Object Storage | MCP Server
The object-storage connector for the agent-utilities fleet: one MCP tool surface over S3 and S3-compatible stores (MinIO, Cloudflare R2), Google Cloud Storage, Azure Blob Storage, and a zero-infra local-filesystem backend.
Version: 1.0.1
Documentation — Installation, deployment, and usage across the API, CLI, and MCP interfaces are maintained in
docs/.
Table of Contents
- Overview
- What it provides
- Backend × capability matrix
- Installation
- Configuration (environment)
- Usage
- MCP config
- Docker deployment
- Development
- License
Overview
objectstore-mcp wraps heterogeneous object stores behind one typed,
deterministic MCP tool surface, plus an optional Pydantic-AI A2A agent server
(objectstore-agent). Safety caps, explicit buckets, and dry-run-by-default
batch deletes are enforced uniformly in the tool layer, regardless of backend.
What it provides
-
A multi-backend store abstraction (
objectstore_mcp.api, CONCEPT:OBJ-1.0) — every provider implements the sameObjectStoreBackendprotocol, validated by a single conformance test suite that runs for real against the filesystem backend. -
Three consolidated, action-routed MCP tools (
objectstore-mcpconsole script):Tool Actions Description objectslist(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_setSingle-object lifecycle and listing on any store bucketslist,create,delete(empty-only, opt-in),exists,info,storesBucket/container admin and store registry introspection transferupload,download,upload_dir,download_prefix(all size/batch-capped)Local-filesystem ⇄ object-store transfer, single or by prefix The whole tool set toggles with
OBJECTSTORETOOL. -
Named multi-store routing —
OBJECTSTORE_STORESJSON maps store names to{backend, bucket?, endpoint?, profile?, ...}; every tool takes an optionalstoreargument. A zero-infralocalfilesystem store always exists, so the server works with no cloud credentials at all. -
A safety governor — size caps on get/put/transfer, list/batch key caps, deletes that demand an explicit bucket+key (no wildcards), batch deletes that are prefix-scoped, capped, and dry-run by default, and bucket deletes that are empty-only and disabled unless explicitly enabled.
Available MCP Tools
Condensed action-routed tools (default — MCP_TOOL_MODE=condensed)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
buckets |
OBJECTSTORETOOL |
Manage buckets/containers and inspect configured stores. |
objects |
OBJECTSTORETOOL |
List, read, write, copy, move, delete, presign, and tag objects. |
transfer |
OBJECTSTORETOOL |
Move data between the local filesystem and object storage. |
Verbose 1:1 API-mapped tools (MCP_TOOL_MODE=verbose or both)
15 per-operation tools — one per public API method (click to expand)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
objectstore_bucket_exists |
OBJECT_STORE_BACKENDTOOL |
Return True when the bucket exists. |
objectstore_bucket_info |
OBJECT_STORE_BACKENDTOOL |
Describe one bucket. Raises NotFoundError when absent. |
objectstore_capabilities |
OBJECT_STORE_BACKENDTOOL |
Advertise optional capabilities. |
objectstore_copy_object |
OBJECT_STORE_BACKENDTOOL |
Server-side (where possible) copy of one object. |
objectstore_create_bucket |
OBJECT_STORE_BACKENDTOOL |
Create a bucket. Raises AlreadyExistsError if it exists. |
objectstore_delete_bucket |
OBJECT_STORE_BACKENDTOOL |
Delete an EMPTY bucket. Raises BucketNotEmptyError otherwise. |
objectstore_delete_object |
OBJECT_STORE_BACKENDTOOL |
Delete exactly one object. Raises NotFoundError when absent. |
objectstore_get_object |
OBJECT_STORE_BACKENDTOOL |
Download an object's bytes. Raises ObjectStoreError when the |
objectstore_get_object_metadata |
OBJECT_STORE_BACKENDTOOL |
Return the user metadata of one object. |
objectstore_head_object |
OBJECT_STORE_BACKENDTOOL |
Stat one object without downloading it. |
objectstore_list_buckets |
OBJECT_STORE_BACKENDTOOL |
List all buckets/containers visible to the credentials. |
objectstore_list_objects |
OBJECT_STORE_BACKENDTOOL |
List objects under prefix, optionally folding at delimiter. |
objectstore_presigned_url |
OBJECT_STORE_BACKENDTOOL |
Mint a presigned URL. Raises UnsupportedOperationError when the |
objectstore_put_object |
OBJECT_STORE_BACKENDTOOL |
Upload bytes to bucket/key (overwrites). |
objectstore_set_object_metadata |
OBJECT_STORE_BACKENDTOOL |
Replace the user metadata of one object. |
3 action-routed tool(s) (default) · 15 verbose 1:1 tool(s). Each is enabled unless its <DOMAIN>TOOL toggle is set false; MCP_TOOL_MODE selects the surface (condensed default · verbose 1:1 · both). Auto-generated — do not edit.
Backend × capability matrix
| Capability | filesystem | s3 / minio / r2 | gcs | azure |
|---|---|---|---|---|
| buckets (list/create/delete/exists/info) | yes | yes | yes | yes |
| objects (list/head/get/put/copy/move/delete) | yes | yes | yes | yes |
| prefix + delimiter listing, pagination | yes | yes | yes | yes |
| user metadata get/set | yes | yes | yes | yes |
| presigned URLs | no | yes | yes (needs service-account key) | yes (needs account key) |
| bucket location | no | yes | yes | no |
Installation
Pick the extra that matches what you want to run (provider extras are additive):
| Extra | Installs | Use when |
|---|---|---|
objectstore-mcp[mcp] |
Slim MCP server only (agent-utilities[mcp] — FastMCP/FastAPI) |
You only run the MCP server (smallest install / image) |
objectstore-mcp[agent] |
Full agent runtime (agent-utilities[agent,logfire] — Pydantic AI + the epistemic-graph engine) |
You run the integrated A2A agent |
objectstore-mcp[all] |
Everything (mcp + agent + s3 + gcs + azure + logfire) |
Development / both surfaces |
pip install objectstore-mcp # core: local filesystem backend only
pip install objectstore-mcp[mcp] # slim MCP server (FastMCP/FastAPI)
pip install objectstore-mcp[agent] # full A2A agent runtime + epistemic-graph engine
pip install objectstore-mcp[mcp,s3] # + boto3 (S3, MinIO, R2)
pip install objectstore-mcp[mcp,gcs] # + google-cloud-storage
pip install objectstore-mcp[mcp,azure] # + azure-storage-blob
pip install objectstore-mcp[all] # everything (MCP + agent + all providers)
Container images (:mcp vs :agent)
One multi-stage docker/Dockerfile builds two right-sized images, selected by --target:
| Image tag | Build target | Contents | Entrypoint |
|---|---|---|---|
knucklessg1/objectstore-mcp:mcp |
--target mcp |
objectstore-mcp[mcp] — slim, no engine/pydantic-ai/dspy/llama-index/tree-sitter |
objectstore-mcp |
knucklessg1/objectstore-mcp:latest |
--target agent (default) |
objectstore-mcp[agent] — full agent runtime + epistemic-graph engine |
objectstore-agent |
docker build --target mcp -t knucklessg1/objectstore-mcp:mcp docker/ # slim MCP server
docker build --target agent -t knucklessg1/objectstore-mcp:latest docker/ # full agent
Or pull a prebuilt image:
docker pull knucklessg1/objectstore-mcp:mcp # slim MCP server
docker pull knucklessg1/objectstore-mcp:latest # full agent (default)
The
:mcptag is the slim MCP-server image (built fromdocker/Dockerfile --target mcp, installingobjectstore-mcp[mcp]). The default:latesttag is the full agent image (--target agent,objectstore-mcp[agent]) which also bundles the Pydantic AI agent and the epistemic-graph engine — use it when you runobjectstore-agent(the agent), not just the MCP server.
Knowledge-graph database (epistemic-graph)
The full agent ([agent] / :latest) embeds the epistemic-graph engine (pulled in
transitively via agent-utilities[agent]). For production — or to share one knowledge graph
across multiple agents — run epistemic-graph as its own database container and point the
agent at it instead of embedding it. Deployment recipes (single-node + Raft HA), connection
config, and the full database architecture (with diagrams) are documented in the
epistemic-graph deployment guide.
The slim [mcp] server does not require the database.
Configuration (environment)
| Var | Default | Meaning |
|---|---|---|
OBJECTSTORE_STORES |
(empty) | JSON: store name → {backend, bucket?, endpoint?, profile?, region?, root?, project?, connection_string?} |
OBJECTSTORE_DEFAULT_STORE |
first configured store, else local |
Store used when a tool call omits store |
OBJECTSTORE_FS_ROOT |
~/.local/share/objectstore-mcp |
Root of the implicit local filesystem store |
OBJECTSTORE_MAX_GET_BYTES |
10485760 (10 MiB) |
Cap on objects get |
OBJECTSTORE_MAX_PUT_BYTES |
10485760 (10 MiB) |
Cap on objects put |
OBJECTSTORE_MAX_TRANSFER_BYTES |
104857600 (100 MiB) |
Cap per transfer (single or batch total) |
OBJECTSTORE_MAX_BATCH_KEYS |
100 |
Cap on batch delete / dir transfer key counts |
OBJECTSTORE_MAX_LIST_KEYS |
1000 |
Cap on one listing page |
OBJECTSTORE_ALLOW_DELETE |
true |
Object deletes (delete/delete_batch/move) |
OBJECTSTORE_ALLOW_BUCKET_DELETE |
false |
Bucket deletes (empty buckets only) |
OBJECTSTORETOOL |
True |
Register the objectstore tool set |
HOST / PORT / TRANSPORT |
0.0.0.0 / 8000 / stdio |
MCP server bind + transport (stdio, streamable-http, sse) |
AUTH_TYPE |
none |
MCP auth mode (container image) |
ENABLE_OTEL |
True |
OTEL/Langfuse telemetry export |
EUNOMIA_TYPE / EUNOMIA_POLICY_FILE |
none / mcp_policies.json |
Eunomia access-governance middleware |
DEFAULT_AGENT_NAME / AGENT_DESCRIPTION / AGENT_SYSTEM_PROMPT |
identity defaults | A2A agent server identity overrides |
MCP_URL |
(empty) | MCP endpoint the A2A agent connects to |
Provider credentials resolve through each SDK's own chain — boto3's
resolution order for S3 (env keys, ~/.aws profiles via the store's
profile, SSO, instance metadata), GOOGLE_APPLICATION_CREDENTIALS /
Application Default Credentials for GCS, and
AZURE_STORAGE_CONNECTION_STRING for Azure Blob.
Example store registry
{
"media": {"backend": "s3", "bucket": "media-prod", "profile": "prod", "region": "us-east-1"},
"minio": {"backend": "s3", "endpoint": "http://minio.arpa:9000"},
"r2": {"backend": "s3", "endpoint": "https://<account>.r2.cloudflarestorage.com"},
"reports": {"backend": "gcs", "bucket": "acme-reports"},
"archive": {"backend": "azure", "bucket": "archive"},
"scratch": {"backend": "filesystem", "root": "~/scratch-store"}
}
Usage
objectstore-mcp # stdio
objectstore-mcp --transport streamable-http --host 0.0.0.0 --port 8000
Example tool calls (any MCP client):
// Write then read a text object on the zero-infra local store
{"tool": "buckets", "arguments": {"action": "create", "params_json": "{\"bucket\": \"notes\"}"}}
{"tool": "objects", "arguments": {"action": "put", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\", \"text\": \"- ship it\"}"}}
{"tool": "objects", "arguments": {"action": "get", "params_json": "{\"bucket\": \"notes\", \"key\": \"todo.md\"}"}}
// Preview then execute a prefix-scoped batch delete on a named S3 store
{"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\"}"}}
{"tool": "objects", "arguments": {"store": "media", "action": "delete_batch", "params_json": "{\"bucket\": \"media-prod\", \"prefix\": \"tmp/\", \"dry_run\": false}"}}
MCP config
Install the slim
[mcp]extra. The example below installsobjectstore-mcp[mcp]— the MCP-server extra that pulls only the FastMCP / FastAPI tooling (agent-utilities[mcp]). It deliberately excludes the heavy agent runtime (the epistemic-graph engine,pydantic-ai,dspy,llama-index,tree-sitter), souvx/container installs are dramatically smaller and faster. Add the provider extras you need ([mcp,s3],[mcp,gcs],[mcp,azure]); use the full[agent]extra only when you need the integrated Pydantic AI agent (see Installation).
{
"mcpServers": {
"objectstore-mcp": {
"command": "uvx",
"args": ["--from", "objectstore-mcp[mcp]", "objectstore-mcp"],
"env": {
"OBJECTSTORE_STORES": "{\"minio\": {\"backend\": \"s3\", \"endpoint\": \"http://minio.arpa:9000\"}}",
"OBJECTSTORE_DEFAULT_STORE": "local"
}
}
}
}
Run the A2A agent server against a live MCP server:
objectstore-agent --mcp-url http://localhost:8000/mcp --host 0.0.0.0 --port 9001
Additional Deployment Options
objectstore-mcp can also run as a local container (Docker / Podman / uv) or be
consumed from a remote deployment. The
Deployment guide has full, copy-paste
mcp_config.json for all four transports — stdio, streamable-http,
local container / uv, and remote URL:
- Local container / uv — launch the server from
mcp_config.jsonviauvx,docker run, orpodman run, or point at a local streamable-http container byurl. - Remote URL — connect to a server deployed behind Caddy at
http://objectstore-mcp.arpa/mcpusing the"url"key.
Docker deployment
docker compose -f docker/mcp.compose.yml up -d # MCP server only
docker compose -f docker/agent.compose.yml up -d # MCP + A2A agent
curl -s http://localhost:8000/health # {"status":"OK"}
Both services read configuration from ../.env (copy
.env.example); see docs/deployment.md.
Development
pip install -e .[test]
pytest # full suite (cloud SDKs not required)
pip install -e .[test-s3] # adds boto3+moto integration tests
pre-commit run --all-files
See docs/ for architecture, concepts, and deployment details.
License
MIT — see LICENSE.
Deploy with agent-os-genesis
This package can be provisioned for you — skill-guided — by the agent-os-genesis
universal skill (its single-package deploy mode): it picks your install method, seeds
secrets to OpenBao/Vault (or .env), trusts your enterprise CA, registers the MCP
server, and verifies it — the same machinery that stands up the whole Agent OS, narrowed
to just this package. Ask your agent to "deploy objectstore-mcp with agent-os-genesis".
| Install mode | Command |
|---|---|
| Bare-metal, prod (PyPI) | uvx objectstore-mcp · or uv tool install objectstore-mcp |
| Bare-metal, dev (editable) | uv pip install -e ".[all]" · or pip install -e ".[all]" |
| Container, prod | deploy knucklessg1/objectstore-mcp:latest via docker-compose / swarm / podman / podman-compose / kubernetes |
| Container, dev (editable) | deploy docker/compose.dev.yml (source-mounted at /src; edits live on restart) |
Secrets are read-existing + seeded via vault_sync — you are only prompted for what's missing.
Environment Variables
Package environment variables
| Variable | Example | Description |
|---|---|---|
HOST |
0.0.0.0 |
|
PORT |
8000 |
|
TRANSPORT |
stdio |
options: stdio, streamable-http, sse |
ENABLE_OTEL |
True |
|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:8080/api/public/otel |
|
OTEL_EXPORTER_OTLP_PUBLIC_KEY |
pk-... |
|
OTEL_EXPORTER_OTLP_SECRET_KEY |
sk-... |
|
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf |
|
EUNOMIA_TYPE |
none |
options: none, embedded, remote |
EUNOMIA_POLICY_FILE |
mcp_policies.json |
|
EUNOMIA_REMOTE_URL |
http://eunomia-server:8000 |
|
OBJECTSTORE_STORES |
{"media": {"backend": "s3", "bucket": "media-prod", "profile": "prod"}, "minio": {"backend": "s3", "endpoint": "http://minio.arpa:9000"}, "reports": {"backend": "gcs", "bucket": "acme-reports"}, "archive": {"backend": "azure", "bucket": "archive"}} |
Named stores (JSON). The zero-infra "local" filesystem store always exists. |
OBJECTSTORE_DEFAULT_STORE |
local |
|
OBJECTSTORE_FS_ROOT |
~/.local/share/objectstore-mcp |
|
OBJECTSTORE_MAX_GET_BYTES |
10485760 |
Safety limits (bytes / keys) |
OBJECTSTORE_MAX_PUT_BYTES |
10485760 |
|
OBJECTSTORE_MAX_TRANSFER_BYTES |
104857600 |
|
OBJECTSTORE_MAX_BATCH_KEYS |
100 |
|
OBJECTSTORE_MAX_LIST_KEYS |
1000 |
|
OBJECTSTORE_ALLOW_DELETE |
true |
|
OBJECTSTORE_ALLOW_BUCKET_DELETE |
false |
|
AZURE_STORAGE_CONNECTION_STRING |
— | Azure is the exception — the code reads this connection string directly: |
DEFAULT_AGENT_NAME |
ObjectStore Agent |
|
AGENT_DESCRIPTION |
AI agent for object-storage operations. |
|
AGENT_SYSTEM_PROMPT |
— | |
MCP_URL |
http://localhost:8000/mcp |
|
OBJECTSTORETOOL |
True |
Inherited agent-utilities variables (apply to every connector)
| Variable | Example | Description |
|---|---|---|
MCP_TOOL_MODE |
condensed |
Tool surface: condensed |
MCP_ENABLED_TOOLS |
— | Comma-separated tool allow-list |
MCP_DISABLED_TOOLS |
— | Comma-separated tool deny-list |
MCP_ENABLED_TAGS |
— | Comma-separated tag allow-list |
MCP_DISABLED_TAGS |
— | Comma-separated tag deny-list |
MCP_CLIENT_AUTH |
— | Outbound MCP auth (oidc-client-credentials for fleet calls) |
OIDC_CLIENT_ID |
— | OIDC client id (service-account auth) |
OIDC_CLIENT_SECRET |
— | OIDC client secret (service-account auth) |
DEBUG |
False |
Verbose logging |
PYTHONUNBUFFERED |
1 |
Unbuffered stdout (recommended in containers) |
PROVIDER |
openai |
LLM provider for the agent |
MODEL_ID |
gpt-4o |
Model id for the agent |
ENABLE_WEB_UI |
True |
Serve the AG-UI web interface |
27 package + 13 inherited variable(s). Auto-generated from .env.example + the shared agent-utilities set — do not edit.
Metadata
Release files for objectstore-mcp 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| objectstore_mcp-1.0.1.tar.gz | 51.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| objectstore_mcp-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.3 kB
Release files / objectstore_mcp-1.0.1.tar.gz
| Download URL | objectstore_mcp-1.0.1.tar.gz |
|---|---|
| Size | 51.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
afe58a9c0f024d84385781fa752d255b9af6470b8275efbec7fcc31f03f24b82
|
|
BLAKE2b-256 checksum How to use checksums |
a987a45d9511b9576574e6fe20e686de74da49483bd2ea37464d250db79f2ec6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / objectstore_mcp-1.0.1-py3-none-any.whl
| Download URL | objectstore_mcp-1.0.1-py3-none-any.whl |
|---|---|
| Size | 41.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
28f951126ab18360bf6ab460084542cf1c3831ea398caba2a2519e26c5d8b1dd
|
|
BLAKE2b-256 checksum How to use checksums |
41f6797945ff7fe6c01db79e579e364bbc92c1e886bbf61439216e501e868c60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|