
Building an MCP server for AIOZ Storage is real, working, and takes less code than it sounds like it should, even though AIOZ Storage doesn't ship an official one yet. Since AIOZ Storage is S3-compatible, the same boto3 client already covered elsewhere in this series drops straight into the official Model Context Protocol Python SDK, giving an AI agent real, conversational read/write access to a bucket. This article walks through the actual working code: setup, three real tools, and what to know before treating a homemade server like a production system.
TL;DR:
An MCP server is just a program that exposes tools an AI agent can call, per the official protocol's own description of how MCP works generally. AIOZ Storage doesn't publish one, but it doesn't need to for this to work, the same S3-compatible endpoint every SDK and CLI in this series already talks to is all a custom MCP server needs underneath it. This isn't a workaround or a hack, it's the same pattern real MCP servers for other S3-compatible platforms use, wrapping an existing SDK client in a small tool-calling layer.
Three things: Python, the official MCP SDK (pip install mcp), and boto3 (pip install boto3), the exact same client already covered for direct AIOZ Storage access. You'll also need an AIOZ Storage access grant with S3 credentials, generated the same way every other SDK guide in this series gets one.
The boto3 client configuration is identical to every other AIOZ Storage integration in this series, the custom endpoint, path-style addressing, and a placeholder region:
from mcp.server import MCPServer
from botocore.config import Config
import boto3
mcp = MCPServer("aioz-storage")
s3 = boto3.client(
"s3",
endpoint_url="https://s3.aiozstorage.network",
aws_access_key_id="<your-access-key>",
aws_secret_access_key="<your-secret-key>",
region_name="us-east-1",
config=Config(s3={"addressing_style": "path"}),
)Skip the addressing_style: path setting and requests fail before they reach a bucket, the same gotcha covered in this series' best-practices checklist, since boto3 defaults to virtual-hosted-style URLs that don't resolve against AIOZ Storage's single endpoint.
The Model Context Protocol's own SDK uses a decorator, @mcp.tool(), on a regular Python function, using the function's type hints and docstring to generate the tool definition an agent actually sees. A listing tool is the simplest useful starting point:
@mcp.tool()
def list_objects(bucket: str) -> str:
"""List the objects in an AIOZ Storage bucket.
Args:
bucket: The name of the bucket to list
"""
response = s3.list_objects_v2(Bucket=bucket)
if "Contents" not in response:
return "Bucket is empty or does not exist."
keys = [obj["Key"] for obj in response["Contents"]]
return "\n".join(keys)That docstring isn't just documentation, it's what the connected agent actually reads to understand what the tool does and what argument to pass.
Two more tools make this a genuinely useful minimal server, kept deliberately separate from listing rather than folded into one do-everything tool:
@mcp.tool()
def upload_object(bucket: str, key: str, content: str) -> str:
"""Upload text content as an object to AIOZ Storage.
Args:
bucket: The destination bucket
key: The object key (path and filename) to write to
content: The text content to upload
"""
s3.put_object(Bucket=bucket, Key=key, Body=content.encode("utf-8"))
return f"Uploaded {key} to {bucket}."
@mcp.tool()
def download_object(bucket: str, key: str) -> str:
"""Download an object's text content from AIOZ Storage.
Args:
bucket: The bucket containing the object
key: The object key to read
"""
response = s3.get_object(Bucket=bucket, Key=key)
return response["Body"].read().decode("utf-8")Keeping listing separate from downloading is a deliberate choice, not an oversight, it lets an agent check what actually exists in a bucket before trying to fetch a specific key, which avoids it guessing at a key that doesn't exist and getting back an error instead of the file it wanted.
The official SDK's pattern for actually starting the server is a single line:
if __name__ == "__main__":
mcp.run(transport="stdio")Run the script directly, and it starts listening for connections from an MCP host, Claude for Desktop or any other MCP-compatible client configured to launch it. From that point on, an agent connected to it can list, upload to, and download from your AIOZ Storage buckets using plain language instead of writing boto3 calls itself.
Worth being direct about the boundaries here. This is a DIY server you write, run, and maintain yourself, not an AIOZ product with AIOZ's own support behind it. The example above has no error handling beyond what boto3 raises by default, no credential rotation, and no limit on which buckets or keys an agent can touch, real gaps to close before pointing this at anything beyond a personal or test setup. AIOZ Storage's own access-grant system is the right place to start narrowing that down, scope the credentials this server uses to exactly the buckets and actions an agent should actually have, the same discipline that applies to any credential handed to automated code.
Does AIOZ Storage have an official MCP server?
No. This is a real, working pattern for building your own using the official MCP Python SDK and AIOZ Storage's existing boto3-compatible client, not an AIOZ-provided product.
What do I need to build a custom MCP server for AIOZ Storage?
Python, the official MCP SDK (pip install mcp), boto3, and an AIOZ Storage access grant with S3 credentials, the same requirements as any other SDK-based integration in this series.
Why does the boto3 client need addressing_style: path?
Because AIOZ Storage isn't set up for virtual-hosted-style URLs, boto3's default. Without path-style addressing explicitly set, requests fail before they ever reach a bucket.
Why use three separate tools instead of one combined tool?
So an agent can list a bucket's contents before trying to fetch a specific object, avoiding wasted calls on keys that don't actually exist. This mirrors the same practice recommended for other custom S3 MCP servers generally.
What does @mcp.tool() actually do?
It's a decorator from the official MCP SDK that turns a regular Python function into a tool an agent can call, using the function's type hints and docstring to generate the tool's definition automatically.
Is this custom server production-ready?
Not as written. The example here has no error handling beyond boto3's defaults, no credential rotation, and no scoping of which buckets it can touch. Treat it as a working starting point, not a finished production system.
How do I limit what buckets or actions this server can access?
Through AIOZ Storage's own access-grant system, scoping the credentials this server uses to exactly the buckets and actions (List, Read, Write, Delete) an agent actually needs, rather than a broad, unscoped credential.

AIOZ Storage has no official MCP server yet. Here is a working MCP server for AIOZ Storage, built with the official Python SDK and boto3, tools included.

What is an MCP server: a standard letting AI agents like Claude use tools and data through one protocol. How MinIO and Azure apply it to object storage.

S3 access logs vs CloudTrail: AWS recommends CloudTrail, but each one catches real events the other misses. Speed, cost, and coverage, compared directly.

Eventual vs strong consistency: whether a read right after a write sees the new data immediately. S3 ran on the first model for 14 years, then changed it.

Bucket policy vs IAM policy: one attaches to the resource, one attaches to the identity. What each can do that the other can't, and how S3 evaluates both.

SSE-S3 vs SSE-KMS vs SSE-C: who manages the encryption key, and what that decision actually costs you. Includes the real 2026 default change to SSE-C.