news 2026/5/8 12:24:14

Photon:一次TypeScript定义,自动生成CLI、Web界面与MCP服务器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Photon:一次TypeScript定义,自动生成CLI、Web界面与MCP服务器

1. 项目概述:Photon,一次定义,处处交付

最近在折腾AI工具链和内部自动化时,我一直在寻找一种能统一逻辑、简化接口开发的方案。传统的做法是,一个核心功能,你得为它写一个CLI脚本、再搭一个简单的Web界面、最后还得想办法让AI助手(比如Claude、Cursor)也能调用它。这三套代码虽然逻辑相似,但实现起来却要重复劳动,维护成本也高。

直到我遇到了Photon,它彻底改变了我的工作流。简单来说,Photon让你只写一个TypeScript类文件,然后自动为你生成三样东西:一个功能完整的CLI命令行工具、一个自动渲染的Web界面(叫Beam),以及一个标准的MCP服务器,能让你的代码直接被Claude Desktop、Cursor等AI客户端调用。

它的核心理念是“意图优先”。你不需要操心HTTP路由、命令行参数解析或者MCP协议细节,你只需要用TypeScript清晰地定义你的“意图”——也就是你的业务逻辑和方法。剩下的,Photon全包了。这种“一次定义,多处交付”的模式,对于快速构建内部工具、AI Agent插件或是个人自动化脚本来说,效率提升是颠覆性的。

2. 核心设计理念与架构拆解

2.1 为什么是“单一文件”哲学?

Photon最吸引我的设计,就是它的“单一文件”哲学。你所有的逻辑、配置、甚至UI描述,都集中在一个.photon.ts文件里。这听起来简单,但背后有深刻的考量。

首先,它极大地降低了认知负担和启动成本。你想做一个天气查询工具?不需要初始化一个Node.js项目、配置tsconfig.json、安装expresscommander。你只需要创建一个文件,写一个类,几个方法,就完成了。Photon内置了TypeScript编译器,你连tsc都不用管。

其次,它强制了逻辑的纯粹性。因为所有接口都源自同一个定义,所以CLI、Web UI和AI Agent看到的是完全一致的API契约。你在JSDoc里写的参数描述,既会成为Web表单的提示文字,也会成为AI调用时的工具描述。这种“单一事实来源”从根本上杜绝了接口不同步的问题。

最后,它让分发和复用变得极其简单。一个Photon文件本身就是一个完整的、可分发的“包”。你可以通过photon add命令从GitHub直接安装他人的Photon,或者通过photon build把它编译成单个可执行文件。这种原子化的封装,非常符合现代“可组合工具”的理念。

2.2 三层接口的自动推导机制

Photon如何从一个类推导出三个接口?这是其架构的精妙之处。它本质上是一个强大的元编程和代码分析工具。

  1. CLI接口生成:Photon会解析你的类方法签名。每个公有方法都会成为一个CLI子命令。方法的参数会根据其类型(string,number,boolean等)被映射为命令行选项(--name Ada)。复杂的对象参数会被展开。它底层利用了类似yargs的库,但配置是完全自动生成的。

  2. Web界面生成:这是Beam的功劳。Beam会分析你的方法签名、JSDoc注释和参数标签(Tags),动态渲染出一个表单界面。

    • string类型且带有{@format email}标签的参数,会变成邮箱输入框并自带验证。
    • number类型带有{@min 1} {@max 7}标签,会变成带范围限制的数字输入框。
    • @param status {@choice pending,completed,failed}会让参数变成一个下拉选择框。
    • 方法上的@format table标签,会让返回的数组数据以表格形式展示。
    • 这一切都无需你写任何HTML、CSS或前端框架代码。
  3. MCP服务器生成:这是连接AI世界的桥梁。Photon会将你的类和方法,按照Model Context Protocol规范,包装成一个MCP服务器。AI客户端(如Claude Desktop)通过标准MCP协议与这个服务器通信,获取可用的工具列表(即你的方法),并在需要时调用它们。你写的JSDoc注释,会直接成为AI理解工具功能的“说明书”。

