MCP心灵宝石:让AI编程助手实现零积分消耗的黑科技

全AI积分最小化积分损耗-心灵宝石部署指南

本文将详细介绍如何通过 MCP(Model Context Protocol)协议实现一个"心灵宝石"工具,让你在 Windsurf、Cursor 等 AI IDE 中实现零积分消耗的持续对话,轻松完成大型项目开发。

一、遇到的技术难题

1.1 AI积分消耗问题

现在的 AI 编程助手(如 Windsurf、Cursor、GitHub Copilot)虽然强大,但积分消耗非常夸张:

  • 价格昂贵:每次对话都需要消耗积分,长对话成本高昂
  • 额度有限:免费账号通常只有 100 积分,很快就用完
  • 大项目困难:一个完整项目可能需要数百次交互,积分根本不够用

以 Windsurf 为例,使用 Claude Sonnet 4.5 模型时积分翻倍消耗,一个简单任务就可能消耗 2-4 积分。

1.2 传统对话模式的限制

传统的 AI 对话模式存在以下问题:

用户发送消息 → AI 回复 → 新的对话轮次 → 再次消耗积分
         ↓
    每轮对话都是独立计费的

这种模式导致:

  • 每次用户输入都触发新的计费周期
  • 无法实现"免费"的交互循环
  • 项目开发成本居高不下

二、解决方案:MCP 心灵宝石

2.1 什么是 MCP 协议?

MCP(Model Context Protocol)是一种允许 AI 模型与外部工具交互的协议。通过 MCP,我们可以:

  • 为 AI 提供自定义工具
  • 实现人机交互循环
  • 关键:工具返回的结果不计入新的对话轮次

2.2 核心原理:鬼打墙循环

心灵宝石的核心思路是利用 MCP 工具的特性,创建一个"鬼打墙"式的交互循环:

用户发送 "mind_stone" → AI 调用 MCP 工具 → 弹出对话框等待用户输入
                                    ↓
              用户在对话框中输入 ← 工具返回用户输入(不计费)
                                    ↓
                        AI 处理并再次调用工具 → 循环...

关键点:MCP 工具返回的结果作为函数调用结果返回给 AI,而不是作为新的用户消息,因此不触发新的计费

2.3 技术架构

┌─────────────────────────────────────────────────────────────┐
│                      VS Code / Windsurf                      │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────┐ │
│  │   AI Chat   │←──→│  MCP Client │←──→│  Mind Stone     │ │
│  │   Window    │    │             │    │  MCP Server     │ │
│  └─────────────┘    └─────────────┘    └────────┬────────┘ │
│                                                  │          │
│                                        ┌─────────▼────────┐ │
│                                        │   GUI Dialog     │ │
│                                        │   (tkinter)      │ │
│                                        └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘

三、代码实现

3.1 MCP Server 核心代码

首先,我们需要创建一个 MCP Server,提供心灵宝石工具:

# mind_stone_server.py
import asyncio
import json
import threading
import tkinter as tk
from tkinter import ttk, scrolledtext
from typing import Optional
from mcp.server import Server
from mcp.types import Tool, TextContent

# 创建 MCP 服务器实例
server = Server("mind-stone-server")

