Skip to content

Commit 37dd6c0

Browse files
feat: Add Miku MCP server with S3-style API support
Implemented new Miku MCP server module with the following features: - Bearer token authentication using QINIU_API_KEY env variable - S3-style API support for bucket operations - create_bucket API endpoint (PUT https://<bucket>.<endpoint>) - Integration with existing MCP server architecture - Added aiohttp dependency for async HTTP requests The implementation follows the same pattern as existing storage/cdn/media_processing modules. Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: callmefisher <[email protected]>
1 parent 8ff3741 commit 37dd6c0

File tree

5 files changed

+138
-0
lines changed

5 files changed

+138
-0
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ authors = [
88
]
99
keywords = ["qiniu", "mcp", "llm"]
1010
dependencies = [
11+
"aiohttp>=3.9.0",
1112
"aioboto3>=13.2.0",
1213
"fastjsonschema>=2.21.1",
1314
"httpx>=0.28.1",

src/mcp_server/core/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .media_processing import load as load_media_processing
44
from .cdn import load as load_cdn
55
from .version import load as load_version
6+
from .miku import load as load_miku
67

78

89
def load():
@@ -17,4 +18,6 @@ def load():
1718
load_cdn(cfg)
1819
# 智能多媒体
1920
load_media_processing(cfg)
21+
# Miku
22+
load_miku(cfg)
2023

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .miku import MikuService
2+
from .tools import register_tools
3+
from ...config import config
4+
5+
6+
def load(cfg: config.Config):
7+
miku = MikuService(cfg)
8+
register_tools(miku)
9+
10+
11+
__all__ = ["load"]

src/mcp_server/core/miku/miku.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import aiohttp
2+
import logging
3+
4+
from typing import Dict, Any
5+
from ...config import config
6+
from ...consts import consts
7+
8+
logger = logging.getLogger(consts.LOGGER_NAME)
9+
10+
11+
class MikuService:
12+
def __init__(self, cfg: config.Config = None):
13+
self.config = cfg
14+
self.api_key = cfg.access_key if cfg else None
15+
self.endpoint_url = cfg.endpoint_url if cfg else None
16+
17+
def _get_auth_header(self) -> Dict[str, str]:
18+
"""Generate Bearer token authorization header"""
19+
if not self.api_key:
20+
raise ValueError("QINIU_API_KEY is not configured")
21+
return {
22+
"Authorization": f"Bearer {self.api_key}"
23+
}
24+
25+
def _build_bucket_url(self, bucket: str) -> str:
26+
"""Build S3-style bucket URL"""
27+
if not self.endpoint_url:
28+
raise ValueError("QINIU_ENDPOINT_URL is not configured")
29+
30+
# Remove protocol if present in endpoint_url
31+
endpoint = self.endpoint_url
32+
if endpoint.startswith("http://"):
33+
endpoint = endpoint[7:]
34+
elif endpoint.startswith("https://"):
35+
endpoint = endpoint[8:]
36+
37+
# Build URL in format: https://<bucket>.<endpoint>
38+
return f"https://{bucket}.{endpoint}"
39+
40+
async def create_bucket(self, bucket: str) -> Dict[str, Any]:
41+
"""
42+
Create a bucket using S3-style API
43+
44+
Args:
45+
bucket: The bucket name to create
46+
47+
Returns:
48+
Dict containing the response status and message
49+
"""
50+
url = self._build_bucket_url(bucket)
51+
headers = self._get_auth_header()
52+
53+
logger.info(f"Creating bucket: {bucket} at {url}")
54+
55+
async with aiohttp.ClientSession() as session:
56+
async with session.put(url, headers=headers) as response:
57+
status = response.status
58+
text = await response.text()
59+
60+
if status == 200 or status == 201:
61+
logger.info(f"Successfully created bucket: {bucket}")
62+
return {
63+
"status": "success",
64+
"bucket": bucket,
65+
"url": url,
66+
"message": f"Bucket '{bucket}' created successfully",
67+
"status_code": status
68+
}
69+
else:
70+
logger.error(f"Failed to create bucket: {bucket}, status: {status}, response: {text}")
71+
return {
72+
"status": "error",
73+
"bucket": bucket,
74+
"url": url,
75+
"message": f"Failed to create bucket: {text}",
76+
"status_code": status
77+
}

src/mcp_server/core/miku/tools.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import logging
2+
3+
from mcp import types
4+
from mcp.types import TextContent
5+
6+
from .miku import MikuService
7+
from ...consts import consts
8+
from ...tools import tools
9+
10+
logger = logging.getLogger(consts.LOGGER_NAME)
11+
12+
_BUCKET_DESC = "Miku bucket name"
13+
14+
15+
class _ToolImpl:
16+
def __init__(self, miku: MikuService):
17+
self.miku = miku
18+
19+
@tools.tool_meta(
20+
types.Tool(
21+
name="miku_create_bucket",
22+
description="Create a new bucket in Miku using S3-style API. The bucket will be created at https://<bucket>.<endpoint_url>",
23+
inputSchema={
24+
"type": "object",
25+
"properties": {
26+
"bucket": {
27+
"type": "string",
28+
"description": _BUCKET_DESC,
29+
},
30+
},
31+
"required": ["bucket"],
32+
},
33+
)
34+
)
35+
async def create_bucket(self, **kwargs) -> list[types.TextContent]:
36+
result = await self.miku.create_bucket(**kwargs)
37+
return [types.TextContent(type="text", text=str(result))]
38+
39+
40+
def register_tools(miku: MikuService):
41+
tool_impl = _ToolImpl(miku)
42+
tools.auto_register_tools(
43+
[
44+
tool_impl.create_bucket,
45+
]
46+
)

0 commit comments

Comments
 (0)