Metadata-Version: 2.4
Name: objectstore-mcp
Version: 2.2.0
Summary: Object storage (S3/MinIO/R2, Google Cloud Storage, Azure Blob, local filesystem) API + MCP Server for Agentic AI!
Author-email: Project Maintainers <maintainers@users.noreply.github.com>
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Environment :: Console
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.2.1
Requires-Dist: python-dotenv>=1.2.4
Provides-Extra: mcp
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.2.1; extra == "mcp"
Provides-Extra: s3
Requires-Dist: boto3>=1.43.114; extra == "s3"
Provides-Extra: gcs
Requires-Dist: google-cloud-storage>=3.17.1; extra == "gcs"
Provides-Extra: azure
Requires-Dist: azure-storage-blob>=12.31.0; extra == "azure"
Provides-Extra: all
Requires-Dist: objectstore-mcp[azure,gcs,mcp,s3]>=1.0.1; extra == "all"
Provides-Extra: test
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
Requires-Dist: pytest>=9.1.1; extra == "test"
Requires-Dist: pytest-asyncio>=1.4.0; extra == "test"
Requires-Dist: pytest-cov>=7.1.0; extra == "test"
Requires-Dist: moto[s3]>=5.2.4; extra == "test"
Dynamic: license-file

# ObjectStore MCP
## Multi-Backend Object Storage | MCP Server

