0908
This commit is contained in:
45
aio-mcp/internal/config/config.go
Normal file
45
aio-mcp/internal/config/config.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Package config 解析 aio-mcp 的启动配置(命令行参数)。
|
||||
package config
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// 支持的传输方式。
|
||||
const (
|
||||
TransportStdio = "stdio"
|
||||
TransportHTTP = "http"
|
||||
)
|
||||
|
||||
// Config 是 aio-mcp 的运行时配置。
|
||||
type Config struct {
|
||||
Transport string // MCP 传输方式:stdio 或 http
|
||||
Addr string // http 模式下的监听地址
|
||||
LogLevel string // 日志级别:debug / info / warn / error
|
||||
DataDir string // 数据目录:SQLite 库文件与工具产物的存放位置
|
||||
}
|
||||
|
||||
// Parse 解析命令行参数。args 不含程序名(通常传 os.Args[1:]),
|
||||
// 用法与错误信息写到 out。
|
||||
func Parse(args []string, out io.Writer) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
|
||||
fs := flag.NewFlagSet("aio-mcp", flag.ContinueOnError)
|
||||
fs.SetOutput(out)
|
||||
fs.StringVar(&cfg.Transport, "transport", TransportHTTP, "传输方式:http(默认,streamable HTTP)或 stdio(本地 Agent 拉起)")
|
||||
fs.StringVar(&cfg.Addr, "addr", "localhost:8000", "http 模式下的监听地址")
|
||||
fs.StringVar(&cfg.LogLevel, "log-level", "info", "日志级别:debug / info / warn / error")
|
||||
fs.StringVar(&cfg.DataDir, "data-dir", "data", "数据目录:SQLite 库文件与工具产物的存放位置")
|
||||
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.Transport != TransportStdio && cfg.Transport != TransportHTTP {
|
||||
return nil, fmt.Errorf("未知 transport: %q(支持: %s, %s)", cfg.Transport, TransportStdio, TransportHTTP)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
26
aio-mcp/internal/deps/deps.go
Normal file
26
aio-mcp/internal/deps/deps.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Package deps 定义工具共享的依赖容器。
|
||||
//
|
||||
// 工具分组(internal/tools/xxx)在注册时接收同一个 *Deps,
|
||||
// 避免各工具各自打开数据库连接、各自读配置。
|
||||
package deps
|
||||
|
||||
import (
|
||||
"aio-mcp/internal/config"
|
||||
)
|
||||
|
||||
// Deps 是注册工具时注入的共享依赖。
|
||||
//
|
||||
// 目前只有数据目录;后续按需在这里加字段即可:
|
||||
// SQLite 连接(*sql.DB)、HTTP client、打印机客户端、检测服务客户端等。
|
||||
// 由 internal/deps.New 统一构造,各工具只从参数取值,不再自建。
|
||||
type Deps struct {
|
||||
// DataDir 是数据目录,SQLite 库文件与工具产物的根路径。
|
||||
DataDir string
|
||||
}
|
||||
|
||||
// New 依据启动配置构造共享依赖。
|
||||
func New(cfg *config.Config) *Deps {
|
||||
return &Deps{
|
||||
DataDir: cfg.DataDir,
|
||||
}
|
||||
}
|
||||
27
aio-mcp/internal/logging/logging.go
Normal file
27
aio-mcp/internal/logging/logging.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package logging 负责 aio-mcp 的全局日志初始化。
|
||||
package logging
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Setup 初始化全局 slog 默认 logger。
|
||||
//
|
||||
// 日志固定输出到 stderr:stdio 模式下 stdout 是 MCP 协议通道,
|
||||
// 任何日志混入都会破坏 JSON-RPC 报文。业务代码同样禁止打印到 stdout。
|
||||
func Setup(level string) {
|
||||
var lvl slog.Level
|
||||
switch level {
|
||||
case "debug":
|
||||
lvl = slog.LevelDebug
|
||||
case "warn":
|
||||
lvl = slog.LevelWarn
|
||||
case "error":
|
||||
lvl = slog.LevelError
|
||||
default:
|
||||
lvl = slog.LevelInfo
|
||||
}
|
||||
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: lvl})))
|
||||
}
|
||||
32
aio-mcp/internal/server/serve.go
Normal file
32
aio-mcp/internal/server/serve.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"aio-mcp/internal/config"
|
||||
)
|
||||
|
||||
// Serve 按传输方式启动服务器,阻塞直到 stdin 关闭、监听失败或出错。
|
||||
func Serve(s *mcp.Server, cfg *config.Config) error {
|
||||
switch cfg.Transport {
|
||||
case config.TransportStdio:
|
||||
slog.Info("aio-mcp starting", "transport", "stdio")
|
||||
// server.Run 会阻塞,直到 stdin 关闭或出错。
|
||||
return s.Run(context.Background(), &mcp.StdioTransport{})
|
||||
|
||||
case config.TransportHTTP:
|
||||
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server { return s }, nil)
|
||||
slog.Info("aio-mcp starting", "transport", "http", "addr", cfg.Addr)
|
||||
return http.ListenAndServe(cfg.Addr, handler)
|
||||
|
||||
default:
|
||||
// config.Parse 已校验过,这里仅为防御性兜底。
|
||||
return fmt.Errorf("未知 transport: %q(支持: %s, %s)",
|
||||
cfg.Transport, config.TransportStdio, config.TransportHTTP)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,26 @@
|
||||
// Package server 负责 MCP 服务器的装配:创建 server 实例并注册全部工具。
|
||||
// Package server 负责 MCP 服务器的装配与运行。
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"aio-mcp/internal/config"
|
||||
"aio-mcp/internal/deps"
|
||||
"aio-mcp/internal/tools"
|
||||
)
|
||||
|
||||
// New 创建并装配 aio-mcp 服务器。
|
||||
// version 为服务器实现版本号,随 MCP initialize 握手上报给客户端。
|
||||
func New(version string) *mcp.Server {
|
||||
//
|
||||
// version 为服务器实现版本号,随 MCP initialize 握手上报给客户端;
|
||||
// cfg 决定的共享依赖(数据目录、后续的连接池等)通过 deps 注入各工具。
|
||||
func New(version string, cfg *config.Config) *mcp.Server {
|
||||
s := mcp.NewServer(&mcp.Implementation{
|
||||
Name: "aio-mcp",
|
||||
Version: version,
|
||||
}, nil)
|
||||
|
||||
// 注册全部工具。新增工具后在 tools.RegisterAll 里追加即可。
|
||||
tools.RegisterAll(s)
|
||||
// 注册全部工具。新增工具组后在 tools.RegisterAll 里追加即可。
|
||||
tools.RegisterAll(s, deps.New(cfg))
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -1,26 +1,40 @@
|
||||
// Package tools 集中管理 aio-mcp 的全部 MCP 工具。
|
||||
// Package tools 是 aio-mcp 的工具注册表:按业务域分组,统一注册。
|
||||
//
|
||||
// # 新增工具的固定步骤
|
||||
// # 新增一个工具组
|
||||
//
|
||||
// 1. 在本目录新建一个文件(如 weather.go),实现
|
||||
// func registerXXX(s *mcp.Server)
|
||||
// 2. 在 RegisterAll 中追加一行 registerXXX(s)
|
||||
// 1. 在 internal/tools/ 下新建子包(如 sqlite/),实现
|
||||
// func Register(s *mcp.Server, d *deps.Deps)
|
||||
// 2. 在 RegisterAll 中追加一行 sqlite.Register(s, d)
|
||||
//
|
||||
// # 在已有组内新增一个工具
|
||||
//
|
||||
// 在对应子包内新建文件(如 sqlite/query.go),实现
|
||||
// func registerQuery(s *mcp.Server, d *deps.Deps),
|
||||
// 并在该组的 Register 中追加一行。
|
||||
//
|
||||
// 工具通过泛型 mcp.AddTool[In, Out] 注册:输入参数用 struct 定义,
|
||||
// 加 json 与 jsonschema tag(描述、必填),SDK 会自动生成 inputSchema
|
||||
// 并做输入校验,无需手工写 JSON Schema。
|
||||
//
|
||||
// 后续工具需要共享状态(SQLite 连接、配置、http client 等)时,
|
||||
// 把 RegisterAll 演进为 RegisterAll(s *mcp.Server, deps *Deps),
|
||||
// 在 server.New 里构造 deps 传入即可,各工具文件只改签名。
|
||||
// 注意:共享依赖放在 internal/deps 而不是本包,
|
||||
// 否则工具子包 import 本包会形成循环依赖。
|
||||
package tools
|
||||
|
||||
import (
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"aio-mcp/internal/deps"
|
||||
"aio-mcp/internal/tools/system"
|
||||
)
|
||||
|
||||
// RegisterAll 注册所有工具。
|
||||
func RegisterAll(s *mcp.Server) {
|
||||
registerPing(s)
|
||||
registerEcho(s)
|
||||
// RegisterAll 注册所有工具组。
|
||||
func RegisterAll(s *mcp.Server, d *deps.Deps) {
|
||||
// 系统组:健康检查与协议演示。
|
||||
system.Register(s, d)
|
||||
|
||||
// 待接入的业务组(目录尚未创建,接入时在此追加):
|
||||
// sqlite.Register(s, d) // 本地数据查询
|
||||
// file.Register(s, d) // 文件读写
|
||||
// print.Register(s, d) // 打印/报告输出
|
||||
// check.Register(s, d) // 硬件检测
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package tools
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -1,4 +1,4 @@
|
||||
package tools
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
14
aio-mcp/internal/tools/system/system.go
Normal file
14
aio-mcp/internal/tools/system/system.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Package system 承载 aio-mcp 自身的系统类工具:健康检查、协议演示等。
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"aio-mcp/internal/deps"
|
||||
)
|
||||
|
||||
// Register 注册本组全部工具。
|
||||
func Register(s *mcp.Server, _ *deps.Deps) {
|
||||
registerPing(s)
|
||||
registerEcho(s)
|
||||
}
|
||||
Reference in New Issue
Block a user