Easy Code Reader 最佳实践
Easy Code Reader 特别适合与 Claude、ChatGPT 等大模型配合使用,接下来以 JoyCode 结合 Claude4 为例,介绍最佳实践:
1. 跨项目调用,根据调用链路分析源码
在比较复杂的项目中一般会拆分多个微服务,某些功能的实现可能会跨多个项目调用,如果靠人梳理相关逻辑会比较耗时,所以可以将涉及的代码 clone 到本地后使用 Code Agent 结合 Easy Code Reader MCP 进行分析。接下来我们以实际业务项目为例,来通过两个例子来演示最佳实践:
解析跨项目的 JSF RPC 调用
我们先来看一个比较简单的例子,比如在本地应用 application-a 中存在以下调用逻辑,其中 YbServiceSubmitOrderPaasResource#submitOrderPaaS 是跨项目的 JSF RPC 调用:
public class YbServiceSubmitOrderRpcImpl implements YbServiceSubmitOrderRpc {private YbServiceSubmitOrderPaasResource ybServiceSubmitOrderPaasResource;public String newSubmitOrder(YbSubmitOrderReq submitOrderReq) {if (log.isInfoEnabled()) {log.info("[提交订单]请求开始,参数-submitOrderReq:" +JSON.toJSONString(submitOrderReq));}String result;try {Result<String> rpcResult = ybServiceSubmitOrderPaasResource.submitOrderPaaS(submitOrderReq);if (log.isInfoEnabled()) {log.info("[提交订单]rpc请求结束,结果-rpcResult:{}" , JSON.toJSONString(rpcResult));}if (rpcResult == null) {throw new RuntimeException("调用接口结果为空");}if (!rpcResult.getSuccess()) {throw new RuntimeException(rpcResult.getCode());}result = rpcResult.getData();} catch (Throwable t) {String logStr = "[提交订单]请求出错,参数-submitOrderReq:" +JSON.toJSONString(submitOrderReq);log.error(logStr, t);throw t;}if (log.isInfoEnabled()) {log.info("[提交订单]请求结束,结果-result:{}" , result);}return result;}}
如果我想要了解 submitOrderPaaS的逻辑,那么我可能要打开相关的项目代码再去一步步找到对应的逻辑。但是如果借助 Easy Code Reader MCP Server 的话,那么便可以通过它来快速了解这个 RPC 接口的实现细节,下面是一个示例 Prompt:
你是一位 Java 技术专家,我想知道 @/xxx/YbServiceSubmitOrderRpcImpl.java 中调用的 Result<String> rpcResult = ybServiceSubmitOrderPaasResource.submitOrderPaaS(submitOrderReq); 方法实现逻辑是什么,这个方法真正的实现逻辑可能在本地项目的 rpc-pxxxorm 或 rpc-pxxxorm-export 中,请你使用 easy-code-reader MCP 检查相应地目录和文件,帮我找到核心实现逻辑并解释它的实现原理
如图所示,它会不断地根据源码调用链路,读取相关源码并进行分析,最终我们就能了解这个 RPC 接口的实现细节,在这个过程会使用到 MCP Easy Code Reader 提供的多个工具,使用 list_all_project 来找到对应的本地项目;使用list_project_files 查找可能相关的文件;使用 read_project_code来阅读源码,根据结果来总结实现原理。
解析消息驱动的分布式事务(协同式 Saga)
在这里我们让 JoyCode 帮我们处理一个相对复杂的任务,在我们的业务中“某类型订单下单流程”使用了协同式 Saga 保证数据的一致性,在这个流程中跨越多个应用且流程复杂,我们可以借助 JoyCode 帮我们从下单消息的接收开始分析,直到最终数据库收单完成。
开始任务时采用的是以下 Prompt,并且使用的是 “智能体团队” 智能体,这个智能体能开启多个任务,避免单一任务上下文太长:
你是一位 Java 技术专家,熟悉分布式事务的原理,我现在想了解“某类型订单下单流程”(不关注换货或退单),但是它的链路非常长,涉及的应用比较多,包括 yb-xxxde, yb-xxxrs, yb-xxxrm 和 lvxxxde 等本地应用,入口在 yb-xxxde 以 JMQ 消息的形式,它的主题是 pxx_xxx_xxxer 定义了 Order3csServiceHandler.java 消费者,请你根据源码分析,从这个消息消费,到调用 yb-xxxrs 再到 lvxxxde 落数据库订单的流程,你需要检查相关链路上的源码和配置文件(包括但不限于 jmq 或 jsf 配置),读取多个本地项目或依赖的 jar 包内容,在这个过程中你需要依赖 easy-code-reader 的 MCP 的能力,输出结果中请帮我画出接口调用的时序图,并告诉我在处理的过程中涉及那些具体的 JMQ 主题,JSF 接口和落数据库的表名注意以下几点:0. 每次创建子任务时需要使用编码智能体,这样才能使用 MCP 工具1. 在读取项目文件时,请严格遵守使用 easy-code-reader MCP 的原则,不能自主扫描和读取应用代码,避免出现读错应用代码的情况2. 如果遇到 jar 包需要读取,也需要使用 easy-code-reader MCP 的工具3. “某类型订单下单流程”链路是自上向下的过程,由 yb-xxxde 到 yb-xxxrs 到 yb-xxxrm 到 lvxxxde,所以你在每分析完一个应用的逻辑后,会获取到衔接下一个应用的逻辑,请你记住这些衔接的逻辑,这些需要作为检查加一个项目的起点
它会执行一个时间非常长的任务,根据 消息 和 JSF RPC 接口的调用链路不断读取多个相关应用的相关代码,如下所示:
最终汇总出结果并绘制出 drawio 的流程图:
结果与业务流程基本一致,这会 极大地降低复杂系统的上手难度,加快开发者对现有微服务项目的理解。说实话我也对 AI 本次任务输出的结果感到吃惊,随着 AI 能力进一步的发展,处理任务的结果只会更好。
2. 阅读 jar 包源码,根据源码完成代码编写
在使用第三方或其他外部依赖时,JoyCode Agent 并不能直接读取 jar 包中的源码,往往需要我们将源码内容手动复制到提示词中才能完成,费时费力。在 Easy Code Reader 中提供了 read_jar_source 工具来读取 jar 包中的源码,帮我们完成开发实现。我们在某项目中以如下提示词为例:
你是一位 Java 技术专家,请你使用 MCP 帮我读取 jar 包中 com.jd.xxx.OfflineInsureOrderResource 的源码信息
在提示词中我们并没有声明是哪个 Maven 依赖及其版本,但是它也能处理:
可以发现,它第一次读取时根据推测并没有找到实际的 Maven 依赖,而是通过读取 pom.xml 补偿了一次后读取到了。
3. 跨项目阅读源码,根据源码完成本项目实现
在大型项目中,某些功能的实现可能会跨多个模块或微服务,如果部分逻辑已经实现并且后续其他应用的逻辑需要依赖这部分逻辑时,可以借助 Easy Code Reader 读取相关模块的源码,帮助我们更好地理解和实现当前项目的功能,示例 Prompt 如下:
你是一位 Java 技术专家,现在我要实现 XXX 的业务逻辑,这部分逻辑的实现需要调用本地项目 A 中 XXX 的接口及其实现,请你借助 MCP easy-code-reader 来帮我读取 A 项目中的源码,并帮我实现 XXX 的业务逻辑
当然除了这几种场景以外,还可以使用 Easy Code Reader 完成以下事项:
异常问题快速溯源:如果有异常信息是外部 jar 包依赖中抛出来的,可以使用
read_jar_source工具根据异常堆栈日志快速定位异常点;依赖升级影响评估(旧/新版本差异核对):同样是使用
read_jar_source工具来完成新旧版本的实现差异,评估升级影响;业务代码逻辑评审:如果业务逻辑开发实现在多个项目中,可以借助读取本地项目代码的工具
list_all_project、list_project_files和read_project_code,来分析新增的逻辑是否满足业务要求;新人快速上手多个微服务:借助读取本地项目代码的工具,可以根据接口调用链路快速理清微服务项目代码之间的关系,提高上手速度。
环境要求
既然它有这么多的应用场景,那么我们该如何接入 Easy Code Reader 呢?下面我们来介绍一下接入步骤,它的环境要求如下:
uv - Python 包和项目管理工具
Python 3.10 或更高版本(一般情况下,可以先安装 uv,安装成功后尝试启动 MCP Server,如果提示缺少 Python 环境再进行安装)
Java Development Kit (JDK) - 用于运行反编译器,要求至少 Java 8
如果您还没有安装 uv,可以通过以下方式快速安装:
# macOS/Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh# Windowspowershell -c "irm https://astral.sh/uv/install.ps1 | iex"
uv 命令。
快速接入(方法一):使用uvx(推荐)
注意以下两个参数变量的配置:
--maven-repo: 指定 Maven 仓库路径,将/custom/path/to/maven/repository内容替换为本地 Maven 仓库路径即可,不配置默认使用 MAVEN_HOME 目录或~/.m2/repository--project-dir: 指定本地项目目录路径,将/customer/path/to/project-dir替换为实际保存所有项目的路径
{"mcpServers": {"Easy Code Reader": {"command": "uvx","args": ["easy-code-reader","--maven-repo","/customer/maven-repository","--project-dir","/customer/path/to/project-dir"]}}}
easy-code-reader://guide 命令获取使用指南 Resource,检查当前的配置是否为符合自己本地的目录配置:
快速接入(方法二):使用uv安装到本地
uv tool install easy-code-reader
安装成功后,执行以下命令获取安装目录:
which easy-code-reader
比如,输出结果是:/Users/wangyilong13/.local/bin/easy-code-reader,那么需要按照如下方式配置 MCP 客户端,注意 args 参数配置,注意 args 参数配置,注意 args 参数配置:
{"mcpServers": {"easy-code-reader": {"command": "/Users/wangyilong13/.local/bin/easy-code-reader","args": ["--maven-repo","/custom/path/to/maven/repository","--project-dir","/customer/path/to/project-dir"],"env": {}}}}
一般这样操作都能完成安装,后续如果有版本更新,可以通过以下命令进行升级:
uv tool install --upgrade easy-code-reader
使用这种方法会面临一个 JoyCode 校验命令白名单的问题:
要么选择配置 MCP 白名单,要么再去重新尝试方法一,因为在执行过 uv tool install easy-code-reader 命令后 Python 相关环境和所需的包都已经安装到本地,再使用方法一启动问题不大。
常见问题
Q1: spawn uvx ENOENT spawn uvx ENOENT
uv 命令未找到,确保已正确安装 uv 并将其路径添加到系统 PATH 中,参考 环境要求,并尝试重启 IDE 后再启动 MCP Server。
Q2: Downloading cpython-3.10.19-macos-aarch64-none (download) (17.7MiB) MCP error -32001: Request timed out
Python 环境下载失败,尝试手动下载或重试下载,或者参考 快速接入(方法二)。
以上内容就是 MCP Easy Code Reader 的介绍和接入方法,接下来的内容主要介绍一下它的实现原理,感兴趣的朋友可以继续往下看。
Easy Code Reader 实现原理
其实编写一个 MCP Server 并不复杂,大家可以参考这篇 Github 上的文章 Model Context Protocol(MCP) 编程极速入门(https://github.com/liaokongVFX/MCP-Chinese-Getting-Started-Guide)。Easy Code Reader 通过 Python 语言实现,它提供了 4 个主要工具来协同完成源码读取工作:
list_all_project: 列出所有本地项目,这个工具能将配置的项目目录--project-dir下所有的文件夹都读取出来,每个文件夹代表一个项目,这样 Code Agent 便能根据项目名称来选择需要读取的项目;list_project_files: 列出指定项目中的所有文件名,这个工具能将指定项目下的所有源码文件名都读取出来,Code Agent 便能根据调用链路选择需要读取的文件;read_project_code: 读取指定项目中的某个文件源码,通过以上两个工具,Code Agent 能够定位到需要读取的文件,然后使用这个工具将源码内容读取出来,供 Code Agent 进行分析;read_jar_source: 读取指定 jar 包中的某个类源码,如果调用链路中有外部 jar 包依赖的话,Code Agent 便可以使用这个工具将 jar 包中的源码读取出来,供分析和编写代码。
这四个工具协同工作,便能实现跨项目、多依赖的源码读取工作,帮助 Code Agent 更好地理解代码逻辑,从而提高代码编写效率和准确度,以下是 MCP Tool 实现的技术细节:
list_all_project
列举项目目录下所有的项目文件夹名称。
用途:
查看所有可用的项目
当输入不完整的项目名时,帮助推理出最接近的项目名
验证项目是否存在
支持项目名称模糊匹配,快速查找特定项目
参数:
project_dir(可选): 项目目录路径,如未提供则使用启动时配置的路径project_name_pattern(可选): 项目名称模糊匹配模式(不区分大小写),用于过滤项目列表支持左右模糊匹配,例如
nacos将匹配包含nacos、Nacos、NACOS的项目名⚠️ 使用建议:如果匹配模式过于严格可能导致遗漏目标项目
💡 最佳实践:若未找到预期结果,建议不传此参数重新查询完整列表
智能提示机制:
当使用
project_name_pattern但未匹配到项目时,返回结果会包含提示信息建议 AI 助手在未找到预期项目时,不传
project_name_pattern参数重新查询有效减少因过度过滤导致的查询失败
示例 1 - 列出所有项目:
{}
示例 2 - 使用项目名称模糊匹配:
{"project_name_pattern": "spring"}
返回格式:
{"project_dir": "/path/to/projects","project_name_pattern": "spring","total_projects": 2,"projects": ["spring-boot","spring-cloud-demo"],"hint": "已使用项目名称模式 'spring' 进行过滤。如果未找到预期的项目,可能是模式匹配过于严格。建议:不传入 project_name_pattern 参数重新调用 list_all_project 工具查看完整项目列表。","total_all_projects": 5}
提示信息说明:
当使用
project_name_pattern但未匹配到任何项目时,hint字段会提示模式可能过于严格,并显示总项目数total_all_projects当使用
project_name_pattern且有匹配结果时,hint字段会提醒如果结果不符合预期可以不传参数重新查询,同时显示总项目数这个智能提示机制帮助 AI 助手更好地调整查询策略,避免因过度过滤错过目标项目
list_project_files
列出 Java 项目中的源代码文件和配置文件路径。
用途:
了解项目结构和文件组织
查找特定的类或配置文件
分析类之间的关系和依赖
当项目文件过多时,聚焦特定模块
支持文件名模糊匹配,快速定位目标文件
支持两种模式:
全项目模式(不指定
sub_path):列出整个项目的所有文件聚焦模式(指定
sub_path):只列出指定子目录下的文件
参数:
project_name(必需): 项目名称,例如nacossub_path(可选): 指定项目内的子目录路径,例如core或address/src/main/javafile_name_pattern(可选): 文件名模糊匹配模式(不区分大小写),用于进一步过滤文件列表支持左右模糊匹配,例如
Service将匹配包含service、Service、SERVICE的文件名⚠️ 使用建议:如果匹配模式过于严格可能导致遗漏目标文件
💡 最佳实践:若未找到预期结果,建议不传此参数重新查询完整列表
project_dir(可选): 项目所在的父目录路径,如未提供则使用启动时配置的路径
自动过滤内容:
✅ 包含:Java 源代码 (.java)、配置文件 (.xml, .properties, .yaml, .json 等)、构建脚本、文档
❌ 排除:测试目录 (
src/test)、编译产物 (target,build)、IDE 配置、版本控制文件
智能提示机制:
当使用
file_name_pattern但未匹配到文件时,返回结果会包含提示信息建议 AI 助手在未找到预期文件时,不传
file_name_pattern参数重新查询有效减少因过度过滤导致的查询失败
示例 1 - 列出整个项目:
{"project_name": "nacos"}
示例 2 - 只列出 core 模块:
{"project_name": "nacos","sub_path": "core"}
示例 3 - 使用文件名模糊匹配:
{"project_name": "nacos","file_name_pattern": "Service"}
返回格式:
{"project_name": "nacos","project_dir": "/path/to/projects/nacos","search_scope": "core","file_name_pattern": "Service","total_files": 15,"files": ["core/src/main/java/com/alibaba/nacos/core/service/NacosService.java","api/src/main/java/com/alibaba/nacos/api/naming/NamingService.java","..."],"hint": "已使用文件名模式 'Service' 进行过滤。如果未找到预期的文件,可能是模式匹配过于严格。建议:不传入 file_name_pattern 参数重新调用 list_project_files 工具查看完整文件列表。"}
提示信息说明:
当使用
file_name_pattern但未匹配到任何文件时,hint字段会提示模式可能过于严格当使用
file_name_pattern且有匹配结果时,hint字段会提醒如果结果不符合预期可以不传参数重新查询这个智能提示机制帮助 AI 助手更好地调整查询策略,避免因过度过滤错过目标文件
read_project_code
从本地项目目录中读取指定文件的源代码或配置文件内容。
用途:
读取具体类或文件的完整源代码
查看配置文件内容(pom.xml、application.yml、application.properties 等)
读取项目文档(README.md、SQL 脚本等)
支持多模块 Maven/Gradle 项目
自动搜索常见的源代码和配置文件路径
参数:
project_name(必需): 项目名称,例如my-projectfile_path(必需): 文件标识符:可以是完全限定的 Java 类名或文件相对路径Java 类名格式:
com.example.MyClass(自动查找对应的 .java 文件)相对路径格式:
src/main/java/com/example/MyClass.java模块相对路径:
core/src/main/java/com/example/MyClass.java配置文件路径:
src/main/resources/application.yml、pom.xml文档文件:
README.md、docs/setup.mdproject_dir(可选): 项目目录路径,如未提供则使用启动时配置的路径
支持的文件类型:
Java 源代码 (.java)
配置文件 (.xml, .properties, .yaml, .yml, .json, .conf, .config)
构建脚本 (.gradle, .gradle.kts, pom.xml)
文档文件 (.md, .txt)
SQL 脚本 (.sql)
Shell 脚本 (.sh, .bat)
自动搜索路径:
对于 Java 类名:
src/main/java/{class_path}.java、src/{class_path}.java、{class_path}.java对于配置文件:项目根目录、
src/main/resources/、src/、config/及子模块支持多模块项目中的子模块路径
推荐工作流程:
使用
list_all_project确认项目存在使用
list_project_files(建议带file_name_pattern参数)查看文件列表使用本工具读取具体文件内容
示例 1 - 使用类名读取 Java 源代码:
{"project_name": "my-spring-app","file_path": "com.example.service.UserService"}
示例 2 - 使用相对路径读取 Java 文件:
{"project_name": "nacos","file_path": "address/src/main/java/com/alibaba/nacos/address/component/AddressServerGeneratorManager.java"}
示例 3 - 读取配置文件:
{"project_name": "my-spring-app","file_path": "src/main/resources/application.yml"}
示例 4 - 读取项目根目录的文件:
{"project_name": "my-spring-app","file_path": "pom.xml"}
返回格式:
{"project_name": "my-spring-app","class_name": "com.example.service.UserService","file_path": "/path/to/projects/my-spring-app/src/main/java/com/example/service/UserService.java","code": "package com.example.service;\n\nimport ...\n\npublic class UserService {\n // ...\n}"}
read_jar_source
从 Maven 依赖中读取 Java 类的源代码(优先从 sources jar,否则反编译)。
参数:
group_id(必需): Maven group ID,例如org.springframeworkartifact_id(必需): Maven artifact ID,例如spring-coreversion(必需): Maven version,例如5.3.21class_name(必需): 完全限定的类名,例如org.springframework.core.SpringVersionprefer_sources(可选,默认true): 优先使用 sources jar 而不是反编译
工作原理:
首先尝试从
-sources.jar中提取源代码(如果prefer_sources=true)如果 sources jar 不存在或提取失败,自动回退到反编译主 JAR 文件
支持 SNAPSHOT 版本的智能处理
智能错误提示:
当 JAR 文件未找到时,工具会提供详细的排查建议:
提示可能的原因(依赖未安装、Maven 坐标错误)
建议使用
read_project_code工具读取项目的pom.xml文件指导在
<dependencies>部分核对正确的 Maven 坐标提示确认坐标后重新调用工具
说明可能需要执行 Maven 构建命令安装依赖
这个智能提示机制特别适合与 AI 助手配合使用,能有效减少因 Maven 坐标错误导致的重复尝试。
示例:
{"group_id": "org.springframework","artifact_id": "spring-core","version": "5.3.21","class_name": "org.springframework.core.SpringVersion"}
返回格式:
{"class_name": "org.springframework.core.SpringVersion","artifact": "org.springframework:spring-core:5.3.21","source_type": "sources.jar","code": "package org.springframework.core;\n\npublic class SpringVersion {\n // ...\n}"}
source_type 字段说明:
source_type 字段标识源码的来源,帮助 AI 助手了解代码的可靠性和新鲜度:
"sources.jar": 从 Maven 的 sources JAR 文件中提取(最可靠,与发布版本完全一致)"decompiled": 通过反编译器新反编译生成(可能存在反编译不完整的情况)"decompiled_cache": 从之前反编译的缓存中读取(避免重复反编译,提升性能)
💡 使用建议:
sources.jar来源的代码最准确,可直接作为分析依据decompiled来源的代码可能会有语法糖恢复、泛型擦除等反编译特征decompiled_cache与decompiled质量相同,只是从缓存读取以提升效率
反编译器选择与缓存机制
read_jar_source 工具支持多个反编译器,并根据 Java 版本自动选择最合适的:
反编译后的文件会被缓存在 JAR 包所在目录的 easy-code-reader/ 子目录中,例如:
如果 JAR 包位置为:
~/.m2/repository/org/springframework/spring-core/5.3.21/spring-core-5.3.21.jar
反编译后的源文件将存储在:
~/.m2/repository/org/springframework/spring-core/5.3.21/easy-code-reader/spring-core-5.3.21.jar
缓存文件本身也是一个 JAR 格式的压缩包,包含所有反编译后的 .java 文件,这样可以避免重复反编译相同的 JAR 包,提高性能。但 针对 SNAPSHOT 版本需要特殊处理: 因为 Maven 针对快照版本会生成带时间戳的 JAR(如 artifact-1.0.0-20251030.085053-1.jar),Easy Code Reader 会自动查找最新的带时间戳版本进行反编译,并且以缓存以 artifact-1.0.0-20251030.085053-1.jar 名称存储,提供版本判断的依据,当检测到新版本时,会自动清理旧的 SNAPSHOT 缓存,生成新的缓存文件。
巨人的肩膀
Github: easy-code-reader(https://github.com/FangYuan33/easy-code-reader)
MCP.so: Easy Code Reader(https://mcp.so/server/easy-code-reader/FangYuan33)
Github: maven-decoder-mcp(https://github.com/salitaba/maven-decoder-mcp)
Github: fernflower(https://github.com/JetBrains/fernflower)
关于JoyCode
JoyCode官网:https://joycode.jd.com/
代码洪流,一念即成
🌟JoyCode Agent 开源链接,欢迎Star收藏支持!
https://github.com/jd-opensource/joycode-agent
https://gitee.com/JD-opensource/joycode-agent
推荐阅读