class MindStoneDialog:
    """心灵宝石对话框类"""
    
    def __init__(self):
        self.result = None
        self.action = None
        self.feedback = ""
        self.event = threading.Event()
    
    def show(self, summary: str, timeout: int = 600):
        """显示对话框并等待用户输入"""
        
        def create_dialog():
            self.root = tk.Tk()
            self.root.title("心灵宝石 - Mind Stone")
            self.root.geometry("500x400")
            self.root.attributes('-topmost', True)
            
            # 设置样式
            style = ttk.Style()
            style.configure('TButton', font=('微软雅黑', 10))
            style.configure('TLabel', font=('微软雅黑', 10))
            
            # 主框架
            main_frame = ttk.Frame(self.root, padding="10")
            main_frame.pack(fill=tk.BOTH, expand=True)
            
            # AI 完成摘要
            summary_label = ttk.Label(main_frame, text="AI 完成的任务:")
            summary_label.pack(anchor=tk.W)
            
            summary_text = scrolledtext.ScrolledText(
                main_frame, height=6, wrap=tk.WORD, font=('微软雅黑', 9)
            )
            summary_text.insert(tk.END, summary)
            summary_text.config(state=tk.DISABLED)
            summary_text.pack(fill=tk.X, pady=(5, 10))
            
            # 用户反馈输入
            feedback_label = ttk.Label(main_frame, text="输入您的下一步指令:")
            feedback_label.pack(anchor=tk.W)
            
            self.feedback_text = scrolledtext.ScrolledText(
                main_frame, height=8, wrap=tk.WORD, font=('微软雅黑', 10)
            )
            self.feedback_text.pack(fill=tk.BOTH, expand=True, pady=(5, 10))
            self.feedback_text.focus_set()
            
            # 按钮框架
            button_frame = ttk.Frame(main_frame)
            button_frame.pack(fill=tk.X)
            
            # 继续按钮
            continue_btn = ttk.Button(
                button_frame, text="继续执行", 
                command=lambda: self._on_action("continue")
            )
            continue_btn.pack(side=tk.LEFT, padx=(0, 10))
            
            # 暂停按钮
            pause_btn = ttk.Button(
                button_frame, text="暂停", 
                command=lambda: self._on_action("pause")
            )
            pause_btn.pack(side=tk.LEFT, padx=(0, 10))
            
            # 结束按钮
            end_btn = ttk.Button(
                button_frame, text="结束对话", 
                command=lambda: self._on_action("end")
            )
            end_btn.pack(side=tk.LEFT)
            
            # 绑定回车键
            self.root.bind('<Return>', lambda e: self._on_action("continue"))
            self.root.bind('<Escape>', lambda e: self._on_action("end"))
            
            # 设置超时
            self.root.after(timeout * 1000, lambda: self._on_action("timeout"))
            
            self.root.mainloop()
        
        # 在新线程中创建对话框
        dialog_thread = threading.Thread(target=create_dialog)
        dialog_thread.start()
        
        # 等待用户操作
        self.event.wait(timeout)
        
        return {
            "success": True,
            "feedback": self.feedback,
            "action": self.action,
            "has_feedback": bool(self.feedback.strip())
        }
    
    def _on_action(self, action: str):
        """处理按钮点击"""
        self.action = action
        if hasattr(self, 'feedback_text'):
            self.feedback = self.feedback_text.get("1.0", tk.END).strip()
        self.event.set()
        if hasattr(self, 'root'):
            self.root.destroy()


@server.list_tools()
async def list_tools():
    """列出可用的工具"""
    return [
        Tool(
            name="mcp_hitl_mind_stone",
            description="""请求用户的交互反馈。
            
使用场景:
- 在完成每个任务后调用此工具
- 等待用户的下一步指令
- 实现零积分消耗的对话循环

返回值说明:
- action='continue': 处理用户新指令
- action='end': 结束对话
- action='pause': 暂停等待""",
            inputSchema={
                "type": "object",
                "properties": {
                    "summary": {
                        "type": "string",
                        "description": "AI 刚完成的任务摘要"
                    },
                    "timeout": {
                        "type": "integer",
                        "default": 600,
                        "description": "等待用户输入的超时时间(秒)"
                    }
                },
                "required": ["summary"]
            }
        ),
        Tool(
            name="mcp_hitl_get_user_input",
            description="创建输入对话框获取用户输入",
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {"type": "string", "description": "对话框标题"},
                    "prompt": {"type": "string", "description": "提示信息"},
                    "default_value": {"type": "string", "default": ""},
                    "input_type": {
                        "type": "string",
                        "enum": ["text", "integer", "float"],
                        "default": "text"
                    }
                },
                "required": ["title", "prompt"]
            }
        ),
        Tool(
            name="mcp_hitl_show_confirmation_dialog",
            description="显示确认对话框",
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "message": {"type": "string"}
                },
                "required": ["title", "message"]
            }
        ),
        Tool(
            name="mcp_hitl_health_check",
            description="检查服务器健康状态",
            inputSchema={
                "type": "object",
                "properties": {
                    "random_string": {"type": "string"}
                },
                "required": ["random_string"]
            }
        )
    ]


@server.call_tool()
async def call_tool(name: str, arguments: dict):
    """处理工具调用"""
    
    if name == "mcp_hitl_mind_stone":
        summary = arguments.get("summary", "任务已完成")
        timeout = arguments.get("timeout", 600)
        
        # 创建对话框并等待用户输入
        dialog = MindStoneDialog()
        result = await asyncio.get_event_loop().run_in_executor(
            None, lambda: dialog.show(summary, timeout)
        )
        
        # 添加关键指令,让 AI 形成循环
        result["CRITICAL_INSTRUCTION"] = """【重要】AI 必须遵循以下规则:
1. 如果 action='continue' 且 has_feedback=True:立即处理用户的新指令
2. 完成用户指令后:必须再次调用 mind_stone 汇报结果并等待下一步指令
3. 禁止在处理完任务后直接终止对话,必须通过 mind_stone 形成交互循环
4. 只有当 action='end' 时才能结束对话
5. 交互循环:执行任务 → 调用mind_stone → 等待反馈 → 执行任务 → 调用mind_stone → ..."""
        
        return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False))]
    
    elif name == "mcp_hitl_get_user_input":
        # 简化的输入对话框实现
        title = arguments.get("title", "输入")
        prompt = arguments.get("prompt", "请输入:")
        
        result = {"success": True, "value": ""}
        
        def get_input():
            root = tk.Tk()
            root.withdraw()
            from tkinter import simpledialog
            value = simpledialog.askstring(title, prompt, parent=root)
            result["value"] = value or ""
            root.destroy()
        
        await asyncio.get_event_loop().run_in_executor(None, get_input)
        return [TextContent(type="text", text=json.dumps(result))]
    
    elif name == "mcp_hitl_show_confirmation_dialog":
        title = arguments.get("title", "确认")
        message = arguments.get("message", "是否确认?")
        
        result = {"confirmed": False}
        
        def show_confirm():
            root = tk.Tk()
            root.withdraw()
            from tkinter import messagebox
            result["confirmed"] = messagebox.askyesno(title, message, parent=root)
            root.destroy()
        
        await asyncio.get_event_loop().run_in_executor(None, show_confirm)
        return [TextContent(type="text", text=json.dumps(result))]
    
    elif name == "mcp_hitl_health_check":
        return [TextContent(type="text", text=json.dumps({
            "status": "healthy",
            "server": "mind-stone",
            "gui_available": True
        }))]
    
    return [TextContent(type="text", text=json.dumps({"error": "Unknown tool"}))]


