DEV Community

韩

Posted on

MCP 的黑暗秘密:99% 开发者不知道的 5 个上下文优化隐藏技巧

MCP 的黑暗秘密:99% 开发者不知道的 5 个上下文优化隐藏技巧

Anthropic 一口气发了 9 个 connector,意外泄露了他们的整个创意产业战略。 但本周真正的故事不是 connector ——而是每个使用 MCP 的 AI Agent 内部正在悄悄发生的上下文危机。

如果你本周在看 Hacker News,你大概看到了这篇爆款帖:"这个 MCP 服务器把 Claude Code 的上下文消耗减少了 98%" —— 570 分,还在涨。作者 Mert Köseoğlu 展示了:一个 Playwright 快照就要消耗 56 KB 的 200K 上下文窗口。20 个 GitHub issue 要 59 KB。Agent 工作 30 分钟后,40% 的上下文就在 AI 处理用户消息之前消失了。

但这只是冰山一角。以下是 90% 用 MCP 开发的开发者不知道的事:

1. 工具定义正从两边吞噬你的上下文

大多数开发者以为 MCP 的"上下文问题"是工具返回的数据太大。并不是。是传入的工具定义太大了。

Cloudflare 的研究显示,工具定义可以用 "Code Mode" 压缩 99.9%。但用标准 MCP 方案,光是 81 个活跃工具,在你的第一条用户消息发出之前就已经消耗了 143K tokens。然后工具开始返回数据。

MCP 协议标准(GitHub 84K stars,10.5K forks,modelcontextprotocol/servers)每次请求都发送完整的 JSON schema。一个 Playwright MCP 工具定义就有约 8KB。

# 之前:原始 MCP 工具调用 —— 每次执行烧掉 56KB
# 来自典型 Playwright MCP 服务器的响应:
tool_result = {
    "html": "<!DOCTYPE html><html><head>...500行渲染后的DOM...",
    "screenshot": "base64编码的4MB图片",
    "accessibility_tree": {...15000个节点...}
}

# 之后:Context Mode MCP —— 压缩到 5.4KB(减少98%)
# MCP服务器在发送给Agent之前先过滤输出
class ContextModeServer:
    def __init__(self, max_output_tokens=512):
        self.max_output_tokens = max_output_tokens

    def execute_tool(self, tool_name, params):
        raw_result = self.delegate_to_real_server(tool_name, params)

        # 第一步:去除HTML/截图噪音
        cleaned = self.remove_noise(raw_result)

        # 第二步:语义压缩
        summary = self.summarize(cleaned, max_tokens=self.max_output_tokens)

        # 第三步:只返回LLM实际需要的内容
        return {"context_compressed": summary, "meta": {"saved_tokens": raw_result.size - summary.size}}

# 验证:315 KB → 5.4 KB(减少98%)
# 来源:https://mksg.lu/blog/context-mode
Enter fullscreen mode Exit fullscreen mode

解决方案不是少用工具——而是在工具输出进入上下文窗口之前加一个中间层来压缩。

2. MCP 多路复用模式:工具调用污染减少 19 倍

大多数 Agent 都是顺序执行 MCP 工具。每次工具调用都往上下文里加 tokens。但如果能一次性批处理多个工具调用呢?

# callmux: MCP多路复用器,工具调用上下文污染减少约19倍
# https://github.com/edimuj/callmux

import asyncio
from callmux import MCPMultiplexer

async def batch_code_review(mcp_server_url: str, pr_data: dict):
    """
    代替10个顺序工具调用(每次都有token开销),
    发送1个批量请求,上下文污染减少约19倍。
    """
    multiplexer = MCPMultiplexer(mcp_server_url)

    # 定义并行操作
    operations = [
        {"tool": "gh", "method": "get_pr_files", "params": {"pr": pr_data["number"]}},
        {"tool": "gh", "method": "get_pr_diff", "params": {"pr": pr_data["number"]}},
        {"tool": "gh", "method": "list_comments", "params": {"pr": pr_data["number"]}},
        {"tool": "filesystem", "method": "read_related", "params": {"files": pr_data["touched_files"]}},
        {"tool": "linter", "method": "analyze", "params": {"files": pr_data["touched_files"]}},
    ]

    # 单次批量调用 —— 1条上下文记录代替5条
    results = await multiplexer.execute_batch(operations, strategy="parallel")

    # 合并并去重结果
    return multiplexer.aggregate(results)

# 效果:工具调用开销减少约19倍
Enter fullscreen mode Exit fullscreen mode

这个模式对代码审查工作流特别有效——你同时调用 gh 获取 PR 数据、filesystem 读取相关文件、linter 做分析——全部并行。

3. 隐藏的 MCP 架构:主动模式 vs 被动模式

大多数开发者所有 MCP 服务器都跑在"主动模式"——每个工具定义、每条响应,永远都在流动。但有一个被动模式可以改变一切。

# 懒加载MCP:只在真正需要时才激活服务器
# 灵感来自GhidraMCP的懒工具加载模式
# https://github.com/bethington/ghidra-mcp