![PyPI - Version](https://img.shields.io/pypi/v/objectstore-mcp)
![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
![PyPI - License](https://img.shields.io/pypi/l/objectstore-mcp)

The object-storage connector for the agent-connector-sdk 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: 2.2.0*

> **Documentation** — Installation, deployment, and usage across the API, CLI, and
> MCP interfaces are maintained in [`docs/`](docs/index.md).

## Table of Contents

- [Overview](#overview)
- [What it provides](#what-it-provides)
- [Backend × capability matrix](#backend--capability-matrix)
- [Installation](#installation)
- [Configuration (environment)](#configuration-environment)
- [Usage](#usage)
- [MCP config](#mcp-config)
- [Docker deployment](#docker-deployment)
- [Development](#development)
- [License](#license)

## Overview

`objectstore-mcp` wraps heterogeneous object stores behind one typed,
(`objectstore-agent`). Safety caps, explicit buckets, and dry-run-by-default
batch deletes are enforced uniformly in the tool layer, in either case of backend.

## What it provides

- **A multi-backend store abstraction** (`objectstore_mcp.api`,
  CONCEPT:OB-OS.governance.every-provider-implements-same) — every provider implements the same
  `ObjectStoreBackend` protocol, validated by a single conformance test
  suite that runs for real against the filesystem backend.
- **Three consolidated, action-routed MCP tools** (`objectstore-mcp`
  console script):

  | Tool | Actions | Description |
  |---|---|---|
  | `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 |
  | `buckets` | `list`, `create`, `delete` (empty-only, opt-in), `exists`, `info`, `stores` | Bucket/container admin and store registry introspection |
  | `transfer` | `upload`, `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_STORES` JSON maps store names
  to `{backend, bucket?, endpoint?, profile?, ...}`; every tool takes an
  optional `store` argument. A zero-infra `local` filesystem 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

<!-- This table is auto-generated by `python -m agent_connector_sdk.mcp.readme_tools` — do not edit by hand. -->

<!-- MCP-TOOLS-TABLE:START -->

#### 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`)

<details>
<summary>15 per-operation tools — one per public API method (click to expand)</summary>

| 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. |

</details>

_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._
<!-- MCP-TOOLS-TABLE:END -->

## 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 the operator want to run (provider extras are additive):

| Extra | Installs | Use when |
|-------|----------|----------|
| `objectstore-mcp[mcp]` | Connector-focused MCP server (`agent-connector-sdk` — FastMCP/FastAPI + `epistemic-graph[full]`) | The operator only run the **MCP server** (smallest install / image) |
| `objectstore-mcp[all]` | Everything (`mcp` + `agent` + `s3` + `gcs` + `azure` + `logfire`) | Development / both surfaces |

```bash
pip install objectstore-mcp            # core: local filesystem backend only
pip install objectstore-mcp[mcp]       # connector-focused MCP server (FastMCP/FastAPI)
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`)

One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):

| Image tag | Build target | Contents | Entrypoint |
|-----------|--------------|----------|------------|
| `example/objectstore-mcp:mcp` | `--target mcp` | `objectstore-mcp[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `objectstore-mcp` |

```bash
docker build --target mcp   -t example/objectstore-mcp:mcp    docker/   # connector-focused MCP server
```

Or pull a prebuilt image:

```bash
docker pull example/objectstore-mcp:mcp      # connector-focused MCP server
docker pull example/objectstore-mcp@sha256:<digest>   # agent runtime (default)
```

> The `:mcp` tag is the **MCP-serving image** (built from
> `docker/Dockerfile --target mcp`, installing `objectstore-mcp[mcp]`). The default
> which also bundles the Pydantic AI agent and the epistemic-graph engine — use it
> when the operator run `objectstore-agent` (the agent), not just the MCP server.

### Knowledge-graph database (`epistemic-graph`)

Agent Connector SDK core dependency (`epistemic-graph[full]`). The `[mcp]` extra keeps
deployments can use the bundled engine. For production or shared state, run
**epistemic-graph as a dedicated database service** and configure the runtime to use it.
Deployment recipes (single-node + Raft HA), connection configuration, and architecture
diagrams are documented in the
[epistemic-graph deployment guide](https://knuckles-team.github.io/epistemic-graph/deployment/).

## 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 |
| `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

```json
{
  "media":   {"backend": "s3", "bucket": "media-prod", "profile": "prod", "region": "us-east-1"},
  "minio":   {"backend": "s3", "endpoint": "http://minio.example.invalid: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

```bash
objectstore-mcp                                   # stdio
objectstore-mcp --transport streamable-http --host 0.0.0.0 --port 8000
```

Example tool calls (any MCP client):

```jsonc
// 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 connector-focused `[mcp]` extra.** Examples use `objectstore-mcp[mcp]` to add
> FastMCP / FastAPI through `agent-connector-sdk`; the required Agent Connector SDK core
> enables model orchestration.
> Combine it with the storage-provider extras needed by the deployment.

```json
{
  "mcpServers": {
    "objectstore-mcp": {
      "command": "uvx",
      "args": ["--from", "objectstore-mcp[mcp]", "objectstore-mcp"],
      "env": {
        "OBJECTSTORE_STORES": "{\"minio\": {\"backend\": \"s3\", \"endpoint\": \"http://minio.example.invalid:9000\"}}",
        "OBJECTSTORE_DEFAULT_STORE": "local"
      }
    }
  }
}
```


```bash
objectstore-agent --mcp-url http://localhost:8000/mcp --host 0.0.0.0 --port 9001
```

<!-- BEGIN GENERATED: additional-deployment-options -->
### Additional Deployment Options

`objectstore-mcp` can run as a local stdio process or container, or behind a remote
network boundary. The
[Deployment guide](https://knuckles-team.github.io/objectstore-mcp/deployment/) carries
the detailed transport contract.

- **Local container** — launch a reviewed immutable image as a least-privilege
  stdio child with no listener or published port.
- **Remote URL** — connect through an operator-supplied authenticated HTTPS
  ingress. Keep its URL, outbound identity references, trust profile, and exact
  `MCP_ALLOWED_HOSTS` in `AgentConfig`.
<!-- END GENERATED: additional-deployment-options -->

## Docker deployment

```bash
docker compose -f docker/mcp.compose.yml up -d      # MCP server only
curl -s http://localhost:8000/health                 # {"status":"OK"}
```

Both services read configuration from `../.env` (copy
[`.env.example`](.env.example)); see [`docs/deployment.md`](docs/deployment.md).

## Development

```bash
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/`](docs/) for architecture, concepts, and deployment details.

## License

MIT — see [LICENSE](LICENSE).



## Environment Variables

<!-- ENV-VARS-TABLE:START -->

#### 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` | secret-injected |  |
| `OTEL_EXPORTER_OTLP_SECRET_KEY` | secret-injected |  |
| `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` | `{"primary": {"backend": "s3", "bucket": "example-bucket", "endpoint": "https://object-store.example"}}` | 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` | — | Provider credentials resolve through each SDK's own chain (this package never reads them itself — the cloud SDK does): S3  : boto3 chain (AWS access key / secret / profile, ~/.aws, instance role) GCS : the gcloud application-default credentials chain (service-account file) 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-connector-sdk variables (apply to every connector)

| Variable | Example | Description |
|----------|---------|-------------|
| `MCP_TOOL_MODE` | `intent` | Tool surface: `intent` \| `condensed` \| `verbose` \| `both` |
| `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 child auth: `oidc-client-credentials` \| `basic` \| `none` |
| `OIDC_CLIENT_ID` | — | OIDC client id (service-account auth) |
| `OIDC_CLIENT_SECRET_REF` | `secret://identity/oidc-client-secret` | Runtime secret reference for the OIDC service account |
| `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
| `MCP_BASIC_AUTH_PASSWORD_REF` | `secret://identity/mcp-basic-password` | Runtime secret reference for HTTP Basic auth (`MCP_CLIENT_AUTH=basic`) |
| `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 + 15 inherited variable(s). Auto-generated from `.env.example` + the shared agent-connector-sdk set — do not edit._
<!-- ENV-VARS-TABLE:END -->

<!-- GOVERNED-CAPABILITY:START -->
## Governed capability contract

This package ships a compact canonical skill surface with specialist procedures
kept as referenced workflows. The current MCP tools, skill metadata,
`connector_manifest.yml`, ontology, mappings, shapes, fixtures, migrations,
tool-schema fingerprints, and certification metadata form one versioned
capability contract. Validate them together; do not rely on stale tool names or
historical per-task skill wrappers.

Runtime endpoints, credentials, certificate trust, tenant identity, retention,
and observability policy are deployment inputs and are never packaged values.
See [Configuration, trust, and privacy](docs/configuration.md) before enabling a
network transport, connector ingestion, Arbora delegation, or trace export.
<!-- GOVERNED-CAPABILITY:END -->