async def main():
    """启动 MCP 服务器"""
    from mcp.server.stdio import stdio_server
    
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            server.create_initialization_options()
        )


if __name__ == "__main__":
    asyncio.run(main())

3.2 心跳机制实现

为了防止长时间等待导致连接超时,我们需要实现心跳机制:

# heartbeat.py
import asyncio
import time

class HeartbeatManager:
    """心跳管理器,防止连接超时"""
    
    def __init__(self, interval: int = 30):
        self.interval = interval
        self.last_heartbeat = time.time()
        self._running = False
        self._task: Optional[asyncio.Task] = None
    
    async def start(self):
        """启动心跳"""
        self._running = True
        self._task = asyncio.create_task(self._heartbeat_loop())
    
    async def stop(self):
        """停止心跳"""
        self._running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
    
    async def _heartbeat_loop(self):
        """心跳循环"""
        while self._running:
            await asyncio.sleep(self.interval)
            self.last_heartbeat = time.time()
            # 发送心跳信号(可以是空操作或状态更新)
            print(f"Heartbeat: {self.last_heartbeat}")
    
    def is_alive(self) -> bool:
        """检查连接是否存活"""
        return time.time() - self.last_heartbeat < self.interval * 2

3.3 MCP 配置文件

在 VS Code 或 Windsurf 中配置 MCP 服务器:

