chore(general): 更新项目配置文件

- 添加必要的配置项
- 优化现有设置
- 确保环境兼容性
This commit is contained in:
2026-01-28 09:35:48 +08:00
parent 70d2606698
commit 5107fdb74c
14 changed files with 1141 additions and 6 deletions

View File

@@ -0,0 +1,65 @@
# lzwcai-mcpskills-template
MCP Server 模板项目,用于快速创建新的 MCP 服务。
## 功能
- 提供 MCP Server 基础框架
- 支持动态工具注册
- 内置日志系统
- 支持环境变量配置
## 安装
```bash
pip install lzwcai-mcpskills-template
```
## 使用
```bash
# 设置环境变量
export API_KEY="your-api-key"
export BASE_URL="http://your-api-server"
# 运行
lzwcai-mcpskills-template
```
## 环境变量
| 变量名 | 说明 | 默认值 |
|--------|------|--------|
| API_KEY | API密钥 | - |
| BASE_URL | 后端API地址 | http://localhost:8080 |
## 项目结构
```
lzwcai_mcpskills_template/
├── main.py # 入口文件
├── pyproject.toml # 项目配置
├── README.md # 说明文档
└── lzwcai_mcpskills_template/ # 核心代码
├── main.py # MCP Server 主逻辑
├── schema_converter.py # Schema 转换器
└── utils/ # 工具模块
├── __init__.py
├── api_client.py # API 客户端
├── env_config.py # 环境变量配置
├── json_helper.py # JSON 工具
└── logger_config.py # 日志配置
```
## 开发
基于此模板创建新项目:
1. 复制整个目录
2. 修改 `pyproject.toml` 中的项目名称
3. 修改 `lzwcai_mcpskills_template` 目录名
4.`main.py` 中实现你的工具逻辑
## License
MIT

View File

@@ -0,0 +1 @@
3.13

View File

