+ CLI 提供命令行界面,支持启动服务器和连接到远程服务器进行交互式对话。 +
+ +# 全局安装
+npm install -g @ai-assistant/cli
+
+# 或使用 pnpm
+pnpm add -g @ai-assistant/cli
+
+# 验证安装
+ai-assistant --version
+
+ | 命令 | +说明 | +示例 | +
|---|---|---|
serve |
+ 启动 HTTP 服务器 | +ai-assistant serve |
+
attach |
+ 连接到服务器 | +ai-assistant attach http://localhost:3000 |
+
--help |
+ 显示帮助信息 | +ai-assistant --help |
+
--version |
+ 显示版本号 | +ai-assistant --version |
+
启动 AI Assistant HTTP 服务器,提供 REST API 和 WebSocket 接口。
+ +ai-assistant serve [选项]
+
+ | 选项 | +说明 | +默认值 | +
|---|---|---|
-p, --port <port> |
+ 服务器端口 | +3000 | +
-h, --host <host> |
+ 监听地址 | +localhost | +
-d, --dir <path> |
+ 工作目录 | +当前目录 | +
--auth |
+ 启用认证 | +非 localhost 时自动启用 | +
--token <token> |
+ 指定认证 Token | +自动生成 | +
# 基本启动
+ai-assistant serve
+
+# 指定端口和目录
+ai-assistant serve --port 8080 --dir /path/to/project
+
+# 远程访问模式
+ai-assistant serve --host 0.0.0.0 --port 3000
+
+# 指定认证 Token
+ai-assistant serve --auth --token my-secret-token
+
+ 🚀 AI Terminal Assistant Server
+
+ Local: http://localhost:3000
+ Network: http://192.168.1.100:3000
+
+ Auth: Enabled
+ Token: abc123...xyz789
+
+ Working Directory: /Users/dev/project
+
+ Press Ctrl+C to stop
+
+ 连接到运行中的 AI Assistant 服务器,进行交互式对话。
+ +ai-assistant attach <url> [选项]
+
+ | 选项 | +说明 | +默认值 | +
|---|---|---|
-t, --token <token> |
+ 认证 Token | +- | +
-s, --session <id> |
+ 指定会话 ID | +自动创建 | +
# 连接本地服务器
+ai-assistant attach http://localhost:3000
+
+# 连接远程服务器(带认证)
+ai-assistant attach https://ai.example.com --token your-token
+
+# 恢复已有会话
+ai-assistant attach http://localhost:3000 --session session-123
+
+ ✓ Connected to http://localhost:3000
+ Session: session-abc123
+
+You: 帮我分析这个项目的结构
+
+AI: 我来分析这个项目的结构...
+
+[调用工具: list_directory]
+路径: /Users/dev/project
+
+项目结构如下:
+├── src/
+│ ├── index.ts
+│ └── utils/
+├── package.json
+└── README.md
+
+这是一个 TypeScript 项目...
+
+You: _
+
+ 在 attach 模式下,支持以下交互式命令:
+ +| 命令 | +说明 | +
|---|---|
/exit 或 /quit |
+ 退出交互 | +
/clear |
+ 清空当前会话历史 | +
/new |
+ 创建新会话 | +
/sessions |
+ 列出所有会话 | +
/switch <id> |
+ 切换到指定会话 | +
/status |
+ 显示连接状态 | +
/help |
+ 显示帮助信息 | +
| 变量 | +说明 | +命令 | +
|---|---|---|
ANTHROPIC_API_KEY |
+ Anthropic API Key | +serve | +
AI_ASSISTANT_TOKEN |
+ 默认认证 Token | +attach | +
AI_ASSISTANT_URL |
+ 默认服务器地址 | +attach | +
# 设置环境变量
+export ANTHROPIC_API_KEY=sk-ant-...
+export AI_ASSISTANT_TOKEN=my-token
+export AI_ASSISTANT_URL=http://localhost:3000
+
+# 使用环境变量(无需每次指定)
+ai-assistant attach
+
+ 可以在 ~/.ai-assistant/config.json 中配置默认选项:
{
+ "defaultServer": "http://localhost:3000",
+ "defaultToken": "your-token",
+ "theme": "dark",
+ "historySize": 1000,
+ "autoConnect": true
+}
+
+ 在项目开发中直接运行:
+ +# 使用 bun 运行
+cd packages/cli
+bun run src/index.ts serve --port 3000
+
+# 或使用 tsx
+npx tsx src/index.ts attach http://localhost:3000
+
+ | 退出码 | +说明 | +
|---|---|
| 0 | 正常退出 |
| 1 | 一般错误 |
| 2 | 连接失败 |
| 3 | 认证失败 |
🚧 开发中 - 基础功能已实现
+ ++ 桌面应用基于 Tauri 构建,提供原生桌面体验,支持 Windows、macOS 和 Linux。 + 复用 Web 前端代码,结合 Rust 后端提供更好的性能和系统集成。 +
+ +# macOS
+xcode-select --install
+
+# Ubuntu/Debian
+sudo apt install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
+
+# Windows
+# 需要安装 Visual Studio C++ Build Tools
+
+ # 进入 desktop 包目录
+cd packages/desktop
+
+# 安装依赖
+pnpm install
+
+# 启动开发模式
+pnpm tauri dev
+
+ # 构建当前平台
+pnpm tauri build
+
+# 输出目录:
+# - macOS: src-tauri/target/release/bundle/dmg/
+# - Windows: src-tauri/target/release/bundle/msi/
+# - Linux: src-tauri/target/release/bundle/deb/
+
+ packages/desktop/
+├── src/ # 前端代码 (复用 web)
+├── src-tauri/ # Tauri/Rust 后端
+│ ├── src/
+│ │ ├── main.rs # 应用入口
+│ │ ├── commands.rs # Tauri 命令
+│ │ ├── tray.rs # 系统托盘
+│ │ └── window.rs # 窗口管理
+│ ├── icons/ # 应用图标
+│ ├── tauri.conf.json # Tauri 配置
+│ └── Cargo.toml # Rust 依赖
+├── index.html
+└── vite.config.ts
+
+ // src-tauri/tauri.conf.json
+{
+ "productName": "AI Terminal Assistant",
+ "version": "0.1.0",
+ "identifier": "com.ai-assistant.app",
+ "build": {
+ "beforeDevCommand": "pnpm dev",
+ "beforeBuildCommand": "pnpm build",
+ "devPath": "http://localhost:5173",
+ "distDir": "../dist"
+ },
+ "app": {
+ "windows": [
+ {
+ "title": "AI Terminal Assistant",
+ "width": 1200,
+ "height": 800,
+ "resizable": true,
+ "fullscreen": false
+ }
+ ],
+ "security": {
+ "csp": null
+ }
+ },
+ "bundle": {
+ "active": true,
+ "targets": "all",
+ "icon": [
+ "icons/32x32.png",
+ "icons/128x128.png",
+ "icons/icon.icns",
+ "icons/icon.ico"
+ ]
+ }
+}
+
+ 在 Rust 中定义可从前端调用的命令:
+ +// src-tauri/src/commands.rs
+use tauri::command;
+
+#[command]
+pub fn get_system_info() -> Result<SystemInfo, String> {
+ Ok(SystemInfo {
+ os: std::env::consts::OS.to_string(),
+ arch: std::env::consts::ARCH.to_string(),
+ })
+}
+
+#[command]
+pub async fn open_project(path: String) -> Result<(), String> {
+ // 打开项目目录
+ std::env::set_current_dir(&path)
+ .map_err(|e| e.to_string())
+}
+
+ 在前端调用:
+ +import { invoke } from '@tauri-apps/api/core';
+
+// 调用 Rust 命令
+const info = await invoke('get_system_info');
+console.log('系统信息:', info);
+
+// 打开项目
+await invoke('open_project', { path: '/path/to/project' });
+
+ // src-tauri/src/tray.rs
+use tauri::{
+ tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
+ Manager,
+};
+
+pub fn create_tray(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
+ let tray = TrayIconBuilder::new()
+ .icon(app.default_window_icon().unwrap().clone())
+ .tooltip("AI Terminal Assistant")
+ .on_tray_icon_event(|tray, event| {
+ if let TrayIconEvent::Click {
+ button: MouseButton::Left,
+ button_state: MouseButtonState::Up,
+ ..
+ } = event
+ {
+ let app = tray.app_handle();
+ if let Some(window) = app.get_webview_window("main") {
+ let _ = window.show();
+ let _ = window.set_focus();
+ }
+ }
+ })
+ .build(app)?;
+
+ Ok(())
+}
+
+ use tauri::Manager;
+
+fn setup_shortcuts(app: &tauri::App) {
+ use tauri_plugin_global_shortcut::GlobalShortcutExt;
+
+ app.handle().plugin(
+ tauri_plugin_global_shortcut::Builder::new()
+ .with_shortcuts(["ctrl+shift+a"])?
+ .with_handler(|app, shortcut, event| {
+ if shortcut.matches(Modifiers::CONTROL | Modifiers::SHIFT, Code::KeyA) {
+ // 显示/隐藏窗口
+ if let Some(window) = app.get_webview_window("main") {
+ if window.is_visible().unwrap_or(false) {
+ let _ = window.hide();
+ } else {
+ let _ = window.show();
+ let _ = window.set_focus();
+ }
+ }
+ }
+ })
+ .build()
+ )?;
+}
+
+ import { open, save } from '@tauri-apps/plugin-dialog';
+import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
+
+// 打开文件选择对话框
+const selected = await open({
+ multiple: false,
+ filters: [{ name: 'Text', extensions: ['txt', 'md'] }]
+});
+
+if (selected) {
+ const content = await readTextFile(selected);
+ console.log('文件内容:', content);
+}
+
+// 保存文件
+const savePath = await save({
+ filters: [{ name: 'Markdown', extensions: ['md'] }]
+});
+
+if (savePath) {
+ await writeTextFile(savePath, '# Hello World');
+}
+
+ // tauri.conf.json
+{
+ "plugins": {
+ "updater": {
+ "active": true,
+ "endpoints": [
+ "https://releases.example.com/{{target}}/{{arch}}/{{current_version}}"
+ ],
+ "pubkey": "YOUR_PUBLIC_KEY"
+ }
+ }
+}
+
+ import { check } from '@tauri-apps/plugin-updater';
+
+async function checkForUpdates() {
+ const update = await check();
+ if (update?.available) {
+ console.log(`发现新版本: ${update.version}`);
+ await update.downloadAndInstall();
+ }
+}
+
+ pnpm tauri dev 热重载+ Web 前端是基于 React + Vite 构建的现代化 Web 应用,提供完整的 AI 对话交互界面。 +
+ +# 进入 web 包目录
+cd packages/web
+
+# 安装依赖
+pnpm install
+
+# 启动开发服务器
+pnpm dev
+
+# 访问 http://localhost:5173
+
+ # 构建生产版本
+pnpm build
+
+# 预览构建结果
+pnpm preview
+
+# 输出目录: dist/
+
+ 在 .env 或 .env.local 中配置:
# API 服务器地址
+VITE_API_URL=http://localhost:3000
+
+# WebSocket 地址(可选,默认从 API_URL 推导)
+VITE_WS_URL=ws://localhost:3000
+
+# 认证 Token(远程连接时需要)
+VITE_AUTH_TOKEN=your-auth-token
+
+ packages/web/
+├── src/
+│ ├── components/ # React 组件
+│ │ ├── Chat/ # 聊天相关组件
+│ │ ├── Message/ # 消息显示组件
+│ │ ├── Tool/ # 工具调用显示
+│ │ └── Layout/ # 布局组件
+│ ├── hooks/ # 自定义 Hooks
+│ │ ├── useWebSocket.ts
+│ │ ├── useSession.ts
+│ │ └── usePermission.ts
+│ ├── services/ # API 服务
+│ │ ├── api.ts # REST API 客户端
+│ │ └── websocket.ts # WebSocket 客户端
+│ ├── stores/ # 状态管理
+│ ├── types/ # TypeScript 类型
+│ ├── App.tsx # 应用入口
+│ └── main.tsx # 渲染入口
+├── public/ # 静态资源
+├── index.html # HTML 模板
+└── vite.config.ts # Vite 配置
+
+ 主聊天容器,管理消息列表和输入:
+ +import { ChatContainer } from '@/components/Chat';
+
+function App() {
+ return (
+ <ChatContainer
+ sessionId="session-123"
+ onMessage={(msg) => console.log(msg)}
+ />
+ );
+}
+
+ 消息列表组件,支持多种消息类型:
+ +import { MessageList } from '@/components/Message';
+
+<MessageList
+ messages={messages}
+ onToolApprove={handleToolApprove}
+ onToolReject={handleToolReject}
+/>
+
+ 工具调用展示组件:
+ +import { ToolCallDisplay } from '@/components/Tool';
+
+<ToolCallDisplay
+ tool={{
+ name: 'read_file',
+ params: { path: '/src/index.ts' },
+ status: 'completed',
+ result: '文件内容...'
+ }}
+/>
+
+ import { useWebSocket } from '@/hooks/useWebSocket';
+
+function ChatComponent() {
+ const {
+ connected,
+ send,
+ lastMessage,
+ disconnect
+ } = useWebSocket(sessionId);
+
+ const handleSend = (content: string) => {
+ send({
+ type: 'message',
+ payload: { content }
+ });
+ };
+
+ // 处理接收的消息
+ useEffect(() => {
+ if (lastMessage) {
+ switch (lastMessage.type) {
+ case 'chunk':
+ appendContent(lastMessage.payload.content);
+ break;
+ case 'tool_call':
+ showToolCall(lastMessage.payload);
+ break;
+ case 'done':
+ finishMessage();
+ break;
+ }
+ }
+ }, [lastMessage]);
+}
+
+ 使用 Zustand 进行状态管理:
+ +import { create } from 'zustand';
+
+interface ChatStore {
+ messages: Message[];
+ currentSession: string | null;
+ addMessage: (msg: Message) => void;
+ setSession: (id: string) => void;
+}
+
+export const useChatStore = create<ChatStore>((set) => ({
+ messages: [],
+ currentSession: null,
+ addMessage: (msg) => set((state) => ({
+ messages: [...state.messages, msg]
+ })),
+ setSession: (id) => set({ currentSession: id })
+}));
+
+ 使用 Tailwind CSS 自定义主题:
+ +// tailwind.config.js
+export default {
+ theme: {
+ extend: {
+ colors: {
+ primary: {
+ 50: '#f0f9ff',
+ // ...
+ 900: '#0c4a6e',
+ },
+ background: '#0a0a0a',
+ surface: '#1a1a1a',
+ },
+ fontFamily: {
+ mono: ['JetBrains Mono', 'monospace'],
+ },
+ },
+ },
+};
+
+ # 构建
+VITE_API_URL=https://api.example.com pnpm build
+
+# 部署 dist/ 目录到任何静态托管服务
+# - Vercel
+# - Netlify
+# - Cloudflare Pages
+# - Nginx
+
+ # Dockerfile.web
+FROM node:20-alpine as builder
+WORKDIR /app
+COPY . .
+RUN npm install -g pnpm
+RUN pnpm install
+RUN pnpm --filter @ai-assistant/web build
+
+FROM nginx:alpine
+COPY --from=builder /app/packages/web/dist /usr/share/nginx/html
+COPY nginx.conf /etc/nginx/conf.d/default.conf
+EXPOSE 80
+
+ + AI Terminal Assistant 支持多层配置系统,可以通过环境变量、配置文件等方式进行配置。 +
+ +| 变量名 | +说明 | +示例 | +
|---|---|---|
ANTHROPIC_API_KEY |
+ Anthropic API 密钥 | +sk-ant-... |
+
| 变量名 | +说明 | +默认值 | +
|---|---|---|
OPENAI_API_KEY |
+ OpenAI API 密钥 | +- | +
DEEPSEEK_API_KEY |
+ DeepSeek API 密钥 | +- | +
TAVILY_API_KEY |
+ Tavily 搜索 API 密钥 | +- | +
AI_MODEL |
+ 默认模型 | +claude-sonnet-4-20250514 |
+
AI_MAX_TOKENS |
+ 最大输出 tokens | +4096 |
+
AI_TEMPERATURE |
+ 温度参数 | +0.7 |
+
# .env 文件示例
+ANTHROPIC_API_KEY=sk-ant-your-key-here
+OPENAI_API_KEY=sk-your-openai-key
+TAVILY_API_KEY=tvly-your-tavily-key
+
+# 模型配置
+AI_MODEL=claude-sonnet-4-20250514
+AI_MAX_TOKENS=8192
+AI_TEMPERATURE=0.7
+
+ 在项目根目录创建 .ai-assistant/config.json:
{
+ "model": "claude-sonnet-4-20250514",
+ "maxTokens": 4096,
+ "temperature": 0.7,
+ "systemPrompt": "你是一个专业的编程助手",
+ "tools": {
+ "enabled": ["read_file", "write_file", "bash", "grep"],
+ "disabled": ["web_search"]
+ },
+ "permissions": {
+ "allowedPaths": ["/project"],
+ "deniedPaths": ["/project/secrets"],
+ "autoApprove": ["read_file", "grep"]
+ }
+}
+
+ 在项目根目录创建 mcp.json:
{
+ "mcpServers": {
+ "filesystem": {
+ "command": "npx",
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
+ "env": {}
+ },
+ "github": {
+ "command": "npx",
+ "args": ["-y", "@modelcontextprotocol/server-github"],
+ "env": {
+ "GITHUB_TOKEN": "${GITHUB_TOKEN}"
+ }
+ }
+ }
+}
+
+ 配置按以下优先级加载(高 → 低):
+ +.ai-assistant/config.json)~/.config/ai-assistant/config.json)| 参数 | +环境变量 | +说明 | +默认值 | +
|---|---|---|---|
--port |
+ PORT |
+ 服务器端口 | +3000 |
+
--host |
+ HOST |
+ 绑定地址 | +127.0.0.1 |
+
--auth |
+ AUTH_ENABLED |
+ 启用认证 | +远程模式自动启用 | +
--token |
+ AUTH_TOKEN |
+ 认证 Token | +自动生成 | +
interface PermissionConfig {
+ // 允许访问的路径
+ allowedPaths: string[];
+
+ // 禁止访问的路径
+ deniedPaths: string[];
+
+ // 自动批准的工具
+ autoApprove: string[];
+
+ // 禁用的工具
+ disabledTools: string[];
+
+ // 允许执行的 Shell 命令模式
+ shellPatterns: string[];
+}
+
+ + 本指南介绍如何在本地搭建 AI Terminal Assistant 开发环境。 +
+ +git clone https://github.com/your-username/ai-terminal-assistant.git
+cd ai-terminal-assistant
+
+ # 使用 pnpm 安装所有依赖
+pnpm install
+
+ # 复制环境变量模板
+cp .env.example .env
+
+# 编辑 .env 文件,添加 API 密钥
+# ANTHROPIC_API_KEY=your-api-key
+
+ # 构建核心包
+pnpm --filter @ai-assistant/core build
+
+# 构建服务器
+pnpm --filter @ai-assistant/server build
+
+# 或一次性构建所有包
+pnpm build
+
+ # 终端 1:启动 HTTP 服务器
+pnpm server:dev
+
+# 终端 2:启动 Web 前端
+cd packages/web && pnpm dev
+
+ 然后访问 http://localhost:5173。
# 启动服务器
+cd packages/cli
+bun run src/index.ts serve --port 3000
+
+ | 命令 | +说明 | +
|---|---|
pnpm build |
+ 构建所有包 | +
pnpm test |
+ 运行所有测试 | +
pnpm --filter @ai-assistant/core build |
+ 只构建 core 包 | +
pnpm --filter @ai-assistant/core test:watch |
+ 监视模式运行 core 测试 | +
pnpm server:dev |
+ 开发模式启动服务器 | +
ai-terminal-assistant/
+├── packages/
+│ ├── core/ # 核心引擎
+│ │ ├── src/
+│ │ │ ├── core/ # Agent 系统
+│ │ │ ├── tools/ # 工具注册
+│ │ │ ├── editors/ # 编辑器
+│ │ │ ├── checkpoint/ # 检查点
+│ │ │ ├── mcp/ # MCP 客户端
+│ │ │ └── lsp/ # LSP 集成
+│ │ └── package.json
+│ │
+│ ├── server/ # HTTP 服务器
+│ │ ├── src/
+│ │ │ ├── routes/ # API 路由
+│ │ │ ├── ws.ts # WebSocket
+│ │ │ └── sse.ts # SSE
+│ │ └── package.json
+│ │
+│ ├── cli/ # 命令行工具
+│ ├── web/ # React 前端
+│ └── desktop/ # Tauri 桌面应用
+│
+├── docs/ # 设计文档
+├── pnpm-workspace.yaml
+└── package.json
+
+ # 启用详细日志
+DEBUG=ai-assistant:* pnpm server:dev
+
+ import { toolRegistry } from '@ai-assistant/core/tools';
+
+// 获取工具
+const readFile = toolRegistry.get('read_file');
+
+// 执行测试
+const result = await readFile.execute({
+ path: '/path/to/file.ts'
+});
+
+console.log(result);
+
+ // .vscode/launch.json
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Debug Server",
+ "type": "node",
+ "request": "launch",
+ "runtimeExecutable": "bun",
+ "runtimeArgs": ["run"],
+ "program": "${workspaceFolder}/packages/server/src/bin/server.ts",
+ "cwd": "${workspaceFolder}"
+ }
+ ]
+}
+
+ # 清理缓存重新安装
+rm -rf node_modules pnpm-lock.yaml
+pnpm store prune
+pnpm install
+
+ # 查找占用端口的进程
+lsof -i :3000
+
+# 使用其他端口
+pnpm server:dev -- --port 3001
+
+ + 本指南介绍如何将 AI Terminal Assistant 部署到生产环境。 +
+ +# Dockerfile
+FROM oven/bun:1 as builder
+
+WORKDIR /app
+COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
+COPY packages ./packages
+
+RUN npm install -g pnpm
+RUN pnpm install --frozen-lockfile
+RUN pnpm build
+
+# 生产镜像
+FROM oven/bun:1-slim
+
+WORKDIR /app
+COPY --from=builder /app/packages/server/dist ./dist
+COPY --from=builder /app/packages/core/dist ./core
+COPY --from=builder /app/node_modules ./node_modules
+
+ENV NODE_ENV=production
+ENV PORT=3000
+
+EXPOSE 3000
+
+CMD ["bun", "run", "dist/bin/server.js"]
+
+ # docker-compose.yml
+version: '3.8'
+
+services:
+ ai-assistant:
+ build: .
+ ports:
+ - "3000:3000"
+ environment:
+ - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
+ - HOST=0.0.0.0
+ - PORT=3000
+ - AUTH_ENABLED=true
+ - AUTH_TOKEN=${AUTH_TOKEN}
+ volumes:
+ - ./projects:/projects:rw
+ restart: unless-stopped
+
+ web:
+ build:
+ context: .
+ dockerfile: Dockerfile.web
+ ports:
+ - "80:80"
+ depends_on:
+ - ai-assistant
+ restart: unless-stopped
+
+ # 构建镜像
+docker build -t ai-assistant .
+
+# 运行容器
+docker run -d \
+ --name ai-assistant \
+ -p 3000:3000 \
+ -e ANTHROPIC_API_KEY=your-key \
+ -e AUTH_TOKEN=your-secret-token \
+ -v /path/to/projects:/projects \
+ ai-assistant
+
+# 使用 Docker Compose
+docker-compose up -d
+
+ # /etc/systemd/system/ai-assistant.service
+[Unit]
+Description=AI Terminal Assistant
+After=network.target
+
+[Service]
+Type=simple
+User=ai-assistant
+WorkingDirectory=/opt/ai-assistant
+ExecStart=/usr/local/bin/bun run dist/bin/server.js
+Restart=on-failure
+RestartSec=10
+Environment=NODE_ENV=production
+Environment=PORT=3000
+Environment=HOST=0.0.0.0
+EnvironmentFile=/opt/ai-assistant/.env
+
+[Install]
+WantedBy=multi-user.target
+
+ # 启用并启动服务
+sudo systemctl enable ai-assistant
+sudo systemctl start ai-assistant
+
+# 查看状态
+sudo systemctl status ai-assistant
+
+# 查看日志
+sudo journalctl -u ai-assistant -f
+
+ // ecosystem.config.js
+module.exports = {
+ apps: [{
+ name: 'ai-assistant',
+ script: 'dist/bin/server.js',
+ interpreter: 'bun',
+ cwd: '/opt/ai-assistant',
+ env: {
+ NODE_ENV: 'production',
+ PORT: 3000,
+ HOST: '0.0.0.0'
+ },
+ env_file: '.env',
+ instances: 1,
+ autorestart: true,
+ watch: false,
+ max_memory_restart: '1G'
+ }]
+};
+
+ # 启动
+pm2 start ecosystem.config.js
+
+# 保存并开机启动
+pm2 save
+pm2 startup
+
+ # /etc/nginx/sites-available/ai-assistant
+server {
+ listen 80;
+ server_name your-domain.com;
+
+ # 重定向到 HTTPS
+ return 301 https://$server_name$request_uri;
+}
+
+server {
+ listen 443 ssl http2;
+ server_name your-domain.com;
+
+ ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
+
+ # API 和 WebSocket
+ location /api/ {
+ proxy_pass http://127.0.0.1:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # WebSocket 超时
+ proxy_read_timeout 86400s;
+ proxy_send_timeout 86400s;
+ }
+
+ # 静态文件
+ location / {
+ root /var/www/ai-assistant;
+ try_files $uri $uri/ /index.html;
+ }
+}
+
+ # 设置 API 地址
+echo "VITE_API_URL=https://api.your-domain.com" > packages/web/.env.production
+
+# 构建
+cd packages/web && pnpm build
+
+# 输出在 dist/ 目录
+
+ // vercel.json
+{
+ "buildCommand": "cd packages/web && pnpm build",
+ "outputDirectory": "packages/web/dist",
+ "framework": "vite",
+ "rewrites": [
+ { "source": "/(.*)", "destination": "/index.html" }
+ ]
+}
+
+ # 使用 Let's Encrypt
+sudo certbot --nginx -d your-domain.com
+
+ # UFW
+sudo ufw allow 80/tcp
+sudo ufw allow 443/tcp
+sudo ufw enable
+
+ # 生成强 Token
+openssl rand -hex 32
+
+# 设置环境变量
+export AUTH_TOKEN=your-generated-token
+
+ # 健康检查
+curl https://your-domain.com/health
+
+# 查看容器日志
+docker logs -f ai-assistant
+
+# 查看系统服务日志
+journalctl -u ai-assistant -f
+
+ + 工具是 AI Agent 与外部世界交互的方式。你可以创建自定义工具来扩展 AI 的能力, + 例如访问数据库、调用 API、执行特定业务逻辑等。 +
+ +每个工具需要定义以下属性:
+ +interface Tool {
+ name: string; // 工具名称(唯一标识)
+ description: string; // 工具描述(AI 用于判断何时使用)
+ parameters: ZodSchema; // 参数 Schema(Zod 定义)
+ execute: (params: T, context: ToolContext) => Promise<ToolResult>;
+}
+
+ import { z } from 'zod';
+import { toolRegistry } from '@ai-assistant/core';
+
+// 定义参数 Schema
+const weatherParams = z.object({
+ city: z.string().describe('城市名称'),
+ units: z.enum(['celsius', 'fahrenheit']).default('celsius')
+});
+
+// 注册工具
+toolRegistry.register({
+ name: 'get_weather',
+ description: '获取指定城市的天气信息',
+ parameters: weatherParams,
+ execute: async (params) => {
+ const { city, units } = params;
+
+ // 调用天气 API
+ const response = await fetch(
+ `https://api.weather.com/v1/current?city=${city}&units=${units}`
+ );
+ const data = await response.json();
+
+ return {
+ success: true,
+ result: `${city} 当前温度: ${data.temperature}°${units === 'celsius' ? 'C' : 'F'}`
+ };
+ }
+});
+
+ ToolContext 提供执行环境信息:
interface ToolContext {
+ workDir: string; // 当前工作目录
+ sessionId: string; // 当前会话 ID
+ abortSignal?: AbortSignal; // 取消信号
+ agent: Agent; // Agent 实例
+}
+
+toolRegistry.register({
+ name: 'list_project_files',
+ description: '列出项目中的文件',
+ parameters: z.object({
+ pattern: z.string().optional()
+ }),
+ execute: async (params, context) => {
+ const { workDir } = context;
+ // 使用 workDir 作为基础路径
+ const files = await glob(params.pattern || '**/*', {
+ cwd: workDir,
+ ignore: ['node_modules/**']
+ });
+ return { success: true, result: files.join('\n') };
+ }
+});
+
+ toolRegistry.register({
+ name: 'read_database',
+ description: '从数据库读取数据',
+ parameters: z.object({
+ query: z.string()
+ }),
+ execute: async (params) => {
+ try {
+ const result = await db.query(params.query);
+ return {
+ success: true,
+ result: JSON.stringify(result, null, 2)
+ };
+ } catch (error) {
+ // 返回错误信息,AI 可以根据错误调整
+ return {
+ success: false,
+ error: `数据库查询失败: ${error.message}`
+ };
+ }
+ }
+});
+
+ toolRegistry.register({
+ name: 'long_running_task',
+ description: '执行长时间运行的任务',
+ parameters: z.object({
+ taskId: z.string()
+ }),
+ execute: async (params, context) => {
+ const { abortSignal } = context;
+
+ for (let i = 0; i < 100; i++) {
+ // 检查是否被取消
+ if (abortSignal?.aborted) {
+ return { success: false, error: '任务已取消' };
+ }
+
+ await processStep(i);
+ }
+
+ return { success: true, result: '任务完成' };
+ }
+});
+
+ 可以为工具设置权限级别:
+ +toolRegistry.register({
+ name: 'delete_file',
+ description: '删除文件',
+ parameters: z.object({
+ path: z.string()
+ }),
+ // 需要用户确认
+ requiresConfirmation: true,
+ // 权限级别
+ permissionLevel: 'dangerous',
+ execute: async (params, context) => {
+ await fs.unlink(path.join(context.workDir, params.path));
+ return { success: true, result: `已删除: ${params.path}` };
+ }
+});
+
+ // 创建工具组
+const databaseTools = createToolGroup('database', {
+ description: '数据库操作工具',
+ tools: [
+ {
+ name: 'query',
+ description: '执行 SQL 查询',
+ parameters: z.object({ sql: z.string() }),
+ execute: async (params) => { /* ... */ }
+ },
+ {
+ name: 'insert',
+ description: '插入数据',
+ parameters: z.object({
+ table: z.string(),
+ data: z.record(z.any())
+ }),
+ execute: async (params) => { /* ... */ }
+ }
+ ]
+});
+
+// 注册工具组
+toolRegistry.registerGroup(databaseTools);
+
+// AI 会看到: database_query, database_insert
+
+ import { z } from 'zod';
+import { toolRegistry } from '@ai-assistant/core';
+import { Octokit } from '@octokit/rest';
+
+const octokit = new Octokit({
+ auth: process.env.GITHUB_TOKEN
+});
+
+// 创建 Issue
+toolRegistry.register({
+ name: 'github_create_issue',
+ description: '在 GitHub 仓库中创建 Issue',
+ parameters: z.object({
+ owner: z.string().describe('仓库所有者'),
+ repo: z.string().describe('仓库名称'),
+ title: z.string().describe('Issue 标题'),
+ body: z.string().describe('Issue 内容'),
+ labels: z.array(z.string()).optional().describe('标签列表')
+ }),
+ execute: async (params) => {
+ const { owner, repo, title, body, labels } = params;
+
+ const { data } = await octokit.issues.create({
+ owner,
+ repo,
+ title,
+ body,
+ labels
+ });
+
+ return {
+ success: true,
+ result: `Issue 创建成功: ${data.html_url}`
+ };
+ }
+});
+
+// 列出 PR
+toolRegistry.register({
+ name: 'github_list_prs',
+ description: '列出 GitHub 仓库的 Pull Requests',
+ parameters: z.object({
+ owner: z.string(),
+ repo: z.string(),
+ state: z.enum(['open', 'closed', 'all']).default('open')
+ }),
+ execute: async (params) => {
+ const { owner, repo, state } = params;
+
+ const { data } = await octokit.pulls.list({
+ owner,
+ repo,
+ state
+ });
+
+ const prs = data.map(pr => `#${pr.number}: ${pr.title}`).join('\n');
+
+ return {
+ success: true,
+ result: prs || '没有找到 PR'
+ };
+ }
+});
+
+ import { describe, it, expect } from 'vitest';
+import { toolRegistry } from '@ai-assistant/core';
+
+describe('get_weather tool', () => {
+ it('should return weather for valid city', async () => {
+ const tool = toolRegistry.get('get_weather');
+ const result = await tool.execute(
+ { city: 'Beijing', units: 'celsius' },
+ { workDir: '/tmp', sessionId: 'test' }
+ );
+
+ expect(result.success).toBe(true);
+ expect(result.result).toContain('Beijing');
+ });
+
+ it('should handle invalid city', async () => {
+ const tool = toolRegistry.get('get_weather');
+ const result = await tool.execute(
+ { city: 'InvalidCity123', units: 'celsius' },
+ { workDir: '/tmp', sessionId: 'test' }
+ );
+
+ expect(result.success).toBe(false);
+ });
+});
+
+ + Hooks 允许你在 Agent 执行的关键节点注入自定义逻辑, + 用于日志记录、监控、修改行为等场景。 +
+ +| Hook | +触发时机 | +用途 | +
|---|---|---|
beforeChat |
+ 发送消息前 | +修改消息、验证输入 | +
afterChat |
+ 收到响应后 | +日志记录、响应处理 | +
beforeToolCall |
+ 工具调用前 | +参数验证、权限检查 | +
afterToolCall |
+ 工具执行后 | +结果处理、审计日志 | +
onError |
+ 发生错误时 | +错误处理、告警 | +
onStream |
+ 流式数据块 | +实时处理、进度显示 | +
import { Agent } from '@ai-assistant/core';
+
+const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: {
+ beforeChat: async (context) => {
+ console.log('即将发送消息:', context.message);
+ // 可以修改消息
+ return {
+ ...context,
+ message: context.message + '\n请用简洁的方式回答。'
+ };
+ },
+
+ afterChat: async (context) => {
+ console.log('收到响应:', context.response);
+ // 记录到数据库
+ await db.logs.insert({
+ sessionId: context.sessionId,
+ message: context.message,
+ response: context.response,
+ timestamp: new Date()
+ });
+ }
+ }
+});
+
+ const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: {
+ beforeToolCall: async (context) => {
+ const { tool, params } = context;
+
+ // 权限检查
+ if (tool.name === 'execute_bash' && !isAllowedCommand(params.command)) {
+ throw new Error('命令不被允许');
+ }
+
+ // 记录工具调用
+ console.log(`调用工具: ${tool.name}`, params);
+
+ return context;
+ },
+
+ afterToolCall: async (context) => {
+ const { tool, params, result, duration } = context;
+
+ // 审计日志
+ await auditLog.record({
+ tool: tool.name,
+ params,
+ result: result.success ? 'success' : 'failure',
+ duration,
+ timestamp: new Date()
+ });
+
+ // 可以修改结果
+ if (tool.name === 'read_file' && result.success) {
+ // 过滤敏感信息
+ return {
+ ...context,
+ result: {
+ ...result,
+ result: filterSensitiveData(result.result)
+ }
+ };
+ }
+
+ return context;
+ }
+ }
+});
+
+ const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: {
+ onError: async (context) => {
+ const { error, phase, tool } = context;
+
+ // 发送告警
+ await alertService.send({
+ level: 'error',
+ message: error.message,
+ context: {
+ phase, // 'chat' | 'tool' | 'stream'
+ tool: tool?.name,
+ sessionId: context.sessionId
+ }
+ });
+
+ // 可以选择恢复或重新抛出
+ if (error.code === 'RATE_LIMIT') {
+ // 等待后重试
+ await sleep(5000);
+ return { retry: true };
+ }
+
+ // 重新抛出错误
+ throw error;
+ }
+ }
+});
+
+ const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: {
+ onStream: async (context) => {
+ const { chunk, type, accumulated } = context;
+
+ if (type === 'text') {
+ // 实时显示
+ process.stdout.write(chunk);
+ } else if (type === 'tool_call') {
+ // 显示工具调用进度
+ console.log(`\n[调用工具: ${chunk.name}]`);
+ }
+
+ // 进度回调
+ if (context.onProgress) {
+ context.onProgress({
+ type,
+ content: chunk,
+ total: accumulated.length
+ });
+ }
+ }
+ }
+});
+
+ 可以注册多个同类型的 Hook,按顺序执行:
+ +import { createHookChain } from '@ai-assistant/core';
+
+const hooks = createHookChain();
+
+// 添加日志 Hook
+hooks.add('beforeChat', async (ctx) => {
+ console.log('[Logger] 消息:', ctx.message);
+ return ctx;
+});
+
+// 添加验证 Hook
+hooks.add('beforeChat', async (ctx) => {
+ if (ctx.message.length > 10000) {
+ throw new Error('消息过长');
+ }
+ return ctx;
+});
+
+// 添加修改 Hook
+hooks.add('beforeChat', async (ctx) => {
+ return {
+ ...ctx,
+ message: ctx.message.trim()
+ };
+});
+
+const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: hooks.toObject()
+});
+
+ import { createConditionalHook } from '@ai-assistant/core';
+
+// 只在特定条件下执行的 Hook
+const debugHook = createConditionalHook(
+ // 条件函数
+ (ctx) => process.env.DEBUG === 'true',
+ // Hook 实现
+ {
+ beforeToolCall: async (ctx) => {
+ console.log('[DEBUG] 工具调用:', ctx.tool.name, ctx.params);
+ return ctx;
+ },
+ afterToolCall: async (ctx) => {
+ console.log('[DEBUG] 工具结果:', ctx.result);
+ return ctx;
+ }
+ }
+);
+
+const agent = new Agent({
+ apiKey: process.env.ANTHROPIC_API_KEY,
+ hooks: debugHook
+});
+
+ import { createLoggerHook } from '@ai-assistant/core/hooks';
+
+const loggerHook = createLoggerHook({
+ level: 'info',
+ output: 'file',
+ path: './logs/agent.log',
+ format: 'json'
+});
+
+const agent = new Agent({
+ hooks: loggerHook
+});
+
+ import { createRateLimitHook } from '@ai-assistant/core/hooks';
+
+const rateLimitHook = createRateLimitHook({
+ maxRequests: 10,
+ windowMs: 60000, // 1 分钟
+ onLimit: async () => {
+ console.log('达到速率限制,等待中...');
+ }
+});
+
+const agent = new Agent({
+ hooks: rateLimitHook
+});
+
+ import { createCacheHook } from '@ai-assistant/core/hooks';
+
+const cacheHook = createCacheHook({
+ ttl: 3600, // 1 小时
+ storage: 'redis',
+ // 只缓存特定工具的结果
+ tools: ['read_file', 'search_code']
+});
+
+const agent = new Agent({
+ hooks: cacheHook
+});
+
+ interface BeforeChatContext {
+ message: string | ContentBlock[];
+ sessionId: string;
+ history: Message[];
+}
+
+interface AfterChatContext extends BeforeChatContext {
+ response: string;
+ toolCalls: ToolCall[];
+ usage: TokenUsage;
+}
+
+interface BeforeToolCallContext {
+ tool: Tool;
+ params: Record<string, any>;
+ sessionId: string;
+}
+
+interface AfterToolCallContext extends BeforeToolCallContext {
+ result: ToolResult;
+ duration: number;
+}
+
+interface ErrorContext {
+ error: Error;
+ phase: 'chat' | 'tool' | 'stream';
+ tool?: Tool;
+ sessionId: string;
+}
+
+interface StreamContext {
+ chunk: string | ToolCallChunk;
+ type: 'text' | 'tool_call' | 'tool_result';
+ accumulated: string;
+}
+
+ + Model Context Protocol (MCP) 是一个开放协议,允许你创建服务器来扩展 AI 的能力。 + 通过开发 MCP 服务器,可以让 AI 访问自定义数据源、执行特定操作、使用预定义提示等。 +
+ +# 创建项目目录
+mkdir my-mcp-server && cd my-mcp-server
+
+# 初始化 npm 项目
+npm init -y
+
+# 安装依赖
+npm install @modelcontextprotocol/sdk zod
+
+# 安装开发依赖
+npm install -D typescript @types/node tsx
+
+ // tsconfig.json
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "outDir": "dist",
+ "strict": true,
+ "esModuleInterop": true
+ },
+ "include": ["src"]
+}
+
+ // src/index.ts
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import {
+ CallToolRequestSchema,
+ ListToolsRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 创建服务器实例
+const server = new Server(
+ {
+ name: 'my-mcp-server',
+ version: '1.0.0',
+ },
+ {
+ capabilities: {
+ tools: {},
+ resources: {},
+ prompts: {},
+ },
+ }
+);
+
+// 列出可用工具
+server.setRequestHandler(ListToolsRequestSchema, async () => ({
+ tools: [
+ {
+ name: 'hello',
+ description: '返回问候语',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ name: {
+ type: 'string',
+ description: '要问候的名字',
+ },
+ },
+ required: ['name'],
+ },
+ },
+ ],
+}));
+
+// 处理工具调用
+server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ if (request.params.name === 'hello') {
+ const name = request.params.arguments?.name as string;
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `你好,${name}!`,
+ },
+ ],
+ };
+ }
+ throw new Error(`未知工具: ${request.params.name}`);
+});
+
+// 启动服务器
+async function main() {
+ const transport = new StdioServerTransport();
+ await server.connect(transport);
+ console.error('MCP 服务器已启动');
+}
+
+main().catch(console.error);
+
+ import {
+ ListResourcesRequestSchema,
+ ReadResourceRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 列出资源
+server.setRequestHandler(ListResourcesRequestSchema, async () => ({
+ resources: [
+ {
+ uri: 'config://app/settings',
+ name: '应用配置',
+ description: '当前应用配置',
+ mimeType: 'application/json',
+ },
+ {
+ uri: 'db://users/list',
+ name: '用户列表',
+ description: '所有用户数据',
+ mimeType: 'application/json',
+ },
+ ],
+}));
+
+// 读取资源
+server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
+ const { uri } = request.params;
+
+ if (uri === 'config://app/settings') {
+ return {
+ contents: [
+ {
+ uri,
+ mimeType: 'application/json',
+ text: JSON.stringify({
+ theme: 'dark',
+ language: 'zh-CN',
+ version: '1.0.0',
+ }),
+ },
+ ],
+ };
+ }
+
+ if (uri === 'db://users/list') {
+ const users = await db.users.findAll();
+ return {
+ contents: [
+ {
+ uri,
+ mimeType: 'application/json',
+ text: JSON.stringify(users),
+ },
+ ],
+ };
+ }
+
+ throw new Error(`未知资源: ${uri}`);
+});
+
+ import {
+ ListPromptsRequestSchema,
+ GetPromptRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 列出提示
+server.setRequestHandler(ListPromptsRequestSchema, async () => ({
+ prompts: [
+ {
+ name: 'code-review',
+ description: '代码审查提示',
+ arguments: [
+ {
+ name: 'file',
+ description: '要审查的文件路径',
+ required: true,
+ },
+ {
+ name: 'focus',
+ description: '审查重点(安全/性能/可读性)',
+ required: false,
+ },
+ ],
+ },
+ ],
+}));
+
+// 获取提示
+server.setRequestHandler(GetPromptRequestSchema, async (request) => {
+ const { name, arguments: args } = request.params;
+
+ if (name === 'code-review') {
+ const file = args?.file as string;
+ const focus = (args?.focus as string) || '整体质量';
+
+ return {
+ messages: [
+ {
+ role: 'user',
+ content: {
+ type: 'text',
+ text: `请审查文件 ${file},重点关注: ${focus}
+
+请按以下格式提供审查意见:
+1. 总体评价
+2. 优点
+3. 需要改进的地方
+4. 具体建议`,
+ },
+ },
+ ],
+ };
+ }
+
+ throw new Error(`未知提示: ${name}`);
+});
+
+ // src/db-server.ts
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import Database from 'better-sqlite3';
+
+const db = new Database('data.db');
+
+const server = new Server(
+ { name: 'sqlite-server', version: '1.0.0' },
+ { capabilities: { tools: {} } }
+);
+
+// 工具列表
+server.setRequestHandler(ListToolsRequestSchema, async () => ({
+ tools: [
+ {
+ name: 'query',
+ description: '执行 SQL 查询',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ sql: { type: 'string', description: 'SQL 查询语句' },
+ },
+ required: ['sql'],
+ },
+ },
+ {
+ name: 'execute',
+ description: '执行 SQL 命令(INSERT/UPDATE/DELETE)',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ sql: { type: 'string', description: 'SQL 命令' },
+ params: {
+ type: 'array',
+ items: {},
+ description: '参数列表',
+ },
+ },
+ required: ['sql'],
+ },
+ },
+ {
+ name: 'schema',
+ description: '获取数据库表结构',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ table: { type: 'string', description: '表名(可选)' },
+ },
+ },
+ },
+ ],
+}));
+
+// 工具调用
+server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ const { name, arguments: args } = request.params;
+
+ switch (name) {
+ case 'query': {
+ const sql = args?.sql as string;
+ // 安全检查:只允许 SELECT
+ if (!sql.trim().toLowerCase().startsWith('select')) {
+ throw new Error('query 只允许 SELECT 语句');
+ }
+ const rows = db.prepare(sql).all();
+ return {
+ content: [{ type: 'text', text: JSON.stringify(rows, null, 2) }],
+ };
+ }
+
+ case 'execute': {
+ const sql = args?.sql as string;
+ const params = (args?.params as any[]) || [];
+ const result = db.prepare(sql).run(...params);
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `执行成功: 影响 ${result.changes} 行`,
+ },
+ ],
+ };
+ }
+
+ case 'schema': {
+ const table = args?.table as string | undefined;
+ let sql = `SELECT name, sql FROM sqlite_master WHERE type='table'`;
+ if (table) {
+ sql += ` AND name = '${table}'`;
+ }
+ const schemas = db.prepare(sql).all();
+ return {
+ content: [{ type: 'text', text: JSON.stringify(schemas, null, 2) }],
+ };
+ }
+
+ default:
+ throw new Error(`未知工具: ${name}`);
+ }
+});
+
+const transport = new StdioServerTransport();
+server.connect(transport);
+
+ // mcp.json
+{
+ "mcpServers": {
+ "my-server": {
+ "command": "node",
+ "args": ["./dist/index.js"],
+ "env": {}
+ },
+ "sqlite": {
+ "command": "node",
+ "args": ["./my-mcp-server/dist/db-server.js"],
+ "env": {
+ "DB_PATH": "/path/to/database.db"
+ }
+ }
+ }
+}
+
+ # 直接运行测试
+echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js
+
+# 使用 MCP Inspector
+npx @modelcontextprotocol/inspector node dist/index.js
+
+ // package.json
+{
+ "name": "my-mcp-server",
+ "version": "1.0.0",
+ "bin": {
+ "my-mcp-server": "./dist/index.js"
+ },
+ "files": ["dist"],
+ "scripts": {
+ "build": "tsc",
+ "prepublishOnly": "npm run build"
+ }
+}
+
+ # 发布到 npm
+npm publish
+
+# 用户可以这样使用
+npx my-mcp-server
+
+