@him0/freee-mcp 0.5.0 → 0.5.2
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 +32 -30
- package/dist/index.cjs +30 -28
- package/dist/index.esm.js +32 -30
- package/dist/openapi/minimal/accounting.json +4777 -0
- package/dist/openapi/minimal/hr.json +2536 -0
- package/dist/openapi/minimal/invoice.json +460 -0
- package/dist/openapi/minimal/pm.json +350 -0
- package/dist/openapi/minimal/sm.json +124 -0
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
`),e=process.env.FREEE_CLIENT_ID||"",n=process.env.FREEE_CLIENT_SECRET||"",r=process.env.FREEE_CALLBACK_PORT?parseInt(process.env.FREEE_CALLBACK_PORT,10):v;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,n=t.clientSecret,r=t.callbackPort||v}let o=process.env.FREEE_DEFAULT_COMPANY_ID||"0";return process.env.FREEE_DEFAULT_COMPANY_ID&&(console.error("Warning: FREEE_DEFAULT_COMPANY_ID \u74B0\u5883\u5909\u6570\u306F\u975E\u63A8\u5968\u3067\u3059\u3002"),console.error(" \u4E8B\u696D\u6240ID\u306F `freee_set_company` \u30C4\u30FC\u30EB\u3067\u52D5\u7684\u306B\u5909\u66F4\u3067\u304D\u307E\u3059\u3002\n")),w={freee:{clientId:e,clientSecret:n,companyId:o,apiUrl:"https://api.freee.co.jp"},oauth:{callbackPort:r,redirectUri:`http://127.0.0.1:${r}/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:j}},w}function He(){if(!w)throw new Error("Config not loaded. Call loadConfig() first.");return w}var w,l,h=q(()=>{"use strict";P();b();w=null;l=new Proxy({},{get(t,e){if(!w)throw new Error("Config not loaded. Call loadConfig() first in async context.");return w[e]}})});h();import{McpServer as at}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as st}from"@modelcontextprotocol/sdk/server/stdio.js";h();import ze from"http";import{URL as Ge}from"url";import Ke from"net";h();import we from"crypto";h();b();import C from"fs/promises";import I from"path";async function y(t){return t.json().catch(()=>({}))}function X(){return I.join(E(),"tokens.json")}async function N(t){let e=X(),n=I.dirname(e);try{console.error(`[info] Creating directory: ${n}`),await C.mkdir(n,{recursive:!0}),console.error(`[info] Writing tokens to: ${e}`),await C.writeFile(e,JSON.stringify(t,null,2),{mode:M}),console.error("[info] Tokens saved successfully")}catch(r){throw console.error("[error] Failed to save tokens:",r),r}}async function Q(){let t=X();try{let e=await C.readFile(t,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT"){let n=await Je();return n||null}throw console.error("[error] Failed to load tokens:",e),e}}function Be(t){return Date.now()<t.expires_at}async function Je(){let t=E();try{let n=(await C.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));if(n.length>0){let r=I.join(t,n[0]),o=await C.readFile(r,"utf8"),i=JSON.parse(o);return await N(i),await Promise.all(n.map(a=>C.unlink(I.join(t,a)).catch(s=>{console.error(`[warn] Failed to clean up legacy token file ${a}:`,s)}))),console.error("[info] Migrated legacy company-specific tokens to user-based tokens"),i}}catch(e){console.error("[warn] Error during legacy token migration attempt:",e)}return null}async function Ve(t){let e=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:l.freee.clientId,client_secret:l.freee.clientSecret})});if(!e.ok){let o=await y(e);throw new Error(`Token refresh failed: ${e.status} ${JSON.stringify(o)}`)}let n=await e.json(),r={access_token:n.access_token,refresh_token:n.refresh_token||t,expires_at:Date.now()+n.expires_in*1e3,token_type:n.token_type||"Bearer",scope:n.scope||l.oauth.scope};return await N(r),r}async function ye(){let t=X();try{await C.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 qe()}async function qe(){let t=E();try{let n=(await C.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));await Promise.all(n.map(r=>C.unlink(I.join(t,r)).catch(o=>{console.error(`[warn] Failed to clear legacy token file ${r}:`,o)}))),n.length>0&&console.error("[info] Cleared legacy company-specific token files")}catch(e){console.error("[warn] Error during legacy token cleanup:",e)}}async function Ce(){let t=await Q();if(!t)return null;if(Be(t))return t.access_token;try{return(await Ve(t.refresh_token)).access_token}catch(e){return console.error("[warn] Failed to refresh token:",e),null}}function ke(){let t=we.randomBytes(32).toString("base64url"),e=we.createHash("sha256").update(t).digest("base64url");return{codeVerifier:t,codeChallenge:e}}function H(t,e,n){let r=new URLSearchParams({response_type:"code",client_id:l.freee.clientId,redirect_uri:n,scope:l.oauth.scope,state:e,code_challenge:t,code_challenge_method:"S256"});return`${l.oauth.authorizationEndpoint}?${r.toString()}`}async function B(t,e,n){let r=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:l.freee.clientId,client_secret:l.freee.clientSecret,code:t,redirect_uri:n,code_verifier:e})});if(!r.ok){let a=await y(r);throw new Error(`Token exchange failed: ${r.status} ${JSON.stringify(a)}`)}let o=await r.json(),i={access_token:o.access_token,refresh_token:o.refresh_token,expires_at:Date.now()+o.expires_in*1e3,token_type:o.token_type||"Bearer",scope:o.scope||l.oauth.scope};return await N(i),i}var Z=class{pendingAuthentications=new Map;cliAuthHandlers=new Map;registerAuthentication(e,n){console.error(`Registering authentication request with state: ${e.substring(0,10)}...`),console.error(`Code verifier: ${n.substring(0,10)}...`);let r=setTimeout(()=>{this.pendingAuthentications.delete(e),console.error(`Authentication timeout for state: ${e.substring(0,10)}...`)},l.auth.timeoutMs);this.pendingAuthentications.set(e,{codeVerifier:n,resolve:o=>{console.error("Authentication completed successfully!")},reject:o=>{console.error("Authentication failed:",o)},timeout:r}),console.error(`Registration complete. Total pending: ${this.pendingAuthentications.size}`)}getPendingAuthentication(e){return this.pendingAuthentications.get(e)}removePendingAuthentication(e){let n=this.pendingAuthentications.get(e);n&&(clearTimeout(n.timeout),this.pendingAuthentications.delete(e))}clearAllPending(){for(let[e,n]of this.pendingAuthentications)clearTimeout(n.timeout),n.reject(new Error("Server shutdown"));this.pendingAuthentications.clear()}get pendingCount(){return this.pendingAuthentications.size}registerCliAuthHandler(e,n){this.cliAuthHandlers.set(e,n)}getCliAuthHandler(e){return this.cliAuthHandlers.get(e)}removeCliAuthHandler(e){this.cliAuthHandlers.delete(e)}},ee=class{server=null;port=null;authManager;constructor(e){this.authManager=e}getRedirectUri(){if(this.port===null)throw new Error("Callback server not started. Call start() first.");return`http://127.0.0.1:${this.port}/callback`}getPort(){return this.port}isRunning(){return this.server!==null}async start(){if(this.server)return;let e=l.oauth.callbackPort,n=await this.findAvailablePort(e);return this.port=n,n!==e&&console.error(`Warning: Port ${e} is in use. Using fallback port ${n} for OAuth callback server.`),new Promise((r,o)=>{this.server=ze.createServer((i,a)=>{console.error(`Callback request: ${i.method} ${i.url}`);let s=new Ge(i.url,`http://127.0.0.1:${n}`);s.pathname==="/callback"?this.handleCallback(s,a):s.pathname==="/"?(a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>freee MCP OAuth Server</h1><p>\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u30B5\u30FC\u30D0\u30FC\u304C\u7A3C\u50CD\u4E2D\u3067\u3059\u3002</p>")):(a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>404 Not Found</h1><p>\u3053\u306E\u30D1\u30B9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093\u3002</p>"))}),this.server.on("error",i=>{console.error("Callback server error:",i),o(i)}),this.server.listen(n,"127.0.0.1",()=>{console.error(`OAuth callback server listening on http://127.0.0.1:${n}`),r()})})}stop(){this.server&&(this.authManager.clearAllPending(),this.server.close(()=>{console.error("OAuth callback server stopped")}),this.server=null,this.port=null)}async checkPortAvailable(e){return new Promise(n=>{let r=Ke.createServer();r.listen(e,"127.0.0.1",()=>{r.close(()=>{n(!0)})}),r.on("error",()=>{n(!1)})})}async findAvailablePort(e,n=50){for(let r=e;r<e+n;r++)if(await this.checkPortAvailable(r))return r;throw new Error(`No available port found after checking ${n} ports starting from ${e}`)}handleCallback(e,n){let r=e.searchParams.get("code"),o=e.searchParams.get("state"),i=e.searchParams.get("error"),a=e.searchParams.get("error_description");console.error(`Callback received - URL: ${e.toString()}`),console.error("Callback parameters:",{code:r?`${r.substring(0,10)}...`:null,state:o?`${o.substring(0,10)}...`:null,error:i,errorDescription:a}),console.error(`Pending authentications count: ${this.authManager.pendingCount}`);let s=o?this.authManager.getCliAuthHandler(o):void 0;if(i){let u=a||i;if(console.error(`OAuth error: ${i} - ${a}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${u}</p>`),s)s.reject(new Error(`OAuth error: ${i} - ${a}`));else if(o){let k=this.authManager.getPendingAuthentication(o);k&&(clearTimeout(k.timeout),k.reject(new Error(`OAuth error: ${i} - ${a}`)),this.authManager.removePendingAuthentication(o))}return}if(!r||!o){console.error("Missing code or state"),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u30B3\u30FC\u30C9\u307E\u305F\u306F\u72B6\u614B\u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002</p>");return}if(s){console.error("Valid CLI callback received"),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u30BF\u30FC\u30DF\u30CA\u30EB\u306B\u623B\u3063\u3066\u304F\u3060\u3055\u3044\u3002</p>"),s.resolve(r);return}let p=this.authManager.getPendingAuthentication(o);if(!p){console.error(`Unknown state: ${o}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u4E0D\u660E\u306A\u8A8D\u8A3C\u72B6\u614B\u3067\u3059\u3002\u8A8D\u8A3C\u3092\u518D\u958B\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>");return}console.error("Valid callback received, exchanging code for tokens..."),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002</p>"),this.authManager.removePendingAuthentication(o),B(r,p.codeVerifier,this.getRedirectUri()).then(u=>{console.error("Token exchange successful!"),p.resolve(u)}).catch(u=>{console.error("Token exchange failed:",u),p.reject(u)})}},te=new Z,ne=new ee(te);function S(){return ne.getRedirectUri()}async function J(){return ne.start()}function _e(t,e){te.registerAuthentication(t,e)}function $(){ne.stop()}function Ae(){return te}h();import Ze from"crypto";import{z as re}from"zod";h();P();import We from"fs/promises";import Ye from"path";function Xe(t){return["application/pdf","application/octet-stream","image/"].some(n=>t.includes(n))}function Qe(t){let e={"application/pdf":".pdf","image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp","text/csv":".csv"};for(let[n,r]of Object.entries(e))if(t.includes(n))return r;return t.includes("image/"),".bin"}async function R(t,e,n,r,o){let i=o||l.freee.apiUrl,a=await A(),s=await Ce();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
|
|
3
|
+
var Fe=Object.defineProperty;var z=(t,e)=>()=>(t&&(e=t(t=0)),e);var fe=(t,e)=>{for(var n in e)Fe(t,n,{get:e[n],enumerable:!0})};import de from"path";import Oe from"os";function A(){return process.env.XDG_CONFIG_HOME?de.join(process.env.XDG_CONFIG_HOME,ge):de.join(Oe.homedir(),".config",ge)}var ge,T,M,N,b=z(()=>{"use strict";ge="freee-mcp";T=54321,M=300*1e3,N=384});var he={};fe(he,{getCompanyInfo:()=>x,getCompanyList:()=>Ne,getCurrentCompanyId:()=>E,getDownloadDir:()=>Y,loadFullConfig:()=>m,saveFullConfig:()=>_,setCurrentCompany:()=>W,setDownloadDir:()=>He});import G from"fs/promises";import me from"path";import Le from"os";function K(){return me.join(A(),"config.json")}async function Ue(){let t=me.dirname(K());await G.mkdir(t,{recursive:!0})}function je(t){return t!=null&&typeof t=="object"&&"defaultCompanyId"in t&&"currentCompanyId"in t&&"companies"in t&&!("clientId"in t)}function Me(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 m(){let t=K();try{let e=await G.readFile(t,"utf8"),n=JSON.parse(e);if(je(n)){let r=Me(n);return await _(r),r}return n}catch(e){if(e.code==="ENOENT"){let n=process.env.FREEE_DEFAULT_COMPANY_ID||"0",r={clientId:void 0,clientSecret:void 0,callbackPort:void 0,defaultCompanyId:n,currentCompanyId:n,companies:{[n]:{id:n,name:"Default Company",description:"Company from environment variable",addedAt:Date.now(),lastUsed:Date.now()}}};return await _(r),r}throw e}}async function _(t){await Ue();let e=K();await G.writeFile(e,JSON.stringify(t,null,2),{mode:N})}async function E(){return(await m()).currentCompanyId}async function W(t,e,n){let r=await m();r.companies[t]?(e||n)&&(e&&(r.companies[t].name=e),n&&(r.companies[t].description=n)):r.companies[t]={id:t,name:e||`Company ${t}`,description:n||void 0,addedAt:Date.now()},r.companies[t].lastUsed=Date.now(),r.currentCompanyId=t,await _(r)}async function Ne(){let t=await m();return Object.values(t.companies).sort((e,n)=>(n.lastUsed||0)-(e.lastUsed||0))}async function x(t){return(await m()).companies[t]||null}async function Y(){return(await m()).downloadDir||Le.tmpdir()}async function He(t){let e=await m();e.downloadDir=t,await _(e)}var P=z(()=>{"use strict";b()});var ye={};fe(ye,{config:()=>l,getConfig:()=>Je,loadConfig:()=>X});function Be(){return!!(process.env.FREEE_CLIENT_ID||process.env.FREEE_CLIENT_SECRET)}async function X(){if(w)return w;let t=await m(),e,n,r;if(Be())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
|
+
`),e=process.env.FREEE_CLIENT_ID||"",n=process.env.FREEE_CLIENT_SECRET||"",r=process.env.FREEE_CALLBACK_PORT?parseInt(process.env.FREEE_CALLBACK_PORT,10):T;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,n=t.clientSecret,r=t.callbackPort||T}let o=process.env.FREEE_DEFAULT_COMPANY_ID||"0";return process.env.FREEE_DEFAULT_COMPANY_ID&&(console.error("Warning: FREEE_DEFAULT_COMPANY_ID \u74B0\u5883\u5909\u6570\u306F\u975E\u63A8\u5968\u3067\u3059\u3002"),console.error(" \u4E8B\u696D\u6240ID\u306F `freee_set_company` \u30C4\u30FC\u30EB\u3067\u52D5\u7684\u306B\u5909\u66F4\u3067\u304D\u307E\u3059\u3002\n")),w={freee:{clientId:e,clientSecret:n,companyId:o,apiUrl:"https://api.freee.co.jp"},oauth:{callbackPort:r,redirectUri:`http://127.0.0.1:${r}/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:M}},w}function Je(){if(!w)throw new Error("Config not loaded. Call loadConfig() first.");return w}var w,l,h=z(()=>{"use strict";P();b();w=null;l=new Proxy({},{get(t,e){if(!w)throw new Error("Config not loaded. Call loadConfig() first in async context.");return w[e]}})});h();import{McpServer as st}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as ct}from"@modelcontextprotocol/sdk/server/stdio.js";h();import Ke from"http";import{URL as We}from"url";import Ye from"net";h();import ke from"crypto";h();b();import C from"fs/promises";import I from"path";async function y(t){return t.json().catch(()=>({}))}function Q(){return I.join(A(),"tokens.json")}async function H(t){let e=Q(),n=I.dirname(e);try{console.error(`[info] Creating directory: ${n}`),await C.mkdir(n,{recursive:!0}),console.error(`[info] Writing tokens to: ${e}`),await C.writeFile(e,JSON.stringify(t,null,2),{mode:N}),console.error("[info] Tokens saved successfully")}catch(r){throw console.error("[error] Failed to save tokens:",r),r}}async function Z(){let t=Q();try{let e=await C.readFile(t,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT"){let n=await qe();return n||null}throw console.error("[error] Failed to load tokens:",e),e}}function Ve(t){return Date.now()<t.expires_at}async function qe(){let t=A();try{let n=(await C.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));if(n.length>0){let r=I.join(t,n[0]),o=await C.readFile(r,"utf8"),i=JSON.parse(o);return await H(i),await Promise.all(n.map(a=>C.unlink(I.join(t,a)).catch(s=>{console.error(`[warn] Failed to clean up legacy token file ${a}:`,s)}))),console.error("[info] Migrated legacy company-specific tokens to user-based tokens"),i}}catch(e){console.error("[warn] Error during legacy token migration attempt:",e)}return null}async function ze(t){let e=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:l.freee.clientId,client_secret:l.freee.clientSecret})});if(!e.ok){let o=await y(e);throw new Error(`Token refresh failed: ${e.status} ${JSON.stringify(o)}`)}let n=await e.json(),r={access_token:n.access_token,refresh_token:n.refresh_token||t,expires_at:Date.now()+n.expires_in*1e3,token_type:n.token_type||"Bearer",scope:n.scope||l.oauth.scope};return await H(r),r}async function Ce(){let t=Q();try{await C.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 Ge()}async function Ge(){let t=A();try{let n=(await C.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));await Promise.all(n.map(r=>C.unlink(I.join(t,r)).catch(o=>{console.error(`[warn] Failed to clear legacy token file ${r}:`,o)}))),n.length>0&&console.error("[info] Cleared legacy company-specific token files")}catch(e){console.error("[warn] Error during legacy token cleanup:",e)}}async function we(){let t=await Z();if(!t)return null;if(Ve(t))return t.access_token;try{return(await ze(t.refresh_token)).access_token}catch(e){return console.error("[warn] Failed to refresh token:",e),null}}function _e(){let t=ke.randomBytes(32).toString("base64url"),e=ke.createHash("sha256").update(t).digest("base64url");return{codeVerifier:t,codeChallenge:e}}function B(t,e,n){let r=new URLSearchParams({response_type:"code",client_id:l.freee.clientId,redirect_uri:n,scope:l.oauth.scope,state:e,code_challenge:t,code_challenge_method:"S256"});return`${l.oauth.authorizationEndpoint}?${r.toString()}`}async function J(t,e,n){let r=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:l.freee.clientId,client_secret:l.freee.clientSecret,code:t,redirect_uri:n,code_verifier:e})});if(!r.ok){let a=await y(r);throw new Error(`Token exchange failed: ${r.status} ${JSON.stringify(a)}`)}let o=await r.json(),i={access_token:o.access_token,refresh_token:o.refresh_token,expires_at:Date.now()+o.expires_in*1e3,token_type:o.token_type||"Bearer",scope:o.scope||l.oauth.scope};return await H(i),i}var ee=class{pendingAuthentications=new Map;cliAuthHandlers=new Map;registerAuthentication(e,n){console.error(`Registering authentication request with state: ${e.substring(0,10)}...`),console.error(`Code verifier: ${n.substring(0,10)}...`);let r=setTimeout(()=>{this.pendingAuthentications.delete(e),console.error(`Authentication timeout for state: ${e.substring(0,10)}...`)},l.auth.timeoutMs);this.pendingAuthentications.set(e,{codeVerifier:n,resolve:o=>{console.error("Authentication completed successfully!")},reject:o=>{console.error("Authentication failed:",o)},timeout:r}),console.error(`Registration complete. Total pending: ${this.pendingAuthentications.size}`)}getPendingAuthentication(e){return this.pendingAuthentications.get(e)}removePendingAuthentication(e){let n=this.pendingAuthentications.get(e);n&&(clearTimeout(n.timeout),this.pendingAuthentications.delete(e))}clearAllPending(){for(let[e,n]of this.pendingAuthentications)clearTimeout(n.timeout),n.reject(new Error("Server shutdown"));this.pendingAuthentications.clear()}get pendingCount(){return this.pendingAuthentications.size}registerCliAuthHandler(e,n){this.cliAuthHandlers.set(e,n)}getCliAuthHandler(e){return this.cliAuthHandlers.get(e)}removeCliAuthHandler(e){this.cliAuthHandlers.delete(e)}},te=class{server=null;port=null;authManager;constructor(e){this.authManager=e}getRedirectUri(){if(this.port===null)throw new Error("Callback server not started. Call start() first.");return`http://127.0.0.1:${this.port}/callback`}getPort(){return this.port}isRunning(){return this.server!==null}async start(){if(this.server)return;let e=l.oauth.callbackPort,n=await this.findAvailablePort(e);return this.port=n,n!==e&&console.error(`Warning: Port ${e} is in use. Using fallback port ${n} for OAuth callback server.`),new Promise((r,o)=>{this.server=Ke.createServer((i,a)=>{console.error(`Callback request: ${i.method} ${i.url}`);let s=new We(i.url,`http://127.0.0.1:${n}`);s.pathname==="/callback"?this.handleCallback(s,a):s.pathname==="/"?(a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>freee MCP OAuth Server</h1><p>\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u30B5\u30FC\u30D0\u30FC\u304C\u7A3C\u50CD\u4E2D\u3067\u3059\u3002</p>")):(a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>404 Not Found</h1><p>\u3053\u306E\u30D1\u30B9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093\u3002</p>"))}),this.server.on("error",i=>{console.error("Callback server error:",i),o(i)}),this.server.listen(n,"127.0.0.1",()=>{console.error(`OAuth callback server listening on http://127.0.0.1:${n}`),r()})})}stop(){this.server&&(this.authManager.clearAllPending(),this.server.close(()=>{console.error("OAuth callback server stopped")}),this.server=null,this.port=null)}async checkPortAvailable(e){return new Promise(n=>{let r=Ye.createServer();r.listen(e,"127.0.0.1",()=>{r.close(()=>{n(!0)})}),r.on("error",()=>{n(!1)})})}async findAvailablePort(e,n=50){for(let r=e;r<e+n;r++)if(await this.checkPortAvailable(r))return r;throw new Error(`No available port found after checking ${n} ports starting from ${e}`)}handleCallback(e,n){let r=e.searchParams.get("code"),o=e.searchParams.get("state"),i=e.searchParams.get("error"),a=e.searchParams.get("error_description");console.error(`Callback received - URL: ${e.toString()}`),console.error("Callback parameters:",{code:r?`${r.substring(0,10)}...`:null,state:o?`${o.substring(0,10)}...`:null,error:i,errorDescription:a}),console.error(`Pending authentications count: ${this.authManager.pendingCount}`);let s=o?this.authManager.getCliAuthHandler(o):void 0;if(i){let u=a||i;if(console.error(`OAuth error: ${i} - ${a}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${u}</p>`),s)s.reject(new Error(`OAuth error: ${i} - ${a}`));else if(o){let k=this.authManager.getPendingAuthentication(o);k&&(clearTimeout(k.timeout),k.reject(new Error(`OAuth error: ${i} - ${a}`)),this.authManager.removePendingAuthentication(o))}return}if(!r||!o){console.error("Missing code or state"),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u30B3\u30FC\u30C9\u307E\u305F\u306F\u72B6\u614B\u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002</p>");return}if(s){console.error("Valid CLI callback received"),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u30BF\u30FC\u30DF\u30CA\u30EB\u306B\u623B\u3063\u3066\u304F\u3060\u3055\u3044\u3002</p>"),s.resolve(r);return}let p=this.authManager.getPendingAuthentication(o);if(!p){console.error(`Unknown state: ${o}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u4E0D\u660E\u306A\u8A8D\u8A3C\u72B6\u614B\u3067\u3059\u3002\u8A8D\u8A3C\u3092\u518D\u958B\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>");return}console.error("Valid callback received, exchanging code for tokens..."),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002</p>"),this.authManager.removePendingAuthentication(o),J(r,p.codeVerifier,this.getRedirectUri()).then(u=>{console.error("Token exchange successful!"),p.resolve(u)}).catch(u=>{console.error("Token exchange failed:",u),p.reject(u)})}},ne=new ee,re=new te(ne);function S(){return re.getRedirectUri()}async function V(){return re.start()}function Ee(t,e){ne.registerAuthentication(t,e)}function $(){re.stop()}function Ae(){return ne}h();import tt from"crypto";import{z as oe}from"zod";h();P();import Xe from"fs/promises";import Qe from"path";function Ze(t){return["application/pdf","application/octet-stream","image/"].some(n=>t.includes(n))}function et(t){let e={"application/pdf":".pdf","image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp","text/csv":".csv"};for(let[n,r]of Object.entries(e))if(t.includes(n))return r;return t.includes("image/"),".bin"}async function R(t,e,n,r,o){let i=o||l.freee.apiUrl,a=await E(),s=await we();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: ${a}
|
|
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=i.endsWith("/")?i:i+"/",u=e.startsWith("/")?e.slice(1):e,k=new URL(u,p);n&&Object.entries(n).forEach(([f,
|
|
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=i.endsWith("/")?i:i+"/",u=e.startsWith("/")?e.slice(1):e,k=new URL(u,p);n&&Object.entries(n).forEach(([f,g])=>{g!==void 0&&k.searchParams.append(f,String(g))}),k.searchParams.append("company_id",String(a));let d=await fetch(k.toString(),{method:t,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:r?JSON.stringify(typeof r=="string"?JSON.parse(r):r):void 0});if(d.status===401||d.status===403){let f=await y(d);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
|
|
7
7
|
\u73FE\u5728\u306E\u4E8B\u696D\u6240ID: ${a}
|
|
8
|
-
\u30A8\u30E9\u30FC\u8A73\u7D30: ${
|
|
8
|
+
\u30A8\u30E9\u30FC\u8A73\u7D30: ${d.status} ${JSON.stringify(f)}
|
|
9
9
|
|
|
10
10
|
\u78BA\u8A8D\u4E8B\u9805:
|
|
11
11
|
1. FREEE_CLIENT_ID\u74B0\u5883\u5909\u6570\u304C\u6B63\u3057\u304F\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u304B
|
|
12
12
|
2. freee\u5074\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u8A2D\u5B9A\u304C\u6B63\u3057\u3044\u304B\uFF08\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8URI\u7B49\uFF09
|
|
13
13
|
3. \u30C8\u30FC\u30AF\u30F3\u306E\u6709\u52B9\u671F\u9650\u304C\u5207\u308C\u3066\u3044\u306A\u3044\u304B
|
|
14
|
-
4. \u4E8B\u696D\u6240ID\u304C\u6B63\u3057\u3044\u304B\uFF08freee_get_current_company \u3067\u78BA\u8A8D\uFF09`)}if(!
|
|
14
|
+
4. \u4E8B\u696D\u6240ID\u304C\u6B63\u3057\u3044\u304B\uFF08freee_get_current_company \u3067\u78BA\u8A8D\uFF09`)}if(!d.ok){let f=await y(d),g=`API request failed: ${d.status}`;if(f&&f.errors&&Array.isArray(f.errors)){let j=[];for(let v of f.errors)v.messages&&Array.isArray(v.messages)&&j.push(...v.messages);j.length>0&&(g+=`
|
|
15
15
|
|
|
16
16
|
\u30A8\u30E9\u30FC\u8A73\u7D30:
|
|
17
|
-
${
|
|
18
|
-
`)}`,
|
|
17
|
+
${j.join(`
|
|
18
|
+
`)}`,d.status===400&&(g+=`
|
|
19
19
|
|
|
20
|
-
\u30D2\u30F3\u30C8: \u4E0D\u6B63\u306A\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002`,
|
|
21
|
-
\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`,
|
|
22
|
-
\u4F8B: get_items, get_partners, get_account_items \u306A\u3069\u3067\u65E2\u5B58\u30C7\u30FC\u30BF\u306E\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`))}throw f?.errors||(
|
|
20
|
+
\u30D2\u30F3\u30C8: \u4E0D\u6B63\u306A\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002`,g+=`
|
|
21
|
+
\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`,g+=`
|
|
22
|
+
\u4F8B: get_items, get_partners, get_account_items \u306A\u3069\u3067\u65E2\u5B58\u30C7\u30FC\u30BF\u306E\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`))}throw f?.errors||(g+=`
|
|
23
23
|
|
|
24
|
-
\u8A73\u7D30: ${JSON.stringify(f)}`),new Error(
|
|
24
|
+
\u8A73\u7D30: ${JSON.stringify(f)}`),new Error(g)}let q=d.headers.get("content-type")||"";if(Ze(q)){let f=await Y(),g=et(q),v=`freee_download_${Date.now()}${g}`,pe=Qe.join(f,v),ue=await d.arrayBuffer();return await Xe.writeFile(pe,Buffer.from(ue)),{type:"binary",filePath:pe,mimeType:q,size:ue.byteLength}}return d.json()}P();function Pe(t){t.tool("freee_current_user","\u73FE\u5728\u306E\u30E6\u30FC\u30B6\u30FC\u60C5\u5831\u3092\u53D6\u5F97\u3002\u8A73\u7D30\u30AC\u30A4\u30C9\u306Ffreee-mcp skill\u3092\u53C2\u7167\u3002",{},async()=>{try{let e=await E(),n=await x(e);if(!e)return{content:[{type:"text",text:"\u4F1A\u793EID\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002freee_set_company \u3067\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"}]};let r=await R("GET","/api/1/users/me");return{content:[{type:"text",text:`\u73FE\u5728\u306E\u30E6\u30FC\u30B6\u30FC\u60C5\u5831:
|
|
25
25
|
\u4F1A\u793EID: ${e}
|
|
26
26
|
\u4F1A\u793E\u540D: ${n?.name||"Unknown"}
|
|
27
27
|
\u30E6\u30FC\u30B6\u30FC\u8A73\u7D30:
|
|
@@ -29,49 +29,51 @@ ${JSON.stringify(r,null,2)}`}]}}catch(e){return{content:[{type:"text",text:`\u30
|
|
|
29
29
|
OAuth\u8A8D\u8A3C\u3092\u884C\u3046\u306B\u306F\u3001freee developers\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3001
|
|
30
30
|
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8ID\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};if(!l.freee.clientSecret)return{content:[{type:"text",text:`FREEE_CLIENT_SECRET\u74B0\u5883\u5909\u6570\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
|
|
31
31
|
OAuth\u8A8D\u8A3C\u3092\u884C\u3046\u306B\u306F\u3001freee developers\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3001
|
|
32
|
-
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let{codeVerifier:e,codeChallenge:n}=
|
|
32
|
+
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let{codeVerifier:e,codeChallenge:n}=_e(),r=tt.randomBytes(16).toString("hex"),o=B(n,r,S());return Ee(r,e),console.error(`Authentication URL: ${o}`),{content:[{type:"text",text:`\u8A8D\u8A3CURL: ${o}
|
|
33
33
|
|
|
34
|
-
\u30D6\u30E9\u30A6\u30B6\u3067\u958B\u3044\u3066\u8A8D\u8A3C\u3057\u3066\u304F\u3060\u3055\u3044\u30025\u5206\u3067\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3059\u3002`}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u958B\u59CB\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_auth_status","\u8A8D\u8A3C\u72B6\u614B\u3092\u78BA\u8A8D\u3002",{},async()=>{try{let e=await
|
|
34
|
+
\u30D6\u30E9\u30A6\u30B6\u3067\u958B\u3044\u3066\u8A8D\u8A3C\u3057\u3066\u304F\u3060\u3055\u3044\u30025\u5206\u3067\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3059\u3002`}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u958B\u59CB\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_auth_status","\u8A8D\u8A3C\u72B6\u614B\u3092\u78BA\u8A8D\u3002",{},async()=>{try{let e=await Z();if(!e)return{content:[{type:"text",text:"\u672A\u8A8D\u8A3C\u3002freee_authenticate \u3067\u8A8D\u8A3C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"}]};let n=Date.now()<e.expires_at,r=new Date(e.expires_at).toLocaleString();return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B: ${n?"\u6709\u52B9":"\u671F\u9650\u5207\u308C"}
|
|
35
35
|
\u6709\u52B9\u671F\u9650: ${r}`+(n?"":`
|
|
36
|
-
\u6B21\u56DEAPI\u4F7F\u7528\u6642\u306B\u81EA\u52D5\u66F4\u65B0\u3055\u308C\u307E\u3059\u3002`)}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B\u306E\u78BA\u8A8D\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_clear_auth","\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3002",{},async()=>{try{return await
|
|
36
|
+
\u6B21\u56DEAPI\u4F7F\u7528\u6642\u306B\u81EA\u52D5\u66F4\u65B0\u3055\u308C\u307E\u3059\u3002`)}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B\u306E\u78BA\u8A8D\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_clear_auth","\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3002",{},async()=>{try{return await Ce(),{content:[{type:"text",text:"\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3057\u305F\u3002\u518D\u8A8D\u8A3C\u3059\u308B\u306B\u306F freee_authenticate \u3092\u4F7F\u7528\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u60C5\u5831\u306E\u30AF\u30EA\u30A2\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_set_company","\u4E8B\u696D\u6240\u3092\u8A2D\u5B9A\u30FB\u5207\u308A\u66FF\u3048\u3002",{company_id:oe.string().describe("\u4E8B\u696D\u6240ID"),name:oe.string().optional().describe("\u4E8B\u696D\u6240\u540D"),description:oe.string().optional().describe("\u8AAC\u660E")},async e=>{try{let{company_id:n,name:r,description:o}=e;return await W(n,r,o),{content:[{type:"text",text:`\u4E8B\u696D\u6240\u3092\u8A2D\u5B9A: ${(await x(n))?.name||n}`}]}}catch(n){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u306E\u8A2D\u5B9A\u306B\u5931\u6557: ${n instanceof Error?n.message:String(n)}`}]}}}),t.tool("freee_get_current_company","\u73FE\u5728\u306E\u4E8B\u696D\u6240\u60C5\u5831\u3092\u8868\u793A\u3002",{},async()=>{try{let e=await E(),n=await x(e);return n?{content:[{type:"text",text:`\u4E8B\u696D\u6240: ${n.name} (ID: ${n.id})`}]}:{content:[{type:"text",text:`\u4E8B\u696D\u6240ID: ${e} (\u8A73\u7D30\u60C5\u5831\u306A\u3057)`}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u60C5\u5831\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_list_companies","\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u8868\u793A\u3002",{},async()=>{try{let e=await R("GET","/api/1/companies"),n=await E();return e?.companies?.length?{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7:
|
|
37
37
|
${e.companies.map(o=>{let i=o.id===parseInt(n)?" *":"";return`${o.name} (${o.id})${i}`}).join(`
|
|
38
|
-
`)}`}]}:{content:[{type:"text",text:"\u4E8B\u696D\u6240\u60C5\u5831\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}})}import{z as c}from"zod";import
|
|
38
|
+
`)}`}]}:{content:[{type:"text",text:"\u4E8B\u696D\u6240\u60C5\u5831\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}})}import{z as c}from"zod";import Te from"node:fs";import F from"node:path";import{fileURLToPath as nt}from"node:url";var ie=F.dirname(nt(import.meta.url));function rt(){let t=[F.resolve(ie,"./openapi/minimal"),F.resolve(ie,"../dist/openapi/minimal"),F.resolve(ie,"../../openapi/minimal")];for(let e of t)if(Te.existsSync(e))return e;throw new Error(`Could not find minimal schema directory. Searched paths:
|
|
39
|
+
${t.join(`
|
|
40
|
+
`)}`)}var ot=rt();function D(t){let e=F.join(ot,t),n=Te.readFileSync(e,"utf-8");return JSON.parse(n)}var ae=null;function se(){return ae===null&&(ae={accounting:{schema:D("accounting.json"),baseUrl:"https://api.freee.co.jp",prefix:"accounting",name:"freee\u4F1A\u8A08 API"},hr:{schema:D("hr.json"),baseUrl:"https://api.freee.co.jp/hr",prefix:"hr",name:"freee\u4EBA\u4E8B\u52B4\u52D9 API"},invoice:{schema:D("invoice.json"),baseUrl:"https://api.freee.co.jp/iv",prefix:"invoice",name:"freee\u8ACB\u6C42\u66F8 API"},pm:{schema:D("pm.json"),baseUrl:"https://api.freee.co.jp/pm",prefix:"pm",name:"freee\u5DE5\u6570\u7BA1\u7406 API"},sm:{schema:D("sm.json"),baseUrl:"https://api.freee.co.jp/sm",prefix:"sm",name:"freee\u8CA9\u58F2 API"}}),ae}var ce=new Proxy({},{get(t,e){return se()[e]},ownKeys(){return Object.keys(se())},getOwnPropertyDescriptor(t,e){let n=se();if(e in n)return{enumerable:!0,configurable:!0,value:n[e]}}});function ve(t,e,n,r){let o=r.schema.paths;if(e in o){let i=o[e];if(t in i)return{isValid:!0,message:"Valid path and method",operation:i[t],actualPath:e,apiType:n,baseUrl:r.baseUrl}}for(let i of Object.keys(o)){let a=i.replace(/\{[^}]+\}/g,"[^/]+");if(new RegExp(`^${a}$`).test(e)){let p=o[i];if(t in p)return{isValid:!0,message:"Valid path and method",operation:p[t],actualPath:e,apiType:n,baseUrl:r.baseUrl}}}return null}function be(t,e,n){let r=t.toLowerCase();if(n!==void 0){let o=ce[n],i=ve(r,e,n,o);return i||{isValid:!1,message:`Path '${e}' not found in ${o.name} schema. Please check the path format or use freee_api_list_paths to see available endpoints.`}}for(let[o,i]of Object.entries(ce)){let a=ve(r,e,o,i);if(a)return a}return{isValid:!1,message:`Path '${e}' not found in any freee API schema. Please check the path format or use freee_api_list_paths to see available endpoints.`}}function xe(){let t=[];for(let[,e]of Object.entries(ce)){let n=e.schema.paths,r=[];Object.entries(n).forEach(([o,i])=>{let a=Object.keys(i).filter(s=>["get","post","put","delete","patch"].includes(s)).map(s=>s.toUpperCase());a.length>0&&r.push(` ${a.join("|")} ${o}`)}),r.length>0&&t.push(`
|
|
39
41
|
## ${e.name} (${e.baseUrl})
|
|
40
42
|
${r.sort().join(`
|
|
41
43
|
`)}`)}return t.join(`
|
|
42
|
-
`)}function
|
|
44
|
+
`)}function it(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="binary"}function at(t){let e=(t.size/1024).toFixed(2);return`\u30D5\u30A1\u30A4\u30EB\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u307E\u3057\u305F
|
|
43
45
|
|
|
44
46
|
\u4FDD\u5B58\u5834\u6240: ${t.filePath}
|
|
45
47
|
MIME\u30BF\u30A4\u30D7: ${t.mimeType}
|
|
46
|
-
\u30B5\u30A4\u30BA: ${e} KB`}var
|
|
48
|
+
\u30B5\u30A4\u30BA: ${e} KB`}var O="service: accounting/hr/invoice/pm/sm",L=c.enum(["accounting","hr","invoice","pm","sm"]).describe("\u5BFE\u8C61\u306Efreee\u30B5\u30FC\u30D3\u30B9");function U(t){return async e=>{try{let{service:n,path:r,query:o,body:i}=e,a=be(t,r,n);if(!a.isValid)return{content:[{type:"text",text:`\u30D1\u30B9\u691C\u8A3C\u30A8\u30E9\u30FC: ${a.message}
|
|
47
49
|
|
|
48
|
-
\u5229\u7528\u53EF\u80FD\u306A\u30D1\u30B9\u3092\u78BA\u8A8D\u3059\u308B\u306B\u306F freee_api_list_paths \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let s=await R(t,a.actualPath,o,i,a.baseUrl);return
|
|
50
|
+
\u5229\u7528\u53EF\u80FD\u306A\u30D1\u30B9\u3092\u78BA\u8A8D\u3059\u308B\u306B\u306F freee_api_list_paths \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let s=await R(t,a.actualPath,o,i,a.baseUrl);return it(s)?{content:[{type:"text",text:at(s)}]}:{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(n){return{content:[{type:"text",text:`API\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC: ${n instanceof Error?n.message:String(n)}`}]}}}}function Ie(t){t.tool("freee_api_get",`freee API GET\u3002${O}`,{service:L,path:c.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals, /invoices)"),query:c.record(c.string(),c.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},U("GET")),t.tool("freee_api_post",`freee API POST\u3002${O}`,{service:L,path:c.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals, /invoices)"),body:c.record(c.string(),c.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.record(c.string(),c.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},U("POST")),t.tool("freee_api_put",`freee API PUT\u3002${O}`,{service:L,path:c.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123, /invoices/123)"),body:c.record(c.string(),c.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.record(c.string(),c.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},U("PUT")),t.tool("freee_api_delete",`freee API DELETE\u3002${O}`,{service:L,path:c.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123)"),query:c.record(c.string(),c.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},U("DELETE")),t.tool("freee_api_patch",`freee API PATCH\u3002${O}`,{service:L,path:c.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123)"),body:c.record(c.string(),c.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.record(c.string(),c.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},U("PATCH")),t.tool("freee_api_list_paths","freee API \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u4E00\u89A7\u3002\u8A73\u7D30\u306A\u30AC\u30A4\u30C9\u306Ffreee-mcp skill\u3092\u53C2\u7167\u3002",{},async()=>({content:[{type:"text",text:`# freee API \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u4E00\u89A7${xe()}
|
|
49
51
|
|
|
50
52
|
\u4F7F\u7528\u4F8B:
|
|
51
53
|
freee_api_get { "service": "accounting", "path": "/api/1/deals", "query": { "limit": 10 } }
|
|
52
54
|
freee_api_get { "service": "invoice", "path": "/invoices" }
|
|
53
|
-
freee_api_post { "service": "accounting", "path": "/api/1/deals", "body": { "issue_date": "2024-01-01", ... } }`}]}))}async function
|
|
55
|
+
freee_api_post { "service": "accounting", "path": "/api/1/deals", "body": { "issue_date": "2024-01-01", ... } }`}]}))}async function Se(){let t=await X(),e=new st({name:t.server.name,version:t.server.version});Pe(e),Ie(e);try{await V(),console.error(`OAuth callback server started on http://127.0.0.1:${t.oauth.callbackPort}`)}catch(r){console.error("Failed to start callback server:",r),console.error("OAuth authentication will fall back to manual mode")}let n=new ct;await e.connect(n),console.error("Freee MCP Server running on stdio"),process.on("SIGINT",()=>{$(),process.exit(0)}),process.on("SIGTERM",()=>{$(),process.exit(0)})}import $e from"prompts";import*as Re from"node:os";import le from"node:crypto";import lt from"open";h();P();b();async function pt(t){let e=await fetch(`${l.freee.apiUrl}/api/1/companies`,{headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"}});if(!e.ok){let r=await y(e);throw new Error(`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${e.status} ${JSON.stringify(r)}`)}return(await e.json()).companies||[]}async function ut(){let t=await Promise.resolve().then(()=>(P(),he)).then(a=>a.loadFullConfig()),e=!!(t.clientId&&t.clientSecret);e&&(console.log("\u65E2\u5B58\u306E\u8A2D\u5B9A\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002"),console.log(` \u5909\u66F4\u3057\u306A\u3044\u9805\u76EE\u306F\u305D\u306E\u307E\u307E Enter \u3092\u62BC\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
54
56
|
`)),console.log(`\u30B9\u30C6\u30C3\u30D7 1/3: OAuth\u8A8D\u8A3C\u60C5\u5831\u306E\u5165\u529B
|
|
55
|
-
`);let n=await
|
|
57
|
+
`);let n=await $e([{type:"text",name:"clientId",message:"FREEE_CLIENT_ID:",initial:t.clientId||void 0,validate:a=>a.trim()?!0:"CLIENT_ID \u306F\u5FC5\u9808\u3067\u3059"},{type:"password",name:"clientSecret",message:e?"FREEE_CLIENT_SECRET (\u5909\u66F4\u3057\u306A\u3044\u5834\u5408\u306F\u7A7A\u6B04):":"FREEE_CLIENT_SECRET:",validate:a=>e&&!a.trim()||a.trim()?!0:"CLIENT_SECRET \u306F\u5FC5\u9808\u3067\u3059"},{type:"text",name:"callbackPort",message:"FREEE_CALLBACK_PORT:",initial:String(t.callbackPort||T)}]);if(!n.clientId)throw new Error("\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002");let r=n.clientId.trim(),o=n.clientSecret.trim()||t.clientSecret,i=parseInt(n.callbackPort.trim(),10);if(!o)throw new Error("CLIENT_SECRET \u306F\u5FC5\u9808\u3067\u3059\u3002");return process.env.FREEE_CLIENT_ID=r,process.env.FREEE_CLIENT_SECRET=o,process.env.FREEE_CALLBACK_PORT=String(i),console.log(`
|
|
56
58
|
\u8A8D\u8A3C\u60C5\u5831\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002
|
|
57
|
-
`),{clientId:r,clientSecret:o,callbackPort:i}}async function
|
|
58
|
-
`),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u30DA\u30FC\u30B8\u3092\u958B\u304D\u307E\u3059..."),await Promise.resolve().then(()=>(h(),
|
|
59
|
+
`),{clientId:r,clientSecret:o,callbackPort:i}}async function ft(){console.log(`\u30B9\u30C6\u30C3\u30D7 2/3: OAuth\u8A8D\u8A3C
|
|
60
|
+
`),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u30DA\u30FC\u30B8\u3092\u958B\u304D\u307E\u3059..."),await Promise.resolve().then(()=>(h(),ye)).then(a=>a.loadConfig()),await V();let t=le.randomBytes(32).toString("base64url"),e=le.createHash("sha256").update(t).digest("base64url"),n=le.randomBytes(16).toString("base64url"),r=B(e,n,S());console.log(`
|
|
59
61
|
\u8A8D\u8A3CURL: ${r}
|
|
60
|
-
`),await
|
|
61
|
-
`);let o=Ae(),i=new Promise((a,s)=>{let p=setTimeout(()=>{s(new Error("\u8A8D\u8A3C\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F\uFF085\u5206\uFF09"))},
|
|
62
|
-
`),{accessToken:s.access_token,refreshToken:s.refresh_token}}finally{o.removeCliAuthHandler(n)}}async function
|
|
63
|
-
`),console.log("\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u53D6\u5F97\u4E2D...");let e=await
|
|
62
|
+
`),await lt(r),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3057\u3066\u304F\u3060\u3055\u3044..."),console.log(`\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3059\u308B\u3068\u81EA\u52D5\u7684\u306B\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u307F\u307E\u3059\u3002
|
|
63
|
+
`);let o=Ae(),i=new Promise((a,s)=>{let p=setTimeout(()=>{s(new Error("\u8A8D\u8A3C\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F\uFF085\u5206\uFF09"))},M);o.registerCliAuthHandler(n,{resolve:u=>{clearTimeout(p),a(u)},reject:u=>{clearTimeout(p),s(u)},codeVerifier:t})});try{let a=await i;console.log("\u8A8D\u8A3C\u30B3\u30FC\u30C9\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002"),console.log("\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u5F97\u4E2D...");let s=await J(a,t,S());return console.log(`\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002
|
|
64
|
+
`),{accessToken:s.access_token,refreshToken:s.refresh_token}}finally{o.removeCliAuthHandler(n)}}async function dt(t){console.log(`\u30B9\u30C6\u30C3\u30D7 3/3: \u30C7\u30D5\u30A9\u30EB\u30C8\u4E8B\u696D\u6240\u306E\u9078\u629E
|
|
65
|
+
`),console.log("\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u53D6\u5F97\u4E2D...");let e=await pt(t);if(e.length===0)throw new Error("\u5229\u7528\u53EF\u80FD\u306A\u4E8B\u696D\u6240\u304C\u3042\u308A\u307E\u305B\u3093\u3002");let n=await $e({type:"select",name:"companyId",message:"\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u4E8B\u696D\u6240\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044:",choices:e.map(o=>({title:`${o.display_name||o.name} (ID: ${o.id}) - ${o.role}`,value:o.id}))});if(!n.companyId)throw new Error("\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002");let r=e.find(o=>o.id===n.companyId);if(!r)throw new Error(`\u9078\u629E\u3057\u305F\u4E8B\u696D\u6240\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ID ${n.companyId}`);return console.log(`
|
|
64
66
|
${r.display_name||r.name} \u3092\u9078\u629E\u3057\u307E\u3057\u305F\u3002
|
|
65
67
|
`),{selected:{id:r.id,name:r.name,displayName:r.display_name||r.name,role:r.role},all:e}}async function gt(t,e,n){let r={clientId:t.clientId,clientSecret:t.clientSecret,callbackPort:t.callbackPort,defaultCompanyId:String(e.id),currentCompanyId:String(e.id),companies:{}};n.forEach(s=>{r.companies[String(s.id)]={id:String(s.id),name:s.display_name||s.name,description:`Role: ${s.role}`,addedAt:Date.now(),lastUsed:s.id===e.id?Date.now():void 0}}),await _(r),console.log(`\u8A2D\u5B9A\u60C5\u5831\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F\u3002
|
|
66
68
|
`),console.log(`=== MCP\u8A2D\u5B9A ===
|
|
67
69
|
`),console.log(`\u4EE5\u4E0B\u306E\u8A2D\u5B9A\u3092Claude desktop\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306B\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044:
|
|
68
|
-
`);let o=
|
|
70
|
+
`);let o=Re.platform(),i="";o==="darwin"?i="~/Library/Application Support/Claude/claude_desktop_config.json":o==="win32"?i="%APPDATA%\\Claude\\claude_desktop_config.json":i="~/.config/Claude/claude_desktop_config.json",console.log(`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u5834\u6240: ${i}
|
|
69
71
|
`),console.log(JSON.stringify({mcpServers:{"freee-mcp":{command:"npx",args:["@him0/freee-mcp","client"]}}},null,2)),console.log(`
|
|
70
72
|
\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86!
|
|
71
73
|
`),console.log("\u8A8D\u8A3C\u60C5\u5831\u306F ~/.config/freee-mcp/config.json \u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002"),console.log("\u30C8\u30FC\u30AF\u30F3\u306F ~/.config/freee-mcp/tokens.json \u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002"),console.log(`Claude desktop\u3092\u518D\u8D77\u52D5\u3059\u308B\u3068\u3001freee-mcp\u304C\u5229\u7528\u53EF\u80FD\u306B\u306A\u308A\u307E\u3059\u3002
|
|
72
|
-
`)}async function
|
|
74
|
+
`)}async function De(){console.log(`
|
|
73
75
|
=== freee-mcp Configuration Setup ===
|
|
74
76
|
`),console.log("\u3053\u306E\u30A6\u30A3\u30B6\u30FC\u30C9\u3067\u306F\u3001freee-mcp\u306E\u8A2D\u5B9A\u3068\u8A8D\u8A3C\u3092\u5BFE\u8A71\u5F0F\u3067\u884C\u3044\u307E\u3059\u3002"),console.log(`freee OAuth\u8A8D\u8A3C\u60C5\u5831\u304C\u5FC5\u8981\u3067\u3059\u3002
|
|
75
|
-
`);try{let t=await
|
|
77
|
+
`);try{let t=await ut(),e=await ft(),{selected:n,all:r}=await dt(e.accessToken);await gt(t,n,r)}catch(t){t instanceof Error?console.error(`
|
|
76
78
|
Error: ${t.message}`):console.error(`
|
|
77
|
-
\u8A2D\u5B9A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:`,t),process.exit(1)}finally{$()}}var
|
|
79
|
+
\u8A2D\u5B9A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:`,t),process.exit(1)}finally{$()}}var mt=async()=>{let e=process.argv.slice(2)[0];if(e==="configure"){await De();return}e&&e!=="client"&&(console.error(`Unknown subcommand: ${e}`),console.error("Usage: freee-mcp [configure]"),console.error(" configure - Interactive configuration setup"),process.exit(1)),console.error("Starting freee MCP server"),await Se()};mt().catch(t=>{console.error("Fatal error:",t),process.exit(1)});
|
package/dist/index.cjs
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`),e=process.env.FREEE_CLIENT_ID||"",n=process.env.FREEE_CLIENT_SECRET||"",r=process.env.FREEE_CALLBACK_PORT?parseInt(process.env.FREEE_CALLBACK_PORT,10):x;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,n=t.clientSecret,r=t.callbackPort||x}let o=process.env.FREEE_DEFAULT_COMPANY_ID||"0";return process.env.FREEE_DEFAULT_COMPANY_ID&&(console.error("Warning: FREEE_DEFAULT_COMPANY_ID \u74B0\u5883\u5909\u6570\u306F\u975E\u63A8\u5968\u3067\u3059\u3002"),console.error(" \u4E8B\u696D\u6240ID\u306F `freee_set_company` \u30C4\u30FC\u30EB\u3067\u52D5\u7684\u306B\u5909\u66F4\u3067\u304D\u307E\u3059\u3002\n")),k={freee:{clientId:e,clientSecret:n,companyId:o,apiUrl:"https://api.freee.co.jp"},oauth:{callbackPort:r,redirectUri:`http://127.0.0.1:${r}/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:M}},k}function it(){if(!k)throw new Error("Config not loaded. Call loadConfig() first.");return k}var k,l,C=X(()=>{"use strict";T();I();k=null;l=new Proxy({},{get(t,e){if(!k)throw new Error("Config not loaded. Call loadConfig() first in async context.");return k[e]}})});var He=require("@modelcontextprotocol/sdk/server/mcp.js"),Be=require("@modelcontextprotocol/sdk/server/stdio.js");C();var ve=p(require("http"),1),be=require("url"),xe=p(require("net"),1);C();var ae=p(require("crypto"),1);C();var h=p(require("fs/promises"),1),v=p(require("path"),1);C();I();async function w(t){return t.json().catch(()=>({}))}function oe(){return v.default.join(P(),"tokens.json")}async function B(t){let e=oe(),n=v.default.dirname(e);try{console.error(`[info] Creating directory: ${n}`),await h.default.mkdir(n,{recursive:!0}),console.error(`[info] Writing tokens to: ${e}`),await h.default.writeFile(e,JSON.stringify(t,null,2),{mode:N}),console.error("[info] Tokens saved successfully")}catch(r){throw console.error("[error] Failed to save tokens:",r),r}}async function ie(){let t=oe();try{let e=await h.default.readFile(t,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT"){let n=await st();return n||null}throw console.error("[error] Failed to load tokens:",e),e}}function at(t){return Date.now()<t.expires_at}async function st(){let t=P();try{let n=(await h.default.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));if(n.length>0){let r=v.default.join(t,n[0]),o=await h.default.readFile(r,"utf8"),i=JSON.parse(o);return await B(i),await Promise.all(n.map(a=>h.default.unlink(v.default.join(t,a)).catch(s=>{console.error(`[warn] Failed to clean up legacy token file ${a}:`,s)}))),console.error("[info] Migrated legacy company-specific tokens to user-based tokens"),i}}catch(e){console.error("[warn] Error during legacy token migration attempt:",e)}return null}async function ct(t){let e=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:l.freee.clientId,client_secret:l.freee.clientSecret})});if(!e.ok){let o=await w(e);throw new Error(`Token refresh failed: ${e.status} ${JSON.stringify(o)}`)}let n=await e.json(),r={access_token:n.access_token,refresh_token:n.refresh_token||t,expires_at:Date.now()+n.expires_in*1e3,token_type:n.token_type||"Bearer",scope:n.scope||l.oauth.scope};return await B(r),r}async function Ee(){let t=oe();try{await h.default.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 lt()}async function lt(){let t=P();try{let n=(await h.default.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));await Promise.all(n.map(r=>h.default.unlink(v.default.join(t,r)).catch(o=>{console.error(`[warn] Failed to clear legacy token file ${r}:`,o)}))),n.length>0&&console.error("[info] Cleared legacy company-specific token files")}catch(e){console.error("[warn] Error during legacy token cleanup:",e)}}async function Pe(){let t=await ie();if(!t)return null;if(at(t))return t.access_token;try{return(await ct(t.refresh_token)).access_token}catch(e){return console.error("[warn] Failed to refresh token:",e),null}}function Te(){let t=ae.default.randomBytes(32).toString("base64url"),e=ae.default.createHash("sha256").update(t).digest("base64url");return{codeVerifier:t,codeChallenge:e}}function J(t,e,n){let r=new URLSearchParams({response_type:"code",client_id:l.freee.clientId,redirect_uri:n,scope:l.oauth.scope,state:e,code_challenge:t,code_challenge_method:"S256"});return`${l.oauth.authorizationEndpoint}?${r.toString()}`}async function V(t,e,n){let r=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:l.freee.clientId,client_secret:l.freee.clientSecret,code:t,redirect_uri:n,code_verifier:e})});if(!r.ok){let a=await w(r);throw new Error(`Token exchange failed: ${r.status} ${JSON.stringify(a)}`)}let o=await r.json(),i={access_token:o.access_token,refresh_token:o.refresh_token,expires_at:Date.now()+o.expires_in*1e3,token_type:o.token_type||"Bearer",scope:o.scope||l.oauth.scope};return await B(i),i}var se=class{pendingAuthentications=new Map;cliAuthHandlers=new Map;registerAuthentication(e,n){console.error(`Registering authentication request with state: ${e.substring(0,10)}...`),console.error(`Code verifier: ${n.substring(0,10)}...`);let r=setTimeout(()=>{this.pendingAuthentications.delete(e),console.error(`Authentication timeout for state: ${e.substring(0,10)}...`)},l.auth.timeoutMs);this.pendingAuthentications.set(e,{codeVerifier:n,resolve:o=>{console.error("Authentication completed successfully!")},reject:o=>{console.error("Authentication failed:",o)},timeout:r}),console.error(`Registration complete. Total pending: ${this.pendingAuthentications.size}`)}getPendingAuthentication(e){return this.pendingAuthentications.get(e)}removePendingAuthentication(e){let n=this.pendingAuthentications.get(e);n&&(clearTimeout(n.timeout),this.pendingAuthentications.delete(e))}clearAllPending(){for(let[e,n]of this.pendingAuthentications)clearTimeout(n.timeout),n.reject(new Error("Server shutdown"));this.pendingAuthentications.clear()}get pendingCount(){return this.pendingAuthentications.size}registerCliAuthHandler(e,n){this.cliAuthHandlers.set(e,n)}getCliAuthHandler(e){return this.cliAuthHandlers.get(e)}removeCliAuthHandler(e){this.cliAuthHandlers.delete(e)}},ce=class{server=null;port=null;authManager;constructor(e){this.authManager=e}getRedirectUri(){if(this.port===null)throw new Error("Callback server not started. Call start() first.");return`http://127.0.0.1:${this.port}/callback`}getPort(){return this.port}isRunning(){return this.server!==null}async start(){if(this.server)return;let e=l.oauth.callbackPort,n=await this.findAvailablePort(e);return this.port=n,n!==e&&console.error(`Warning: Port ${e} is in use. Using fallback port ${n} for OAuth callback server.`),new Promise((r,o)=>{this.server=ve.default.createServer((i,a)=>{console.error(`Callback request: ${i.method} ${i.url}`);let s=new be.URL(i.url,`http://127.0.0.1:${n}`);s.pathname==="/callback"?this.handleCallback(s,a):s.pathname==="/"?(a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>freee MCP OAuth Server</h1><p>\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u30B5\u30FC\u30D0\u30FC\u304C\u7A3C\u50CD\u4E2D\u3067\u3059\u3002</p>")):(a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>404 Not Found</h1><p>\u3053\u306E\u30D1\u30B9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093\u3002</p>"))}),this.server.on("error",i=>{console.error("Callback server error:",i),o(i)}),this.server.listen(n,"127.0.0.1",()=>{console.error(`OAuth callback server listening on http://127.0.0.1:${n}`),r()})})}stop(){this.server&&(this.authManager.clearAllPending(),this.server.close(()=>{console.error("OAuth callback server stopped")}),this.server=null,this.port=null)}async checkPortAvailable(e){return new Promise(n=>{let r=xe.default.createServer();r.listen(e,"127.0.0.1",()=>{r.close(()=>{n(!0)})}),r.on("error",()=>{n(!1)})})}async findAvailablePort(e,n=50){for(let r=e;r<e+n;r++)if(await this.checkPortAvailable(r))return r;throw new Error(`No available port found after checking ${n} ports starting from ${e}`)}handleCallback(e,n){let r=e.searchParams.get("code"),o=e.searchParams.get("state"),i=e.searchParams.get("error"),a=e.searchParams.get("error_description");console.error(`Callback received - URL: ${e.toString()}`),console.error("Callback parameters:",{code:r?`${r.substring(0,10)}...`:null,state:o?`${o.substring(0,10)}...`:null,error:i,errorDescription:a}),console.error(`Pending authentications count: ${this.authManager.pendingCount}`);let s=o?this.authManager.getCliAuthHandler(o):void 0;if(i){let f=a||i;if(console.error(`OAuth error: ${i} - ${a}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${f}</p>`),s)s.reject(new Error(`OAuth error: ${i} - ${a}`));else if(o){let _=this.authManager.getPendingAuthentication(o);_&&(clearTimeout(_.timeout),_.reject(new Error(`OAuth error: ${i} - ${a}`)),this.authManager.removePendingAuthentication(o))}return}if(!r||!o){console.error("Missing code or state"),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u30B3\u30FC\u30C9\u307E\u305F\u306F\u72B6\u614B\u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002</p>");return}if(s){console.error("Valid CLI callback received"),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u30BF\u30FC\u30DF\u30CA\u30EB\u306B\u623B\u3063\u3066\u304F\u3060\u3055\u3044\u3002</p>"),s.resolve(r);return}let u=this.authManager.getPendingAuthentication(o);if(!u){console.error(`Unknown state: ${o}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u4E0D\u660E\u306A\u8A8D\u8A3C\u72B6\u614B\u3067\u3059\u3002\u8A8D\u8A3C\u3092\u518D\u958B\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>");return}console.error("Valid callback received, exchanging code for tokens..."),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002</p>"),this.authManager.removePendingAuthentication(o),V(r,u.codeVerifier,this.getRedirectUri()).then(f=>{console.error("Token exchange successful!"),u.resolve(f)}).catch(f=>{console.error("Token exchange failed:",f),u.reject(f)})}},le=new se,pe=new ce(le);function $(){return pe.getRedirectUri()}async function q(){return pe.start()}function Ie(t,e){le.registerAuthentication(t,e)}function R(){pe.stop()}function Se(){return le}var De=p(require("crypto"),1),z=require("zod");C();C();T();var $e=p(require("fs/promises"),1),Re=p(require("path"),1);function pt(t){return["application/pdf","application/octet-stream","image/"].some(n=>t.includes(n))}function ut(t){let e={"application/pdf":".pdf","image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp","text/csv":".csv"};for(let[n,r]of Object.entries(e))if(t.includes(n))return r;return t.includes("image/"),".bin"}async function D(t,e,n,r,o){let i=o||l.freee.apiUrl,a=await E(),s=await Pe();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
|
|
1
|
+
"use strict";var Ke=Object.create;var Y=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var Ye=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Qe=Object.prototype.hasOwnProperty;var X=(t,e)=>()=>(t&&(e=t(t=0)),e);var we=(t,e)=>{for(var n in e)Y(t,n,{get:e[n],enumerable:!0})},Ze=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ye(e))!Qe.call(t,o)&&o!==n&&Y(t,o,{get:()=>e[o],enumerable:!(r=We(e,o))||r.enumerable});return t};var p=(t,e,n)=>(n=t!=null?Ke(Xe(t)):{},Ze(e||!t||!t.__esModule?Y(n,"default",{value:t,enumerable:!0}):n,t));function P(){return process.env.XDG_CONFIG_HOME?Q.default.join(process.env.XDG_CONFIG_HOME,ke):Q.default.join(_e.default.homedir(),".config",ke)}var Q,_e,ke,I,N,H,S=X(()=>{"use strict";Q=p(require("path"),1),_e=p(require("os"),1),ke="freee-mcp";I=54321,N=300*1e3,H=384});var Ae={};we(Ae,{getCompanyInfo:()=>$,getCompanyList:()=>rt,getCurrentCompanyId:()=>A,getDownloadDir:()=>ne,loadFullConfig:()=>y,saveFullConfig:()=>E,setCurrentCompany:()=>te,setDownloadDir:()=>ot});function ee(){return Z.default.join(P(),"config.json")}async function et(){let t=Z.default.dirname(ee());await B.default.mkdir(t,{recursive:!0})}function tt(t){return t!=null&&typeof t=="object"&&"defaultCompanyId"in t&&"currentCompanyId"in t&&"companies"in t&&!("clientId"in t)}function nt(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 y(){let t=ee();try{let e=await B.default.readFile(t,"utf8"),n=JSON.parse(e);if(tt(n)){let r=nt(n);return await E(r),r}return n}catch(e){if(e.code==="ENOENT"){let n=process.env.FREEE_DEFAULT_COMPANY_ID||"0",r={clientId:void 0,clientSecret:void 0,callbackPort:void 0,defaultCompanyId:n,currentCompanyId:n,companies:{[n]:{id:n,name:"Default Company",description:"Company from environment variable",addedAt:Date.now(),lastUsed:Date.now()}}};return await E(r),r}throw e}}async function E(t){await et();let e=ee();await B.default.writeFile(e,JSON.stringify(t,null,2),{mode:H})}async function A(){return(await y()).currentCompanyId}async function te(t,e,n){let r=await y();r.companies[t]?(e||n)&&(e&&(r.companies[t].name=e),n&&(r.companies[t].description=n)):r.companies[t]={id:t,name:e||`Company ${t}`,description:n||void 0,addedAt:Date.now()},r.companies[t].lastUsed=Date.now(),r.currentCompanyId=t,await E(r)}async function rt(){let t=await y();return Object.values(t.companies).sort((e,n)=>(n.lastUsed||0)-(e.lastUsed||0))}async function $(t){return(await y()).companies[t]||null}async function ne(){return(await y()).downloadDir||Ee.default.tmpdir()}async function ot(t){let e=await y();e.downloadDir=t,await E(e)}var B,Z,Ee,v=X(()=>{"use strict";B=p(require("fs/promises"),1),Z=p(require("path"),1),Ee=p(require("os"),1);S()});var Pe={};we(Pe,{config:()=>l,getConfig:()=>at,loadConfig:()=>re});function it(){return!!(process.env.FREEE_CLIENT_ID||process.env.FREEE_CLIENT_SECRET)}async function re(){if(k)return k;let t=await y(),e,n,r;if(it())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
|
|
2
|
+
`),e=process.env.FREEE_CLIENT_ID||"",n=process.env.FREEE_CLIENT_SECRET||"",r=process.env.FREEE_CALLBACK_PORT?parseInt(process.env.FREEE_CALLBACK_PORT,10):I;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,n=t.clientSecret,r=t.callbackPort||I}let o=process.env.FREEE_DEFAULT_COMPANY_ID||"0";return process.env.FREEE_DEFAULT_COMPANY_ID&&(console.error("Warning: FREEE_DEFAULT_COMPANY_ID \u74B0\u5883\u5909\u6570\u306F\u975E\u63A8\u5968\u3067\u3059\u3002"),console.error(" \u4E8B\u696D\u6240ID\u306F `freee_set_company` \u30C4\u30FC\u30EB\u3067\u52D5\u7684\u306B\u5909\u66F4\u3067\u304D\u307E\u3059\u3002\n")),k={freee:{clientId:e,clientSecret:n,companyId:o,apiUrl:"https://api.freee.co.jp"},oauth:{callbackPort:r,redirectUri:`http://127.0.0.1:${r}/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:N}},k}function at(){if(!k)throw new Error("Config not loaded. Call loadConfig() first.");return k}var k,l,C=X(()=>{"use strict";v();S();k=null;l=new Proxy({},{get(t,e){if(!k)throw new Error("Config not loaded. Call loadConfig() first in async context.");return k[e]}})});var Be=require("@modelcontextprotocol/sdk/server/mcp.js"),Je=require("@modelcontextprotocol/sdk/server/stdio.js");C();var xe=p(require("http"),1),Ie=require("url"),Se=p(require("net"),1);C();var ae=p(require("crypto"),1);C();var h=p(require("fs/promises"),1),T=p(require("path"),1);C();S();async function w(t){return t.json().catch(()=>({}))}function oe(){return T.default.join(P(),"tokens.json")}async function J(t){let e=oe(),n=T.default.dirname(e);try{console.error(`[info] Creating directory: ${n}`),await h.default.mkdir(n,{recursive:!0}),console.error(`[info] Writing tokens to: ${e}`),await h.default.writeFile(e,JSON.stringify(t,null,2),{mode:H}),console.error("[info] Tokens saved successfully")}catch(r){throw console.error("[error] Failed to save tokens:",r),r}}async function ie(){let t=oe();try{let e=await h.default.readFile(t,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT"){let n=await ct();return n||null}throw console.error("[error] Failed to load tokens:",e),e}}function st(t){return Date.now()<t.expires_at}async function ct(){let t=P();try{let n=(await h.default.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));if(n.length>0){let r=T.default.join(t,n[0]),o=await h.default.readFile(r,"utf8"),i=JSON.parse(o);return await J(i),await Promise.all(n.map(a=>h.default.unlink(T.default.join(t,a)).catch(s=>{console.error(`[warn] Failed to clean up legacy token file ${a}:`,s)}))),console.error("[info] Migrated legacy company-specific tokens to user-based tokens"),i}}catch(e){console.error("[warn] Error during legacy token migration attempt:",e)}return null}async function lt(t){let e=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:t,client_id:l.freee.clientId,client_secret:l.freee.clientSecret})});if(!e.ok){let o=await w(e);throw new Error(`Token refresh failed: ${e.status} ${JSON.stringify(o)}`)}let n=await e.json(),r={access_token:n.access_token,refresh_token:n.refresh_token||t,expires_at:Date.now()+n.expires_in*1e3,token_type:n.token_type||"Bearer",scope:n.scope||l.oauth.scope};return await J(r),r}async function ve(){let t=oe();try{await h.default.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 pt()}async function pt(){let t=P();try{let n=(await h.default.readdir(t)).filter(r=>r.startsWith("tokens-")&&r.endsWith(".json"));await Promise.all(n.map(r=>h.default.unlink(T.default.join(t,r)).catch(o=>{console.error(`[warn] Failed to clear legacy token file ${r}:`,o)}))),n.length>0&&console.error("[info] Cleared legacy company-specific token files")}catch(e){console.error("[warn] Error during legacy token cleanup:",e)}}async function Te(){let t=await ie();if(!t)return null;if(st(t))return t.access_token;try{return(await lt(t.refresh_token)).access_token}catch(e){return console.error("[warn] Failed to refresh token:",e),null}}function be(){let t=ae.default.randomBytes(32).toString("base64url"),e=ae.default.createHash("sha256").update(t).digest("base64url");return{codeVerifier:t,codeChallenge:e}}function V(t,e,n){let r=new URLSearchParams({response_type:"code",client_id:l.freee.clientId,redirect_uri:n,scope:l.oauth.scope,state:e,code_challenge:t,code_challenge_method:"S256"});return`${l.oauth.authorizationEndpoint}?${r.toString()}`}async function q(t,e,n){let r=await fetch(l.oauth.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:l.freee.clientId,client_secret:l.freee.clientSecret,code:t,redirect_uri:n,code_verifier:e})});if(!r.ok){let a=await w(r);throw new Error(`Token exchange failed: ${r.status} ${JSON.stringify(a)}`)}let o=await r.json(),i={access_token:o.access_token,refresh_token:o.refresh_token,expires_at:Date.now()+o.expires_in*1e3,token_type:o.token_type||"Bearer",scope:o.scope||l.oauth.scope};return await J(i),i}var se=class{pendingAuthentications=new Map;cliAuthHandlers=new Map;registerAuthentication(e,n){console.error(`Registering authentication request with state: ${e.substring(0,10)}...`),console.error(`Code verifier: ${n.substring(0,10)}...`);let r=setTimeout(()=>{this.pendingAuthentications.delete(e),console.error(`Authentication timeout for state: ${e.substring(0,10)}...`)},l.auth.timeoutMs);this.pendingAuthentications.set(e,{codeVerifier:n,resolve:o=>{console.error("Authentication completed successfully!")},reject:o=>{console.error("Authentication failed:",o)},timeout:r}),console.error(`Registration complete. Total pending: ${this.pendingAuthentications.size}`)}getPendingAuthentication(e){return this.pendingAuthentications.get(e)}removePendingAuthentication(e){let n=this.pendingAuthentications.get(e);n&&(clearTimeout(n.timeout),this.pendingAuthentications.delete(e))}clearAllPending(){for(let[e,n]of this.pendingAuthentications)clearTimeout(n.timeout),n.reject(new Error("Server shutdown"));this.pendingAuthentications.clear()}get pendingCount(){return this.pendingAuthentications.size}registerCliAuthHandler(e,n){this.cliAuthHandlers.set(e,n)}getCliAuthHandler(e){return this.cliAuthHandlers.get(e)}removeCliAuthHandler(e){this.cliAuthHandlers.delete(e)}},ce=class{server=null;port=null;authManager;constructor(e){this.authManager=e}getRedirectUri(){if(this.port===null)throw new Error("Callback server not started. Call start() first.");return`http://127.0.0.1:${this.port}/callback`}getPort(){return this.port}isRunning(){return this.server!==null}async start(){if(this.server)return;let e=l.oauth.callbackPort,n=await this.findAvailablePort(e);return this.port=n,n!==e&&console.error(`Warning: Port ${e} is in use. Using fallback port ${n} for OAuth callback server.`),new Promise((r,o)=>{this.server=xe.default.createServer((i,a)=>{console.error(`Callback request: ${i.method} ${i.url}`);let s=new Ie.URL(i.url,`http://127.0.0.1:${n}`);s.pathname==="/callback"?this.handleCallback(s,a):s.pathname==="/"?(a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>freee MCP OAuth Server</h1><p>\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u30B5\u30FC\u30D0\u30FC\u304C\u7A3C\u50CD\u4E2D\u3067\u3059\u3002</p>")):(a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end("<h1>404 Not Found</h1><p>\u3053\u306E\u30D1\u30B9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093\u3002</p>"))}),this.server.on("error",i=>{console.error("Callback server error:",i),o(i)}),this.server.listen(n,"127.0.0.1",()=>{console.error(`OAuth callback server listening on http://127.0.0.1:${n}`),r()})})}stop(){this.server&&(this.authManager.clearAllPending(),this.server.close(()=>{console.error("OAuth callback server stopped")}),this.server=null,this.port=null)}async checkPortAvailable(e){return new Promise(n=>{let r=Se.default.createServer();r.listen(e,"127.0.0.1",()=>{r.close(()=>{n(!0)})}),r.on("error",()=>{n(!1)})})}async findAvailablePort(e,n=50){for(let r=e;r<e+n;r++)if(await this.checkPortAvailable(r))return r;throw new Error(`No available port found after checking ${n} ports starting from ${e}`)}handleCallback(e,n){let r=e.searchParams.get("code"),o=e.searchParams.get("state"),i=e.searchParams.get("error"),a=e.searchParams.get("error_description");console.error(`Callback received - URL: ${e.toString()}`),console.error("Callback parameters:",{code:r?`${r.substring(0,10)}...`:null,state:o?`${o.substring(0,10)}...`:null,error:i,errorDescription:a}),console.error(`Pending authentications count: ${this.authManager.pendingCount}`);let s=o?this.authManager.getCliAuthHandler(o):void 0;if(i){let f=a||i;if(console.error(`OAuth error: ${i} - ${a}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end(`<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${f}</p>`),s)s.reject(new Error(`OAuth error: ${i} - ${a}`));else if(o){let _=this.authManager.getPendingAuthentication(o);_&&(clearTimeout(_.timeout),_.reject(new Error(`OAuth error: ${i} - ${a}`)),this.authManager.removePendingAuthentication(o))}return}if(!r||!o){console.error("Missing code or state"),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u8A8D\u8A3C\u30B3\u30FC\u30C9\u307E\u305F\u306F\u72B6\u614B\u30D1\u30E9\u30E1\u30FC\u30BF\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002</p>");return}if(s){console.error("Valid CLI callback received"),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u30BF\u30FC\u30DF\u30CA\u30EB\u306B\u623B\u3063\u3066\u304F\u3060\u3055\u3044\u3002</p>"),s.resolve(r);return}let u=this.authManager.getPendingAuthentication(o);if(!u){console.error(`Unknown state: ${o}`),n.writeHead(400,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u30A8\u30E9\u30FC</h1><p>\u4E0D\u660E\u306A\u8A8D\u8A3C\u72B6\u614B\u3067\u3059\u3002\u8A8D\u8A3C\u3092\u518D\u958B\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>");return}console.error("Valid callback received, exchanging code for tokens..."),n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end("<h1>\u8A8D\u8A3C\u5B8C\u4E86</h1><p>\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u3053\u306E\u30DA\u30FC\u30B8\u3092\u9589\u3058\u3066\u304F\u3060\u3055\u3044\u3002</p>"),this.authManager.removePendingAuthentication(o),q(r,u.codeVerifier,this.getRedirectUri()).then(f=>{console.error("Token exchange successful!"),u.resolve(f)}).catch(f=>{console.error("Token exchange failed:",f),u.reject(f)})}},le=new se,pe=new ce(le);function R(){return pe.getRedirectUri()}async function z(){return pe.start()}function $e(t,e){le.registerAuthentication(t,e)}function D(){pe.stop()}function Re(){return le}var Oe=p(require("crypto"),1),G=require("zod");C();C();v();var De=p(require("fs/promises"),1),Fe=p(require("path"),1);function ut(t){return["application/pdf","application/octet-stream","image/"].some(n=>t.includes(n))}function ft(t){let e={"application/pdf":".pdf","image/png":".png","image/jpeg":".jpg","image/gif":".gif","image/webp":".webp","text/csv":".csv"};for(let[n,r]of Object.entries(e))if(t.includes(n))return r;return t.includes("image/"),".bin"}async function F(t,e,n,r,o){let i=o||l.freee.apiUrl,a=await A(),s=await Te();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
|
|
3
3
|
\u73FE\u5728\u306E\u4E8B\u696D\u6240ID: ${a}
|
|
4
|
-
\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 u=i.endsWith("/")?i:i+"/",f=e.startsWith("/")?e.slice(1):e,_=new URL(f,u);n&&Object.entries(n).forEach(([
|
|
4
|
+
\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 u=i.endsWith("/")?i:i+"/",f=e.startsWith("/")?e.slice(1):e,_=new URL(f,u);n&&Object.entries(n).forEach(([d,m])=>{m!==void 0&&_.searchParams.append(d,String(m))}),_.searchParams.append("company_id",String(a));let g=await fetch(_.toString(),{method:t,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:r?JSON.stringify(typeof r=="string"?JSON.parse(r):r):void 0});if(g.status===401||g.status===403){let d=await w(g);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
|
|
5
5
|
\u73FE\u5728\u306E\u4E8B\u696D\u6240ID: ${a}
|
|
6
|
-
\u30A8\u30E9\u30FC\u8A73\u7D30: ${
|
|
6
|
+
\u30A8\u30E9\u30FC\u8A73\u7D30: ${g.status} ${JSON.stringify(d)}
|
|
7
7
|
|
|
8
8
|
\u78BA\u8A8D\u4E8B\u9805:
|
|
9
9
|
1. FREEE_CLIENT_ID\u74B0\u5883\u5909\u6570\u304C\u6B63\u3057\u304F\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u308B\u304B
|
|
10
10
|
2. freee\u5074\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u8A2D\u5B9A\u304C\u6B63\u3057\u3044\u304B\uFF08\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8URI\u7B49\uFF09
|
|
11
11
|
3. \u30C8\u30FC\u30AF\u30F3\u306E\u6709\u52B9\u671F\u9650\u304C\u5207\u308C\u3066\u3044\u306A\u3044\u304B
|
|
12
|
-
4. \u4E8B\u696D\u6240ID\u304C\u6B63\u3057\u3044\u304B\uFF08freee_get_current_company \u3067\u78BA\u8A8D\uFF09`)}if(!
|
|
12
|
+
4. \u4E8B\u696D\u6240ID\u304C\u6B63\u3057\u3044\u304B\uFF08freee_get_current_company \u3067\u78BA\u8A8D\uFF09`)}if(!g.ok){let d=await w(g),m=`API request failed: ${g.status}`;if(d&&d.errors&&Array.isArray(d.errors)){let M=[];for(let x of d.errors)x.messages&&Array.isArray(x.messages)&&M.push(...x.messages);M.length>0&&(m+=`
|
|
13
13
|
|
|
14
14
|
\u30A8\u30E9\u30FC\u8A73\u7D30:
|
|
15
|
-
${
|
|
16
|
-
`)}`,
|
|
15
|
+
${M.join(`
|
|
16
|
+
`)}`,g.status===400&&(m+=`
|
|
17
17
|
|
|
18
18
|
\u30D2\u30F3\u30C8: \u4E0D\u6B63\u306A\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002`,m+=`
|
|
19
19
|
\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`,m+=`
|
|
20
|
-
\u4F8B: get_items, get_partners, get_account_items \u306A\u3069\u3067\u65E2\u5B58\u30C7\u30FC\u30BF\u306E\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`))}throw
|
|
20
|
+
\u4F8B: get_items, get_partners, get_account_items \u306A\u3069\u3067\u65E2\u5B58\u30C7\u30FC\u30BF\u306E\u69CB\u9020\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002`))}throw d?.errors||(m+=`
|
|
21
21
|
|
|
22
|
-
\u8A73\u7D30: ${JSON.stringify(
|
|
22
|
+
\u8A73\u7D30: ${JSON.stringify(d)}`),new Error(m)}let W=g.headers.get("content-type")||"";if(ut(W)){let d=await ne(),m=ft(W),x=`freee_download_${Date.now()}${m}`,ye=Fe.default.join(d,x),Ce=await g.arrayBuffer();return await De.default.writeFile(ye,Buffer.from(Ce)),{type:"binary",filePath:ye,mimeType:W,size:Ce.byteLength}}return g.json()}v();function Le(t){t.tool("freee_current_user","\u73FE\u5728\u306E\u30E6\u30FC\u30B6\u30FC\u60C5\u5831\u3092\u53D6\u5F97\u3002\u8A73\u7D30\u30AC\u30A4\u30C9\u306Ffreee-mcp skill\u3092\u53C2\u7167\u3002",{},async()=>{try{let e=await A(),n=await $(e);if(!e)return{content:[{type:"text",text:"\u4F1A\u793EID\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002freee_set_company \u3067\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"}]};let r=await F("GET","/api/1/users/me");return{content:[{type:"text",text:`\u73FE\u5728\u306E\u30E6\u30FC\u30B6\u30FC\u60C5\u5831:
|
|
23
23
|
\u4F1A\u793EID: ${e}
|
|
24
24
|
\u4F1A\u793E\u540D: ${n?.name||"Unknown"}
|
|
25
25
|
\u30E6\u30FC\u30B6\u30FC\u8A73\u7D30:
|
|
@@ -27,49 +27,51 @@ ${JSON.stringify(r,null,2)}`}]}}catch(e){return{content:[{type:"text",text:`\u30
|
|
|
27
27
|
OAuth\u8A8D\u8A3C\u3092\u884C\u3046\u306B\u306F\u3001freee developers\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3001
|
|
28
28
|
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8ID\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};if(!l.freee.clientSecret)return{content:[{type:"text",text:`FREEE_CLIENT_SECRET\u74B0\u5883\u5909\u6570\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002
|
|
29
29
|
OAuth\u8A8D\u8A3C\u3092\u884C\u3046\u306B\u306F\u3001freee developers\u3067\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3092\u4F5C\u6210\u3057\u3001
|
|
30
|
-
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let{codeVerifier:e,codeChallenge:n}=
|
|
30
|
+
\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u3092\u74B0\u5883\u5909\u6570\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let{codeVerifier:e,codeChallenge:n}=be(),r=Oe.default.randomBytes(16).toString("hex"),o=V(n,r,R());return $e(r,e),console.error(`Authentication URL: ${o}`),{content:[{type:"text",text:`\u8A8D\u8A3CURL: ${o}
|
|
31
31
|
|
|
32
32
|
\u30D6\u30E9\u30A6\u30B6\u3067\u958B\u3044\u3066\u8A8D\u8A3C\u3057\u3066\u304F\u3060\u3055\u3044\u30025\u5206\u3067\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3059\u3002`}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u958B\u59CB\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_auth_status","\u8A8D\u8A3C\u72B6\u614B\u3092\u78BA\u8A8D\u3002",{},async()=>{try{let e=await ie();if(!e)return{content:[{type:"text",text:"\u672A\u8A8D\u8A3C\u3002freee_authenticate \u3067\u8A8D\u8A3C\u3057\u3066\u304F\u3060\u3055\u3044\u3002"}]};let n=Date.now()<e.expires_at,r=new Date(e.expires_at).toLocaleString();return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B: ${n?"\u6709\u52B9":"\u671F\u9650\u5207\u308C"}
|
|
33
33
|
\u6709\u52B9\u671F\u9650: ${r}`+(n?"":`
|
|
34
|
-
\u6B21\u56DEAPI\u4F7F\u7528\u6642\u306B\u81EA\u52D5\u66F4\u65B0\u3055\u308C\u307E\u3059\u3002`)}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B\u306E\u78BA\u8A8D\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_clear_auth","\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3002",{},async()=>{try{return await
|
|
34
|
+
\u6B21\u56DEAPI\u4F7F\u7528\u6642\u306B\u81EA\u52D5\u66F4\u65B0\u3055\u308C\u307E\u3059\u3002`)}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u72B6\u614B\u306E\u78BA\u8A8D\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_clear_auth","\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3002",{},async()=>{try{return await ve(),{content:[{type:"text",text:"\u8A8D\u8A3C\u60C5\u5831\u3092\u30AF\u30EA\u30A2\u3057\u307E\u3057\u305F\u3002\u518D\u8A8D\u8A3C\u3059\u308B\u306B\u306F freee_authenticate \u3092\u4F7F\u7528\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u8A8D\u8A3C\u60C5\u5831\u306E\u30AF\u30EA\u30A2\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_set_company","\u4E8B\u696D\u6240\u3092\u8A2D\u5B9A\u30FB\u5207\u308A\u66FF\u3048\u3002",{company_id:G.z.string().describe("\u4E8B\u696D\u6240ID"),name:G.z.string().optional().describe("\u4E8B\u696D\u6240\u540D"),description:G.z.string().optional().describe("\u8AAC\u660E")},async e=>{try{let{company_id:n,name:r,description:o}=e;return await te(n,r,o),{content:[{type:"text",text:`\u4E8B\u696D\u6240\u3092\u8A2D\u5B9A: ${(await $(n))?.name||n}`}]}}catch(n){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u306E\u8A2D\u5B9A\u306B\u5931\u6557: ${n instanceof Error?n.message:String(n)}`}]}}}),t.tool("freee_get_current_company","\u73FE\u5728\u306E\u4E8B\u696D\u6240\u60C5\u5831\u3092\u8868\u793A\u3002",{},async()=>{try{let e=await A(),n=await $(e);return n?{content:[{type:"text",text:`\u4E8B\u696D\u6240: ${n.name} (ID: ${n.id})`}]}:{content:[{type:"text",text:`\u4E8B\u696D\u6240ID: ${e} (\u8A73\u7D30\u60C5\u5831\u306A\u3057)`}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u60C5\u5831\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}}),t.tool("freee_list_companies","\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u8868\u793A\u3002",{},async()=>{try{let e=await F("GET","/api/1/companies"),n=await A();return e?.companies?.length?{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7:
|
|
35
35
|
${e.companies.map(o=>{let i=o.id===parseInt(n)?" *":"";return`${o.name} (${o.id})${i}`}).join(`
|
|
36
|
-
`)}`}]}:{content:[{type:"text",text:"\u4E8B\u696D\u6240\u60C5\u5831\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}})}var c=require("zod");var
|
|
36
|
+
`)}`}]}:{content:[{type:"text",text:"\u4E8B\u696D\u6240\u60C5\u5831\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"}]}}catch(e){return{content:[{type:"text",text:`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557: ${e instanceof Error?e.message:String(e)}`}]}}})}var c=require("zod");var me=p(require("node:fs"),1),b=p(require("node:path"),1),je=require("node:url"),mt={},ue=b.default.dirname((0,je.fileURLToPath)(mt.url));function dt(){let t=[b.default.resolve(ue,"./openapi/minimal"),b.default.resolve(ue,"../dist/openapi/minimal"),b.default.resolve(ue,"../../openapi/minimal")];for(let e of t)if(me.default.existsSync(e))return e;throw new Error(`Could not find minimal schema directory. Searched paths:
|
|
37
|
+
${t.join(`
|
|
38
|
+
`)}`)}var gt=dt();function O(t){let e=b.default.join(gt,t),n=me.default.readFileSync(e,"utf-8");return JSON.parse(n)}var fe=null;function de(){return fe===null&&(fe={accounting:{schema:O("accounting.json"),baseUrl:"https://api.freee.co.jp",prefix:"accounting",name:"freee\u4F1A\u8A08 API"},hr:{schema:O("hr.json"),baseUrl:"https://api.freee.co.jp/hr",prefix:"hr",name:"freee\u4EBA\u4E8B\u52B4\u52D9 API"},invoice:{schema:O("invoice.json"),baseUrl:"https://api.freee.co.jp/iv",prefix:"invoice",name:"freee\u8ACB\u6C42\u66F8 API"},pm:{schema:O("pm.json"),baseUrl:"https://api.freee.co.jp/pm",prefix:"pm",name:"freee\u5DE5\u6570\u7BA1\u7406 API"},sm:{schema:O("sm.json"),baseUrl:"https://api.freee.co.jp/sm",prefix:"sm",name:"freee\u8CA9\u58F2 API"}}),fe}var ge=new Proxy({},{get(t,e){return de()[e]},ownKeys(){return Object.keys(de())},getOwnPropertyDescriptor(t,e){let n=de();if(e in n)return{enumerable:!0,configurable:!0,value:n[e]}}});function Ue(t,e,n,r){let o=r.schema.paths;if(e in o){let i=o[e];if(t in i)return{isValid:!0,message:"Valid path and method",operation:i[t],actualPath:e,apiType:n,baseUrl:r.baseUrl}}for(let i of Object.keys(o)){let a=i.replace(/\{[^}]+\}/g,"[^/]+");if(new RegExp(`^${a}$`).test(e)){let u=o[i];if(t in u)return{isValid:!0,message:"Valid path and method",operation:u[t],actualPath:e,apiType:n,baseUrl:r.baseUrl}}}return null}function Me(t,e,n){let r=t.toLowerCase();if(n!==void 0){let o=ge[n],i=Ue(r,e,n,o);return i||{isValid:!1,message:`Path '${e}' not found in ${o.name} schema. Please check the path format or use freee_api_list_paths to see available endpoints.`}}for(let[o,i]of Object.entries(ge)){let a=Ue(r,e,o,i);if(a)return a}return{isValid:!1,message:`Path '${e}' not found in any freee API schema. Please check the path format or use freee_api_list_paths to see available endpoints.`}}function Ne(){let t=[];for(let[,e]of Object.entries(ge)){let n=e.schema.paths,r=[];Object.entries(n).forEach(([o,i])=>{let a=Object.keys(i).filter(s=>["get","post","put","delete","patch"].includes(s)).map(s=>s.toUpperCase());a.length>0&&r.push(` ${a.join("|")} ${o}`)}),r.length>0&&t.push(`
|
|
37
39
|
## ${e.name} (${e.baseUrl})
|
|
38
40
|
${r.sort().join(`
|
|
39
41
|
`)}`)}return t.join(`
|
|
40
|
-
`)}function
|
|
42
|
+
`)}function ht(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="binary"}function yt(t){let e=(t.size/1024).toFixed(2);return`\u30D5\u30A1\u30A4\u30EB\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u307E\u3057\u305F
|
|
41
43
|
|
|
42
44
|
\u4FDD\u5B58\u5834\u6240: ${t.filePath}
|
|
43
45
|
MIME\u30BF\u30A4\u30D7: ${t.mimeType}
|
|
44
|
-
\u30B5\u30A4\u30BA: ${e} KB`}var
|
|
46
|
+
\u30B5\u30A4\u30BA: ${e} KB`}var L="service: accounting/hr/invoice/pm/sm",U=c.z.enum(["accounting","hr","invoice","pm","sm"]).describe("\u5BFE\u8C61\u306Efreee\u30B5\u30FC\u30D3\u30B9");function j(t){return async e=>{try{let{service:n,path:r,query:o,body:i}=e,a=Me(t,r,n);if(!a.isValid)return{content:[{type:"text",text:`\u30D1\u30B9\u691C\u8A3C\u30A8\u30E9\u30FC: ${a.message}
|
|
45
47
|
|
|
46
|
-
\u5229\u7528\u53EF\u80FD\u306A\u30D1\u30B9\u3092\u78BA\u8A8D\u3059\u308B\u306B\u306F freee_api_list_paths \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let s=await
|
|
48
|
+
\u5229\u7528\u53EF\u80FD\u306A\u30D1\u30B9\u3092\u78BA\u8A8D\u3059\u308B\u306B\u306F freee_api_list_paths \u30C4\u30FC\u30EB\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`}]};let s=await F(t,a.actualPath,o,i,a.baseUrl);return ht(s)?{content:[{type:"text",text:yt(s)}]}:{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(n){return{content:[{type:"text",text:`API\u30EA\u30AF\u30A8\u30B9\u30C8\u30A8\u30E9\u30FC: ${n instanceof Error?n.message:String(n)}`}]}}}}function He(t){t.tool("freee_api_get",`freee API GET\u3002${L}`,{service:U,path:c.z.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals, /invoices)"),query:c.z.record(c.z.string(),c.z.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},j("GET")),t.tool("freee_api_post",`freee API POST\u3002${L}`,{service:U,path:c.z.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals, /invoices)"),body:c.z.record(c.z.string(),c.z.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.z.record(c.z.string(),c.z.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},j("POST")),t.tool("freee_api_put",`freee API PUT\u3002${L}`,{service:U,path:c.z.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123, /invoices/123)"),body:c.z.record(c.z.string(),c.z.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.z.record(c.z.string(),c.z.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},j("PUT")),t.tool("freee_api_delete",`freee API DELETE\u3002${L}`,{service:U,path:c.z.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123)"),query:c.z.record(c.z.string(),c.z.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},j("DELETE")),t.tool("freee_api_patch",`freee API PATCH\u3002${L}`,{service:U,path:c.z.string().describe("API\u30D1\u30B9 (\u4F8B: /api/1/deals/123)"),body:c.z.record(c.z.string(),c.z.unknown()).describe("\u30EA\u30AF\u30A8\u30B9\u30C8\u30DC\u30C7\u30A3"),query:c.z.record(c.z.string(),c.z.unknown()).optional().describe("\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (\u30AA\u30D7\u30B7\u30E7\u30F3)")},j("PATCH")),t.tool("freee_api_list_paths","freee API \u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u4E00\u89A7\u3002\u8A73\u7D30\u306A\u30AC\u30A4\u30C9\u306Ffreee-mcp skill\u3092\u53C2\u7167\u3002",{},async()=>({content:[{type:"text",text:`# freee API \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u4E00\u89A7${Ne()}
|
|
47
49
|
|
|
48
50
|
\u4F7F\u7528\u4F8B:
|
|
49
51
|
freee_api_get { "service": "accounting", "path": "/api/1/deals", "query": { "limit": 10 } }
|
|
50
52
|
freee_api_get { "service": "invoice", "path": "/invoices" }
|
|
51
|
-
freee_api_post { "service": "accounting", "path": "/api/1/deals", "body": { "issue_date": "2024-01-01", ... } }`}]}))}async function
|
|
53
|
+
freee_api_post { "service": "accounting", "path": "/api/1/deals", "body": { "issue_date": "2024-01-01", ... } }`}]}))}async function Ve(){let t=await re(),e=new Be.McpServer({name:t.server.name,version:t.server.version});Le(e),He(e);try{await z(),console.error(`OAuth callback server started on http://127.0.0.1:${t.oauth.callbackPort}`)}catch(r){console.error("Failed to start callback server:",r),console.error("OAuth authentication will fall back to manual mode")}let n=new Je.StdioServerTransport;await e.connect(n),console.error("Freee MCP Server running on stdio"),process.on("SIGINT",()=>{D(),process.exit(0)}),process.on("SIGTERM",()=>{D(),process.exit(0)})}var he=p(require("prompts"),1),qe=p(require("node:os"),1),K=p(require("node:crypto"),1),ze=p(require("open"),1);C();v();S();async function Ct(t){let e=await fetch(`${l.freee.apiUrl}/api/1/companies`,{headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"}});if(!e.ok){let r=await w(e);throw new Error(`\u4E8B\u696D\u6240\u4E00\u89A7\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${e.status} ${JSON.stringify(r)}`)}return(await e.json()).companies||[]}async function wt(){let t=await Promise.resolve().then(()=>(v(),Ae)).then(a=>a.loadFullConfig()),e=!!(t.clientId&&t.clientSecret);e&&(console.log("\u65E2\u5B58\u306E\u8A2D\u5B9A\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002"),console.log(` \u5909\u66F4\u3057\u306A\u3044\u9805\u76EE\u306F\u305D\u306E\u307E\u307E Enter \u3092\u62BC\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
52
54
|
`)),console.log(`\u30B9\u30C6\u30C3\u30D7 1/3: OAuth\u8A8D\u8A3C\u60C5\u5831\u306E\u5165\u529B
|
|
53
|
-
`);let n=await(0,
|
|
55
|
+
`);let n=await(0,he.default)([{type:"text",name:"clientId",message:"FREEE_CLIENT_ID:",initial:t.clientId||void 0,validate:a=>a.trim()?!0:"CLIENT_ID \u306F\u5FC5\u9808\u3067\u3059"},{type:"password",name:"clientSecret",message:e?"FREEE_CLIENT_SECRET (\u5909\u66F4\u3057\u306A\u3044\u5834\u5408\u306F\u7A7A\u6B04):":"FREEE_CLIENT_SECRET:",validate:a=>e&&!a.trim()||a.trim()?!0:"CLIENT_SECRET \u306F\u5FC5\u9808\u3067\u3059"},{type:"text",name:"callbackPort",message:"FREEE_CALLBACK_PORT:",initial:String(t.callbackPort||I)}]);if(!n.clientId)throw new Error("\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002");let r=n.clientId.trim(),o=n.clientSecret.trim()||t.clientSecret,i=parseInt(n.callbackPort.trim(),10);if(!o)throw new Error("CLIENT_SECRET \u306F\u5FC5\u9808\u3067\u3059\u3002");return process.env.FREEE_CLIENT_ID=r,process.env.FREEE_CLIENT_SECRET=o,process.env.FREEE_CALLBACK_PORT=String(i),console.log(`
|
|
54
56
|
\u8A8D\u8A3C\u60C5\u5831\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002
|
|
55
|
-
`),{clientId:r,clientSecret:o,callbackPort:i}}async function
|
|
56
|
-
`),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u30DA\u30FC\u30B8\u3092\u958B\u304D\u307E\u3059..."),await Promise.resolve().then(()=>(C(),
|
|
57
|
+
`),{clientId:r,clientSecret:o,callbackPort:i}}async function kt(){console.log(`\u30B9\u30C6\u30C3\u30D7 2/3: OAuth\u8A8D\u8A3C
|
|
58
|
+
`),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u30DA\u30FC\u30B8\u3092\u958B\u304D\u307E\u3059..."),await Promise.resolve().then(()=>(C(),Pe)).then(a=>a.loadConfig()),await z();let t=K.default.randomBytes(32).toString("base64url"),e=K.default.createHash("sha256").update(t).digest("base64url"),n=K.default.randomBytes(16).toString("base64url"),r=V(e,n,R());console.log(`
|
|
57
59
|
\u8A8D\u8A3CURL: ${r}
|
|
58
|
-
`),await(0,
|
|
59
|
-
`);let o=
|
|
60
|
-
`),{accessToken:s.access_token,refreshToken:s.refresh_token}}finally{o.removeCliAuthHandler(n)}}async function
|
|
61
|
-
`),console.log("\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u53D6\u5F97\u4E2D...");let e=await
|
|
60
|
+
`),await(0,ze.default)(r),console.log("\u30D6\u30E9\u30A6\u30B6\u3067\u8A8D\u8A3C\u3092\u5B8C\u4E86\u3057\u3066\u304F\u3060\u3055\u3044..."),console.log(`\u8A8D\u8A3C\u304C\u5B8C\u4E86\u3059\u308B\u3068\u81EA\u52D5\u7684\u306B\u6B21\u306E\u30B9\u30C6\u30C3\u30D7\u306B\u9032\u307F\u307E\u3059\u3002
|
|
61
|
+
`);let o=Re(),i=new Promise((a,s)=>{let u=setTimeout(()=>{s(new Error("\u8A8D\u8A3C\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F\uFF085\u5206\uFF09"))},N);o.registerCliAuthHandler(n,{resolve:f=>{clearTimeout(u),a(f)},reject:f=>{clearTimeout(u),s(f)},codeVerifier:t})});try{let a=await i;console.log("\u8A8D\u8A3C\u30B3\u30FC\u30C9\u3092\u53D7\u3051\u53D6\u308A\u307E\u3057\u305F\u3002"),console.log("\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u5F97\u4E2D...");let s=await q(a,t,R());return console.log(`\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002
|
|
62
|
+
`),{accessToken:s.access_token,refreshToken:s.refresh_token}}finally{o.removeCliAuthHandler(n)}}async function _t(t){console.log(`\u30B9\u30C6\u30C3\u30D7 3/3: \u30C7\u30D5\u30A9\u30EB\u30C8\u4E8B\u696D\u6240\u306E\u9078\u629E
|
|
63
|
+
`),console.log("\u4E8B\u696D\u6240\u4E00\u89A7\u3092\u53D6\u5F97\u4E2D...");let e=await Ct(t);if(e.length===0)throw new Error("\u5229\u7528\u53EF\u80FD\u306A\u4E8B\u696D\u6240\u304C\u3042\u308A\u307E\u305B\u3093\u3002");let n=await(0,he.default)({type:"select",name:"companyId",message:"\u30C7\u30D5\u30A9\u30EB\u30C8\u306E\u4E8B\u696D\u6240\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044:",choices:e.map(o=>({title:`${o.display_name||o.name} (ID: ${o.id}) - ${o.role}`,value:o.id}))});if(!n.companyId)throw new Error("\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F\u3002");let r=e.find(o=>o.id===n.companyId);if(!r)throw new Error(`\u9078\u629E\u3057\u305F\u4E8B\u696D\u6240\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ID ${n.companyId}`);return console.log(`
|
|
62
64
|
${r.display_name||r.name} \u3092\u9078\u629E\u3057\u307E\u3057\u305F\u3002
|
|
63
|
-
`),{selected:{id:r.id,name:r.name,displayName:r.display_name||r.name,role:r.role},all:e}}async function
|
|
65
|
+
`),{selected:{id:r.id,name:r.name,displayName:r.display_name||r.name,role:r.role},all:e}}async function Et(t,e,n){let r={clientId:t.clientId,clientSecret:t.clientSecret,callbackPort:t.callbackPort,defaultCompanyId:String(e.id),currentCompanyId:String(e.id),companies:{}};n.forEach(s=>{r.companies[String(s.id)]={id:String(s.id),name:s.display_name||s.name,description:`Role: ${s.role}`,addedAt:Date.now(),lastUsed:s.id===e.id?Date.now():void 0}}),await E(r),console.log(`\u8A2D\u5B9A\u60C5\u5831\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F\u3002
|
|
64
66
|
`),console.log(`=== MCP\u8A2D\u5B9A ===
|
|
65
67
|
`),console.log(`\u4EE5\u4E0B\u306E\u8A2D\u5B9A\u3092Claude desktop\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306B\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044:
|
|
66
|
-
`);let o=
|
|
68
|
+
`);let o=qe.platform(),i="";o==="darwin"?i="~/Library/Application Support/Claude/claude_desktop_config.json":o==="win32"?i="%APPDATA%\\Claude\\claude_desktop_config.json":i="~/.config/Claude/claude_desktop_config.json",console.log(`\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u306E\u5834\u6240: ${i}
|
|
67
69
|
`),console.log(JSON.stringify({mcpServers:{"freee-mcp":{command:"npx",args:["@him0/freee-mcp","client"]}}},null,2)),console.log(`
|
|
68
70
|
\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86!
|
|
69
71
|
`),console.log("\u8A8D\u8A3C\u60C5\u5831\u306F ~/.config/freee-mcp/config.json \u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002"),console.log("\u30C8\u30FC\u30AF\u30F3\u306F ~/.config/freee-mcp/tokens.json \u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F\u3002"),console.log(`Claude desktop\u3092\u518D\u8D77\u52D5\u3059\u308B\u3068\u3001freee-mcp\u304C\u5229\u7528\u53EF\u80FD\u306B\u306A\u308A\u307E\u3059\u3002
|
|
70
|
-
`)}async function
|
|
72
|
+
`)}async function Ge(){console.log(`
|
|
71
73
|
=== freee-mcp Configuration Setup ===
|
|
72
74
|
`),console.log("\u3053\u306E\u30A6\u30A3\u30B6\u30FC\u30C9\u3067\u306F\u3001freee-mcp\u306E\u8A2D\u5B9A\u3068\u8A8D\u8A3C\u3092\u5BFE\u8A71\u5F0F\u3067\u884C\u3044\u307E\u3059\u3002"),console.log(`freee OAuth\u8A8D\u8A3C\u60C5\u5831\u304C\u5FC5\u8981\u3067\u3059\u3002
|
|
73
|
-
`);try{let t=await
|
|
75
|
+
`);try{let t=await wt(),e=await kt(),{selected:n,all:r}=await _t(e.accessToken);await Et(t,n,r)}catch(t){t instanceof Error?console.error(`
|
|
74
76
|
Error: ${t.message}`):console.error(`
|
|
75
|
-
\u8A2D\u5B9A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:`,t),process.exit(1)}finally{
|
|
77
|
+
\u8A2D\u5B9A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F:`,t),process.exit(1)}finally{D()}}var At=async()=>{let e=process.argv.slice(2)[0];if(e==="configure"){await Ge();return}e&&e!=="client"&&(console.error(`Unknown subcommand: ${e}`),console.error("Usage: freee-mcp [configure]"),console.error(" configure - Interactive configuration setup"),process.exit(1)),console.error("Starting freee MCP server"),await Ve()};At().catch(t=>{console.error("Fatal error:",t),process.exit(1)});
|