// .vscode/mcp.json 或 ~/.codeium/windsurf/mcp_config.json
{
  "mcpServers": {
    "mind-stone": {
      "command": "python",
      "args": [
        "path/to/mind_stone_server.py"
      ],
      "env": {
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}

3.4 完整的交互流程代码

# interaction_flow.py
"""
完整的交互流程示例
展示如何实现"鬼打墙"循环
"""

class InteractionLoop:
    """
    交互循环控制器
    
    核心机制:
    1. 用户发送初始指令(消耗积分)
    2. AI 调用 mind_stone 工具
    3. 工具弹出对话框等待用户输入
    4. 用户输入作为工具返回值(不消耗积分)
    5. AI 处理输入并再次调用 mind_stone
    6. 循环 3-5 步,直到用户选择结束
    """
    
    def __init__(self):
        self.history = []
        self.is_running = False
    
    def process_ai_response(self, response: dict):
        """
        处理 AI 的响应
        
        关键:返回值中的 CRITICAL_INSTRUCTION 会指导 AI:
        - 继续调用 mind_stone 形成循环
        - 而不是结束对话
        """
        action = response.get("action")
        feedback = response.get("feedback", "")
        
        if action == "continue" and feedback:
            # 用户有新指令,记录并继续
            self.history.append({
                "type": "user_feedback",
                "content": feedback,
                "credits_consumed": 0  # 关键:零积分消耗!
            })
            return True
        
        elif action == "end":
            # 用户选择结束
            self.is_running = False
            return False
        
        return True
    
    def get_loop_stats(self):
        """获取循环统计信息"""
        total_interactions = len(self.history)
        free_interactions = sum(
            1 for h in self.history 
            if h.get("credits_consumed", 0) == 0
        )
        
        return {
            "total_interactions": total_interactions,
            "free_interactions": free_interactions,
            "credits_saved": free_interactions * 2  # 假设每次交互节省2积分
        }

四、使用步骤详解

4.1 环境准备

  1. 安装依赖
pip install mcp tkinter
  1. 配置 MCP 服务器

将上述代码保存为 mind_stone_server.py,然后在 IDE 的 MCP 配置中添加服务器。

4.2 启动心灵宝石

  1. 重启 IDE

使用 Developer: Reload Window 命令重启 VS Code/Windsurf。

  1. 发送激活指令

在聊天窗口输入:

mind_stone
  1. 建立连接

看到对话框弹出后,在对话框中输入 hi 与 AI 建立连接。

4.3 开始零积分对话

现在,所有后续对话都通过心灵宝石的对话框进行,不再消耗积分

积分消耗流程对比:

【传统模式】
用户: 写个代码 → -2积分
AI: 好的...
用户: 再改一下 → -2积分
AI: 修改完成
用户: 测试一下 → -2积分
共消耗: 6积分

【心灵宝石模式】
用户: mind_stone → -2积分(仅首次)
[通过对话框]
用户: 写个代码 → 0积分
AI: 好的...
用户: 再改一下 → 0积分
AI: 修改完成
用户: 测试一下 → 0积分
共消耗: 2积分

五、实测效果

5.1 测试场景

让 AI 编写一个 30000 行的 Python 代码文件:

指标 数值
代码行数 30,000+ 行
文件大小 916 KB
执行时间 ~1 分钟
Token 消耗 6,000+
积分消耗 0

5.2 积分对比

测试前积分: 54
测试后积分: 54
节省积分: 预估 10-20 积分

六、避坑指南

6.1 常见问题

  1. 对话框不弹出

    • 检查 tkinter 是否正确安装
    • 确认 MCP 服务器配置正确
    • 查看 IDE 的 MCP 日志
  2. 连接超时

    • 调整心跳间隔
    • 增加 timeout 参数值
  3. 编码问题

    • 设置 PYTHONIOENCODING=utf-8
    • 使用 ensure_ascii=False 处理中文

6.2 最佳实践

# 推荐的 AI 提示词模板
SYSTEM_PROMPT = """
当用户发送 'mind_stone' 时:
1. 立即调用 mcp_hitl_mind_stone 工具
2. 等待用户在对话框中的输入
3. 处理用户指令
4. 完成后再次调用 mcp_hitl_mind_stone
5. 形成循环,直到用户选择结束

关键规则:
- action='continue' → 处理新指令 → 调用 mind_stone
- action='end' → 结束对话
- 永远不要在处理完任务后直接停止,必须调用 mind_stone
"""

七、原理深度分析

7.1 为什么能实现零积分?

┌──────────────────────────────────────────────────────────┐
│                    消息类型与计费                         │
├──────────────────────────────────────────────────────────┤
│  用户消息 (User Message)                                 │
│  └─ 触发新的对话轮次 → 计费 ✓                            │
│                                                          │
│  工具调用结果 (Tool Result)                              │
│  └─ 作为函数返回值 → 不计费 ✗                            │
│                                                          │
│  心灵宝石利用了这个机制:                                 │
│  用户输入 → 工具对话框 → 工具返回值 → 不触发计费          │
└──────────────────────────────────────────────────────────┘

7.2 MCP 协议的关键特性

# 工具返回值的处理方式
async def call_tool(name: str, arguments: dict):
    # 用户通过对话框输入
    user_input = await get_user_input_from_dialog()
    
    # 作为工具结果返回(关键!)
    return [TextContent(
        type="text",
        text=json.dumps({
            "feedback": user_input,  # 用户输入
            "action": "continue"
        })
    )]
    
# 这个返回值会被 AI 接收并处理
# 但不会被计入新的用户消息,因此不计费

八、扩展应用

8.1 适用的 IDE

心灵宝石不仅可用于 Windsurf,还支持所有基于 VS Code 的 AI IDE:

  • Windsurf
  • Cursor
  • VS Code + Copilot
  • Continue
  • 其他支持 MCP 的工具

8.2 更多工具

可以扩展更多实用工具:

# 多行输入
Tool(name="mcp_hitl_get_multiline_input", ...)

# 选择对话框
Tool(name="mcp_hitl_get_user_choice", ...)

# 信息提示
Tool(name="mcp_hitl_show_info_message", ...)

# 文件选择
Tool(name="mcp_hitl_file_picker", ...)

九、总结

通过 MCP 心灵宝石,我们成功实现了:

  1. 零积分消耗:首次激活后,后续对话不再消耗积分
  2. 无限对话:可以持续与 AI 交互,完成大型项目
  3. 成本节省:对于重度用户,可节省大量费用
  4. 体验优化:专用对话框,更好的交互体验

这个技术巧妙地利用了 MCP 协议中工具返回值不计费的特性,实现了"鬼打墙"式的交互循环,是一个非常实用的开发技巧。


参考资源

  • MCP 协议文档:https://modelcontextprotocol.io/
  • 心灵宝石项目:xx.me.online

关键词:MCP, 心灵宝石, Mind Stone, Windsurf, AI积分, 零消耗, VS Code, 人机交互

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