
Building an MCP server for AIOZ Storage is real, working, and takes less code than it sounds like it should. AIOZ Storage does ship an official MCP server now, but it's scoped entirely to vector database operations, buckets, indexes, and vectors, not general file access. For listing, uploading, or downloading regular objects conversationally, that gap is still open, and this article closes it: 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's actual files.
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's own MCP server exists now, but it only exposes vector-bucket, index, and vector tools, general object operations, listing a bucket, uploading a file, downloading one, aren't part of it. The same S3-compatible endpoint every SDK and CLI in this series already talks to is all a custom MCP server needs underneath it to fill that specific gap. 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, applied to the one surface AIOZ's own server doesn't cover.
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?
Yes, but it only covers vector database operations, buckets, indexes, and vectors. It doesn't expose general file list/upload/download tools, which is exactly the gap this custom server, built with the official MCP Python SDK and AIOZ Storage's existing boto3-compatible client, fills.
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 Super Intelligence Memory gives AI agents memory: Record a statement, Recall it by meaning, with no embeddings or vector index to manage yourself.

Static website hosting on AIOZ Storage turns any bucket into a live site with a custom domain. Here is the full setup, from bucket to DNS verification.

An embedding model turns text, images, or audio into vectors so similar meanings land close together in space. Here is how embedding models actually work.

Retrieval-augmented generation (RAG) grounds an LLM answer in your own data, not its training set. Here is how the retrieval and generation steps work.

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.