这三层共享同一套核心:类型验证。你在TypeScript中定义的类型和通过标签添加的约束(如正则表达式{@pattern}),会在CLI解析、Web表单提交和MCP调用时被统一强制执行。这确保了数据流入逻辑层之前就是干净、合规的。

2.3 状态、事件与协调:超越简单CRUD

Photon不仅仅是一个接口生成器,它还内置了构建复杂应用所需的基础设施,其中最关键的两个概念是事件

分布式锁:通过@locked装饰器标记的方法,在任何时刻都只允许一个调用者执行。这个锁是跨进程的。想象一个场景:你有一个“部署生产环境”的方法。一个人类用户通过Web UI点击了部署,同时一个AI Agent也尝试触发部署。如果没有锁,可能会导致灾难性的并发操作。@locked确保了操作的序列化,无论是来自Web、CLI还是AI的请求,都乖乖排队。

实时事件:这是实现交互式、实时应用的关键。在Photon方法内部,你可以调用this.emit({ event: 'eventName', data: ... })。在前端(无论是自动生成的Beam还是你的自定义UI),你可以通过一个全局注入的对象(以你的Photon命名,如chess.on('eventName', handler))来监听这些事件。底层,Photon使用Server-Sent Events通过MCP的流式HTTP传输协议来推送消息,你无需自己搭建WebSocket。

两者结合:锁和事件共同实现了“带实时状态同步的协调工作流”。文档里举的象棋例子非常贴切:move方法被@locked,确保了人类和AI轮流走棋。每走一步,服务器就emit一个boardUpdated事件,所有连接的客户端(Web界面、AI对话界面)的棋盘都会实时更新。这在构建审批流、协作编辑、实时监控面板等场景下威力巨大。

3. 从零开始:创建你的第一个Photon

理论说了这么多,我们动手创建一个。假设我们要做一个简单的“待办事项”管理器。

3.1 环境准备与安装

首先,确保你的系统安装了Node.js 20或更高版本。然后通过npm全局安装Photon:

npm install -g @portel/photon

安装完成后,运行photon --version检查是否成功。你也可以使用npx来避免全局安装,但为了方便演示,我们使用全局命令。

3.2 创建项目骨架

在你喜欢的工作目录下,运行以下命令来创建一个新的Photon:

photon new todo

这个命令会在当前目录生成一个名为todo.photon.ts的文件,里面已经包含了一个简单的示例类。我们打开它,将其替换为我们自己的内容。

3.3 编写核心逻辑

todo.photon.ts的内容修改如下:

