1. 项目概述一个为AI代理提供结构化数据访问的“翻译官”最近在折腾AI代理Agent应用开发的朋友估计都绕不开一个核心问题如何让AI安全、高效地访问外部工具和数据无论是让AI帮你查数据库、读文档还是操作第三方API你总不能直接把数据库密码或API密钥一股脑塞给大模型吧这不仅不安全而且不同工具五花八门的接口格式也足以让AI“晕头转向”。这正是strands-agents/mcp-server这个项目要解决的痛点。简单来说它是一个实现了模型上下文协议Model Context Protocol, MCP的服务器端实现。你可以把它理解为一个“翻译官”或“安全网关”专门负责在AI代理比如Claude Desktop、Cursor等支持MCP的客户端和外部资源如文件系统、数据库、API服务之间架起一座标准化的桥梁。想象一下你有一个AI助手你想让它帮你分析项目目录下的代码结构。没有MCP你可能需要写一个复杂的插件处理文件读取、路径解析、格式转换等一系列脏活累活。而有了strands-agents/mcp-server你只需要按照MCP的标准实现几个核心的“工具”Tools和“资源”Resources接口你的AI助手就能通过标准协议像调用本地函数一样安全地请求“列出/src目录下的所有Python文件”或“读取config.yaml文件的内容”。这个服务器负责处理所有底层的IO操作、权限校验和数据格式转换最终将结构化的结果返回给AI。这个项目由Strands-Agents团队维护它不是一个孤立的工具而是整个MCP生态中的一个关键组件。MCP是由Anthropic主导推动的一个开放协议旨在标准化AI应用与外部数据和工具之间的交互方式。strands-agents/mcp-server提供了一个高质量的、可扩展的参考实现让开发者能够快速构建自己的MCP服务器从而将任何数据源或工具无缝集成到支持MCP的AI应用中去。对于想要构建复杂AI工作流、提升AI代理能力的开发者而言理解和运用这个项目相当于掌握了一把开启AI“外挂”能力的钥匙。2. MCP协议核心思想与架构拆解要真正用好strands-agents/mcp-server我们必须先吃透MCP协议的设计哲学。它解决的远不止是“让AI读文件”这么简单其核心目标是建立一套安全、声明式、可发现的上下文供给机制。2.1 为什么是“协议”而非“库”这是第一个关键点。MCP是一个协议类似于HTTP或WebSocket它定义了客户端AI应用与服务器数据/工具提供方之间通信的格式、语义和生命周期。strands-agents/mcp-server是这个协议的一个服务端实现。这种设计带来了巨大优势语言和框架无关性客户端可以用TypeScript写服务器可以用Python就像本项目、Go或Rust实现。只要双方遵守同一份协议规范就能互通。进程隔离与安全性服务器通常作为一个独立的进程运行。这意味着即使服务器进程崩溃也不会拖垮主AI应用。更重要的是服务器可以被严格限制权限例如只能访问某个特定目录实现了安全的沙箱环境。动态可插拔AI应用可以在运行时动态加载和卸载不同的MCP服务器无需重启。用户可以根据需要随时为AI助手“安装”新的能力模块比如一个专读数据库的服务器或一个专管日历的服务器。2.2 核心概念工具、资源与提示模板MCP协议定义了三种主要的上下文类型这也是你在实现一个MCP服务器时需要关注的核心工具Tools这是AI可以主动调用的“函数”。每个工具都有名称、描述和严格的输入参数模式基于JSON Schema定义。例如你可以定义一个名为search_files的工具参数是query搜索关键词和root_path搜索根目录。当AI需要搜索文件时它会通过MCP协议调用这个工具服务器执行搜索逻辑并返回结果。注意工具描述至关重要。清晰、准确的描述直接决定了AI是否能正确理解和使用这个工具。避免使用晦涩的技术术语用AI能理解的日常语言描述工具的功能和参数。资源Resources代表AI可以读取的静态或动态数据“URI”。资源有唯一的uri标识如file:///home/user/project/README.md或db://users/table?limit10和一个mimeType。服务器可以声明自己提供了哪些资源当AI需要某个资源的内容时会向服务器发起请求。与工具不同资源是“被动”提供数据的。静态资源内容基本不变如配置文件模板。动态资源内容随时间或查询条件变化如“当前系统状态”或“数据库查询结果视图”。服务器可以通知客户端资源内容已更新。提示模板Prompts预定义的对话提示片段。这允许服务器提供一些复杂的、结构化的提示词AI可以直接引用或组合使用确保特定任务执行的规范性和一致性。例如一个代码审查服务器可以提供名为“code_review_standard”的提示模板里面包含了详细的审查清单和格式要求。strands-agents/mcp-server的架构就是围绕实现对这些概念的声明、管理和服务来构建的。它内部会维护这些组件的注册表处理来自客户端的标准化请求如tools/list,tools/call,resources/list,resources/read并调用你实现的具体业务逻辑。2.3 通信层Stdio与SSEMCP协议目前主要支持两种传输方式strands-agents/mcp-server对此都有良好的支持Stdio标准输入/输出这是最常用、最简单的模式。服务器作为一个子进程启动通过stdin接收JSON-RPC请求通过stdout发送JSON-RPC响应。这种方式部署简单适合大多数本地集成场景。Claude Desktop默认就使用这种方式加载MCP服务器。SSE服务器发送事件这是一种基于HTTP的协议允许服务器主动向客户端推送事件如资源更新通知。SSE模式更适合服务器需要长期运行并主动推送信息的场景例如监控日志或实时数据流。在项目实践中Stdio模式足以应对90%的需求。你需要确保你的服务器实现能够正确解析来自stdin的JSON行并将响应输出到stdout。3. 从零构建一个自定义MCP服务器的实战指南了解了理论我们动手实现一个具体的MCP服务器。假设我们要构建一个“项目分析助手”它能让AI读取项目文件、分析依赖关系。我们将基于strands-agents/mcp-server这个Python实现来开发。3.1 环境准备与项目初始化首先确保你的环境有Python 3.8。然后创建一个新的项目目录并安装核心依赖。mkdir my-project-analyzer-server cd my-project-analyzer-server python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install mcp[cli] # 安装MCP库包含CLI工具strands-agents/mcp-server项目本身是一个库我们通过安装mcp包来获取其核心功能。接下来创建我们的服务器入口文件server.py。# server.py import anyio import click from mcp import ClientOptions, StdioServerParameters from mcp.server import Server from mcp.server.models import InitializationOptions import mcp.server.stdio from typing import Any # 创建Server实例 app Server(project-analyzer) app.list_tools() async def handle_list_tools() - list[Any]: 列出所有可用的工具 # 我们将在后续步骤中添加工具定义 return [] app.list_resources() async def handle_list_resources() - list[Any]: 列出所有可用的资源 # 我们将在后续步骤中添加资源定义 return [] async def main(): # 配置Stdio通信参数 server_params StdioServerParameters( commandpython, args[server.py, run], # 这里指向自身实际会通过子进程调用 envNone, ) async with mcp.server.stdio.stdio_server(server_params) as (read_stream, write_stream): await app.run( read_stream, write_stream, InitializationOptions( server_nameproject-analyzer, server_version0.1.0, capabilitiesapp.get_capabilities( notification_optionsNone, experimental_capabilities{}, ), ), ) if __name__ __main__: anyio.run(main)这是一个最简骨架。目前它还不能做任何事但已经是一个能跑通的MCP服务器。你可以用MCP CLI工具测试它# 在另一个终端安装mcp cli如果尚未安装 pip install mcp[cli] # 运行测试连接到我们的服务器 mcp dev server.py如果看到连接成功的日志说明基础框架搭建正确。3.2 实现核心工具文件系统浏览与依赖分析现在让我们添加两个实用的工具。工具一list_project_files- 列出项目文件结构这个工具允许AI获取指定目录下的文件树帮助它了解项目布局。from mcp.server.models import Tool from pydantic import BaseModel, Field from pathlib import Path import os class ListProjectFilesArgs(BaseModel): 列出项目文件的参数 root_path: str Field( default., description项目的根目录路径。默认为当前目录。 ) max_depth: int Field( default3, description遍历的最大深度。避免过深的目录导致响应过载。, ge1, le10 ) app.list_tools() async def handle_list_tools() - list[Tool]: return [ Tool( namelist_project_files, description列出指定目录下的文件树结构帮助了解项目布局。, inputSchemaListProjectFilesArgs.model_json_schema(), ), # 后续会添加第二个工具 ] app.call_tool() async def handle_call_tool(name: str, arguments: dict) - list[Any]: 处理工具调用请求 if name list_project_files: args ListProjectFilesArgs(**arguments) return await list_project_files(args.root_path, args.max_depth) # 后续添加其他工具的处理逻辑 raise ValueError(f未知的工具: {name}) async def list_project_files(root_path: str, max_depth: int) - list[str]: 实际执行文件列表的逻辑 result_lines [] root Path(root_path).resolve() if not root.exists() or not root.is_dir(): return [f错误路径 {root_path} 不存在或不是一个目录。] for current_path in root.rglob(*): try: # 计算深度 depth len(current_path.relative_to(root).parts) if depth max_depth: continue indent * depth if current_path.is_dir(): result_lines.append(f{indent}{current_path.name}/) else: # 可以附加文件大小等信息 size current_path.stat().st_size result_lines.append(f{indent}{current_path.name} ({size} bytes)) except (PermissionError, OSError) as e: result_lines.append(f{indent}[无法访问: {current_path.name}]) # 如果结果太多进行截断 if len(result_lines) 200: result_lines result_lines[:200] result_lines.append(... (已截断文件过多)) return [{type: text, text: \n.join(result_lines)}]工具二analyze_python_dependencies- 分析Python项目依赖这个工具更专业它会解析pyproject.toml或requirements.txt提取依赖信息。import tomli # 需要 pip install tomli from typing import Optional class AnalyzeDependenciesArgs(BaseModel): 分析项目依赖的参数 project_path: str Field( default., description包含pyproject.toml或requirements.txt的项目路径。 ) # 更新工具列表 app.list_tools() async def handle_list_tools() - list[Tool]: return [ Tool( namelist_project_files, description列出指定目录下的文件树结构帮助了解项目布局。, inputSchemaListProjectFilesArgs.model_json_schema(), ), Tool( nameanalyze_python_dependencies, description分析Python项目的依赖关系从pyproject.toml或requirements.txt中提取。, inputSchemaAnalyzeDependenciesArgs.model_json_schema(), ) ] # 更新工具调用处理器 app.call_tool() async def handle_call_tool(name: str, arguments: dict) - list[Any]: if name list_project_files: args ListProjectFilesArgs(**arguments) return await list_project_files(args.root_path, args.max_depth) elif name analyze_python_dependencies: args AnalyzeDependenciesArgs(**arguments) return await analyze_python_dependencies(args.project_path) raise ValueError(f未知的工具: {name}) async def analyze_python_dependencies(project_path: str) - list[str]: 分析Python依赖 path Path(project_path) dependencies [] # 1. 尝试解析 pyproject.toml (PEP 621标准) pyproject_toml path / pyproject.toml if pyproject_toml.exists(): try: with open(pyproject_toml, rb) as f: data tomli.load(f) deps data.get(project, {}).get(dependencies, []) if deps: dependencies.extend(deps) return [{type: text, text: f从pyproject.toml发现依赖: {, .join(deps)}}] except Exception as e: pass # 解析失败尝试其他文件 # 2. 尝试解析 requirements.txt req_file path / requirements.txt if req_file.exists(): try: with open(req_file, r) as f: deps [] for line in f: line line.strip() if line and not line.startswith(#): deps.append(line.split()[0].split()[0]) # 提取包名 if deps: return [{type: text, text: f从requirements.txt发现依赖: {, .join(deps)}}] except Exception as e: pass return [{type: text, text: 未找到明确的依赖配置文件 (pyproject.toml 或 requirements.txt)。}]实操心得在实现工具时输入参数的JSON Schema定义是重中之重。使用Pydantic的Field和description为每个参数提供清晰、具体的描述。AI尤其是Claude会仔细阅读这些描述来决定如何调用工具。模糊的描述会导致AI误用或不敢用。例如root_path的描述明确指出了默认值和用途max_depth则说明了限制原因和取值范围。3.3 实现动态资源暴露项目概览除了工具我们还可以提供资源。假设我们想提供一个动态资源显示项目的基本统计信息。from mcp.server.models import Resource app.list_resources() async def handle_list_resources() - list[Resource]: 声明本服务器提供的资源 return [ Resource( uriproject://overview, name项目概览, description当前项目的基本统计信息文件数、类型分布等。, mimeTypetext/plain, ) ] app.read_resource() async def handle_read_resource(uri: str) - str: 处理资源读取请求 if uri project://overview: return await generate_project_overview() raise ValueError(f未知的资源URI: {uri}) async def generate_project_overview() - str: 生成项目概览内容 import os from collections import Counter stats { total_files: 0, total_dirs: 0, by_extension: Counter(), total_size_kb: 0, } for root, dirs, files in os.walk(.): stats[total_dirs] len(dirs) for file in files: stats[total_files] 1 _, ext os.path.splitext(file) stats[by_extension][ext.lower()] 1 filepath os.path.join(root, file) try: stats[total_size_kb] os.path.getsize(filepath) / 1024 except OSError: pass # 格式化输出 output_lines [ 项目概览 , f总目录数: {stats[total_dirs]}, f总文件数: {stats[total_files]}, f总大小: {stats[total_size_kb]:.2f} KB, , 文件类型分布:, ] for ext, count in stats[by_extension].most_common(10): if ext: # 忽略无扩展名的文件 output_lines.append(f {ext or (无扩展名)}: {count} 个) return \n.join(output_lines)现在AI客户端就可以通过读取project://overview这个URI直接获取到项目的动态统计信息而无需调用工具。这对于需要快速了解项目背景的场景非常有用。3.4 配置与运行集成到Claude Desktop开发完成后我们需要让Claude Desktop能发现并加载我们的服务器。这需要通过一个配置文件来完成。在Claude Desktop的MCP服务器配置目录通常是~/.config/claude/mcp-servers/或%APPDATA%\Claude\mcp-servers\下创建一个JSON配置文件例如my_project_analyzer.json{ mcpServers: { project-analyzer: { command: /absolute/path/to/your/venv/bin/python, args: [/absolute/path/to/your/project/server.py], env: { PYTHONPATH: /absolute/path/to/your/project } } } }关键细节command必须使用虚拟环境venv中Python解释器的绝对路径。直接写python可能因为环境变量问题导致找不到正确的依赖。args服务器入口脚本的绝对路径。env可以设置必要的环境变量确保你的代码能正确导入模块。保存配置文件后重启Claude Desktop。在Claude的输入框里你应该能看到一个新的“工具”图标点击后能发现list_project_files和analyze_python_dependencies这两个工具。现在你就可以直接对Claude说“请用list_project_files工具看看我这个项目里有什么root_path设为.max_depth设为2。”Claude就会通过你写的MCP服务器获取并展示文件列表了。4. 高级特性与性能优化实战一个基础的MCP服务器跑起来后我们还需要关注它的健壮性、性能和扩展性。strands-agents/mcp-server库提供了一些高级特性来帮助我们。4.1 实现资源变更通知对于动态资源如project://overview项目文件变化后其内容可能过时。MCP支持服务器主动通知客户端资源已更新。这需要用到SSE传输模式但即使在Stdio模式下我们也可以实现一个简化的“提示”机制。我们可以修改工具使其在更改项目状态后触发一个逻辑上的“资源更新事件”。虽然Stdio模式下不能主动推送但我们可以让工具返回一个特殊的提示建议AI重新读取资源。async def list_project_files(root_path: str, max_depth: int) - list[Any]: # ... 原有的文件列表逻辑 ... result_text \n.join(result_lines) # 在返回文件列表的同时附加一个提示告知概览资源可能需要更新 return [ {type: text, text: result_text}, { type: text, text: 提示项目文件结构已变动project://overview资源中的统计信息可能已过期如需最新数据请重新读取该资源。 } ]更高级的实现需要用到app.request_context和更复杂的事件机制但对于大多数场景上述提示已足够。4.2 错误处理与日志记录生产级的MCP服务器必须有完善的错误处理。strands-agents/mcp-server的app.call_tool()装饰器会自动捕获异常并返回给客户端但信息可能不够友好。最佳实践是进行分层错误处理from mcp.server.exceptions import ToolExecutionError import traceback app.call_tool() async def handle_call_tool(name: str, arguments: dict) - list[Any]: try: if name list_project_files: args ListProjectFilesArgs(**arguments) # 增加前置验证 target_path Path(args.root_path).resolve() if not target_path.exists(): raise ToolExecutionError(f路径不存在: {args.root_path}) if not target_path.is_dir(): raise ToolExecutionError(f路径不是一个目录: {args.root_path}) # 安全检查防止路径遍历攻击 current_dir Path.cwd().resolve() if not target_path.is_relative_to(current_dir): raise ToolExecutionError(f访问路径超出允许范围。) return await list_project_files(args.root_path, args.max_depth) # ... 其他工具 ... except ToolExecutionError: # 已知的业务错误直接抛出 raise except Exception as e: # 未知的系统错误记录日志并返回友好信息 error_detail traceback.format_exc() # 在实际项目中这里应该写入日志文件或监控系统 print(f[ERROR] 工具 {name} 执行失败: {error_detail}, flushTrue) raise ToolExecutionError(f执行工具 {name} 时发生内部错误。请稍后重试或检查服务器日志。)同时建议为你的服务器配置一个简单的日志系统将运行日志、错误堆栈输出到文件便于排查问题。4.3 性能考量异步与缓存MCP服务器本质是一个IO密集型的网络服务即使是Stdio。strands-agents/mcp-server基于anyio天然支持异步操作。在实现工具时务必使用async/await并在执行可能阻塞的操作如文件IO、网络请求时使用对应的异步库或使用anyio.to_thread.run_sync将同步函数放到线程池中执行避免阻塞整个事件循环。对于计算密集或IO开销大的操作如遍历巨型目录、复杂分析引入缓存机制可以大幅提升响应速度。from functools import lru_cache import anyio # 同步的、耗时的计算函数 def _compute_expensive_overview(path: str) - dict: # ... 耗时的统计计算 ... return result_stats app.read_resource() async def handle_read_resource(uri: str) - str: if uri project://overview: # 将同步的耗时函数放到线程池中运行避免阻塞事件循环 stats await anyio.to_thread.run_sync( _compute_expensive_overview, ., cancellableTrue ) return format_stats(stats)对于工具结果可以根据业务逻辑决定是否缓存。例如list_project_files的结果变化频繁不适合长期缓存。但analyze_python_dependencies的结果在依赖文件不变的情况下是稳定的可以设置一个短期缓存。from datetime import datetime, timedelta _deps_cache {} _deps_cache_time {} async def analyze_python_dependencies(project_path: str) - list[str]: cache_key project_path now datetime.now() # 检查缓存5分钟内有效 if cache_key in _deps_cache and _deps_cache_time.get(cache_key, now) now - timedelta(minutes5): return _deps_cache[cache_key] # ... 执行实际的分析逻辑 ... result [{type: text, text: f发现依赖: {deps_str}}] # 更新缓存 _deps_cache[cache_key] result _deps_cache_time[cache_key] now return result5. 调试、测试与常见问题排查开发MCP服务器过程中调试是必不可少的环节。由于服务器运行在独立的子进程中传统的print调试可能不方便查看。5.1 使用MCP CLI进行本地调试mcp包自带的CLI工具是开发和调试的利器。# 1. 最简测试检查服务器是否能正常启动和握手 mcp dev server.py # 2. 更详细的测试可以模拟客户端请求 # 首先在一个终端启动服务器进入调试模式 mcp dev --verbose server.py # 这会启动服务器并保持连接等待请求。 # 3. 在另一个终端使用mcp inspect工具发送测试请求 # 首先找到服务器启动后监听的stdio通道通常是一个socket文件。 # 更简单的方法是使用 mcp dev 自带的测试功能或者编写一个简单的测试脚本。一个更实用的方法是编写一个简单的测试客户端脚本# test_client.py import asyncio import json import subprocess import sys async def test_tool(): # 启动服务器子进程 proc await asyncio.create_subprocess_exec( sys.executable, server.py, stdinsubprocess.PIPE, stdoutsubprocess.PIPE, stderrsubprocess.PIPE, ) # 构建一个标准的MCP请求列出所有工具 request { jsonrpc: 2.0, id: 1, method: tools/list, params: {} } # 发送请求 proc.stdin.write((json.dumps(request) \n).encode()) await proc.stdin.drain() # 读取响应 line await proc.stdout.readline() response json.loads(line.decode()) print(服务器响应:, json.dumps(response, indent2)) # 清理 proc.terminate() await proc.wait() if __name__ __main__: asyncio.run(test_tool())运行这个脚本可以验证你的服务器是否能正确响应基本的协议请求。5.2 集成测试与模拟对于更复杂的逻辑建议为你的工具函数编写单元测试独立于MCP协议层。这能确保核心业务逻辑的正确性。# test_tools.py import pytest from pathlib import Path import tempfile from your_server_module import list_project_files, analyze_python_dependencies pytest.mark.asyncio async def test_list_project_files(): with tempfile.TemporaryDirectory() as tmpdir: # 在临时目录创建测试文件结构 (Path(tmpdir) / test.txt).write_text(hello) (Path(tmpdir) / subdir).mkdir() (Path(tmpdir) / subdir / app.py).write_text(print(hi)) result await list_project_files(tmpdir, max_depth2) # 断言结果中包含预期的文件和目录 assert any(test.txt in item[text] for item in result) assert any(subdir/ in item[text] for item in result)5.3 常见问题与解决方案速查表在实际开发和部署中你可能会遇到以下典型问题问题现象可能原因排查步骤与解决方案Claude Desktop无法加载服务器提示“连接失败”或“初始化错误”。1. 配置文件路径错误。2. 命令或参数使用了相对路径。3. Python环境缺少依赖。1.检查配置文件路径确保JSON文件放在正确的Claude MCP配置目录。2.使用绝对路径将command和args中的路径全部改为绝对路径。3.验证环境在终端手动用配置文件中的命令运行服务器脚本看是否报错如ModuleNotFoundError。确保虚拟环境已激活且安装了mcp包。工具在Claude中可见但调用时失败返回“内部错误”。1. 工具处理函数抛出未捕获的异常。2. 参数验证失败。3. 异步函数被阻塞。1.查看服务器日志确保你的服务器将错误输出到stderrClaude Desktop可能会捕获并显示。在代码中添加print或日志记录到文件。2.简化测试先用一个最简单的工具如返回固定字符串测试排除业务逻辑问题。3.检查参数确保AI传递的参数完全符合你定义的JSON Schema。可以在工具函数开头打印arguments参数进行验证。服务器启动慢或工具响应延迟高。1. 服务器启动时加载了重型资源。2. 工具函数执行了同步阻塞操作。3. 没有缓存。1.延迟初始化将耗时的初始化操作移到第一次请求时进行或使用异步方式。2.异步化将文件读写、网络请求等操作改为使用aiofiles、httpx等异步库或用anyio.to_thread.run_sync包装。3.引入缓存对计算结果稳定的工具或资源实施缓存策略。资源内容不更新。1. 资源是静态的未实现动态更新逻辑。2. 客户端未订阅资源更新通知SSE模式。1.检查资源实现read_resource处理函数是否每次都重新生成内容对于动态资源应避免返回固定值。2.Stdio模式限制在Stdio模式下服务器无法主动推送更新。可以考虑在相关工具被调用后让工具返回提示建议AI“重新读取”资源。或者仅在SSE模式下实现完整的通知机制。权限问题无法访问特定路径。1. 服务器进程运行用户权限不足。2. 路径访问越界安全限制。1.明确权限边界在工具描述中说明可访问的范围。在代码中进行路径解析和安全性检查确保访问路径在允许的根目录之下如前文示例中的is_relative_to检查。2.提升权限需谨慎尽量避免让MCP服务器以高权限运行。如果必须访问特定受限路径考虑通过配置白名单的方式。5.4 安全最佳实践最后安全是MCP服务器设计的生命线。请务必遵循以下原则最小权限原则服务器进程应以尽可能低的权限运行。在配置中可以通过env和环境变量来限制其访问范围如设置一个PROJECT_ROOT环境变量所有文件操作都限制在此目录下。输入验证与消毒对所有来自客户端的输入如文件路径、URL参数进行严格的验证和消毒。防止路径遍历../../../etc/passwd、命令注入等攻击。敏感信息隔离绝对不要在工具描述、返回内容或日志中泄露API密钥、数据库密码、个人令牌等敏感信息。这些应通过环境变量或安全的配置管理系统传入。超时与限流为长时间运行的工具设置超时限制。考虑对复杂或耗资源的工具实现限流防止被滥用导致服务器资源耗尽。审计与日志记录关键操作日志如工具调用、资源访问便于事后审计和问题追踪。但注意日志中也不要包含敏感数据。构建一个健壮、安全、高效的MCP服务器是一个持续迭代的过程。从strands-agents/mcp-server这个优秀的参考实现出发理解协议本质关注细节处理你就能为你的AI助手打造出强大而可靠的数据与工具桥梁。