@@ -0,0 +1,281 @@
#!/usr/bin/env python3
"""
MCP Server 模板
支持从本地 JSON 或 API 动态加载工具配置
使用方式:
- local: 从本地 JSON 文件加载工具配置
- api: 从远程 API 加载工具配置
"""
import json
import os
import logging
import argparse
import anyio
import mcp.types as types
from mcp.server import NotificationOptions, Server
from mcp.server.models import InitializationOptions
from mcp.server.stdio import stdio_server
try:
from .schema_converter import convert_sql_params_to_input_schema
from .utils.api_client import call_api
from .utils.env_config import get_api_key, get_base_url
from .utils.logger_config import setup_system_logging, get_logger
except ImportError:
from schema_converter import convert_sql_params_to_input_schema
from utils.api_client import call_api
from utils.env_config import get_api_key, get_base_url
from utils.logger_config import setup_system_logging, get_logger
# 初始化日志系统
setup_system_logging(app_name="lzwcai_mcpskills_template", log_level=logging.DEBUG)
logger = get_logger(__name__)
# 初始化 MCP Server
server = Server("mcpskills_template_server")
# 全局配置
_tools_config: list[dict] = []
_config: dict = {}
def parse_arguments():
"""解析命令行参数"""
parser = argparse.ArgumentParser(description="MCP Skills Template Server")
parser.add_argument(
"--mode",
type=str,
choices=["local", "api"],
default="local",
help="数据加载模式: local(本地JSON默认) 或 api(远程API)"
)
parser.add_argument(
"--json-path",
type=str,
default=None,
help="本地 JSON 文件路径 (local 模式)"
)
return parser.parse_args()
class DataLoader:
"""数据加载器基类"""
def load(self) -> list[dict]:
raise NotImplementedError
class LocalLoader(DataLoader):
"""本地 JSON 文件加载器"""
def __init__(self, json_path: str = None):
if json_path is None:
json_path = os.path.join(os.path.dirname(__file__), "tools_config.json")
self.json_path = json_path
def load(self) -> list[dict]:
try:
with open(self.json_path, "r", encoding="utf-8") as f:
data = json.load(f)
logger.info(f"从本地加载 {len(data)} 条配置: {self.json_path}")
return data
except FileNotFoundError:
logger.error(f"配置文件不存在: {self.json_path}")
return []
except json.JSONDecodeError as e:
logger.error(f"JSON 解析错误: {e}")
return []
class ApiLoader(DataLoader):
"""API 远程加载器"""
def __init__(self):
self.base_url = get_base_url()
self.api_key = get_api_key()
logger.debug(f"ApiLoader 初始化base_url: {self.base_url}")
def load(self) -> list[dict]:
try:
# TODO: 根据实际 API 修改此处
logger.info(f"开始从 API 加载工具配置")
response = call_api("/api/tools", method="GET")
if response.get("code") != 200:
logger.error(f"获取工具配置失败: {response.get('msg')}")
return []
data = response.get("data", [])
if isinstance(data, dict):
data = [data]
logger.info(f"从 API 加载工具配置成功,数量: {len(data)}")
return data
except Exception as e:
logger.error(f"API 请求失败: {e}", exc_info=True)
return []
def create_loader(mode: str, **kwargs) -> DataLoader:
"""创建数据加载器"""
if mode == "local":
return LocalLoader(json_path=kwargs.get("json_path"))
elif mode == "api":
return ApiLoader()
else:
raise ValueError(f"不支持的模式: {mode}")
def init_tools(loader: DataLoader):
"""初始化工具配置"""
global _tools_config
_tools_config = loader.load()
logger.info(f"已加载 {len(_tools_config)} 个工具配置")
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
"""列出所有可用工具"""
logger.info(f"收到 ListTools 请求,当前配置数量: {len(_tools_config)}")
tools = []
for tool in _tools_config:
name = tool.get("name", "")
description = tool.get("description") or tool.get("toolPrompt", "")
sql_params = tool.get("sqlParams", "[]")
# 转换参数为 inputSchema
input_schema = convert_sql_params_to_input_schema(sql_params)
tools.append(
types.Tool(
name=name,
description=description,
inputSchema=input_schema
)
)
logger.info(f"ListTools 响应: 返回 {len(tools)} 个工具")
return tools
@server.call_tool()
async def handle_call_tool(
name: str,
arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
"""调用工具"""
logger.info(f"收到 CallTool 请求: name={name}, arguments={json.dumps(arguments, ensure_ascii=False) if arguments else 'None'}")
# 查找对应的工具配置
tool_config = None
for tool in _tools_config:
if tool.get("name") == name:
tool_config = tool
break
if tool_config is None:
logger.error(f"未找到工具配置: {name}")
raise ValueError(f"未知工具: {name}")
# TODO: 在这里实现你的工具逻辑
# 示例:简单返回参数
try:
result = execute_tool(name, arguments or {}, tool_config)
logger.info(f"工具执行成功: {name}")
except Exception as e:
logger.error(f"工具执行失败: {e}", exc_info=True)
result = {"error": str(e), "tool_name": name}
return [
types.TextContent(
type="text",
text=json.dumps(result, ensure_ascii=False, indent=2)
)
]
def execute_tool(name: str, arguments: dict, config: dict) -> dict:
"""
执行工具逻辑
TODO: 根据实际需求修改此函数
"""
# 示例实现
if name == "example_hello_world":
return {"message": f"Hello, {arguments.get('name', 'World')}!"}
elif name == "example_calculator":
a = float(arguments.get("a", 0))
b = float(arguments.get("b", 0))
op = arguments.get("operation", "+")
if op == "+":
result = a + b
elif op == "-":
result = a - b
elif op == "*":
result = a * b
elif op == "/":
result = a / b if b != 0 else "除数不能为0"
else:
result = "未知运算符"
return {"result": result, "expression": f"{a} {op} {b}"}
# 默认返回参数
return {
"tool_name": name,
"arguments": arguments,
"message": "工具执行成功(默认实现)"
}
async def run_server():
"""运行 MCP Server (stdio 模式)"""
async with stdio_server() as streams:
await server.run(
streams[0],
streams[1],
InitializationOptions(
server_name="mcpskills_template_server",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
def main():
"""主入口"""
global _config
logger.info("=" * 50)
logger.info("MCP Skills Template Server 启动")
logger.info("=" * 50)
# 解析命令行参数
args = parse_arguments()
_config = vars(args)
logger.info(f"命令行参数: {_config}")
# 创建加载器并初始化工具
logger.info(f"使用模式: {args.mode}")
loader = create_loader(
mode=args.mode,
json_path=args.json_path
)
init_tools(loader)
logger.info("开始运行 MCP Server (stdio 模式)")
# 运行服务器
anyio.run(run_server)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,168 @@
"""
Schema 转换器
将 sqlParams 数组格式转换为 MCP 工具需要的 JSON Schema 格式
支持的类型:
- string: 文本输入
- paragraph: 段落/多行文本
- select: 下拉选项
- number: 数字输入
"""
import json
from typing import Any
def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
"""
将单个参数转换为 JSON Schema property
Args:
param: 参数配置,格式如:
{
"type": "string",
"name": "param_name",
"displayName": "参数显示名",
"maxLength": 200,
"defaultValue": "",
"required": true,
"options": ["选项1", "选项2"] # 仅 select 类型
}
Returns:
tuple: (property_name, property_schema, is_required)
"""
param_type = param.get("type", "string")
param_name = param.get("name", "")
display_name = param.get("displayName", param_name)
default_value = param.get("defaultValue", "")
max_length = param.get("maxLength")
is_required = param.get("required", False)
options = param.get("options", [])
property_schema = {
"description": display_name
}
if param_type == "string":
property_schema["type"] = "string"
if max_length:
property_schema["maxLength"] = max_length
elif param_type == "paragraph":
property_schema["type"] = "string"
property_schema["format"] = "paragraph"
if max_length:
property_schema["maxLength"] = max_length
elif param_type == "select":
property_schema["type"] = "string"
if options:
property_schema["enum"] = options
elif param_type == "number":
property_schema["type"] = "number"
else:
# 默认当作 string 处理
property_schema["type"] = "string"
# 添加默认值
if default_value not in (None, ""):
if param_type == "number":
try:
property_schema["default"] = int(default_value) if str(default_value).isdigit() else float(default_value)
except (ValueError, TypeError):
property_schema["default"] = default_value
else:
property_schema["default"] = default_value
return param_name, property_schema, is_required
def convert_sql_params_to_input_schema(sql_params: str | list) -> dict:
"""
将 sqlParams 转换为 MCP 工具的 inputSchema
Args:
sql_params: sqlParams 字段值,可以是 JSON 字符串或已解析的列表
格式: [{"type": "string", "name": "xxx", ...}, ...]
Returns:
dict: MCP 工具的 inputSchema格式如:
{
"type": "object",
"properties": {...},
"required": [...]
}
"""
# 解析 JSON 字符串
if isinstance(sql_params, str):
try:
params_list = json.loads(sql_params)
except json.JSONDecodeError:
return {"type": "object", "properties": {}, "required": []}
else:
params_list = sql_params
if not isinstance(params_list, list):
return {"type": "object", "properties": {}, "required": []}
input_schema = {
"type": "object",
"properties": {},
"required": []
}
for param in params_list:
if not isinstance(param, dict):
continue
name, schema, is_required = convert_param_to_schema_property(param)
if name:
input_schema["properties"][name] = schema
if is_required:
input_schema["required"].append(name)
return input_schema
def convert_tool_config_to_mcp_tool(config: dict) -> dict:
"""
将单个工具配置转换为 MCP Tool 配置
Args:
config: 工具配置对象
Returns:
dict: MCP Tool 配置
"""
name = config.get("name", "")
description = config.get("description") or config.get("toolPrompt", "")
sql_params = config.get("sqlParams", "[]")
input_schema = convert_sql_params_to_input_schema(sql_params)
return {
"name": name,
"description": description,
"inputSchema": input_schema,
"_raw": config # 保留原始数据
}
# 测试用
if __name__ == "__main__":
# 测试单个参数转换
test_param = {
"type": "select",
"name": "operation",
"displayName": "运算符",
"required": True,
"options": ["+", "-", "*", "/"]
}
name, schema, required = convert_param_to_schema_property(test_param)
print(f"参数名: {name}")
print(f"Schema: {json.dumps(schema, ensure_ascii=False, indent=2)}")
print(f"必填: {required}")

View File

@@ -0,0 +1,16 @@
[
{
"id": "example_tool_001",
"name": "example_hello_world",
"description": "示例工具 - Hello World",
"toolPrompt": "这是一个示例工具,用于演示 MCP 工具的基本结构",
"sqlParams": "[{\"type\":\"string\",\"name\":\"name\",\"displayName\":\"名称\",\"maxLength\":100,\"defaultValue\":\"World\",\"required\":true}]"
},
{
"id": "example_tool_002",
"name": "example_calculator",
"description": "示例工具 - 简单计算器",
"toolPrompt": "执行简单的数学计算",
"sqlParams": "[{\"type\":\"number\",\"name\":\"a\",\"displayName\":\"数字A\",\"required\":true},{\"type\":\"number\",\"name\":\"b\",\"displayName\":\"数字B\",\"required\":true},{\"type\":\"select\",\"name\":\"operation\",\"displayName\":\"运算符\",\"required\":true,\"options\":[\"+\",\"-\",\"*\",\"/\"]}]"
}
]

View File

@@ -0,0 +1,19 @@
"""Utils package for lzwcai_mcpskills_template"""
from .json_helper import load_json
from .api_client import call_api, APIClient, get_default_client
from .env_config import get_api_key, get_base_url, get_env_config, set_env_variable
from .logger_config import setup_system_logging, get_logger
__all__ = [
'load_json',
'call_api',
'APIClient',
'get_default_client',
'get_api_key',
'get_base_url',
'get_env_config',
'set_env_variable',
'setup_system_logging',
'get_logger'
]

View File

@@ -0,0 +1,197 @@
"""
API 调用客户端
通用的 HTTP API 客户端封装
"""
import httpx
import json
from typing import Dict, Any, Optional
try:
from .env_config import get_base_url, get_api_key
from .logger_config import get_logger
except ImportError:
from env_config import get_base_url, get_api_key
from logger_config import get_logger
logger = get_logger(__name__)
# 默认超时配置(秒)
DEFAULT_TIMEOUT = 30.0
LONG_TIMEOUT = 300.0
class APIClient:
"""通用 API 客户端"""
def __init__(
self,
base_url: Optional[str] = None,
api_key: Optional[str] = None,
default_timeout: float = DEFAULT_TIMEOUT
):
"""
初始化 API 客户端
Args:
base_url: API 基础 URL默认从环境变量读取
api_key: API 密钥(默认从环境变量读取)
default_timeout: 默认超时时间(秒)
"""
self.base_url = (base_url or get_base_url()).rstrip('/')
self.api_key = api_key or get_api_key()
self.default_timeout = default_timeout
self._client: Optional[httpx.Client] = None
logger.info(f"[客户端初始化] base_url={self.base_url}")
@property
def client(self) -> httpx.Client:
"""懒加载 HTTP 客户端"""
if self._client is None:
self._client = httpx.Client(timeout=self.default_timeout)
return self._client
def _get_headers(self) -> Dict[str, str]:
"""获取请求头"""
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
if self.api_key:
headers['X-API-Key'] = self.api_key
return headers
def request(
self,
endpoint: str,
method: str = "GET",
data: Optional[Dict[str, Any]] = None,
params: Optional[Dict[str, Any]] = None,
timeout: Optional[float] = None
) -> Dict[str, Any]:
"""
发送 HTTP 请求
Args:
endpoint: API 端点路径
method: HTTP 方法
data: 请求体数据
params: URL 查询参数
timeout: 超时时间
Returns:
API 响应数据
"""
url = f"{self.base_url}{endpoint}"
timeout = timeout or self.default_timeout
try:
logger.info(f"[API请求] {method} {url}")
if method.upper() == "GET":
response = self.client.get(
url,
headers=self._get_headers(),
params=params,
timeout=timeout
)
elif method.upper() == "POST":
response = self.client.post(
url,
headers=self._get_headers(),
json=data,
params=params,
timeout=timeout
)
elif method.upper() == "PUT":
response = self.client.put(
url,
headers=self._get_headers(),
json=data,
params=params,
timeout=timeout
)
elif method.upper() == "DELETE":
response = self.client.delete(
url,
headers=self._get_headers(),
params=params,
timeout=timeout
)
else:
raise ValueError(f"不支持的 HTTP 方法: {method}")
logger.info(f"[API响应] HTTP {response.status_code}")
response.raise_for_status()
return response.json()
except httpx.TimeoutException:
error_msg = f"API 请求超时: {url}"
logger.error(f"[API错误] {error_msg}")
raise Exception(error_msg)
except httpx.HTTPStatusError as e:
error_msg = f"API 请求失败 (HTTP {e.response.status_code}): {url}"
logger.error(f"[API错误] {error_msg}")
raise Exception(error_msg)
except Exception as e:
error_msg = f"API 请求异常: {str(e)}"
logger.error(f"[API错误] {error_msg}", exc_info=True)
raise Exception(error_msg)
def close(self):
"""关闭 HTTP 客户端"""
if self._client is not None:
self._client.close()
self._client = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
return False
# 懒加载的默认客户端
_default_client: Optional[APIClient] = None
def get_default_client() -> APIClient:
"""获取默认客户端(懒加载)"""
global _default_client
if _default_client is None:
_default_client = APIClient()
return _default_client
def call_api(
endpoint: str,
method: str = "GET",
data: Optional[Dict[str, Any]] = None,
params: Optional[Dict[str, Any]] = None,
timeout: Optional[float] = None
) -> Dict[str, Any]:
"""
便捷函数:调用 API
Args:
endpoint: API 端点路径
method: HTTP 方法
data: 请求体数据
params: URL 查询参数
timeout: 超时时间
Returns:
API 响应数据
"""
return get_default_client().request(
endpoint=endpoint,
method=method,
data=data,
params=params,
timeout=timeout
)

View File

@@ -0,0 +1,60 @@
"""环境变量配置模块"""
import os
from typing import Optional
def get_api_key(default: str = "") -> str:
"""
获取 API 密钥环境变量
Args:
default: 默认值
Returns:
str: API 密钥
Environment Variables:
API_KEY: API 密钥
"""
return os.environ.get("API_KEY", default)
def get_base_url(default: str = "http://localhost:8080") -> str:
"""
获取后端 API 基础 URL 环境变量
Args:
default: 默认值
Returns:
str: 后端 API 基础 URL
Environment Variables:
BASE_URL: 后端 API 基础 URL
"""
return os.environ.get("BASE_URL", default)
def get_env_config() -> dict:
"""
获取所有环境配置
Returns:
dict: 包含所有配置的字典
"""
return {
"api_key": get_api_key(),
"base_url": get_base_url()
}
def set_env_variable(key: str, value: str) -> None:
"""
设置环境变量(仅在当前进程中有效)
Args:
key: 环境变量名
value: 环境变量值
"""
os.environ[key] = value

View File

@@ -0,0 +1,41 @@
"""JSON 文件读取工具"""
import json
from pathlib import Path
from typing import Any, Union
def load_json(json_path: Union[str, Path]) -> Any:
"""
读取 JSON 文件并返回其内容
Args:
json_path: JSON 文件的路径
Returns:
JSON 文件中解析后的数据
Raises:
FileNotFoundError: 当文件不存在时
json.JSONDecodeError: 当 JSON 格式无效时
"""
try:
path = Path(json_path)
if not path.exists():
raise FileNotFoundError(f"JSON 文件不存在: {json_path}")
if not path.is_file():
raise ValueError(f"路径不是一个文件: {json_path}")
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
return data
except json.JSONDecodeError as e:
raise json.JSONDecodeError(f"JSON 格式错误: {e.msg}", e.doc, e.pos)
except FileNotFoundError:
raise
except Exception as e:
raise Exception(f"读取 JSON 文件时发生错误: {str(e)}")

View File

@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
"""
统一日志配置模块
提供系统级别的日志配置和管理
"""
import os
import sys
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
from pathlib import Path
class LoggerConfig:
"""日志配置管理类"""
def __init__(self, logs_dir: str = None):
"""初始化日志配置"""
if logs_dir:
self.logs_dir = Path(logs_dir)
else:
project_root = Path(__file__).parent.parent
self.logs_dir = project_root / "logs"
self.logs_dir.mkdir(exist_ok=True)
self.log_format = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
self.date_format = '%Y-%m-%d %H:%M:%S'
self.log_level = self._get_log_level_from_env()
self._initialized = False
def _get_log_level_from_env(self) -> int:
log_level_str = os.getenv('LOG_LEVEL', 'INFO').upper()
level_mapping = {
'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'WARN': logging.WARNING,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL,
'FATAL': logging.CRITICAL
}
return level_mapping.get(log_level_str, logging.INFO)
def setup_logging(self,
app_name: str = "lzwcai_mcpskills_template",
log_level: int = logging.INFO,
max_file_size: int = 10 * 1024 * 1024,
backup_count: int = 5,
console_output: bool = True) -> logging.Logger:
if self._initialized:
return logging.getLogger()
root_logger = logging.getLogger()
root_logger.setLevel(log_level)
for handler in root_logger.handlers[:]:
root_logger.removeHandler(handler)
formatter = logging.Formatter(self.log_format, self.date_format)
# 1. 主日志文件 - 按大小滚动
main_log_file = self.logs_dir / f"{app_name}.log"
file_handler = RotatingFileHandler(
main_log_file,
maxBytes=max_file_size,
backupCount=backup_count,
encoding='utf-8'
)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
root_logger.addHandler(file_handler)
# 2. 错误日志文件
error_log_file = self.logs_dir / f"{app_name}_error.log"
error_handler = RotatingFileHandler(
error_log_file,
maxBytes=max_file_size,
backupCount=backup_count,
encoding='utf-8'
)
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(formatter)
root_logger.addHandler(error_handler)
# 3. 按日期滚动的日志文件
daily_log_file = self.logs_dir / f"{app_name}_daily.log"
daily_handler = TimedRotatingFileHandler(
daily_log_file,
when='midnight',
interval=1,
backupCount=30,
encoding='utf-8'
)
daily_handler.setLevel(log_level)
daily_handler.setFormatter(formatter)
daily_handler.suffix = "%Y-%m-%d"
root_logger.addHandler(daily_handler)
# 4. 控制台输出 (MCP协议使用stdio时必须将日志输出到stderr)
if console_output:
console_handler = logging.StreamHandler(sys.stderr)
console_handler.setLevel(log_level)
console_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
self.date_format
)
console_handler.setFormatter(console_formatter)
root_logger.addHandler(console_handler)
self._initialized = True
root_logger.info(f"日志系统初始化完成 - 日志目录: {self.logs_dir}")
return root_logger
def get_module_logger(self, module_name: str) -> logging.Logger:
return logging.getLogger(module_name)
# 全局日志配置实例
logger_config = LoggerConfig()
def setup_system_logging(app_name: str = "lzwcai_mcpskills_template",
log_level: int = logging.INFO) -> logging.Logger:
return logger_config.setup_logging(app_name, log_level)
def get_logger(name: str) -> logging.Logger:
return logger_config.get_module_logger(name)

View File

@@ -0,0 +1,15 @@
"""
Entry point for lzwcai-mcpskills-template
MCP Server 模板项目入口
"""
import os
if __name__ == "__main__":
# 设置环境变量(根据实际需求修改)
os.environ["API_KEY"] = "your-api-key"
os.environ["BASE_URL"] = "http://localhost:8080"
# Import and run the actual MCP server
from lzwcai_mcpskills_template.main import main
main()

View File

@@ -0,0 +1,31 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "lzwcai_mcpskills_template"
version = "0.1.0"
description = "MCP Server 模板项目 - 用于快速创建新的 MCP 服务"
readme = "README.md"
requires-python = ">=3.13"
license = {text = "MIT"}
authors = [
{name = "lzwcai", email = "your-email@example.com"},
]
keywords = ["mcp", "template", "server"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"httpx>=0.28.1",
"mcp[cli]>=1.10.1",
]
[project.scripts]
lzwcai_mcpskills_template = "lzwcai_mcpskills_template.main:main"
[tool.hatch.build.targets.wheel]
packages = ["lzwcai_mcpskills_template"]