@codify-ai/mcp-client 1.0.15 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mcp-client.js CHANGED
@@ -119,7 +119,7 @@ function isEmpty(value) {
119
119
  const mcpServer = new McpServer(
120
120
  {
121
121
  name: 'Codify-MCP-Client',
122
- version: '1.0.15'
122
+ version: '1.0.16'
123
123
  },
124
124
  {
125
125
  capabilities: {
package/mcp-client.min.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{z}from"zod";import axios from"axios";import t from"fs";import e from"path";import n from"os";import{fileURLToPath as r}from"url";const s=r(import.meta.url),o=e.dirname(s);!function(){const r="codify-gen",s=e.join(o,"skills",r);if(!t.existsSync(s))return;const i=n.homedir(),a=process.cwd(),c=process.env.CODIFY_SKILLS_DIR?e.join(process.env.CODIFY_SKILLS_DIR,r):null;if(c){const n=[c];for(const r of n)try{t.mkdirSync(r,{recursive:!0});for(const n of t.readdirSync(s))t.copyFileSync(e.join(s,n),e.join(r,n))}catch{}return}const p=e.join(a,".cursor","skills"),m=e.join(p,r),g=t.existsSync(e.join(a,".cursor")),d=[e.join(i,".cursor","skills",r),e.join(i,".windsurf","skills",r),e.join(i,".codeium","windsurf","skills",r),e.join(i,".trae","skills",r)].filter(n=>t.existsSync(e.dirname(e.dirname(n)))),l=[];g&&l.push(m),l.push(...d),0===l.length&&l.push(e.join(i,".cursor","skills",r));for(const n of l)try{t.mkdirSync(n,{recursive:!0});for(const r of t.readdirSync(s)){const o=e.join(s,r),i=e.join(n,r);t.copyFileSync(o,i)}}catch{}}();const{serverUrl:SERVER_URL}=function(){const t=process.argv.slice(2);let e=process.env.CODIFY_SERVER_URL||"http://localhost:8080";for(let n=0;n<t.length;n++){const r=t[n];"--help"!==r&&"-h"!==r||process.exit(0),"--version"!==r&&"-v"!==r||process.exit(0),r.startsWith("--url=")?e=r.substring(6):"--url"===r&&n+1<t.length?e=t[++n]:r.startsWith("-")||(e=r)}return{serverUrl:e}}(),ACCESS_KEY=process.env.CODIFY_ACCESS_KEY;function i(t){return null==t||""===t||"string"==typeof t&&""===t.trim()}const a=new McpServer({name:"Codify-MCP-Client",version:"1.0.15"},{capabilities:{resources:{},tools:{},prompts:{}}});a.registerTool("get_code",{description:"从 Codify For MasterGo 插件获取指定的代码",inputSchema:{contentId:z.string().describe("从Codify插件复制图层的指令"),outDir:z.string().describe("必填。保存生成代码和相关资源的本地目录。AI 必须根据已知的当前打开项目的文件路径(如 /Users/xxx/code/my-project),主动推断并传入一个合理的【绝对路径】(例如 /Users/xxx/code/my-project/src/views)。请注意,不要省略此参数,因为工具运行环境的默认路径可能是用户的 Home 目录而非项目根目录。")}},async n=>{try{const{contentId:r,outDir:s}=n;if(!r)return{content:[{type:"text",text:`参数错误: 未提供 contentId\n- args: ${JSON.stringify(n)}`}],isError:!0};const o={};ACCESS_KEY&&(o.Authorization=`Bearer ${ACCESS_KEY}`);const a=`${SERVER_URL}/api/getCode/${r}`;try{const n=(await axios.get(a,{headers:o})).data;if(!n.code)return{content:[{type:"text",text:`⚠️ 未找到代码内容\n- contentId: ${r}\n- 可能该内容尚未从 Codify 插件同步`}],isError:!1};const c=s?e.resolve(process.cwd(),s):e.resolve(process.cwd(),`codify-output/${r}`);t.existsSync(c)||t.mkdirSync(c,{recursive:!0});const p=`${r}.html`,m=e.join(c,p);t.writeFileSync(m,n.code,"utf8");const g=async(n,r,s)=>{if(i(n))return 0;let o;try{o="string"==typeof n?JSON.parse(n):n}catch(t){return 0}const a=Object.keys(o);if(0===a.length)return 0;const p=e.join(c,r);t.existsSync(p)||t.mkdirSync(p,{recursive:!0});const m=Object.entries(o).map(async([n,o])=>{const i=n.match(/(.+)\.([a-zA-Z0-9]+)$/);let a=n,c=s;i&&(a=i[1],c=i[2]),a=a.replace(/[^a-zA-Z0-9_-]/g,"_");const m=e.join(p,`${a}.${c}`);let g=o,d="utf8";if("string"!=typeof g)g=JSON.stringify(g,null,2),t.writeFileSync(m,g,d);else if(g.startsWith("http://")||g.startsWith("https://"))try{const e=await axios.get(g,{responseType:"arraybuffer"});t.writeFileSync(m,e.data)}catch(t){console.error(`[Codify MCP] Failed to download resource from ${g}:`,t.message)}else if(g.startsWith("data:image/")){const e=g.match(/^data:image\/([A-Za-z-+\/]+);base64,(.+)$/);e&&3===e.length&&(d="base64",g=e[2]),t.writeFileSync(m,g,d)}else"images"===r&&(d="base64"),t.writeFileSync(m,g,d)});return await Promise.all(m),a.length};let d={image:"asset/images",svg:"asset/icons",shape:"asset/shapes"};if(!i(n.resourcePath))try{const t="string"==typeof n.resourcePath?JSON.parse(n.resourcePath):n.resourcePath;t.image&&(d.image=t.image.replace(/^\.\//,"")),t.svg&&(d.svg=t.svg.replace(/^\.\//,"")),t.shape&&(d.shape=t.shape.replace(/^\.\//,""))}catch(t){console.error("[Codify MCP] Failed to parse resourcePath:",t)}const l=await g(n.shape,d.shape,"json"),y=await g(n.svg,d.svg,"svg"),u=await g(n.image,d.image,"png");let x="代码和资源已成功拉取并保存到本地。\n\n";return x+=`目标目录: ${c}\n`,x+=`代码文件: ${p} (长度: ${n.code.length} 字符)\n`,n.teamId&&(x+=`团队 ID: ${n.teamId}\n`),l>0&&(x+=`Shape: 成功保存 ${l} 个文件至 ${d.shape} 目录\n`),y>0&&(x+=`SVG: 成功保存 ${y} 个文件至 ${d.svg} 目录\n`),u>0&&(x+=`Image: 成功保存 ${u} 个文件至 ${d.image} 目录\n`),x+=`\n**执行结果**:以上文件已自动写入本地系统。请注意阅读 ${p} 并检查代码中使用的 relative 路径。若业务文件不叫 ${p},你可以依据此文件重构/合并到你的业务主入口中。`,{content:[{type:"text",text:x}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 404:return{content:[{type:"text",text:`❌ 未找到内容\n- contentId: ${r}\n- 请检查 contentId 是否正确,或该内容是否已从 Codify 插件同步`}],isError:!0};case 403:return void 0!==n.mcp_get_limit||n.message?.includes("limit")?{content:[{type:"text",text:`❌ 配额不足\n- ${n.message||"您已达到获取代码的次数限制"}\n- 剩余配额: ${void 0!==n.mcp_get_limit?n.mcp_get_limit:"未知"}\n- 请升级您的计划或联系支持团队`}],isError:!0}:{content:[{type:"text",text:`❌ 权限不足\n- contentId: ${r}\n- 您没有权限访问该内容\n- 请检查您的 access_key 是否包含正确的团队权限`}],isError:!0};case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取代码失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- contentId: ${r}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取代码失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("get_code_list",{description:"获取所有可用的代码列表",inputSchema:z.object({}).describe("无需参数,直接调用即可获取所有代码列表")},async t=>{try{const t={};ACCESS_KEY&&(t.Authorization=`Bearer ${ACCESS_KEY}`);const e=`${SERVER_URL}/api/getCodeList`;try{const n=(await axios.get(e,{headers:t})).data;if(!Array.isArray(n))return{content:[{type:"text",text:"⚠️ 服务器返回的数据格式不正确\n- 期望: 数组\n- 实际: "+typeof n}],isError:!0};if(0===n.length)return{content:[{type:"text",text:"📋 代码列表为空\n\n当前没有可用的代码内容。\n请先从 Codify 插件同步代码。"}],isError:!1};let r=`✅ 成功获取代码列表 (共 ${n.length} 项)\n\n`;return r+="--- 代码列表 ---\n\n",n.forEach((t,e)=>{r+=`${e+1}. **${t.contentId}**\n`,r+=` - 代码长度: ${t.codeLength} 字符\n`,t.teamId&&(r+=` - 团队 ID: ${t.teamId}\n`),t.fileInfo&&(r+=` - 文件信息: ${JSON.stringify(t.fileInfo)}\n`),t.createdAt&&(r+=` - 创建时间: ${t.createdAt}\n`),t.updatedAt&&(r+=` - 更新时间: ${t.updatedAt}\n`),r+="\n"}),r+="\n--- 使用说明 ---\n",r+="使用 get_code 工具获取具体代码内容:\n",r+='- get_code({ contentId: "your-content-id" })',{content:[{type:"text",text:r}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 403:return{content:[{type:"text",text:"❌ 权限不足\n- 您没有权限访问代码列表\n- 请检查您的 access_key 是否包含正确的团队权限"}],isError:!0};case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取代码列表失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取代码列表失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("get_user_info",{description:"获取当前登录用户的信息,包括配额、团队等",inputSchema:z.object({}).describe("无需参数,直接调用即可获取当前用户信息")},async t=>{try{const t={};ACCESS_KEY&&(t.Authorization=`Bearer ${ACCESS_KEY}`);const e=`${SERVER_URL}/api/getUserInfo`;try{const n=(await axios.get(e,{headers:t})).data;let r="✅ 用户信息\n\n";return r+=`👤 用户ID: ${n.userId}\n`,n.userName&&(r+=`📧 用户名: ${n.userName}\n`),n.realname&&(r+=`📝 真实姓名: ${n.realname}\n`),r+="\n📊 配额信息:\n",n.quota&&(r+=` - 生成设计: ${n.quota.mcp_generate_count||0} / ${n.quota.mcp_generate_limit||"无限制"}\n`,r+=` - 获取代码: ${n.quota.mcp_get_count||0} / ${n.quota.mcp_get_limit||"无限制"}\n`),n.teams&&n.teams.length>0&&(r+=`\n👥 团队信息 (共 ${n.teams.length} 个团队):\n`,n.teams.forEach((t,e)=>{r+=` ${e+1}. ${t.name||t.teamId} (ID: ${t.teamId})\n`,t.auth&&(r+=` 权限: ${t.auth}\n`)})),n.currentTeamId&&(r+=`\n🔖 当前团队ID: ${n.currentTeamId}`),{content:[{type:"text",text:r}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};case 403:return{content:[{type:"text",text:`❌ 权限不足 (403)\n\n${n.message||"您没有权限访问该资源"}`}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取用户信息失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取用户信息失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("send_to_codify",{description:"将代码发送到 Codify 插件转换为设计稿",inputSchema:{code:z.string().describe("要发送的代码内容")}},async t=>{try{const{code:e}=t;if(!e)return{content:[{type:"text",text:"参数错误: 未提供代码内容"}],isError:!0};const n={"Content-Type":"application/json"};ACCESS_KEY&&(n.Authorization=`Bearer ${ACCESS_KEY}`);try{return(await axios.post(`${SERVER_URL}/api/sendToCanvas`,{code:e},{headers:n})).data.success,{content:[{type:"text",text:"✅ 代码已成功发送到 Codify 插件,等待转换为设计稿"}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};return 404===e?{content:[{type:"text",text:"❌ 未找到活跃的 Codify 插件连接\n\n请确保:\n1. Codify 插件已打开并连接到服务器\n2. 使用了相同的 access_key"}],isError:!0}:400===e?{content:[{type:"text",text:`❌ 请求参数错误: ${n.message||"Bad request"}`}],isError:!0}:401===e||403===e?void 0!==n.mcp_generate_limit||n.message?.includes("limit")?{content:[{type:"text",text:`❌ 配额不足\n- ${n.message||"您已达到生成设计的次数限制"}\n- 剩余配额: ${void 0!==n.mcp_generate_limit?n.mcp_generate_limit:"未知"}\n- 请升级您的计划或联系支持团队`}],isError:!0}:{content:[{type:"text",text:`❌ 认证失败 (${e})\n\n请检查 CODIFY_ACCESS_KEY 是否正确`}],isError:!0}:{content:[{type:"text",text:`❌ 发送失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}`}],isError:!0}}}catch(t){return{content:[{type:"text",text:`❌ 代码发送失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("upload_image",{description:"将本地图片文件上传缓存到 MCP 服务器的 data/cache 目录,返回缓存路径",inputSchema:{filePath:z.string().describe("本地图片文件的绝对路径,例如 /Users/xxx/Desktop/image.png")}},async n=>{try{const{filePath:r}=n;if(!r)return{content:[{type:"text",text:"参数错误: 未提供 filePath"}],isError:!0};let s;try{s=t.readFileSync(r)}catch(t){return{content:[{type:"text",text:`❌ 无法读取文件: ${r}\n错误: ${t.message||String(t)}`}],isError:!0}}const o=e.basename(r),i={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".ico":"image/x-icon"}[e.extname(o).toLowerCase()]||"application/octet-stream",a=s.toString("base64"),c={"Content-Type":"application/json"};ACCESS_KEY&&(c.Authorization=`Bearer ${ACCESS_KEY}`);try{const t=(await axios.post(`${SERVER_URL}/api/uploadImage`,{imageData:a,fileName:o,mimeType:i},{headers:c})).data;return{content:[{type:"text",text:`✅ 图片已成功缓存到服务器\n- 原始文件: ${o}\n- 缓存路径: ${t.cachePath}\n- 文件大小: ${t.size} bytes\n- 类型: ${t.mimeType||i}`}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};return 401===e||403===e?{content:[{type:"text",text:`❌ 认证失败 (${e})\n\n请检查 CODIFY_ACCESS_KEY 是否正确`}],isError:!0}:{content:[{type:"text",text:`❌ 上传失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}`}],isError:!0}}}catch(t){return{content:[{type:"text",text:`❌ 图片上传失败: ${t.message||String(t)}`}],isError:!0}}});try{const t=new StdioServerTransport;await a.connect(t)}catch(t){process.exit(1)}
2
+ import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{z}from"zod";import axios from"axios";import t from"fs";import e from"path";import n from"os";import{fileURLToPath as r}from"url";const s=r(import.meta.url),o=e.dirname(s);!function(){const r="codify-gen",s=e.join(o,"skills",r);if(!t.existsSync(s))return;const i=n.homedir(),a=process.cwd(),c=process.env.CODIFY_SKILLS_DIR?e.join(process.env.CODIFY_SKILLS_DIR,r):null;if(c){const n=[c];for(const r of n)try{t.mkdirSync(r,{recursive:!0});for(const n of t.readdirSync(s))t.copyFileSync(e.join(s,n),e.join(r,n))}catch{}return}const p=e.join(a,".cursor","skills"),m=e.join(p,r),g=t.existsSync(e.join(a,".cursor")),d=[e.join(i,".cursor","skills",r),e.join(i,".windsurf","skills",r),e.join(i,".codeium","windsurf","skills",r),e.join(i,".trae","skills",r)].filter(n=>t.existsSync(e.dirname(e.dirname(n)))),l=[];g&&l.push(m),l.push(...d),0===l.length&&l.push(e.join(i,".cursor","skills",r));for(const n of l)try{t.mkdirSync(n,{recursive:!0});for(const r of t.readdirSync(s)){const o=e.join(s,r),i=e.join(n,r);t.copyFileSync(o,i)}}catch{}}();const{serverUrl:SERVER_URL}=function(){const t=process.argv.slice(2);let e=process.env.CODIFY_SERVER_URL||"http://localhost:8080";for(let n=0;n<t.length;n++){const r=t[n];"--help"!==r&&"-h"!==r||process.exit(0),"--version"!==r&&"-v"!==r||process.exit(0),r.startsWith("--url=")?e=r.substring(6):"--url"===r&&n+1<t.length?e=t[++n]:r.startsWith("-")||(e=r)}return{serverUrl:e}}(),ACCESS_KEY=process.env.CODIFY_ACCESS_KEY;function i(t){return null==t||""===t||"string"==typeof t&&""===t.trim()}const a=new McpServer({name:"Codify-MCP-Client",version:"1.0.16"},{capabilities:{resources:{},tools:{},prompts:{}}});a.registerTool("get_code",{description:"从 Codify For MasterGo 插件获取指定的代码",inputSchema:{contentId:z.string().describe("从Codify插件复制图层的指令"),outDir:z.string().describe("必填。保存生成代码和相关资源的本地目录。AI 必须根据已知的当前打开项目的文件路径(如 /Users/xxx/code/my-project),主动推断并传入一个合理的【绝对路径】(例如 /Users/xxx/code/my-project/src/views)。请注意,不要省略此参数,因为工具运行环境的默认路径可能是用户的 Home 目录而非项目根目录。")}},async n=>{try{const{contentId:r,outDir:s}=n;if(!r)return{content:[{type:"text",text:`参数错误: 未提供 contentId\n- args: ${JSON.stringify(n)}`}],isError:!0};const o={};ACCESS_KEY&&(o.Authorization=`Bearer ${ACCESS_KEY}`);const a=`${SERVER_URL}/api/getCode/${r}`;try{const n=(await axios.get(a,{headers:o})).data;if(!n.code)return{content:[{type:"text",text:`⚠️ 未找到代码内容\n- contentId: ${r}\n- 可能该内容尚未从 Codify 插件同步`}],isError:!1};const c=s?e.resolve(process.cwd(),s):e.resolve(process.cwd(),`codify-output/${r}`);t.existsSync(c)||t.mkdirSync(c,{recursive:!0});const p=`${r}.html`,m=e.join(c,p);t.writeFileSync(m,n.code,"utf8");const g=async(n,r,s)=>{if(i(n))return 0;let o;try{o="string"==typeof n?JSON.parse(n):n}catch(t){return 0}const a=Object.keys(o);if(0===a.length)return 0;const p=e.join(c,r);t.existsSync(p)||t.mkdirSync(p,{recursive:!0});const m=Object.entries(o).map(async([n,o])=>{const i=n.match(/(.+)\.([a-zA-Z0-9]+)$/);let a=n,c=s;i&&(a=i[1],c=i[2]),a=a.replace(/[^a-zA-Z0-9_-]/g,"_");const m=e.join(p,`${a}.${c}`);let g=o,d="utf8";if("string"!=typeof g)g=JSON.stringify(g,null,2),t.writeFileSync(m,g,d);else if(g.startsWith("http://")||g.startsWith("https://"))try{const e=await axios.get(g,{responseType:"arraybuffer"});t.writeFileSync(m,e.data)}catch(t){console.error(`[Codify MCP] Failed to download resource from ${g}:`,t.message)}else if(g.startsWith("data:image/")){const e=g.match(/^data:image\/([A-Za-z-+\/]+);base64,(.+)$/);e&&3===e.length&&(d="base64",g=e[2]),t.writeFileSync(m,g,d)}else"images"===r&&(d="base64"),t.writeFileSync(m,g,d)});return await Promise.all(m),a.length};let d={image:"asset/images",svg:"asset/icons",shape:"asset/shapes"};if(!i(n.resourcePath))try{const t="string"==typeof n.resourcePath?JSON.parse(n.resourcePath):n.resourcePath;t.image&&(d.image=t.image.replace(/^\.\//,"")),t.svg&&(d.svg=t.svg.replace(/^\.\//,"")),t.shape&&(d.shape=t.shape.replace(/^\.\//,""))}catch(t){console.error("[Codify MCP] Failed to parse resourcePath:",t)}const l=await g(n.shape,d.shape,"json"),y=await g(n.svg,d.svg,"svg"),u=await g(n.image,d.image,"png");let x="代码和资源已成功拉取并保存到本地。\n\n";return x+=`目标目录: ${c}\n`,x+=`代码文件: ${p} (长度: ${n.code.length} 字符)\n`,n.teamId&&(x+=`团队 ID: ${n.teamId}\n`),l>0&&(x+=`Shape: 成功保存 ${l} 个文件至 ${d.shape} 目录\n`),y>0&&(x+=`SVG: 成功保存 ${y} 个文件至 ${d.svg} 目录\n`),u>0&&(x+=`Image: 成功保存 ${u} 个文件至 ${d.image} 目录\n`),x+=`\n**执行结果**:以上文件已自动写入本地系统。请注意阅读 ${p} 并检查代码中使用的 relative 路径。若业务文件不叫 ${p},你可以依据此文件重构/合并到你的业务主入口中。`,{content:[{type:"text",text:x}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 404:return{content:[{type:"text",text:`❌ 未找到内容\n- contentId: ${r}\n- 请检查 contentId 是否正确,或该内容是否已从 Codify 插件同步`}],isError:!0};case 403:return void 0!==n.mcp_get_limit||n.message?.includes("limit")?{content:[{type:"text",text:`❌ 配额不足\n- ${n.message||"您已达到获取代码的次数限制"}\n- 剩余配额: ${void 0!==n.mcp_get_limit?n.mcp_get_limit:"未知"}\n- 请升级您的计划或联系支持团队`}],isError:!0}:{content:[{type:"text",text:`❌ 权限不足\n- contentId: ${r}\n- 您没有权限访问该内容\n- 请检查您的 access_key 是否包含正确的团队权限`}],isError:!0};case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取代码失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- contentId: ${r}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取代码失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("get_code_list",{description:"获取所有可用的代码列表",inputSchema:z.object({}).describe("无需参数,直接调用即可获取所有代码列表")},async t=>{try{const t={};ACCESS_KEY&&(t.Authorization=`Bearer ${ACCESS_KEY}`);const e=`${SERVER_URL}/api/getCodeList`;try{const n=(await axios.get(e,{headers:t})).data;if(!Array.isArray(n))return{content:[{type:"text",text:"⚠️ 服务器返回的数据格式不正确\n- 期望: 数组\n- 实际: "+typeof n}],isError:!0};if(0===n.length)return{content:[{type:"text",text:"📋 代码列表为空\n\n当前没有可用的代码内容。\n请先从 Codify 插件同步代码。"}],isError:!1};let r=`✅ 成功获取代码列表 (共 ${n.length} 项)\n\n`;return r+="--- 代码列表 ---\n\n",n.forEach((t,e)=>{r+=`${e+1}. **${t.contentId}**\n`,r+=` - 代码长度: ${t.codeLength} 字符\n`,t.teamId&&(r+=` - 团队 ID: ${t.teamId}\n`),t.fileInfo&&(r+=` - 文件信息: ${JSON.stringify(t.fileInfo)}\n`),t.createdAt&&(r+=` - 创建时间: ${t.createdAt}\n`),t.updatedAt&&(r+=` - 更新时间: ${t.updatedAt}\n`),r+="\n"}),r+="\n--- 使用说明 ---\n",r+="使用 get_code 工具获取具体代码内容:\n",r+='- get_code({ contentId: "your-content-id" })',{content:[{type:"text",text:r}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 403:return{content:[{type:"text",text:"❌ 权限不足\n- 您没有权限访问代码列表\n- 请检查您的 access_key 是否包含正确的团队权限"}],isError:!0};case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取代码列表失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取代码列表失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("get_user_info",{description:"获取当前登录用户的信息,包括配额、团队等",inputSchema:z.object({}).describe("无需参数,直接调用即可获取当前用户信息")},async t=>{try{const t={};ACCESS_KEY&&(t.Authorization=`Bearer ${ACCESS_KEY}`);const e=`${SERVER_URL}/api/getUserInfo`;try{const n=(await axios.get(e,{headers:t})).data;let r="✅ 用户信息\n\n";return r+=`👤 用户ID: ${n.userId}\n`,n.userName&&(r+=`📧 用户名: ${n.userName}\n`),n.realname&&(r+=`📝 真实姓名: ${n.realname}\n`),r+="\n📊 配额信息:\n",n.quota&&(r+=` - 生成设计: ${n.quota.mcp_generate_count||0} / ${n.quota.mcp_generate_limit||"无限制"}\n`,r+=` - 获取代码: ${n.quota.mcp_get_count||0} / ${n.quota.mcp_get_limit||"无限制"}\n`),n.teams&&n.teams.length>0&&(r+=`\n👥 团队信息 (共 ${n.teams.length} 个团队):\n`,n.teams.forEach((t,e)=>{r+=` ${e+1}. ${t.name||t.teamId} (ID: ${t.teamId})\n`,t.auth&&(r+=` 权限: ${t.auth}\n`)})),n.currentTeamId&&(r+=`\n🔖 当前团队ID: ${n.currentTeamId}`),{content:[{type:"text",text:r}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};switch(e){case 401:return{content:[{type:"text",text:"❌ 认证失败 (401)\n\n请检查 CODIFY_ACCESS_KEY 是否正确"}],isError:!0};case 403:return{content:[{type:"text",text:`❌ 权限不足 (403)\n\n${n.message||"您没有权限访问该资源"}`}],isError:!0};default:return{content:[{type:"text",text:`❌ 获取用户信息失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}\n- 服务器: ${SERVER_URL}`}],isError:!0}}}}catch(t){return{content:[{type:"text",text:`❌ 获取用户信息失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("send_to_codify",{description:"将代码发送到 Codify 插件转换为设计稿",inputSchema:{code:z.string().describe("要发送的代码内容")}},async t=>{try{const{code:e}=t;if(!e)return{content:[{type:"text",text:"参数错误: 未提供代码内容"}],isError:!0};const n={"Content-Type":"application/json"};ACCESS_KEY&&(n.Authorization=`Bearer ${ACCESS_KEY}`);try{return(await axios.post(`${SERVER_URL}/api/sendToCanvas`,{code:e},{headers:n})).data.success,{content:[{type:"text",text:"✅ 代码已成功发送到 Codify 插件,等待转换为设计稿"}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};return 404===e?{content:[{type:"text",text:"❌ 未找到活跃的 Codify 插件连接\n\n请确保:\n1. Codify 插件已打开并连接到服务器\n2. 使用了相同的 access_key"}],isError:!0}:400===e?{content:[{type:"text",text:`❌ 请求参数错误: ${n.message||"Bad request"}`}],isError:!0}:401===e||403===e?void 0!==n.mcp_generate_limit||n.message?.includes("limit")?{content:[{type:"text",text:`❌ 配额不足\n- ${n.message||"您已达到生成设计的次数限制"}\n- 剩余配额: ${void 0!==n.mcp_generate_limit?n.mcp_generate_limit:"未知"}\n- 请升级您的计划或联系支持团队`}],isError:!0}:{content:[{type:"text",text:`❌ 认证失败 (${e})\n\n请检查 CODIFY_ACCESS_KEY 是否正确`}],isError:!0}:{content:[{type:"text",text:`❌ 发送失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}`}],isError:!0}}}catch(t){return{content:[{type:"text",text:`❌ 代码发送失败: ${t.message||String(t)}`}],isError:!0}}}),a.registerTool("upload_image",{description:"将本地图片文件上传缓存到 MCP 服务器的 data/cache 目录,返回缓存路径",inputSchema:{filePath:z.string().describe("本地图片文件的绝对路径,例如 /Users/xxx/Desktop/image.png")}},async n=>{try{const{filePath:r}=n;if(!r)return{content:[{type:"text",text:"参数错误: 未提供 filePath"}],isError:!0};let s;try{s=t.readFileSync(r)}catch(t){return{content:[{type:"text",text:`❌ 无法读取文件: ${r}\n错误: ${t.message||String(t)}`}],isError:!0}}const o=e.basename(r),i={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".ico":"image/x-icon"}[e.extname(o).toLowerCase()]||"application/octet-stream",a=s.toString("base64"),c={"Content-Type":"application/json"};ACCESS_KEY&&(c.Authorization=`Bearer ${ACCESS_KEY}`);try{const t=(await axios.post(`${SERVER_URL}/api/uploadImage`,{imageData:a,fileName:o,mimeType:i},{headers:c})).data;return{content:[{type:"text",text:`✅ 图片已成功缓存到服务器\n- 原始文件: ${o}\n- 缓存路径: ${t.cachePath}\n- 文件大小: ${t.size} bytes\n- 类型: ${t.mimeType||i}`}]}}catch(t){const e=t.response?.status,n=t.response?.data||{};return 401===e||403===e?{content:[{type:"text",text:`❌ 认证失败 (${e})\n\n请检查 CODIFY_ACCESS_KEY 是否正确`}],isError:!0}:{content:[{type:"text",text:`❌ 上传失败: ${t.message||String(t)}${n.message?`\n详情: ${n.message}`:""}`}],isError:!0}}}catch(t){return{content:[{type:"text",text:`❌ 图片上传失败: ${t.message||String(t)}`}],isError:!0}}});try{const t=new StdioServerTransport;await a.connect(t)}catch(t){process.exit(1)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codify-ai/mcp-client",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Codify MCP 客户端 - 连接到远程 Codify MCP 服务器,供 CLI 或 Cursor 等 IDE 使用",
5
5
  "type": "module",
6
6
  "bin": {