/** * 简单的个人待办事项管理器 * @icon 📝 */ export default class Todo { // 使用内存存储,实际项目中可使用 this.memory 或数据库 private items: Array<{ id: number; task: string; completed: boolean }> = []; private nextId = 1; /** * 添加一个新的待办事项 * @param task 任务描述 {@example 购买 groceries} */ add(params: { task: string }): { id: number; task: string } { if (!params.task.trim()) { throw new Error('任务描述不能为空'); } const newItem = { id: this.nextId++, task: params.task, completed: false, }; this.items.push(newItem); // 触发一个事件,通知前端列表已更新 this.emit({ event: 'listUpdated', data: this.items }); return { id: newItem.id, task: newItem.task }; } /** * 列出所有待办事项 * @param showCompleted 是否显示已完成事项 {@default false} * @format table */ list(params: { showCompleted?: boolean } = {}): Array<{ id: number; task: string; completed: boolean }> { const { showCompleted = false } = params; if (showCompleted) { return this.items; } return this.items.filter(item => !item.completed); } /** * 标记一个待办事项为完成或未完成 * @param id 待办事项的ID * @param completed 完成状态 */ mark(params: { id: number; completed: boolean }): { success: boolean; message: string } { const item = this.items.find(item => item.id === params.id); if (!item) { return { success: false, message: `未找到ID为 ${params.id} 的待办事项` }; } item.completed = params.completed; this.emit({ event: 'listUpdated', data: this.items }); return { success: true, message: `事项 "${item.task}" 已标记为 ${params.completed ? '完成' : '未完成'}` }; } /** * 清理所有已完成的事项 * @locked */ clearCompleted(): { removed: number } { const initialLength = this.items.length; this.items = this.items.filter(item => !item.completed); const removed = initialLength - this.items.length; this.emit({ event: 'listUpdated', data: this.items }); return { removed }; } }

代码解读与注意事项:

  1. JSDoc是UI和AI的桥梁:注意看add方法中@param task后面的描述和{@example}。这个描述会直接显示在Beam Web界面的输入框标签上,而{@example}会提供一个占位符示例。同时,当AI(如Claude)查看这个工具时,它读到的也是这段描述,从而知道该如何使用。
  2. @format table:在list方法上,我们添加了@format table标签。这意味着当通过Beam Web界面或CLI调用该方法时,返回的数组会自动以美观的表格形式呈现,而不是原始的JSON。
  3. @lockedclearCompleted方法被标记为@locked。这意味着即使这个Photon的多个实例同时运行,或者被多个用户同时调用,清理操作也会被序列化,防止数据竞争。
  4. this.emit:我们在addmarkclearCompleted方法中都调用了this.emit,发送listUpdated事件。这样,任何连接到这个Photon的Web界面(后面会看到)都能实时收到列表变更的通知,实现无刷新更新。
  5. 错误处理:在add方法中,我们对空任务进行了校验并抛出错误。Photon会自动捕获这些错误,并以结构化的方式返回给调用方(CLI、Web或AI),包括错误类型和消息。

3.4 运行与体验三种接口

现在,让我们看看这一个文件如何变成三个工具。

1. 启动Web界面:

photon

执行后,默认会在浏览器打开http://localhost:3008,这就是Beam的仪表盘。你应该能看到刚刚创建的Todo光子。点击进入,你会看到一个完全根据你的代码生成的界面:有“添加任务”的表单(带输入框和示例提示)、“列出任务”的按钮(带一个“显示已完成”的复选框)、“标记完成”的表单(需要输入ID和选择状态)以及“清理已完成”的按钮。

尝试添加几个任务,然后标记完成一两个。你会发现操作非常流畅,list方法返回的数据自动渲染成了表格。这就是“意图即界面”。

2. 作为CLI工具使用:打开另一个终端窗口。

# 列出所有未完成的任务 photon cli todo list # 列出所有任务(包括已完成) photon cli todo list --showCompleted true # 添加一个新任务 photon cli todo add --task "学习Photon的高级功能" # 标记ID为1的任务为完成 photon cli todo mark --id 1 --completed true # 清理已完成的任务(由于有@locked,这个操作是安全的) photon cli todo clearCompleted

CLI的输出是格式化的JSON或表格(取决于@format),非常适合集成到脚本中。

3. 作为MCP服务器供AI调用:首先,我们需要以MCP服务器模式运行Photon:

photon mcp todo

这个命令会启动一个MCP服务器。为了让AI客户端(如Claude Desktop)能连接它,我们需要获取连接配置。

photon info todo --mcp

这个命令会输出一段JSON配置,类似于:

{ "mcpServers": { "todo": { "command": "photon", "args": ["mcp", "todo"] } } }

接下来,你需要将这段配置添加到你的AI客户端的MCP服务器配置中。

  • Claude Desktop: 配置文件通常位于~/Library/Application Support/Claude/claude_desktop_config.json(Mac) 或%APPDATA%\Claude\claude_desktop_config.json(Windows)。在mcpServers对象中添加上述配置。
  • Cursor: 在设置中搜索MCP进行配置。

配置完成后,重启你的AI客户端。现在,当你与AI对话时,它就能“看到”并调用你的Todo工具了。你可以对AI说:“帮我添加一个待办事项:写一篇关于Photon的博客”,AI会理解并使用add方法。这就是“一次定义,AI亦可调用”的魅力。

注意:首次以MCP模式运行时,Photon可能会提示安装一些必要的npm依赖(如果你在代码中声明了@dependencies)。这是一个非常贴心的功能,确保了环境的自包含性。

4. 进阶功能与实战技巧

掌握了基础用法后,我们来探索一些能让你的Photon变得更强大的高级特性。

4.1 依赖管理与环境配置

真实的工具往往依赖外部包或需要配置。Photon通过构造器和标签优雅地处理这些。

声明NPM依赖:如果你的Photon需要用到axiosdate-fns这样的库,你不需要用户手动npm install。在类级别使用@dependencies标签即可。

/** * 天气查询工具 * @dependencies axios@^1.6.0 * @cli curl -V # 声明需要系统安装curl */ export default class Weather { constructor(private apiKey: string) {} async forecast(city: string) { // axios 会被自动安装,直接可用 const response = await axios.get(`https://api.weatherapi.com/v1/forecast.json?key=${this.apiKey}&q=${city}`); return response.data; } }

当用户第一次运行这个Photon时,Photon会自动检测并安装axios@cli标签则用于声明系统级的命令行依赖,如果未找到,Photon会给出明确的安装指引。

通过构造器注入配置:构造器的参数会自动映射为配置项。对于上面的Weather类,apiKey会成为一个必需的配置。

  • 在Beam中:它会出现在“设置”面板,作为一个密码输入框。
  • 在CLI中:你需要通过环境变量WEATHER_API_KEY来提供它,或者在首次运行时通过交互式提示输入。
  • 在MCP上下文中:配置通常通过环境变量或宿主(如Claude Desktop)的配置机制来管理。

这种设计将敏感信息(如API密钥)与代码逻辑分离,符合安全最佳实践。

4.2 构建自定义交互界面

虽然Beam的自动表单很强大,但有时你需要更复杂的UI。Photon支持完全自定义的HTML界面。

步骤:

  1. 在Photon文件同目录下创建ui文件夹。
  2. ui文件夹内创建HTML文件,例如ui/weather.html
  3. 在Photon类或方法上使用@ui ./ui/weather.html标签来关联这个界面。

关键机制:Photon Bridge API在你的自定义HTML中,Photon会自动注入一个全局对象,其名称与你的Photon文件同名(例如weather)。通过这个对象,你可以:

  • 调用服务器方法weather.forecast({city: 'Beijing'}).then(...)
  • 监听服务器事件weather.on('forecastData', (data) => { ... })
  • 接收实时渲染:如果服务器方法中调用了this.render('...'),内容会推送到前端。

示例:一个简单的自定义天气界面

<!-- ui/weather.html --> <!DOCTYPE html> <html> <body> <input id="cityInput" placeholder="输入城市"> <button onclick="getForecast()">查询</button> <div id="result"></div> <script> // `weather` 对象由Photon自动注入 function getForecast() { const city = document.getElementById('cityInput').value; weather.forecast({ city }) .then(data => { document.getElementById('result').innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`; }) .catch(err => { document.getElementById('result').innerHTML = `错误: ${err.message}`; }); } // 监听服务器事件(如果需要) weather.on('newAlert', (alert) => { console.log('天气警报:', alert); }); </script> </body> </html>

这样,当你在Beam中点击这个Photon时,就会加载这个自定义界面,而不是默认的表单。这个UI也可以作为MCP App嵌入到支持的应用(如新版Claude Desktop)中。

4.3 计划任务与Webhook

Photon让定时任务和对外提供HTTP接口变得异常简单。

计划任务:使用@scheduled标签,你可以让任何方法按Cron表达式定时运行。

export default class DataBackup { /** * 每天凌晨2点备份数据库 * @scheduled 0 2 * * * */ async backupDatabase() { // 执行备份逻辑... this.emit({ event: 'backupCompleted', data: { timestamp: new Date() } }); } }

通过photon ps命令,你可以查看和管理所有计划任务的状态。

Webhook:使用@webhook标签,可以将一个方法暴露为HTTP端点,供外部服务(如GitHub、Zapier)调用。

export default class GithubBot { /** * 接收GitHub Webhook * @webhook POST /github/webhook */ async handleWebhook(payload: any) { if (payload.action === 'opened' && payload.pull_request) { // 自动给新PR添加标签 await this.addLabel(payload.pull_request.number, 'needs-review'); } return { received: true }; } }

启动Photon后,这个端点就可以通过http://localhost:3008/webhook/github/webhook访问。Photon会自动处理HTTP请求的解析、验证(可结合OAuth)并将payload传递给方法。

4.4 状态持久化与跨Photon调用

持久化存储:每个Photon实例都有一个内置的、隔离的键值存储this.memory。它基于SQLite,数据在Photon守护进程重启后依然存在,非常适合存储用户偏好、会话状态或小型数据集。

export default class UserPrefs { async setTheme(theme: 'light' | 'dark') { this.memory.set('userTheme', theme); return { success: true }; } async getTheme() { return { theme: this.memory.get('userTheme') || 'light' }; } }

跨Photon调用:在一个Photon中,你可以通过this.call()方法调用另一个Photon的方法,实现服务编排。

export default class WorkflowOrchestrator { async runDailyReport() { // 1. 从数据库Photon获取数据 const data = await this.call('analytics', 'getDailyMetrics'); // 2. 用图表Photon生成图表 const chart = await this.call('chart-generator', 'createChart', { data, type: 'line' }); // 3. 通过邮件Photon发送报告 await this.call('email-sender', 'sendReport', { chart, recipients: ['team@example.com'] }); return { status: 'report sent' }; } }

这允许你将复杂的功能拆分成多个单一职责的Photon,然后通过一个协调者Photon将它们组合起来,符合微服务的设计思想。

5. 生产环境部署与问题排查

5.1 编译为独立二进制文件

对于分发,你可以将Photon编译成单个可执行文件,这样目标机器上甚至不需要安装Node.js。

# 编译当前平台的二进制文件 photon build todo # 交叉编译(例如,在Mac上编译Linux版本) photon build todo -t bun-linux-x64 # 编译并嵌入Beam UI,形成一个独立的桌面应用 photon build todo --with-app

编译功能基于Bun的打包器。生成的二进制文件包含了Photon代码、所有声明的@dependencies以及Photon运行时,体积小巧,部署方便。

5.2 部署选项

Photon本身是一个Node.js应用,部署方式非常灵活:

  • 长期运行(Systemd/Docker):将photon mcp <your-photon>作为后台服务运行。你可以编写一个systemd service文件或Dockerfile。记得处理好配置(环境变量)和持久化数据(~/.photon目录)的挂载。
  • Serverless(实验性):通过适配器,可以将Photon部署到Cloudflare Workers或AWS Lambda。这需要将Photon的HTTP服务器逻辑适配到Serverless环境。社区正在积极完善这方面的支持。
  • 静态托管+Serverless函数:一种更前沿的模式是将自定义UI(HTML/JS)部署到Netlify/Vercel等静态托管,而将Photon的后端方法作为Serverless函数部署,两者通过Photon Bridge API通信。这能实现前后端分离的部署。

5.3 常见问题与排查技巧

在实际使用中,你可能会遇到以下问题:

1. 启动失败:Error: Cannot find module

  • 原因:通常是因为@dependencies声明的npm包尚未安装。
  • 解决:首次运行Photon时,它会尝试自动安装。如果失败,可以手动进入Photon文件所在目录,运行npm install <package-name>。也可以运行photon doctor检查环境。

2. MCP客户端连接失败

  • 原因:Claude Desktop/Cursor配置错误,或Photon的MCP服务器未在运行。
  • 排查
    1. 确保已运行photon mcp <name>
    2. 运行photon info <name> --mcp,仔细核对输出的JSON配置,并完整复制到客户端的配置文件中。
    3. 检查客户端日志。Claude Desktop的日志通常包含MCP连接错误信息。
    4. 确认端口是否冲突(默认是动态的,由MCP over stdio通信,一般无端口问题)。

3. 自定义UI无法加载或photon对象未定义

  • 原因:HTML文件路径错误,或Photon Bridge API脚本未正确注入。
  • 解决
    1. 确认@ui标签路径正确,且HTML文件位于ui/目录下。
    2. 在浏览器开发者工具中检查Console和Network标签页,看是否有404错误。
    3. 确保你的HTML中没有其他JS库覆盖了全局的photon对象(通常以你的Photon文件名命名)。

4.@scheduled任务没有执行

  • 原因:计划任务需要Photon守护进程处于运行状态。
  • 解决:通过photon ps命令查看守护进程和任务状态。确保你是通过photon命令启动的Web界面或photon mcp启动的MCP服务器,而不是一次性CLI命令。计划任务只在长期运行的过程中生效。

5. 性能或内存问题

  • 原因:Photon为每个连接的客户端(Web浏览器、AI会话)维护独立的实例状态。如果方法中有繁重操作或内存泄漏,可能导致问题。
  • 优化
    • 对于计算密集型任务,考虑使用@locked防止并发,或拆分成更小的光子。
    • 使用this.memory存储大量数据时需谨慎,定期清理。
    • 使用photon ps监控运行中的会话和资源占用。

调试建议

  • 使用photon mcp <name> --dev模式启动,它支持热重载,并在控制台输出更详细的日志。
  • 在代码中使用console.log进行调试,输出会显示在运行Photon的终端里。
  • 查阅Photon生成的日志文件,通常位于~/.photon/logs目录下。

Photon是一个正在快速发展的项目,它的理念是将开发者从重复的接口开发中解放出来,专注于核心逻辑。虽然在某些边缘场景或深度定制化需求上可能遇到限制,但对于构建原型、内部工具、AI增强应用以及需要多端接口的服务来说,它的效率和简洁性是无与伦比的。我最欣赏的一点是,它用极简的约定和强大的元编程,创造了一种全新的、以意图为中心的开发体验。当你习惯了这种模式后,就很难再回到那种为每个接口单独编写样板代码的日子了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/8 12:24:13

歌词滚动姬:专业歌词制作工具的高效使用指南

歌词滚动姬&#xff1a;专业歌词制作工具的高效使用指南 【免费下载链接】lrc-maker 歌词滚动姬&#xff5c;可能是你所能见到的最好用的歌词制作工具 项目地址: https://gitcode.com/gh_mirrors/lr/lrc-maker 歌词滚动姬&#xff08;LRC Maker&#xff09;是一款专为歌…

作者头像 李华
网站建设 2026/5/8 12:21:49

Fast-GitHub终极指南:三步解决国内GitHub访问慢的完整方案

Fast-GitHub终极指南&#xff1a;三步解决国内GitHub访问慢的完整方案 【免费下载链接】Fast-GitHub 国内Github下载很慢&#xff0c;用上了这个插件后&#xff0c;下载速度嗖嗖嗖的~&#xff01; 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 你是否曾经因…

作者头像 李华
网站建设 2026/5/8 12:18:48

科技与科学领域重点新闻摘要-2026年5月8日

科技与科学领域重点新闻摘要 日期: 2026年5月8日 1. 腾讯发布混元3D世界模型2.0&#xff1a;一句话造出3D世界 核心要点: 腾讯正式发布并开源混元3D世界模型2.0&#xff08;HY-World 2.0&#xff09;&#xff0c;这是首个能理解文字、图片、视频等多模态输入并自动生成、重建…

作者头像 李华
网站建设 2026/5/8 12:16:41

大语言模型驱动的自主渗透测试:PentestGPT实战部署与核心架构解析

1. 项目概述&#xff1a;当大语言模型拿起渗透测试的“手术刀” 如果你和我一样&#xff0c;在网络安全这个行当里摸爬滚打了十几年&#xff0c;从手动敲Nmap扫描到写自动化脚本&#xff0c;再到看着各种安全工具百花齐放&#xff0c;那你肯定能感受到一个趋势&#xff1a;安全…

作者头像 李华