class LazyMCPLoader:
    def __init__(self, server_registry: dict):
        # 服务器注册表只存元数据,不存活跃连接
        self.server_registry = server_registry  
        self.active_servers = {}

    async def invoke(self, tool_name: str, params: dict):
        server_name = self._resolve_server(tool_name)

        # 懒初始化 —— 只在第一次使用时启动服务器
        if server_name not in self.active_servers:
            print(f"🔌 懒加载MCP服务器: {server_name}")
            self.active_servers[server_name] = await self._start_server(
                self.server_registry[server_name]
            )

        return await self.active_servers[server_name].invoke(tool_name, params)

    async def invoke_batch(self, tools: list):
        """预先热启动可能会一起使用的工具的服务器"""
        servers_needed = {self._resolve_server(t['tool']) for t in tools}
        for srv in servers_needed:
            if srv not in self.active_servers:
                self.active_servers[srv] = await self._start_server(
                    self.server_registry[srv]
                )

        # 现在所有服务器都预热好了,可以并行执行
        return await asyncio.gather(*[
            self.active_servers[self._resolve_server(t['tool'])].invoke(t['tool'], t['params'])
            for t in tools
        ])

# 注册服务器 —— 启动时只加载这些(全部!)
# 500字节 vs 50,000字节的工具定义
SERVER_REGISTRY = {
    "github": {"host": "localhost", "port": 3100, "tools": 23},
    "filesystem": {"host": "localhost", "port": 3101, "tools": 8},
    "ghidra": {"host": "localhost", "port": 3102, "tools": 110},  # 懒加载
}
Enter fullscreen mode Exit fullscreen mode

这正是 GhidraMCP 服务器 实现 110+ 逆向工程工具而不打爆上下文的方式——懒工具加载 + 批量预热。

4. RAG 增强型 MCP:代码库上下文注入,不再 token 爆炸

这个模式几乎没人提:不要把整个代码库都塞进 Agent 的上下文,而是用一个轻量级 MCP 工具按需回答关于代码的问题。

# ragtoolina: 为AI编码Agent添加代码库RAG的MCP工具
# https://www.ragtoolina.com

from ragtoolina import CodebaseRAG

rag = CodebaseRAG(project_root="./my-project")

# 不要再把50个文件都丢进上下文...
# ...先问RAG层
query = "认证中间件是怎么工作的?"
context_snippets = rag.query(query, top_k=3)

# 返回:
# [
#   {"file": "src/middleware/auth.py", "lines": "24-67", 
#    "content": "async def auth_middleware(req, ctx): ...", 
#    "relevance": 0.94},
#   {"file": "src/routes/auth.py", "lines": "1-30", 
#    "content": "@router.post('/login') async def login(req): ...", 
#    "relevance": 0.87}
# ]

# 现在Agent只收到500 tokens的高相关性上下文
# 而不是50,000 tokens的"全部倾倒"
Enter fullscreen mode Exit fullscreen mode

这个思路在 Hacker News 上被广泛讨论——你的 Agent 不需要知道代码库里的一切;它应该查询它需要的东西。

5. 多 Agent MCP 模式:分而治之你的上下文

最前沿的模式是把 MCP 分配给多个专业 Agent,每个 Agent 有自己独立的上下文窗口。

# Prism MCP: 多Agent集群 + 本地LLM
# https://github.com/dcostenco/prism-coder

class MCPAgentHivemind:
    """
    将MCP工具分配给不同的Agent。每个Agent获得全新的上下文。
    一个协调Agent综合结果。
    """

    def __init__(self, mcp_config: dict):
        # 每个子Agent获得自己的MCP服务器子集
        self.agents = {
            "backend": Agent(
                name="backend-dev",
                mcp_servers=["github", "docker", "postgres"],
                llm="prism-coder:7b"  # 本地,无API费用
            ),
            "frontend": Agent(
                name="frontend-dev", 
                mcp_servers=["playwright", "filesystem", "npm"],
                llm="prism-coder:7b"
            ),
            "security": Agent(
                name="security-reviewer",
                mcp_servers=["semgrep", "trivy", "ghidra"],
                llm="prism-coder:7b"
            ),
            "coordinator": Agent(
                name="coordinator",
                mcp_servers=["mcp_bridge"],  # 连接各子Agent
                llm="claude-sonnet-4"
            )
        }

    async def review_pr(self, pr_url: str):
        # 并行执行 —— 每个Agent获得自己干净的上下文
        backend_result = await self.agents["backend"].analyze(pr_url)
        frontend_result = await self.agents["frontend"].analyze(pr_url)
        security_result = await self.agents["security"].analyze(pr_url)

        # 协调Agent综合三个全新上下文
        final_report = await self.agents["coordinator"].synthesize({
            "backend": backend_result,
            "frontend": frontend_result,
            "security": security_result
        })

        return final_report

# 效果:3个Agent × 200K上下文 = 600K有效上下文
# vs 1个Agent只有200K,每次工具调用都会降级
Enter fullscreen mode Exit fullscreen mode

这对你意味着什么

MCP 生态已经大爆发——官方服务器仓库 84K stars,专门针对逆向工程WhatsApp文档搜索代码库 RAG 的 MCP 服务器百花齐放。但大多数开发者用得很原始。

现在正在发生的转变是:从"MCP 作为工具总线"到"MCP 作为上下文优化层"。本周 HN 570 分的那篇帖子只是开始。

"用了两年 vibe coding 之后,我又回去手写代码了。" — After two years of vibecoding, I'm back to writing by hand(HN 865 分)

对 AI 辅助编程的反弹不是 AI 不行——而是 Agent 没有节制地烧上下文。最先搞定上下文优化的开发者,将拥有最强悍的 Agent。


数据来源:


你在哪个MCP上下文优化技巧上省了最多tokens? 评论区见——特别想听听大家自建过哪些小众MCP服务器。

标签: AI, Programming, Github, Tutorial, MCP, DeveloperTools, LLM

Top comments (0)