@him0/freee-mcp 0.6.2 → 0.6.4
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/bin/cli.js +4 -4
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
|
|
3
|
-
var At=Object.defineProperty;var le=(t,e)=>()=>(t&&(e=t(t=0)),e);var $e=(t,e)=>{for(var r in e)At(t,r,{get:e[r],enumerable:!0})};import Me from"path";import Tt from"os";function A(){return process.env.XDG_CONFIG_HOME?Me.join(process.env.XDG_CONFIG_HOME,Fe):Me.join(Tt.homedir(),".config",Fe)}var Fe,j,R,W,X,Pt,Oe,w=le(()=>{"use strict";Fe="freee-mcp";j=54321,R=300*1e3,W=384,X="https://api.freee.co.jp",Pt="0.6.
|
|
3
|
+
var At=Object.defineProperty;var le=(t,e)=>()=>(t&&(e=t(t=0)),e);var $e=(t,e)=>{for(var r in e)At(t,r,{get:e[r],enumerable:!0})};import Me from"path";import Tt from"os";function A(){return process.env.XDG_CONFIG_HOME?Me.join(process.env.XDG_CONFIG_HOME,Fe):Me.join(Tt.homedir(),".config",Fe)}var Fe,j,R,W,X,Pt,Oe,w=le(()=>{"use strict";Fe="freee-mcp";j=54321,R=300*1e3,W=384,X="https://api.freee.co.jp",Pt="0.6.4",Oe=`freee-mcp/${Pt} (MCP Server; +https://github.com/him0/freee-mcp)`});var Ue={};$e(Ue,{CompanyConfigSchema:()=>je,FullConfigSchema:()=>Ne,getCompanyInfo:()=>N,getCurrentCompanyId:()=>b,getDownloadDir:()=>me,loadFullConfig:()=>v,saveFullConfig:()=>$,setCurrentCompany:()=>fe});import pe from"fs/promises";import De from"path";import St from"os";import{z as d}from"zod";function ue(){return De.join(A(),"config.json")}async function vt(){let t=De.dirname(ue());await pe.mkdir(t,{recursive:!0})}function bt(t){return t!=null&&typeof t=="object"&&"defaultCompanyId"in t&&"currentCompanyId"in t&&"companies"in t&&!("clientId"in t)}function It(t){return console.error("\u{1F4E6} \u53E4\u3044\u8A2D\u5B9A\u5F62\u5F0F\u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u3002\u65B0\u3057\u3044\u5F62\u5F0F\u306B\u79FB\u884C\u3057\u307E\u3059..."),{clientId:void 0,clientSecret:void 0,callbackPort:void 0,defaultCompanyId:t.defaultCompanyId,currentCompanyId:t.currentCompanyId,companies:t.companies}}async function v(){let t=ue();try{let e=await pe.readFile(t,"utf8"),r=JSON.parse(e);if(bt(r)){let o=It(r);return await $(o),o}let n=Ne.safeParse(r);if(!n.success)throw new Error(`Invalid config file: ${n.error.message}`);return n.data}catch(e){if(e.code==="ENOENT"){let r={clientId:void 0,clientSecret:void 0,callbackPort:void 0,defaultCompanyId:"0",currentCompanyId:"0",companies:{}};return await $(r),r}throw e}}async function $(t){await vt();let e=ue();await pe.writeFile(e,JSON.stringify(t,null,2),{mode:W})}async function b(){return(await v()).currentCompanyId}async function fe(t,e,r){let n=await v();n.companies[t]?(e||r)&&(e&&(n.companies[t].name=e),r&&(n.companies[t].description=r)):n.companies[t]={id:t,name:e||`Company ${t}`,description:r||void 0,addedAt:Date.now()},n.companies[t].lastUsed=Date.now(),n.currentCompanyId=t,await $(n)}async function N(t){return(await v()).companies[t]||null}async function me(){return(await v()).downloadDir||St.tmpdir()}var je,Ne,M=le(()=>{"use strict";w();je=d.object({id:d.string(),name:d.string().optional(),description:d.string().optional(),addedAt:d.number(),lastUsed:d.number().optional()}),Ne=d.object({clientId:d.string().optional(),clientSecret:d.string().optional(),callbackPort:d.number().optional(),defaultCompanyId:d.string(),currentCompanyId:d.string(),companies:d.record(d.string(),je),downloadDir:d.string().optional()})});var Le={};$e(Le,{getConfig:()=>h,loadConfig:()=>de});function xt(){return!!(process.env.FREEE_CLIENT_ID||process.env.FREEE_CLIENT_SECRET)}async function de(){if(F)return F;let t=await v(),e,r,n;if(xt())console.error("Warning: \u74B0\u5883\u5909\u6570\u3067\u306E\u8A8D\u8A3C\u60C5\u5831\u8A2D\u5B9A\u306F\u975E\u63A8\u5968\u3067\u3059\u3002"),console.error(" `freee-mcp configure` \u3092\u5B9F\u884C\u3057\u3066\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306B\u79FB\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"),console.error(` \u74B0\u5883\u5909\u6570\u8A2D\u5B9A\u306F\u5C06\u6765\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3067\u524A\u9664\u3055\u308C\u308B\u4E88\u5B9A\u3067\u3059\u3002
|
|
4
4
|
`),e=process.env.FREEE_CLIENT_ID||"",r=process.env.FREEE_CLIENT_SECRET||"",n=process.env.FREEE_CALLBACK_PORT?parseInt(process.env.FREEE_CALLBACK_PORT,10):j;else{if(!t.clientId||!t.clientSecret)throw new Error("\u8A8D\u8A3C\u60C5\u5831\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\n`freee-mcp configure` \u3092\u5B9F\u884C\u3057\u3066\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3057\u3066\u304F\u3060\u3055\u3044\u3002");e=t.clientId,r=t.clientSecret,n=t.callbackPort||j}return F={freee:{clientId:e,clientSecret:r,companyId:"0",apiUrl:X},oauth:{callbackPort:n,redirectUri:`http://127.0.0.1:${n}/callback`,authorizationEndpoint:"https://accounts.secure.freee.co.jp/public_api/authorize",tokenEndpoint:"https://accounts.secure.freee.co.jp/public_api/token",scope:"read write"},server:{name:"freee",version:"1.0.0"},auth:{timeoutMs:R}},F}function h(){if(!F)throw new Error("Config not loaded. Call loadConfig() first in async context.");return F}var F,T=le(()=>{"use strict";M();w();F=null});T();import{McpServer as Kt}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as Wt}from"@modelcontextprotocol/sdk/server/stdio.js";T();import Lt from"crypto";import{z as P}from"zod";T();T();w();import Z from"fs/promises";import Ve from"path";import{z as C}from"zod";async function _(t){try{return{success:!0,data:await t.json()}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function l(t){return{content:[{type:"text",text:t}]}}function k(t){return t instanceof Error?t.message:String(t)}function Q(t,e){return{access_token:t.access_token,refresh_token:t.refresh_token||e.refreshToken||"",expires_at:Date.now()+t.expires_in*1e3,token_type:t.token_type||"Bearer",scope:t.scope||e.scope}}w();import Y from"fs/promises";import ge from"path";async function Je(){let t=A();try{return(await Y.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"))}catch{return[]}}async function Be(t){let e=A();try{let r=await Je();if(r.length>0){let n=ge.join(e,r[0]),o=await Y.readFile(n,"utf8"),a=JSON.parse(o),i=he.safeParse(a);if(!i.success)return console.error("[error] Invalid legacy token file:",i.error.message),null;let s=i.data;return await t(s),await Promise.all(r.map(p=>Y.unlink(ge.join(e,p)).catch(u=>{console.error(`[warn] Failed to clean up legacy token file ${p}:`,u)}))),console.error("[info] Migrated legacy company-specific tokens to user-based tokens"),s}}catch(r){console.error("[warn] Error during legacy token migration attempt:",r)}return null}async function He(){let t=A();try{let e=await Je();await Promise.all(e.map(r=>Y.unlink(ge.join(t,r)).catch(n=>{console.error(`[warn] Failed to clear legacy token file ${r}:`,n)}))),e.length>0&&console.error("[info] Cleared legacy company-specific token files")}catch(e){console.error("[warn] Error during legacy token cleanup:",e)}}var he=C.object({access_token:C.string(),refresh_token:C.string(),expires_at:C.number(),token_type:C.string(),scope:C.string()}),ye=C.object({access_token:C.string(),refresh_token:C.string().optional(),expires_in:C.number(),token_type:C.string().optional(),scope:C.string().optional()});function Ce(){return Ve.join(A(),"tokens.json")}async function ee(t){let e=Ce(),r=Ve.dirname(e);try{console.error(`[info] Creating directory: ${r}`),await Z.mkdir(r,{recursive:!0}),console.error(`[info] Writing tokens to: ${e}`),await Z.writeFile(e,JSON.stringify(t,null,2),{mode:W}),console.error("[info] Tokens saved successfully")}catch(n){throw console.error("[error] Failed to save tokens:",n),n}}async function we(){let t=Ce();try{let e=await Z.readFile(t,"utf8"),r=JSON.parse(e),n=he.safeParse(r);return n.success?n.data:(console.error("[error] Invalid token file:",n.error.message),null)}catch(e){if(e.code==="ENOENT"){let r=await Be(ee);return r||null}throw console.error("[error] Failed to load tokens:",e),e}}function Rt(t){return Date.now()<t.expires_at}async function $t(t){let e=h(),r=await fetch(e.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:e.freee.clientId,client_secret:e.freee.clientSecret})});if(!r.ok){let i=await _(r),s=i.success?JSON.stringify(i.data):`(JSON parse failed: ${i.error})`;throw new Error(`Token refresh failed: ${r.status} ${s}`)}let n=await r.json(),o=ye.safeParse(n);if(!o.success)throw new Error(`Invalid token response format: ${o.error.message}`);let a=Q(o.data,{refreshToken:t,scope:e.oauth.scope});return await ee(a),a}async function ze(){let t=Ce();try{await Z.unlink(t),console.error("[info] Tokens cleared successfully")}catch(e){if(e.code==="ENOENT"){console.error("[info] No tokens to clear (file does not exist)");return}throw console.error("[error] Failed to clear tokens:",e),e}await He()}async function qe(){let t=await we();return t?Rt(t)?t.access_token:(await $t(t.refresh_token)).access_token:null}M();w();import Mt from"fs/promises";import Ft from"path";function Ge(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="binary"}function Ot(t){return["application/pdf","application/octet-stream","image/"].some(r=>t.includes(r))}function Dt(t){let e={"application/pdf":".pdf","image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp","text/csv":".csv"};for(let[r,n]of Object.entries(e))if(t.includes(r))return n;return t.includes("image/"),".bin"}async function U(t,e,r,n,o){let a=o||h().freee.apiUrl,i=await b(),s=await qe();if(!s)throw new Error(`\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002freee_authenticate \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u8A8D\u8A3C\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
5
5
|
\u73FE\u5728\u306E\u4E8B\u696D\u6240ID: ${i}
|
|
6
6
|
\u307E\u305F\u306F\u3001FREEE_CLIENT_ID\u74B0\u5883\u5909\u6570\u304C\u6B63\u3057\u304F\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);let p=a.endsWith("/")?a:a+"/",u=e.startsWith("/")?e.slice(1):e,x=new URL(u,p);r&&Object.entries(r).forEach(([m,f])=>{f!==void 0&&x.searchParams.append(m,String(f))});let se=r?.company_id;if(se!==void 0&&String(se)!==String(i))throw new Error(`company_id \u306E\u4E0D\u6574\u5408: \u30EA\u30AF\u30A8\u30B9\u30C8\u306E company_id (${se}) \u3068\u73FE\u5728\u306E\u4E8B\u696D\u6240 (${i}) \u304C\u7570\u306A\u308A\u307E\u3059\u3002
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
freee_set_current_company \u3067\u4E8B\u696D\u6240\u3092\u5207\u308A\u66FF\u3048\u308B\u304B\u3001\u30EA\u30AF\u30A8\u30B9\u30C8\u306E company_id \u3092\u4FEE\u6B63\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);let ce=n?.company_id;if(ce!==void 0&&String(ce)!==String(i))throw new Error(`company_id \u306E\u4E0D\u6574\u5408: \u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3\u306E company_id (${ce}) \u3068\u73FE\u5728\u306E\u4E8B\u696D\u6240 (${i}) \u304C\u7570\u306A\u308A\u307E\u3059\u3002
|
|
8
|
+
freee_set_current_company \u3067\u4E8B\u696D\u6240\u3092\u5207\u308A\u66FF\u3048\u308B\u304B\u3001\u30EA\u30AF\u30A8\u30B9\u30C8\u306E company_id \u3092\u4FEE\u6B63\u3057\u3066\u304F\u3060\u3055\u3044\u3002`);let y=await fetch(x.toString(),{method:t,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json","User-Agent":Oe},body:n?JSON.stringify(typeof n=="string"?JSON.parse(n):n):void 0});if(y.status===401){let m=await _(y),f=m.success?JSON.stringify(m.data):`(JSON parse failed: ${m.error})`;throw new Error(`\u8A8D\u8A3C\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002freee_authenticate \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u518D\u8A8D\u8A3C\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
9
9
|
\u73FE\u5728\u306E\u4E8B\u696D\u6240ID: ${i}
|
|
10
10
|
\u30A8\u30E9\u30FC\u8A73\u7D30: ${y.status} ${f}
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ ${D.join(`
|
|
|
25
25
|
|
|
26
26
|
\u30D2\u30F3\u30C8: \u4E0D\u6B63\u306A\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002`,f+=`
|
|
27
27
|
\u65E2\u5B58\u306E\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u3066\u6B63\u3057\u3044\u69CB\u9020\u3092\u78BA\u8A8D\u3059\u308B\u3053\u3068\u3092\u304A\u52E7\u3081\u3057\u307E\u3059\u3002`,f+=`
|
|
28
|
-
\u4F8B:
|
|
28
|
+
\u4F8B: freee_api_get \u3067\u65E2\u5B58\u30C7\u30FC\u30BF\u3092\u53D6\u5F97\u3057\u3001\u6B63\u3057\u3044\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`))}S?.errors||(f+=`
|
|
29
29
|
|
|
30
30
|
\u8A73\u7D30: ${JSON.stringify(S)}`)}else f+=`
|
|
31
31
|
|