@easbot/mcp 0.2.22 → 0.2.23
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/dist/index.cjs +2 -2
- package/dist/index.d.cts +126 -54
- package/dist/index.d.ts +126 -54
- package/dist/index.mjs +2 -2
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var chunk4DCCWUIJ_cjs=require('./chunks/chunk-4DCCWUIJ.cjs'),mcp=require('@modelcontextprotocol/sdk/server/mcp'),stdio=require('@modelcontextprotocol/sdk/server/stdio'),events=require('events'),l=require('zod/v4'),z=require('http'),streamableHttp=require('@modelcontextprotocol/sdk/server/streamableHttp'),index_js=require('@modelcontextprotocol/sdk/client/index.js'),stdio_js=require('@modelcontextprotocol/sdk/client/stdio.js'),streamableHttp_js=require('@modelcontextprotocol/sdk/client/streamableHttp.js'),sse_js=require('@modelcontextprotocol/sdk/client/sse.js'),types_js=require('@modelcontextprotocol/sdk/types.js'),auth_js=require('@modelcontextprotocol/sdk/client/auth.js'),utils=require('@easbot/utils'),v=require('zod');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var l__default=/*#__PURE__*/_interopDefault(l);var z__default=/*#__PURE__*/_interopDefault(z);var v__default=/*#__PURE__*/_interopDefault(v);var H={STDIO:"stdio",HTTP:"http"},c={STOPPED:"stopped",STARTING:"starting",RUNNING:"running",STOPPING:"stopping",ERROR:"error"};var j=chunk4DCCWUIJ_cjs.b.create({service:"tool-registry"}),T={REGISTERED:"mcp.tool.registered",UNREGISTERED:"mcp.tool.unregistered",CLEARED:"mcp.tool.cleared"},x=class extends events.EventEmitter{constructor(){super();chunk4DCCWUIJ_cjs.a(this,"tools",new Map);}register(e){if(!e.name||typeof e.name!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u65E0\u6548\uFF1A\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e.name)){j?.debug("tool already registered, skipping",{tool:e.name});return}this.tools.set(e.name,e),this.emit(T.REGISTERED,e);}unregister(e){return this.tools.has(e)?(this.tools.delete(e),this.emit(T.UNREGISTERED,e),true):false}get(e){return this.tools.get(e)}getAll(){return Array.from(this.tools.values())}getTools(){return Array.from(this.tools.values()).map(({handler:e,...r})=>r)}has(e){return this.tools.has(e)}getSize(){return this.tools.size}clear(){this.tools.clear(),this.emit(T.CLEARED);}},y=new x;var g=chunk4DCCWUIJ_cjs.b.create({service:"mcp.server.stdio"}),w=class{constructor(t){chunk4DCCWUIJ_cjs.a(this,"config");chunk4DCCWUIJ_cjs.a(this,"server",null);chunk4DCCWUIJ_cjs.a(this,"info");chunk4DCCWUIJ_cjs.a(this,"isStarting",false);chunk4DCCWUIJ_cjs.a(this,"isStopping",false);chunk4DCCWUIJ_cjs.a(this,"toolEventCleanup",null);chunk4DCCWUIJ_cjs.a(this,"handleToolRegistered",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:c.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now(),enabled:t.enabled};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of y.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool loaded",{tool:t.name});}}subscribeToolEvents(){this.toolEventCleanup=()=>{y.off(T.REGISTERED,this.handleToolRegistered);},y.on(T.REGISTERED,this.handleToolRegistered);}adaptToolHandler(t){return async(e,r)=>{let o={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,o)}}unsubscribeToolEvents(){this.toolEventCleanup&&(this.toolEventCleanup(),this.toolEventCleanup=null);}convertToZodSchema(t){if(t instanceof l__default.default.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},o=e.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l__default.default.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l__default.default.object(u)}if(e.type==="string")return l__default.default.string();if(e.type==="number")return l__default.default.number();if(e.type==="boolean")return l__default.default.boolean();if(e.type==="array"){let r=e.items;return r?l__default.default.array(this.jsonSchemaToZod(r)):l__default.default.array(l__default.default.unknown())}}return l__default.default.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return l__default.default.string();case "number":return l__default.default.number();case "integer":return l__default.default.number().int();case "boolean":return l__default.default.boolean();case "null":return l__default.default.null();case "array":{let r=t.items;return r?l__default.default.array(this.jsonSchemaToZod(r)):l__default.default.array(l__default.default.unknown())}case "object":{let r=t.properties||{},o=t.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l__default.default.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l__default.default.object(u)}default:return l__default.default.unknown()}}async start(){if(this.isStarting){g.warn("server is already starting",{id:this.info.id});return}if(this.info.status===c.RUNNING){g.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=c.STARTING;try{g.info("starting stdio mcp server",{id:this.info.id,name:this.info.name,command:this.config.command,args:this.config.args});let t=new stdio.StdioServerTransport;await t.start(),this.server=new mcp.McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeToolEvents(),await this.server.connect(t),this.info.status=c.RUNNING,this.info.lastActivityAt=Date.now(),g.info("stdio mcp server started successfully",{id:this.info.id,name:this.info.name,toolCount:y.getSize()});}catch(t){throw this.info.status=c.ERROR,g.error("failed to start stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){g.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==c.RUNNING&&this.info.status!==c.ERROR){g.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=c.STOPPING;try{g.info("stopping stdio mcp server",{id:this.info.id,name:this.info.name}),this.unsubscribeToolEvents(),this.server&&(await this.server.close(),this.server=null),this.info.status=c.STOPPED,g.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=c.ERROR,g.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){g.info("restarting stdio mcp server",{id:this.info.id}),await this.stop(),await this.start();}};function L(m){return new w(m)}async function Z(m){let t=new w(m);return await t.start(),t.createInstance()}var h=chunk4DCCWUIJ_cjs.b.create({service:"mcp.server.http"}),E=class{constructor(t){chunk4DCCWUIJ_cjs.a(this,"config");chunk4DCCWUIJ_cjs.a(this,"server",null);chunk4DCCWUIJ_cjs.a(this,"transport",null);chunk4DCCWUIJ_cjs.a(this,"httpServer",null);chunk4DCCWUIJ_cjs.a(this,"info");chunk4DCCWUIJ_cjs.a(this,"isStarting",false);chunk4DCCWUIJ_cjs.a(this,"isStopping",false);chunk4DCCWUIJ_cjs.a(this,"toolCleanup",null);chunk4DCCWUIJ_cjs.a(this,"handleTool",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),h.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:c.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now()};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of y.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),h.info("tool loaded",{tool:t.name});}}subscribeTools(){this.toolCleanup=()=>{y.off(T.REGISTERED,this.handleTool);},y.on(T.REGISTERED,this.handleTool);}convertToZodSchema(t){if(t instanceof l__default.default.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},o=e.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l__default.default.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l__default.default.object(u)}if(e.type==="string")return l__default.default.string();if(e.type==="number")return l__default.default.number();if(e.type==="boolean")return l__default.default.boolean();if(e.type==="array"){let r=e.items;return r?l__default.default.array(this.jsonSchemaToZod(r)):l__default.default.array(l__default.default.unknown())}}return l__default.default.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return l__default.default.string();case "number":return l__default.default.number();case "integer":return l__default.default.number().int();case "boolean":return l__default.default.boolean();case "null":return l__default.default.null();case "array":{let r=t.items;return r?l__default.default.array(this.jsonSchemaToZod(r)):l__default.default.array(l__default.default.unknown())}case "object":{let r=t.properties||{},o=t.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l__default.default.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l__default.default.object(u)}default:return l__default.default.unknown()}}adaptToolHandler(t){return async(e,r)=>{let o={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,o)}}unsubscribeTools(){this.toolCleanup&&(this.toolCleanup(),this.toolCleanup=null);}async start(){if(this.isStarting){h.warn("already starting",{id:this.info.id});return}if(this.info.status===c.RUNNING){h.debug("already running",{id:this.info.id});return}this.isStarting=true,this.info.status=c.STARTING;try{h.info("starting",{id:this.info.id,name:this.info.name,url:this.config.url});let t;try{t=new URL(this.config.url);}catch{throw new Error(`\u65E0\u6548\u7684 URL: ${this.config.url}`)}let e=parseInt(t.port||"3000",10),r=t.hostname||"0.0.0.0";if(Number.isNaN(e)||e<1||e>65535)throw new Error(`\u65E0\u6548\u7684\u7AEF\u53E3\u53F7: ${t.port}`);this.transport=new streamableHttp.StreamableHTTPServerTransport({sessionIdGenerator:()=>crypto.randomUUID()}),this.server=new mcp.McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeTools(),await this.server.connect(this.transport),this.httpServer=z__default.default.createServer((o,n)=>{let b=o.headers.origin,u=(f,a,A)=>{n.writeHead(f,a),A?n.end(A):n.end();},i={"Access-Control-Allow-Origin":b||"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, mcpsessionid, mcp-protocol-version","Access-Control-Max-Age":"86400"};if(o.method==="OPTIONS"){u(204,i);return}if(o.method==="POST"){let f="";o.setEncoding("utf8"),o.on("data",a=>{f+=a;}),o.on("end",()=>{let a;if(f)try{a=JSON.parse(f);}catch{a=void 0;}this.transport&&this.transport.handleRequest(o,n,a);}),o.on("error",a=>{h.error("HTTP request error",{error:a.message}),u(500,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}}));});}else o.method==="GET"?this.transport&&this.transport.handleRequest(o,n,void 0):u(405,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32601,message:"Method not found"}}));}),this.httpServer.on("error",o=>{h.error("HTTP server error",{error:o.message}),this.info.status=c.ERROR;}),this.httpServer.on("clientError",(o,n)=>{h.warn("HTTP client error",{error:o.message}),n.writable&&n.end(`HTTP/1.1 400 Bad Request\r
|
|
1
|
+
'use strict';var chunk4DCCWUIJ_cjs=require('./chunks/chunk-4DCCWUIJ.cjs'),mcp_js=require('@modelcontextprotocol/sdk/server/mcp.js'),stdio_js=require('@modelcontextprotocol/sdk/server/stdio.js'),events=require('events'),d=require('zod/v4'),z=require('http'),streamableHttp_js=require('@modelcontextprotocol/sdk/server/streamableHttp.js'),index_js=require('@modelcontextprotocol/sdk/client/index.js'),stdio_js$1=require('@modelcontextprotocol/sdk/client/stdio.js'),streamableHttp_js$1=require('@modelcontextprotocol/sdk/client/streamableHttp.js'),sse_js=require('@modelcontextprotocol/sdk/client/sse.js'),types_js=require('@modelcontextprotocol/sdk/types.js'),auth_js=require('@modelcontextprotocol/sdk/client/auth.js'),utils=require('@easbot/utils'),v=require('zod');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var d__default=/*#__PURE__*/_interopDefault(d);var z__default=/*#__PURE__*/_interopDefault(z);var v__default=/*#__PURE__*/_interopDefault(v);var I={STDIO:"stdio",HTTP:"http"},l={STOPPED:"stopped",STARTING:"starting",RUNNING:"running",STOPPING:"stopping",ERROR:"error"};var N=chunk4DCCWUIJ_cjs.b.create({service:"tool-registry"}),b={REGISTERED:"mcp.tool.registered",UNREGISTERED:"mcp.tool.unregistered",CLEARED:"mcp.tool.cleared"},A=class extends events.EventEmitter{constructor(){super();chunk4DCCWUIJ_cjs.a(this,"tools",new Map);}register(e){if(!e.name||typeof e.name!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u65E0\u6548\uFF1A\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e.name)){N?.debug("tool already registered, skipping",{tool:e.name});return}this.tools.set(e.name,e),this.emit(b.REGISTERED,e);}unregister(e){return this.tools.has(e)?(this.tools.delete(e),this.emit(b.UNREGISTERED,e),true):false}get(e){return this.tools.get(e)}getAll(){return Array.from(this.tools.values())}getTools(){return Array.from(this.tools.values()).map(({handler:e,...r})=>r)}has(e){return this.tools.has(e)}getSize(){return this.tools.size}clear(){this.tools.clear(),this.emit(b.CLEARED);}},C=new A;var S=chunk4DCCWUIJ_cjs.b.create({service:"mcp.server.stdio"}),R=class{constructor(t){chunk4DCCWUIJ_cjs.a(this,"config");chunk4DCCWUIJ_cjs.a(this,"server",null);chunk4DCCWUIJ_cjs.a(this,"info");chunk4DCCWUIJ_cjs.a(this,"isStarting",false);chunk4DCCWUIJ_cjs.a(this,"isStopping",false);chunk4DCCWUIJ_cjs.a(this,"toolEventCleanup",null);chunk4DCCWUIJ_cjs.a(this,"handleToolRegistered",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),S.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:l.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now(),enabled:t.enabled};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of C.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),S.info("tool loaded",{tool:t.name});}}subscribeToolEvents(){this.toolEventCleanup=()=>{C.off(b.REGISTERED,this.handleToolRegistered);},C.on(b.REGISTERED,this.handleToolRegistered);}adaptToolHandler(t){return async(e,r)=>{let n={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,n)}}unsubscribeToolEvents(){this.toolEventCleanup&&(this.toolEventCleanup(),this.toolEventCleanup=null);}convertToZodSchema(t){if(t instanceof d__default.default.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},n=e.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d__default.default.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d__default.default.object(f)}if(e.type==="string")return d__default.default.string();if(e.type==="number")return d__default.default.number();if(e.type==="boolean")return d__default.default.boolean();if(e.type==="array"){let r=e.items;return r?d__default.default.array(this.jsonSchemaToZod(r)):d__default.default.array(d__default.default.unknown())}}return d__default.default.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return d__default.default.string();case "number":return d__default.default.number();case "integer":return d__default.default.number().int();case "boolean":return d__default.default.boolean();case "null":return d__default.default.null();case "array":{let r=t.items;return r?d__default.default.array(this.jsonSchemaToZod(r)):d__default.default.array(d__default.default.unknown())}case "object":{let r=t.properties||{},n=t.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d__default.default.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d__default.default.object(f)}default:return d__default.default.unknown()}}async start(){if(this.isStarting){S.warn("server is already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){S.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{S.info("starting stdio mcp server",{id:this.info.id,name:this.info.name,command:this.config.command,args:this.config.args});let t=new stdio_js.StdioServerTransport;this.server=new mcp_js.McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeToolEvents(),await this.server.connect(t),this.info.status=l.RUNNING,this.info.lastActivityAt=Date.now(),S.info("stdio mcp server started successfully",{id:this.info.id,name:this.info.name,toolCount:C.getSize()});}catch(t){throw this.info.status=l.ERROR,S.error("failed to start stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){S.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){S.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{S.info("stopping stdio mcp server",{id:this.info.id,name:this.info.name}),this.unsubscribeToolEvents(),this.server&&(await this.server.close(),this.server=null),this.info.status=l.STOPPED,S.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=l.ERROR,S.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){S.info("restarting stdio mcp server",{id:this.info.id}),await this.stop(),await this.start();}};function U(s){return new R(s)}async function Z(s){let t=new R(s);return await t.start(),t.createInstance()}var g=chunk4DCCWUIJ_cjs.b.create({service:"mcp.server.http"}),w=class{constructor(t){chunk4DCCWUIJ_cjs.a(this,"config");chunk4DCCWUIJ_cjs.a(this,"server",null);chunk4DCCWUIJ_cjs.a(this,"transport",null);chunk4DCCWUIJ_cjs.a(this,"httpServer",null);chunk4DCCWUIJ_cjs.a(this,"info");chunk4DCCWUIJ_cjs.a(this,"isStarting",false);chunk4DCCWUIJ_cjs.a(this,"isStopping",false);chunk4DCCWUIJ_cjs.a(this,"toolCleanup",null);chunk4DCCWUIJ_cjs.a(this,"handleTool",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:l.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now()};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of C.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool loaded",{tool:t.name});}}subscribeTools(){this.toolCleanup=()=>{C.off(b.REGISTERED,this.handleTool);},C.on(b.REGISTERED,this.handleTool);}convertToZodSchema(t){if(t instanceof d__default.default.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},n=e.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d__default.default.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d__default.default.object(f)}if(e.type==="string")return d__default.default.string();if(e.type==="number")return d__default.default.number();if(e.type==="boolean")return d__default.default.boolean();if(e.type==="array"){let r=e.items;return r?d__default.default.array(this.jsonSchemaToZod(r)):d__default.default.array(d__default.default.unknown())}}return d__default.default.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return d__default.default.string();case "number":return d__default.default.number();case "integer":return d__default.default.number().int();case "boolean":return d__default.default.boolean();case "null":return d__default.default.null();case "array":{let r=t.items;return r?d__default.default.array(this.jsonSchemaToZod(r)):d__default.default.array(d__default.default.unknown())}case "object":{let r=t.properties||{},n=t.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d__default.default.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d__default.default.object(f)}default:return d__default.default.unknown()}}adaptToolHandler(t){return async(e,r)=>{let n={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,n)}}unsubscribeTools(){this.toolCleanup&&(this.toolCleanup(),this.toolCleanup=null);}async start(){if(this.isStarting){g.warn("already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){g.debug("already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{g.info("starting",{id:this.info.id,name:this.info.name,url:this.config.url});let t;try{t=new URL(this.config.url);}catch{throw new Error(`\u65E0\u6548\u7684 URL: ${this.config.url}`)}let e=parseInt(t.port||"3000",10),r=t.hostname||"0.0.0.0";if(Number.isNaN(e)||e<1||e>65535)throw new Error(`\u65E0\u6548\u7684\u7AEF\u53E3\u53F7: ${t.port}`);this.transport=new streamableHttp_js.StreamableHTTPServerTransport({sessionIdGenerator:()=>crypto.randomUUID()}),this.server=new mcp_js.McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeTools(),await this.server.connect(this.transport),this.httpServer=z__default.default.createServer((n,o)=>{let m=n.headers.origin,f=(h,c,k)=>{o.writeHead(h,c),k?o.end(k):o.end();},i={"Access-Control-Allow-Origin":m||"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, mcpsessionid, mcp-protocol-version","Access-Control-Max-Age":"86400"};if(n.method==="OPTIONS"){f(204,i);return}if(n.method==="POST"){let h="";n.setEncoding("utf8"),n.on("data",c=>{h+=c;}),n.on("end",()=>{let c;if(h)try{c=JSON.parse(h);}catch{c=void 0;}this.transport&&this.transport.handleRequest(n,o,c);}),n.on("error",c=>{g.error("HTTP request error",{error:c.message}),f(500,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}}));});}else n.method==="GET"?this.transport&&this.transport.handleRequest(n,o,void 0):f(405,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32601,message:"Method not found"}}));}),this.httpServer.on("error",n=>{g.error("HTTP server error",{error:n.message}),this.info.status=l.ERROR;}),this.httpServer.on("clientError",(n,o)=>{g.warn("HTTP client error",{error:n.message}),o.writable&&o.end(`HTTP/1.1 400 Bad Request\r
|
|
2
2
|
\r
|
|
3
|
-
`);}),this.httpServer.listen(e,r),h.info("HTTP server listening",{hostname:r,port:e}),this.info.status=c.RUNNING,this.info.lastActivityAt=Date.now(),h.info("started",{id:this.info.id,name:this.info.name,toolCount:y.getSize()});}catch(t){throw this.info.status=c.ERROR,h.error("failed to start",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){h.warn("already stopping",{id:this.info.id});return}if(this.info.status!==c.RUNNING&&this.info.status!==c.ERROR){h.debug("not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=c.STOPPING;try{h.info("stopping",{id:this.info.id,name:this.info.name}),this.unsubscribeTools(),this.httpServer&&(await new Promise(t=>{this.httpServer.close(()=>t());}),this.httpServer=null),this.transport&&(await this.transport.close(),this.transport=null),this.server&&(await this.server.close(),this.server=null),this.info.status=c.STOPPED,h.info("stopped",{id:this.info.id});}catch(t){this.info.status=c.ERROR,h.error("failed to stop",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){h.info("restarting",{id:this.info.id}),await this.stop(),await this.start();}};function U(m){return new E(m)}async function V(m){let t=new E(m);return await t.start(),t.createInstance()}var M={version:"0.2.22"};function P(){return M.version}var d=chunk4DCCWUIJ_cjs.b.create({service:"mcp.client"}),I=3e4,Vt=v__default.default.discriminatedUnion("status",[v__default.default.object({status:v__default.default.literal("connected")}).meta({ref:"MCPStatusConnected"}),v__default.default.object({status:v__default.default.literal("disconnected")}).meta({ref:"MCPStatusDisconnected"}),v__default.default.object({status:v__default.default.literal("failed"),error:v__default.default.string()}).meta({ref:"MCPStatusFailed"}),v__default.default.object({status:v__default.default.literal("needs_auth")}).meta({ref:"MCPStatusNeedsAuth"}),v__default.default.object({status:v__default.default.literal("needs_client_registration"),error:v__default.default.string()}).meta({ref:"MCPStatusNeedsClientRegistration"})]),k=class{constructor(){chunk4DCCWUIJ_cjs.a(this,"id","");chunk4DCCWUIJ_cjs.a(this,"client",null);chunk4DCCWUIJ_cjs.a(this,"_info");chunk4DCCWUIJ_cjs.a(this,"notificationCleanup",null);chunk4DCCWUIJ_cjs.a(this,"pendingTransport",null);chunk4DCCWUIJ_cjs.a(this,"oauthState","");chunk4DCCWUIJ_cjs.a(this,"toolListChangedHandler",null);this._info=this.createInitialInfo();}get info(){return {...this._info}}get status(){return this._info.status}get tools(){return [...this._info.tools]}async connect(t,e){d.info("connecting to MCP server",{id:t,type:e.type}),await this.disconnect(),this.id=t,this._info=this.createInitialInfo(),this._info.id=t,this._info.name=t;try{if(this.client=await this.createClient(e),!this.client)return;this._info.status={status:"connected"},this._info.connectedAt=Date.now(),await this.fetchCapabilities(),d.info("connected to MCP server",{id:t,toolCount:this._info.tools.length});}catch(r){let o=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:o},this._info.error=o,d.error("failed to connect to MCP server",{id:t,error:o});}}async startAuth(){if(!this.pendingTransport)throw new Error("No pending OAuth flow. Please connect to a server that requires authentication first.");return this.oauthState=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(t=>t.toString(16).padStart(2,"0")).join(""),{authorizationUrl:"",state:this.oauthState}}async finishAuth(t){if(!this.pendingTransport)throw new Error("No pending OAuth flow.");t&&await this.pendingTransport.finishAuth?.(t),this.pendingTransport=null,d.info("OAuth completed, reconnecting...",{id:this.id});}async disconnect(){this.notificationCleanup&&(this.notificationCleanup(),this.notificationCleanup=null),this.client&&(await this.client.close().catch(t=>{d.error("Failed to close MCP client",{error:t});}),this.client=null),this.pendingTransport=null,this.toolListChangedHandler=null,this._info.status.status==="connected"&&(this._info.status={status:"disconnected"}),d.info("disconnected from MCP server",{id:this.id});}async listTools(){if(!this.client||this._info.status.status!=="connected")return {};let t={};for(let e of this._info.tools)t[e.name]={name:e.name,description:e.description,inputSchema:e.inputSchema};return t}async callTool(t,e,r){let o=Date.now();if(!this.client||this._info.status.status!=="connected")return {toolName:t,args:e,result:null,success:false,error:"Client not connected",duration:Date.now()-o};try{let n=await utils.withTimeout(this.client.callTool({name:t,arguments:e},types_js.CallToolResultSchema,{resetTimeoutOnProgress:!0,timeout:r}),r??I);return {toolName:t,args:e,result:n.content,success:!0,duration:Date.now()-o}}catch(n){return {toolName:t,args:e,result:null,success:false,error:n instanceof Error?n.message:String(n),duration:Date.now()-o}}}async listResources(){return [...this._info.resources]}async readResource(t){if(!this.client||this._info.status.status!=="connected"){d.warn("client not connected for readResource");return}return this.client.readResource({uri:t}).catch(e=>{d.error("failed to read resource",{uri:t,error:e.message});})}async listPrompts(){return [...this._info.prompts]}async getPrompt(t,e){if(!this.client||this._info.status.status!=="connected"){d.warn("client not connected for getPrompt");return}return this.client.getPrompt({name:t,arguments:e}).catch(r=>{d.error("failed to get prompt",{name:t,error:r.message});})}async refreshTools(){if(!(!this.client||this._info.status.status!=="connected"))try{let t=await utils.withTimeout(this.client.listTools(),I);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema})),d.info("tools refreshed",{id:this.id,count:this._info.tools.length});}catch(t){d.error("failed to refresh tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}}async createClient(t){return t.type==="local"?this.createLocalClient(t):t.type==="remote"?this.createRemoteClient(t):null}async fetchCapabilities(){if(this.client){try{let t=await utils.withTimeout(this.client.listTools(),I);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));}catch(t){d.debug("failed to get tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}try{let t=await utils.withTimeout(this.client.listResources(),5e3);this._info.resources=t.resources.map(e=>({name:e.name,uri:e.uri,description:e.description,mimeType:e.mimeType}));}catch{d.debug("failed to get resources",{id:this.id});}try{let t=await utils.withTimeout(this.client.listPrompts(),5e3);this._info.prompts=t.prompts.map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(r=>({name:r.name,description:r.description,required:r.required}))}));}catch{d.debug("failed to get prompts",{id:this.id});}}}async createLocalClient(t){let[e,...r]=t.command;if(!e)return this._info.status={status:"failed",error:"Command is empty"},null;let o=new stdio_js.StdioClientTransport({stderr:"pipe",command:e,args:r.length>0?r:void 0,cwd:process.cwd(),env:Object.fromEntries(Object.entries({...process.env,...t.environment}).filter(([,n])=>n!==void 0))});o.stderr?.on("data",n=>{d.info(`mcp stderr: ${n.toString()}`,{id:this.id});});try{let n=new index_js.Client({name:"easbot-mcp",version:P()});return await utils.withTimeout(n.connect(o),t.timeout??I),this.registerNotificationHandler(n),n}catch(n){let b=n instanceof Error?n.message:String(n);return this._info.status={status:"failed",error:b},d.error("local mcp startup failed",{command:[e,...r],error:b}),null}}async createRemoteClient(t){t.oauth===false;let r={headers:t.headers};if((t.transport||"streamable-http")==="sse"){d.info("using SSE transport",{url:t.url});let n=new sse_js.SSEClientTransport(new URL(t.url),{requestInit:r});return this.connectWithTransport(n,t)}else {d.info("using StreamableHTTP transport",{url:t.url});let n=new streamableHttp_js.StreamableHTTPClientTransport(new URL(t.url),{requestInit:r});return this.connectWithTransport(n,t)}}async connectWithTransport(t,e){try{let r=new index_js.Client({name:"easbot-mcp",version:P()});return await utils.withTimeout(r.connect(t),e.timeout??I),this.registerNotificationHandler(r),r}catch(r){if(r instanceof auth_js.UnauthorizedError){let o=r instanceof Error?r.message:String(r);o.includes("registration")||o.includes("client_id")?this._info.status={status:"needs_client_registration",error:"Server does not support dynamic client registration. Please provide clientId in config."}:(this._info.status={status:"needs_auth"},this.pendingTransport=t);}else {let o=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:o};}return d.error("remote mcp connection failed",{url:e.url,error:this._info.status}),null}}registerToolListChangedHandler(t){this.toolListChangedHandler=t;}registerNotificationHandler(t){let e=async()=>{d.info("tools list changed notification received",{id:this.id}),await this.refreshTools(),this.toolListChangedHandler&&await this.toolListChangedHandler();};t.setNotificationHandler(types_js.ToolListChangedNotificationSchema,e),this.notificationCleanup=()=>{t.removeNotificationHandler("notifications/tools/list_changed");};}createInitialInfo(){return {id:"",name:"",status:{status:"disconnected"},tools:[],resources:[],prompts:[]}}};function Bt(){return new k}var Wt="0.2.20",$t="@easbot/mcp";async function Qt(m){let{Log:t}=await import('./chunks/log-WXSBDTHF.cjs'),e=false;await t.init({logDir:m.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:m.print??false,dev:m.dev??e,level:m.level??("INFO")});}Object.defineProperty(exports,"Log",{enumerable:true,get:function(){return chunk4DCCWUIJ_cjs.b}});exports.HttpServerAdapter=E;exports.MCPClient=k;exports.NAME=$t;exports.ServerStatus=c;exports.ServerTransportType=H;exports.Status=Vt;exports.StdioServerAdapter=w;exports.VERSION=Wt;exports.createAndStartHttpServer=V;exports.createAndStartStdioServer=Z;exports.createHttpServer=U;exports.createMCPClient=Bt;exports.createStdioServer=L;exports.getVersion=P;exports.initLog=Qt;
|
|
3
|
+
`);}),this.httpServer.listen(e,r),g.info("HTTP server listening",{hostname:r,port:e}),this.info.status=l.RUNNING,this.info.lastActivityAt=Date.now(),g.info("started",{id:this.info.id,name:this.info.name,toolCount:C.getSize()});}catch(t){throw this.info.status=l.ERROR,g.error("failed to start",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){g.warn("already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){g.debug("not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{g.info("stopping",{id:this.info.id,name:this.info.name}),this.unsubscribeTools(),this.httpServer&&(await new Promise(t=>{this.httpServer.close(()=>t());}),this.httpServer=null),this.transport&&(await this.transport.close(),this.transport=null),this.server&&(await this.server.close(),this.server=null),this.info.status=l.STOPPED,g.info("stopped",{id:this.info.id});}catch(t){this.info.status=l.ERROR,g.error("failed to stop",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){g.info("restarting",{id:this.info.id}),await this.stop(),await this.start();}};function V(s){return new w(s)}async function F(s){let t=new w(s);return await t.start(),t.createInstance()}var H={version:"0.2.23"};function E(){return H.version}var O=chunk4DCCWUIJ_cjs.b.create({service:"mcp.server.factory"});function K(s){return s.type==="local"}function $(s){return s.type==="remote"}function J(s,t){if(!t.command)throw new Error(`MCP server ${s} has no command specified`);return {id:s,name:s,version:"1.0.0",transportType:I.STDIO,enabled:t.enabled,timeout:t.timeout,command:t.command,args:t.args?.length?t.args:void 0,env:t.env}}function W(s,t){return {id:s,name:s,version:"1.0.0",transportType:I.HTTP,enabled:t.enabled,timeout:t.timeout,url:t.url,headers:t.headers}}async function Q(s,t){if(O.debug("creating server from config",{name:s,type:t.type}),K(t)){let e=J(s,t),r=new R(e);return await r.start(),r.createInstance()}if($(t)){let e=W(s,t),r=new w(e);return await r.start(),r.createInstance()}throw new Error(`Unsupported MCP config type: ${t.type}`)}async function Zt(s){let t={};for(let[e,r]of Object.entries(s))try{let n=await Q(e,r);t[e]=n;}catch(n){O.error("failed to create server from config",{name:e,error:n instanceof Error?n.message:String(n)});}return t}var p=chunk4DCCWUIJ_cjs.b.create({service:"mcp.client"}),x=3e4,M=class{constructor(){chunk4DCCWUIJ_cjs.a(this,"id","");chunk4DCCWUIJ_cjs.a(this,"client",null);chunk4DCCWUIJ_cjs.a(this,"_info");chunk4DCCWUIJ_cjs.a(this,"notificationCleanup",null);chunk4DCCWUIJ_cjs.a(this,"pendingTransport",null);chunk4DCCWUIJ_cjs.a(this,"oauthState","");chunk4DCCWUIJ_cjs.a(this,"capturedRedirectUrl",null);chunk4DCCWUIJ_cjs.a(this,"oauthConfig");chunk4DCCWUIJ_cjs.a(this,"toolListChangedHandler",null);chunk4DCCWUIJ_cjs.a(this,"oauthProvider",null);this._info=this.createInitialInfo();}get info(){return {...this._info}}get status(){return this._info.status}get tools(){return [...this._info.tools]}get resources(){return [...this._info.resources]}get prompts(){return [...this._info.prompts]}get clientId(){return this.id}setToolListChangedHandler(t){this.toolListChangedHandler=t;}setOAuthProvider(t){this.oauthProvider=t;}async connect(t,e){p.info("connecting to MCP server",{id:t,type:e.type}),await this.disconnect(),this.id=t,this._info=this.createInitialInfo(),this._info.id=t,this._info.name=t;try{if(e.type==="remote"&&(this.oauthConfig=e.oauth===!1?void 0:e.oauth??{}),this.client=await this.createClient(e),!this.client)return;this._info.status={status:"connected"},this._info.connectedAt=Date.now(),await this.fetchCapabilities(),p.info("connected to MCP server",{id:t,toolCount:this._info.tools.length});}catch(r){let n=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:n},this._info.error=n,p.error("failed to connect to MCP server",{id:t,error:n});}}async startAuth(){if(!this.pendingTransport)throw new Error("No pending OAuth flow. Please connect to a server that requires authentication first.");return this.oauthState=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(t=>t.toString(16).padStart(2,"0")).join(""),this.oauthProvider&&await this.oauthProvider.saveState(this.oauthState),{authorizationUrl:this.capturedRedirectUrl?.toString()??"",state:this.oauthState}}async finishAuth(t){if(!this.pendingTransport)throw new Error("No pending OAuth flow.");try{await this.pendingTransport.finishAuth?.(t);}catch(e){throw p.error("failed to finish OAuth",{id:this.id,error:e}),e}this.pendingTransport=null,this.capturedRedirectUrl=null,p.info("OAuth completed, ready to reconnect",{id:this.id});}isAuthRequired(){return this._info.status.status==="needs_auth"}isClientRegistrationRequired(){return this._info.status.status==="needs_client_registration"}getPendingTransport(){return this.pendingTransport}getAuthorizationUrl(){return this.capturedRedirectUrl?.toString()??""}async disconnect(){this.notificationCleanup&&(this.notificationCleanup(),this.notificationCleanup=null),this.client&&(await this.client.close().catch(t=>{p.error("Failed to close MCP client",{id:this.id,error:t});}),this.client=null),this.pendingTransport=null,this.capturedRedirectUrl=null,this.toolListChangedHandler=null,this._info.status.status==="connected"&&(this._info.status={status:"disconnected"}),p.info("disconnected from MCP server",{id:this.id});}async listTools(){if(!this.client||this._info.status.status!=="connected")return {};let t={};for(let e of this._info.tools)t[e.name]={name:e.name,description:e.description,inputSchema:e.inputSchema};return t}async callTool(t,e,r){let n=Date.now();if(!this.client||this._info.status.status!=="connected")return {toolName:t,args:e,content:[],success:false,error:"Client not connected",duration:Date.now()-n};try{let o=await utils.withTimeout(this.client.callTool({name:t,arguments:e},types_js.CallToolResultSchema,{resetTimeoutOnProgress:!0,timeout:r}),r??x);return {toolName:t,args:e,content:o.content.map(m=>m.type==="text"?{type:"text",text:m.text}:m.type==="image"?{type:"image",data:m.data,mimeType:m.mimeType}:m.type==="resource"?{type:"resource",resource:m.resource}:{type:"text",text:String(m)}),success:!0,duration:Date.now()-n,metadata:o.metadata}}catch(o){return {toolName:t,args:e,content:[],success:false,error:o instanceof Error?o.message:String(o),duration:Date.now()-n}}}async listResources(){return [...this._info.resources]}async readResource(t){if(!this.client||this._info.status.status!=="connected"){p.warn("client not connected for readResource",{id:this.id});return}return this.client.readResource({uri:t}).catch(e=>{p.error("failed to read resource",{id:this.id,uri:t,error:e.message});})}async listPrompts(){return [...this._info.prompts]}async getPrompt(t,e){if(!this.client||this._info.status.status!=="connected"){p.warn("client not connected for getPrompt",{id:this.id});return}return this.client.getPrompt({name:t,arguments:e}).catch(r=>{p.error("failed to get prompt",{id:this.id,name:t,error:r.message});})}async refreshTools(){if(!(!this.client||this._info.status.status!=="connected"))try{let t=await utils.withTimeout(this.client.listTools(),x);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema})),p.info("tools refreshed",{id:this.id,count:this._info.tools.length});}catch(t){p.error("failed to refresh tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}}async createClient(t){return t.type==="local"?await this.createLocalClient(t):t.type==="remote"?await this.createRemoteClient(t):null}async fetchCapabilities(){if(this.client){try{let t=await utils.withTimeout(this.client.listTools(),x);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));}catch(t){p.debug("failed to get tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}try{let t=await utils.withTimeout(this.client.listResources(),5e3);this._info.resources=t.resources.map(e=>({name:e.name,uri:e.uri,description:e.description,mimeType:e.mimeType}));}catch{p.debug("failed to get resources",{id:this.id});}try{let t=await utils.withTimeout(this.client.listPrompts(),5e3);this._info.prompts=t.prompts.map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(r=>({name:r.name,description:r.description,required:r.required}))}));}catch{p.debug("failed to get prompts",{id:this.id});}}}async createLocalClient(t){let[e,...r]=t.command;if(!e)return this._info.status={status:"failed",error:"Command is empty"},null;let n=new stdio_js$1.StdioClientTransport({stderr:"pipe",command:e,args:r.length>0?r:void 0,cwd:t.cwd??process.cwd(),env:Object.fromEntries(Object.entries({...process.env,...t.environment}).filter(([,o])=>o!==void 0))});n.stderr?.on("data",o=>{p.info(`mcp stderr: ${o.toString()}`,{id:this.id});});try{let o=new index_js.Client({name:"easbot-mcp",version:E()});return await utils.withTimeout(o.connect(n),t.timeout??x),this.registerNotificationHandler(o),o}catch(o){let m=o instanceof Error?o.message:String(o);return this._info.status={status:"failed",error:m},p.error("local mcp startup failed",{id:this.id,command:[e,...r],error:m}),null}}async createRemoteClient(t){let e={headers:t.headers};if((t.transport||"streamable-http")==="sse"){p.info("using SSE transport",{id:this.id,url:t.url});let n=new sse_js.SSEClientTransport(new URL(t.url),{requestInit:e});return await this.connectWithTransport(n,t)}else {p.info("using StreamableHTTP transport",{id:this.id,url:t.url});let n=new streamableHttp_js$1.StreamableHTTPClientTransport(new URL(t.url),{requestInit:e});return await this.connectWithTransport(n,t)}}async connectWithTransport(t,e){try{let r=new index_js.Client({name:"easbot-mcp",version:E()});return await r.connect(t),this.registerNotificationHandler(r),r}catch(r){return this.handleConnectionError(r,t,e),null}}handleConnectionError(t,e,r){if(t instanceof auth_js.UnauthorizedError){let n=t instanceof Error?t.message:String(t);n.includes("registration")||n.includes("client_id")?this._info.status={status:"needs_client_registration",error:"Server does not support dynamic client registration. Please provide clientId in config."}:(this._info.status={status:"needs_auth"},this.pendingTransport=e,this.capturedRedirectUrl=this.extractRedirectUrl(t));}else {let n=t instanceof Error?t.message:String(t);this._info.status={status:"failed",error:n};}p.error("remote mcp connection failed",{id:this.id,url:r.url,status:this._info.status});}extractRedirectUrl(t){let r=t.message.match(/https?:\/\/[^\s]+/);if(r)try{return new URL(r[0])}catch{return null}return null}registerNotificationHandler(t){let e=async()=>{p.info("tools list changed notification received",{id:this.id}),await this.refreshTools(),this.toolListChangedHandler&&await this.toolListChangedHandler();};t.setNotificationHandler(types_js.ToolListChangedNotificationSchema,e),this.notificationCleanup=()=>{t.removeNotificationHandler("notifications/tools/list_changed");};}createInitialInfo(){return {id:"",name:"",status:{status:"disconnected"},tools:[],resources:[],prompts:[]}}};function ot(){return new M}var ce=v__default.default.discriminatedUnion("status",[v__default.default.object({status:v__default.default.literal("connected")}).meta({ref:"MCPStatusConnected"}),v__default.default.object({status:v__default.default.literal("disconnected")}).meta({ref:"MCPStatusDisconnected"}),v__default.default.object({status:v__default.default.literal("failed"),error:v__default.default.string()}).meta({ref:"MCPStatusFailed"}),v__default.default.object({status:v__default.default.literal("needs_auth")}).meta({ref:"MCPStatusNeedsAuth"}),v__default.default.object({status:v__default.default.literal("needs_client_registration"),error:v__default.default.string()}).meta({ref:"MCPStatusNeedsClientRegistration"}),v__default.default.object({status:v__default.default.literal("disabled")}).meta({ref:"MCPStatusDisabled"})]);var he="@easbot/mcp";async function ge(s){let{Log:t}=await import('./chunks/log-WXSBDTHF.cjs'),e=false;await t.init({logDir:s.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:s.print??false,dev:s.dev??e,level:s.level??("INFO")});}exports.HttpServerAdapter=w;exports.MCPClient=M;exports.NAME=he;exports.ServerStatus=l;exports.ServerTransportType=I;exports.Status=ce;exports.StdioServerAdapter=R;exports.ToolRegistry=A;exports.ToolRegistryEvent=b;exports.createAndStartHttpServer=F;exports.createAndStartStdioServer=Z;exports.createHttpServer=V;exports.createMCPClient=ot;exports.createServerFromConfig=Q;exports.createServersFromConfigMap=Zt;exports.createStdioServer=U;exports.getVersion=E;exports.initLog=ge;exports.tools=C;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
|
|
2
|
-
import
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import z, { ZodType } from 'zod';
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
6
|
+
import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
7
|
|
|
4
8
|
interface McpLocalConfig {
|
|
5
9
|
type: 'local';
|
|
6
|
-
command: string
|
|
7
|
-
|
|
10
|
+
command: string;
|
|
11
|
+
args?: string[];
|
|
12
|
+
env?: Record<string, string>;
|
|
8
13
|
enabled?: boolean;
|
|
9
14
|
timeout?: number;
|
|
15
|
+
description?: string;
|
|
10
16
|
}
|
|
11
17
|
interface McpOAuthConfig {
|
|
12
18
|
clientId?: string;
|
|
@@ -20,6 +26,7 @@ interface McpRemoteConfig {
|
|
|
20
26
|
headers?: Record<string, string>;
|
|
21
27
|
oauth?: McpOAuthConfig | false;
|
|
22
28
|
timeout?: number;
|
|
29
|
+
description?: string;
|
|
23
30
|
}
|
|
24
31
|
type McpConfig = McpLocalConfig | McpRemoteConfig;
|
|
25
32
|
declare const ServerTransportType: {
|
|
@@ -50,7 +57,7 @@ interface StdioServerConfig {
|
|
|
50
57
|
name: string;
|
|
51
58
|
version: string;
|
|
52
59
|
transportType: typeof ServerTransportType.STDIO;
|
|
53
|
-
command
|
|
60
|
+
command?: string;
|
|
54
61
|
args?: string[];
|
|
55
62
|
env?: Record<string, string>;
|
|
56
63
|
cwd?: string;
|
|
@@ -141,6 +148,9 @@ declare class HttpServerAdapter {
|
|
|
141
148
|
declare function createHttpServer(config: HttpServerConfig): HttpServerAdapter;
|
|
142
149
|
declare function createAndStartHttpServer(config: HttpServerConfig): Promise<ServerInstance>;
|
|
143
150
|
|
|
151
|
+
declare function createServerFromConfig(name: string, config: McpConfig): Promise<ServerInstance$2>;
|
|
152
|
+
declare function createServersFromConfigMap(configs: Record<string, McpConfig>): Promise<Record<string, ServerInstance$2>>;
|
|
153
|
+
|
|
144
154
|
interface OAuthConfig {
|
|
145
155
|
clientId?: string;
|
|
146
156
|
clientSecret?: string;
|
|
@@ -150,6 +160,7 @@ interface OAuthConfig {
|
|
|
150
160
|
interface LocalMCPConfig {
|
|
151
161
|
type: 'local';
|
|
152
162
|
command: string[];
|
|
163
|
+
cwd?: string;
|
|
153
164
|
environment?: Record<string, string>;
|
|
154
165
|
timeout?: number;
|
|
155
166
|
}
|
|
@@ -162,6 +173,7 @@ interface RemoteMCPConfig {
|
|
|
162
173
|
timeout?: number;
|
|
163
174
|
}
|
|
164
175
|
type MCPConfig = LocalMCPConfig | RemoteMCPConfig;
|
|
176
|
+
type ToolListChangedHandler = () => void | Promise<void>;
|
|
165
177
|
declare const Status: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
166
178
|
status: z.ZodLiteral<"connected">;
|
|
167
179
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -174,6 +186,8 @@ declare const Status: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
174
186
|
}, z.core.$strip>, z.ZodObject<{
|
|
175
187
|
status: z.ZodLiteral<"needs_client_registration">;
|
|
176
188
|
error: z.ZodString;
|
|
189
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
190
|
+
status: z.ZodLiteral<"disabled">;
|
|
177
191
|
}, z.core.$strip>], "status">;
|
|
178
192
|
type Status = z.infer<typeof Status>;
|
|
179
193
|
interface ToolMetadata {
|
|
@@ -196,6 +210,60 @@ interface PromptMetadata {
|
|
|
196
210
|
required?: boolean;
|
|
197
211
|
}>;
|
|
198
212
|
}
|
|
213
|
+
interface ToolContentItem {
|
|
214
|
+
type: 'text' | 'image' | 'resource';
|
|
215
|
+
text?: string;
|
|
216
|
+
data?: string;
|
|
217
|
+
mimeType?: string;
|
|
218
|
+
resource?: {
|
|
219
|
+
uri: string;
|
|
220
|
+
mimeType?: string;
|
|
221
|
+
blob?: string;
|
|
222
|
+
text?: string;
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
interface ToolCallResult {
|
|
226
|
+
toolName: string;
|
|
227
|
+
args: Record<string, unknown>;
|
|
228
|
+
content: ToolContentItem[];
|
|
229
|
+
success: boolean;
|
|
230
|
+
error?: string;
|
|
231
|
+
duration: number;
|
|
232
|
+
metadata?: Record<string, unknown>;
|
|
233
|
+
}
|
|
234
|
+
interface AuthResult {
|
|
235
|
+
authorizationUrl: string;
|
|
236
|
+
state: string;
|
|
237
|
+
}
|
|
238
|
+
interface OAuthClientProviderAdapter {
|
|
239
|
+
saveState(state: string): Promise<void>;
|
|
240
|
+
getState(): Promise<string | undefined>;
|
|
241
|
+
clearState(): Promise<void>;
|
|
242
|
+
saveCodeVerifier(verifier: string): Promise<void>;
|
|
243
|
+
getCodeVerifier(): Promise<string | undefined>;
|
|
244
|
+
saveClientInfo(info: {
|
|
245
|
+
clientId: string;
|
|
246
|
+
clientSecret?: string;
|
|
247
|
+
clientIdIssuedAt?: number;
|
|
248
|
+
clientSecretExpiresAt?: number;
|
|
249
|
+
}): Promise<void>;
|
|
250
|
+
getClientInfo(): Promise<{
|
|
251
|
+
clientId: string;
|
|
252
|
+
clientSecret?: string;
|
|
253
|
+
} | undefined>;
|
|
254
|
+
saveTokens(tokens: {
|
|
255
|
+
accessToken: string;
|
|
256
|
+
refreshToken?: string;
|
|
257
|
+
expiresAt?: number;
|
|
258
|
+
scope?: string;
|
|
259
|
+
}): Promise<void>;
|
|
260
|
+
getTokens(): Promise<{
|
|
261
|
+
accessToken: string;
|
|
262
|
+
refreshToken?: string;
|
|
263
|
+
expiresAt?: number;
|
|
264
|
+
scope?: string;
|
|
265
|
+
} | undefined>;
|
|
266
|
+
}
|
|
199
267
|
interface ClientInfo {
|
|
200
268
|
id: string;
|
|
201
269
|
name: string;
|
|
@@ -208,18 +276,7 @@ interface ClientInfo {
|
|
|
208
276
|
prompts: PromptMetadata[];
|
|
209
277
|
error?: string;
|
|
210
278
|
}
|
|
211
|
-
|
|
212
|
-
toolName: string;
|
|
213
|
-
args: Record<string, unknown>;
|
|
214
|
-
result: unknown;
|
|
215
|
-
success: boolean;
|
|
216
|
-
error?: string;
|
|
217
|
-
duration: number;
|
|
218
|
-
}
|
|
219
|
-
interface AuthResult {
|
|
220
|
-
authorizationUrl: string;
|
|
221
|
-
state?: string;
|
|
222
|
-
}
|
|
279
|
+
|
|
223
280
|
declare class MCPClient {
|
|
224
281
|
private id;
|
|
225
282
|
private client;
|
|
@@ -227,14 +284,26 @@ declare class MCPClient {
|
|
|
227
284
|
private notificationCleanup;
|
|
228
285
|
private pendingTransport;
|
|
229
286
|
private oauthState;
|
|
287
|
+
private capturedRedirectUrl;
|
|
288
|
+
private oauthConfig;
|
|
230
289
|
private toolListChangedHandler;
|
|
290
|
+
private oauthProvider;
|
|
231
291
|
constructor();
|
|
232
292
|
get info(): ClientInfo;
|
|
233
293
|
get status(): Status;
|
|
234
294
|
get tools(): ToolMetadata[];
|
|
295
|
+
get resources(): ResourceMetadata[];
|
|
296
|
+
get prompts(): PromptMetadata[];
|
|
297
|
+
get clientId(): string;
|
|
298
|
+
setToolListChangedHandler(handler: ToolListChangedHandler | null): void;
|
|
299
|
+
setOAuthProvider(provider: OAuthClientProviderAdapter | null): void;
|
|
235
300
|
connect(id: string, config: MCPConfig): Promise<void>;
|
|
236
301
|
startAuth(): Promise<AuthResult>;
|
|
237
|
-
finishAuth(authorizationCode
|
|
302
|
+
finishAuth(authorizationCode: string): Promise<void>;
|
|
303
|
+
isAuthRequired(): boolean;
|
|
304
|
+
isClientRegistrationRequired(): boolean;
|
|
305
|
+
getPendingTransport(): StreamableHTTPClientTransport | SSEClientTransport | null;
|
|
306
|
+
getAuthorizationUrl(): string;
|
|
238
307
|
disconnect(): Promise<void>;
|
|
239
308
|
listTools(): Promise<Record<string, unknown>>;
|
|
240
309
|
callTool(toolName: string, args: Record<string, unknown>, timeout?: number): Promise<ToolCallResult>;
|
|
@@ -352,57 +421,60 @@ declare class MCPClient {
|
|
|
352
421
|
private createLocalClient;
|
|
353
422
|
private createRemoteClient;
|
|
354
423
|
private connectWithTransport;
|
|
355
|
-
|
|
424
|
+
private handleConnectionError;
|
|
425
|
+
private extractRedirectUrl;
|
|
356
426
|
private registerNotificationHandler;
|
|
357
427
|
private createInitialInfo;
|
|
358
428
|
}
|
|
359
429
|
declare function createMCPClient(): MCPClient;
|
|
360
430
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
info(message?: any, extra?: Record<string, any>): void;
|
|
373
|
-
error(message?: any, extra?: Record<string, any>): void;
|
|
374
|
-
warn(message?: any, extra?: Record<string, any>): void;
|
|
375
|
-
tag(key: string, value: string): Logger;
|
|
376
|
-
clone(): Logger;
|
|
377
|
-
time(message: string, extra?: Record<string, any>): {
|
|
378
|
-
stop(): void;
|
|
379
|
-
[Symbol.dispose](): void;
|
|
380
|
-
};
|
|
431
|
+
type ToolInputSchema = ZodType | Record<string, unknown>;
|
|
432
|
+
type RequestId = string | number;
|
|
433
|
+
interface ToolContext {
|
|
434
|
+
signal?: AbortSignal;
|
|
435
|
+
sessionId?: string;
|
|
436
|
+
requestId: RequestId;
|
|
437
|
+
taskId?: string;
|
|
438
|
+
_meta?: Record<string, unknown>;
|
|
439
|
+
authInfo?: {
|
|
440
|
+
type: string;
|
|
441
|
+
claims?: Record<string, unknown>;
|
|
381
442
|
};
|
|
382
|
-
const Default: Logger;
|
|
383
|
-
interface Options {
|
|
384
|
-
print: boolean;
|
|
385
|
-
logDir: string;
|
|
386
|
-
logFile?: string;
|
|
387
|
-
dev?: boolean;
|
|
388
|
-
level?: Level;
|
|
389
|
-
}
|
|
390
|
-
function file(): string;
|
|
391
|
-
function init(options: Options): Promise<void>;
|
|
392
|
-
function close(): Promise<void>;
|
|
393
|
-
function create(tags?: Record<string, any>): Logger;
|
|
394
443
|
}
|
|
444
|
+
type ToolHandler = (args: unknown, ctx: ToolContext) => Promise<CallToolResult>;
|
|
445
|
+
interface ToolDefinition extends Omit<Tool, 'inputSchema'> {
|
|
446
|
+
inputSchema?: ToolInputSchema;
|
|
447
|
+
handler: ToolHandler;
|
|
448
|
+
}
|
|
449
|
+
declare const ToolRegistryEvent: {
|
|
450
|
+
readonly REGISTERED: "mcp.tool.registered";
|
|
451
|
+
readonly UNREGISTERED: "mcp.tool.unregistered";
|
|
452
|
+
readonly CLEARED: "mcp.tool.cleared";
|
|
453
|
+
};
|
|
454
|
+
type ToolRegistryEvent = (typeof ToolRegistryEvent)[keyof typeof ToolRegistryEvent];
|
|
455
|
+
declare class ToolRegistry extends EventEmitter {
|
|
456
|
+
private tools;
|
|
457
|
+
constructor();
|
|
458
|
+
register(tool: ToolDefinition): void;
|
|
459
|
+
unregister(name: string): boolean;
|
|
460
|
+
get(name: string): ToolDefinition | undefined;
|
|
461
|
+
getAll(): ToolDefinition[];
|
|
462
|
+
getTools(): Omit<ToolDefinition, 'handler'>[];
|
|
463
|
+
has(name: string): boolean;
|
|
464
|
+
getSize(): number;
|
|
465
|
+
clear(): void;
|
|
466
|
+
}
|
|
467
|
+
declare const tools: ToolRegistry;
|
|
395
468
|
|
|
396
469
|
declare function getVersion(): string;
|
|
397
470
|
|
|
398
|
-
declare const VERSION = "0.2.20";
|
|
399
471
|
declare const NAME = "@easbot/mcp";
|
|
400
472
|
declare function initLog(options: {
|
|
401
473
|
print: boolean;
|
|
402
|
-
logDir
|
|
474
|
+
logDir: string;
|
|
403
475
|
logFile?: string;
|
|
404
476
|
dev?: boolean;
|
|
405
477
|
level?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
406
478
|
}): Promise<void>;
|
|
407
479
|
|
|
408
|
-
export { type AuthResult, type ClientInfo, HttpServerAdapter, type HttpServerConfig, type LocalMCPConfig,
|
|
480
|
+
export { type AuthResult, type ClientInfo, HttpServerAdapter, type HttpServerConfig, type LocalMCPConfig, MCPClient, type MCPConfig, type McpConfig, type McpLocalConfig, type McpOAuthConfig, type McpRemoteConfig, NAME, type OAuthClientProviderAdapter, type OAuthConfig, type PromptMetadata, type RemoteMCPConfig, type RequestId, type ResourceMetadata, type ServerInfo, type ServerInstance$2 as ServerInstance, ServerStatus, ServerTransportType, Status, StdioServerAdapter, type StdioServerConfig, type ToolCallResult, type ToolContentItem, type ToolContext, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolListChangedHandler, type ToolMetadata, ToolRegistry, ToolRegistryEvent, createAndStartHttpServer, createAndStartStdioServer, createHttpServer, createMCPClient, createServerFromConfig, createServersFromConfigMap, createStdioServer, getVersion, initLog, tools };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
|
|
2
|
-
import
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import z, { ZodType } from 'zod';
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
6
|
+
import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
7
|
|
|
4
8
|
interface McpLocalConfig {
|
|
5
9
|
type: 'local';
|
|
6
|
-
command: string
|
|
7
|
-
|
|
10
|
+
command: string;
|
|
11
|
+
args?: string[];
|
|
12
|
+
env?: Record<string, string>;
|
|
8
13
|
enabled?: boolean;
|
|
9
14
|
timeout?: number;
|
|
15
|
+
description?: string;
|
|
10
16
|
}
|
|
11
17
|
interface McpOAuthConfig {
|
|
12
18
|
clientId?: string;
|
|
@@ -20,6 +26,7 @@ interface McpRemoteConfig {
|
|
|
20
26
|
headers?: Record<string, string>;
|
|
21
27
|
oauth?: McpOAuthConfig | false;
|
|
22
28
|
timeout?: number;
|
|
29
|
+
description?: string;
|
|
23
30
|
}
|
|
24
31
|
type McpConfig = McpLocalConfig | McpRemoteConfig;
|
|
25
32
|
declare const ServerTransportType: {
|
|
@@ -50,7 +57,7 @@ interface StdioServerConfig {
|
|
|
50
57
|
name: string;
|
|
51
58
|
version: string;
|
|
52
59
|
transportType: typeof ServerTransportType.STDIO;
|
|
53
|
-
command
|
|
60
|
+
command?: string;
|
|
54
61
|
args?: string[];
|
|
55
62
|
env?: Record<string, string>;
|
|
56
63
|
cwd?: string;
|
|
@@ -141,6 +148,9 @@ declare class HttpServerAdapter {
|
|
|
141
148
|
declare function createHttpServer(config: HttpServerConfig): HttpServerAdapter;
|
|
142
149
|
declare function createAndStartHttpServer(config: HttpServerConfig): Promise<ServerInstance>;
|
|
143
150
|
|
|
151
|
+
declare function createServerFromConfig(name: string, config: McpConfig): Promise<ServerInstance$2>;
|
|
152
|
+
declare function createServersFromConfigMap(configs: Record<string, McpConfig>): Promise<Record<string, ServerInstance$2>>;
|
|
153
|
+
|
|
144
154
|
interface OAuthConfig {
|
|
145
155
|
clientId?: string;
|
|
146
156
|
clientSecret?: string;
|
|
@@ -150,6 +160,7 @@ interface OAuthConfig {
|
|
|
150
160
|
interface LocalMCPConfig {
|
|
151
161
|
type: 'local';
|
|
152
162
|
command: string[];
|
|
163
|
+
cwd?: string;
|
|
153
164
|
environment?: Record<string, string>;
|
|
154
165
|
timeout?: number;
|
|
155
166
|
}
|
|
@@ -162,6 +173,7 @@ interface RemoteMCPConfig {
|
|
|
162
173
|
timeout?: number;
|
|
163
174
|
}
|
|
164
175
|
type MCPConfig = LocalMCPConfig | RemoteMCPConfig;
|
|
176
|
+
type ToolListChangedHandler = () => void | Promise<void>;
|
|
165
177
|
declare const Status: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
166
178
|
status: z.ZodLiteral<"connected">;
|
|
167
179
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -174,6 +186,8 @@ declare const Status: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
174
186
|
}, z.core.$strip>, z.ZodObject<{
|
|
175
187
|
status: z.ZodLiteral<"needs_client_registration">;
|
|
176
188
|
error: z.ZodString;
|
|
189
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
190
|
+
status: z.ZodLiteral<"disabled">;
|
|
177
191
|
}, z.core.$strip>], "status">;
|
|
178
192
|
type Status = z.infer<typeof Status>;
|
|
179
193
|
interface ToolMetadata {
|
|
@@ -196,6 +210,60 @@ interface PromptMetadata {
|
|
|
196
210
|
required?: boolean;
|
|
197
211
|
}>;
|
|
198
212
|
}
|
|
213
|
+
interface ToolContentItem {
|
|
214
|
+
type: 'text' | 'image' | 'resource';
|
|
215
|
+
text?: string;
|
|
216
|
+
data?: string;
|
|
217
|
+
mimeType?: string;
|
|
218
|
+
resource?: {
|
|
219
|
+
uri: string;
|
|
220
|
+
mimeType?: string;
|
|
221
|
+
blob?: string;
|
|
222
|
+
text?: string;
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
interface ToolCallResult {
|
|
226
|
+
toolName: string;
|
|
227
|
+
args: Record<string, unknown>;
|
|
228
|
+
content: ToolContentItem[];
|
|
229
|
+
success: boolean;
|
|
230
|
+
error?: string;
|
|
231
|
+
duration: number;
|
|
232
|
+
metadata?: Record<string, unknown>;
|
|
233
|
+
}
|
|
234
|
+
interface AuthResult {
|
|
235
|
+
authorizationUrl: string;
|
|
236
|
+
state: string;
|
|
237
|
+
}
|
|
238
|
+
interface OAuthClientProviderAdapter {
|
|
239
|
+
saveState(state: string): Promise<void>;
|
|
240
|
+
getState(): Promise<string | undefined>;
|
|
241
|
+
clearState(): Promise<void>;
|
|
242
|
+
saveCodeVerifier(verifier: string): Promise<void>;
|
|
243
|
+
getCodeVerifier(): Promise<string | undefined>;
|
|
244
|
+
saveClientInfo(info: {
|
|
245
|
+
clientId: string;
|
|
246
|
+
clientSecret?: string;
|
|
247
|
+
clientIdIssuedAt?: number;
|
|
248
|
+
clientSecretExpiresAt?: number;
|
|
249
|
+
}): Promise<void>;
|
|
250
|
+
getClientInfo(): Promise<{
|
|
251
|
+
clientId: string;
|
|
252
|
+
clientSecret?: string;
|
|
253
|
+
} | undefined>;
|
|
254
|
+
saveTokens(tokens: {
|
|
255
|
+
accessToken: string;
|
|
256
|
+
refreshToken?: string;
|
|
257
|
+
expiresAt?: number;
|
|
258
|
+
scope?: string;
|
|
259
|
+
}): Promise<void>;
|
|
260
|
+
getTokens(): Promise<{
|
|
261
|
+
accessToken: string;
|
|
262
|
+
refreshToken?: string;
|
|
263
|
+
expiresAt?: number;
|
|
264
|
+
scope?: string;
|
|
265
|
+
} | undefined>;
|
|
266
|
+
}
|
|
199
267
|
interface ClientInfo {
|
|
200
268
|
id: string;
|
|
201
269
|
name: string;
|
|
@@ -208,18 +276,7 @@ interface ClientInfo {
|
|
|
208
276
|
prompts: PromptMetadata[];
|
|
209
277
|
error?: string;
|
|
210
278
|
}
|
|
211
|
-
|
|
212
|
-
toolName: string;
|
|
213
|
-
args: Record<string, unknown>;
|
|
214
|
-
result: unknown;
|
|
215
|
-
success: boolean;
|
|
216
|
-
error?: string;
|
|
217
|
-
duration: number;
|
|
218
|
-
}
|
|
219
|
-
interface AuthResult {
|
|
220
|
-
authorizationUrl: string;
|
|
221
|
-
state?: string;
|
|
222
|
-
}
|
|
279
|
+
|
|
223
280
|
declare class MCPClient {
|
|
224
281
|
private id;
|
|
225
282
|
private client;
|
|
@@ -227,14 +284,26 @@ declare class MCPClient {
|
|
|
227
284
|
private notificationCleanup;
|
|
228
285
|
private pendingTransport;
|
|
229
286
|
private oauthState;
|
|
287
|
+
private capturedRedirectUrl;
|
|
288
|
+
private oauthConfig;
|
|
230
289
|
private toolListChangedHandler;
|
|
290
|
+
private oauthProvider;
|
|
231
291
|
constructor();
|
|
232
292
|
get info(): ClientInfo;
|
|
233
293
|
get status(): Status;
|
|
234
294
|
get tools(): ToolMetadata[];
|
|
295
|
+
get resources(): ResourceMetadata[];
|
|
296
|
+
get prompts(): PromptMetadata[];
|
|
297
|
+
get clientId(): string;
|
|
298
|
+
setToolListChangedHandler(handler: ToolListChangedHandler | null): void;
|
|
299
|
+
setOAuthProvider(provider: OAuthClientProviderAdapter | null): void;
|
|
235
300
|
connect(id: string, config: MCPConfig): Promise<void>;
|
|
236
301
|
startAuth(): Promise<AuthResult>;
|
|
237
|
-
finishAuth(authorizationCode
|
|
302
|
+
finishAuth(authorizationCode: string): Promise<void>;
|
|
303
|
+
isAuthRequired(): boolean;
|
|
304
|
+
isClientRegistrationRequired(): boolean;
|
|
305
|
+
getPendingTransport(): StreamableHTTPClientTransport | SSEClientTransport | null;
|
|
306
|
+
getAuthorizationUrl(): string;
|
|
238
307
|
disconnect(): Promise<void>;
|
|
239
308
|
listTools(): Promise<Record<string, unknown>>;
|
|
240
309
|
callTool(toolName: string, args: Record<string, unknown>, timeout?: number): Promise<ToolCallResult>;
|
|
@@ -352,57 +421,60 @@ declare class MCPClient {
|
|
|
352
421
|
private createLocalClient;
|
|
353
422
|
private createRemoteClient;
|
|
354
423
|
private connectWithTransport;
|
|
355
|
-
|
|
424
|
+
private handleConnectionError;
|
|
425
|
+
private extractRedirectUrl;
|
|
356
426
|
private registerNotificationHandler;
|
|
357
427
|
private createInitialInfo;
|
|
358
428
|
}
|
|
359
429
|
declare function createMCPClient(): MCPClient;
|
|
360
430
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
info(message?: any, extra?: Record<string, any>): void;
|
|
373
|
-
error(message?: any, extra?: Record<string, any>): void;
|
|
374
|
-
warn(message?: any, extra?: Record<string, any>): void;
|
|
375
|
-
tag(key: string, value: string): Logger;
|
|
376
|
-
clone(): Logger;
|
|
377
|
-
time(message: string, extra?: Record<string, any>): {
|
|
378
|
-
stop(): void;
|
|
379
|
-
[Symbol.dispose](): void;
|
|
380
|
-
};
|
|
431
|
+
type ToolInputSchema = ZodType | Record<string, unknown>;
|
|
432
|
+
type RequestId = string | number;
|
|
433
|
+
interface ToolContext {
|
|
434
|
+
signal?: AbortSignal;
|
|
435
|
+
sessionId?: string;
|
|
436
|
+
requestId: RequestId;
|
|
437
|
+
taskId?: string;
|
|
438
|
+
_meta?: Record<string, unknown>;
|
|
439
|
+
authInfo?: {
|
|
440
|
+
type: string;
|
|
441
|
+
claims?: Record<string, unknown>;
|
|
381
442
|
};
|
|
382
|
-
const Default: Logger;
|
|
383
|
-
interface Options {
|
|
384
|
-
print: boolean;
|
|
385
|
-
logDir: string;
|
|
386
|
-
logFile?: string;
|
|
387
|
-
dev?: boolean;
|
|
388
|
-
level?: Level;
|
|
389
|
-
}
|
|
390
|
-
function file(): string;
|
|
391
|
-
function init(options: Options): Promise<void>;
|
|
392
|
-
function close(): Promise<void>;
|
|
393
|
-
function create(tags?: Record<string, any>): Logger;
|
|
394
443
|
}
|
|
444
|
+
type ToolHandler = (args: unknown, ctx: ToolContext) => Promise<CallToolResult>;
|
|
445
|
+
interface ToolDefinition extends Omit<Tool, 'inputSchema'> {
|
|
446
|
+
inputSchema?: ToolInputSchema;
|
|
447
|
+
handler: ToolHandler;
|
|
448
|
+
}
|
|
449
|
+
declare const ToolRegistryEvent: {
|
|
450
|
+
readonly REGISTERED: "mcp.tool.registered";
|
|
451
|
+
readonly UNREGISTERED: "mcp.tool.unregistered";
|
|
452
|
+
readonly CLEARED: "mcp.tool.cleared";
|
|
453
|
+
};
|
|
454
|
+
type ToolRegistryEvent = (typeof ToolRegistryEvent)[keyof typeof ToolRegistryEvent];
|
|
455
|
+
declare class ToolRegistry extends EventEmitter {
|
|
456
|
+
private tools;
|
|
457
|
+
constructor();
|
|
458
|
+
register(tool: ToolDefinition): void;
|
|
459
|
+
unregister(name: string): boolean;
|
|
460
|
+
get(name: string): ToolDefinition | undefined;
|
|
461
|
+
getAll(): ToolDefinition[];
|
|
462
|
+
getTools(): Omit<ToolDefinition, 'handler'>[];
|
|
463
|
+
has(name: string): boolean;
|
|
464
|
+
getSize(): number;
|
|
465
|
+
clear(): void;
|
|
466
|
+
}
|
|
467
|
+
declare const tools: ToolRegistry;
|
|
395
468
|
|
|
396
469
|
declare function getVersion(): string;
|
|
397
470
|
|
|
398
|
-
declare const VERSION = "0.2.20";
|
|
399
471
|
declare const NAME = "@easbot/mcp";
|
|
400
472
|
declare function initLog(options: {
|
|
401
473
|
print: boolean;
|
|
402
|
-
logDir
|
|
474
|
+
logDir: string;
|
|
403
475
|
logFile?: string;
|
|
404
476
|
dev?: boolean;
|
|
405
477
|
level?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
406
478
|
}): Promise<void>;
|
|
407
479
|
|
|
408
|
-
export { type AuthResult, type ClientInfo, HttpServerAdapter, type HttpServerConfig, type LocalMCPConfig,
|
|
480
|
+
export { type AuthResult, type ClientInfo, HttpServerAdapter, type HttpServerConfig, type LocalMCPConfig, MCPClient, type MCPConfig, type McpConfig, type McpLocalConfig, type McpOAuthConfig, type McpRemoteConfig, NAME, type OAuthClientProviderAdapter, type OAuthConfig, type PromptMetadata, type RemoteMCPConfig, type RequestId, type ResourceMetadata, type ServerInfo, type ServerInstance$2 as ServerInstance, ServerStatus, ServerTransportType, Status, StdioServerAdapter, type StdioServerConfig, type ToolCallResult, type ToolContentItem, type ToolContext, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolListChangedHandler, type ToolMetadata, ToolRegistry, ToolRegistryEvent, createAndStartHttpServer, createAndStartStdioServer, createHttpServer, createMCPClient, createServerFromConfig, createServersFromConfigMap, createStdioServer, getVersion, initLog, tools };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {b,a}from'./chunks/chunk-PJM3ON7Z.mjs';export{b as Log}from'./chunks/chunk-PJM3ON7Z.mjs';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio';import {EventEmitter}from'events';import l from'zod/v4';import q from'http';import {StreamableHTTPServerTransport}from'@modelcontextprotocol/sdk/server/streamableHttp';import {Client}from'@modelcontextprotocol/sdk/client/index.js';import {StdioClientTransport}from'@modelcontextprotocol/sdk/client/stdio.js';import {StreamableHTTPClientTransport}from'@modelcontextprotocol/sdk/client/streamableHttp.js';import {SSEClientTransport}from'@modelcontextprotocol/sdk/client/sse.js';import {CallToolResultSchema,ToolListChangedNotificationSchema}from'@modelcontextprotocol/sdk/types.js';import {UnauthorizedError}from'@modelcontextprotocol/sdk/client/auth.js';import {withTimeout}from'@easbot/utils';import v from'zod';var N={STDIO:"stdio",HTTP:"http"},c={STOPPED:"stopped",STARTING:"starting",RUNNING:"running",STOPPING:"stopping",ERROR:"error"};var _=b.create({service:"tool-registry"}),T={REGISTERED:"mcp.tool.registered",UNREGISTERED:"mcp.tool.unregistered",CLEARED:"mcp.tool.cleared"},k=class extends EventEmitter{constructor(){super();a(this,"tools",new Map);}register(e){if(!e.name||typeof e.name!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u65E0\u6548\uFF1A\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e.name)){_?.debug("tool already registered, skipping",{tool:e.name});return}this.tools.set(e.name,e),this.emit(T.REGISTERED,e);}unregister(e){return this.tools.has(e)?(this.tools.delete(e),this.emit(T.UNREGISTERED,e),true):false}get(e){return this.tools.get(e)}getAll(){return Array.from(this.tools.values())}getTools(){return Array.from(this.tools.values()).map(({handler:e,...r})=>r)}has(e){return this.tools.has(e)}getSize(){return this.tools.size}clear(){this.tools.clear(),this.emit(T.CLEARED);}},y=new k;var g=b.create({service:"mcp.server.stdio"}),E=class{constructor(t){a(this,"config");a(this,"server",null);a(this,"info");a(this,"isStarting",false);a(this,"isStopping",false);a(this,"toolEventCleanup",null);a(this,"handleToolRegistered",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:c.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now(),enabled:t.enabled};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of y.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool loaded",{tool:t.name});}}subscribeToolEvents(){this.toolEventCleanup=()=>{y.off(T.REGISTERED,this.handleToolRegistered);},y.on(T.REGISTERED,this.handleToolRegistered);}adaptToolHandler(t){return async(e,r)=>{let o={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,o)}}unsubscribeToolEvents(){this.toolEventCleanup&&(this.toolEventCleanup(),this.toolEventCleanup=null);}convertToZodSchema(t){if(t instanceof l.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},o=e.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l.object(u)}if(e.type==="string")return l.string();if(e.type==="number")return l.number();if(e.type==="boolean")return l.boolean();if(e.type==="array"){let r=e.items;return r?l.array(this.jsonSchemaToZod(r)):l.array(l.unknown())}}return l.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return l.string();case "number":return l.number();case "integer":return l.number().int();case "boolean":return l.boolean();case "null":return l.null();case "array":{let r=t.items;return r?l.array(this.jsonSchemaToZod(r)):l.array(l.unknown())}case "object":{let r=t.properties||{},o=t.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l.object(u)}default:return l.unknown()}}async start(){if(this.isStarting){g.warn("server is already starting",{id:this.info.id});return}if(this.info.status===c.RUNNING){g.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=c.STARTING;try{g.info("starting stdio mcp server",{id:this.info.id,name:this.info.name,command:this.config.command,args:this.config.args});let t=new StdioServerTransport;await t.start(),this.server=new McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeToolEvents(),await this.server.connect(t),this.info.status=c.RUNNING,this.info.lastActivityAt=Date.now(),g.info("stdio mcp server started successfully",{id:this.info.id,name:this.info.name,toolCount:y.getSize()});}catch(t){throw this.info.status=c.ERROR,g.error("failed to start stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){g.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==c.RUNNING&&this.info.status!==c.ERROR){g.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=c.STOPPING;try{g.info("stopping stdio mcp server",{id:this.info.id,name:this.info.name}),this.unsubscribeToolEvents(),this.server&&(await this.server.close(),this.server=null),this.info.status=c.STOPPED,g.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=c.ERROR,g.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){g.info("restarting stdio mcp server",{id:this.info.id}),await this.stop(),await this.start();}};function Z(m){return new E(m)}async function z(m){let t=new E(m);return await t.start(),t.createInstance()}var h=b.create({service:"mcp.server.http"}),I=class{constructor(t){a(this,"config");a(this,"server",null);a(this,"transport",null);a(this,"httpServer",null);a(this,"info");a(this,"isStarting",false);a(this,"isStopping",false);a(this,"toolCleanup",null);a(this,"handleTool",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),h.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:c.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now()};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of y.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),h.info("tool loaded",{tool:t.name});}}subscribeTools(){this.toolCleanup=()=>{y.off(T.REGISTERED,this.handleTool);},y.on(T.REGISTERED,this.handleTool);}convertToZodSchema(t){if(t instanceof l.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},o=e.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l.object(u)}if(e.type==="string")return l.string();if(e.type==="number")return l.number();if(e.type==="boolean")return l.boolean();if(e.type==="array"){let r=e.items;return r?l.array(this.jsonSchemaToZod(r)):l.array(l.unknown())}}return l.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return l.string();case "number":return l.number();case "integer":return l.number().int();case "boolean":return l.boolean();case "null":return l.null();case "array":{let r=t.items;return r?l.array(this.jsonSchemaToZod(r)):l.array(l.unknown())}case "object":{let r=t.properties||{},o=t.required||[],n={};for(let[i,f]of Object.entries(r))n[i]=this.jsonSchemaToZod(f);if(Object.keys(r).filter(i=>!o.includes(i)).length===0)return l.object(n);let u={};for(let[i,f]of Object.entries(r)){let a=n[i];a&&(o.includes(i)?u[i]=a:u[i]=a.optional());}return l.object(u)}default:return l.unknown()}}adaptToolHandler(t){return async(e,r)=>{let o={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,o)}}unsubscribeTools(){this.toolCleanup&&(this.toolCleanup(),this.toolCleanup=null);}async start(){if(this.isStarting){h.warn("already starting",{id:this.info.id});return}if(this.info.status===c.RUNNING){h.debug("already running",{id:this.info.id});return}this.isStarting=true,this.info.status=c.STARTING;try{h.info("starting",{id:this.info.id,name:this.info.name,url:this.config.url});let t;try{t=new URL(this.config.url);}catch{throw new Error(`\u65E0\u6548\u7684 URL: ${this.config.url}`)}let e=parseInt(t.port||"3000",10),r=t.hostname||"0.0.0.0";if(Number.isNaN(e)||e<1||e>65535)throw new Error(`\u65E0\u6548\u7684\u7AEF\u53E3\u53F7: ${t.port}`);this.transport=new StreamableHTTPServerTransport({sessionIdGenerator:()=>crypto.randomUUID()}),this.server=new McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeTools(),await this.server.connect(this.transport),this.httpServer=q.createServer((o,n)=>{let b=o.headers.origin,u=(f,a,M)=>{n.writeHead(f,a),M?n.end(M):n.end();},i={"Access-Control-Allow-Origin":b||"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, mcpsessionid, mcp-protocol-version","Access-Control-Max-Age":"86400"};if(o.method==="OPTIONS"){u(204,i);return}if(o.method==="POST"){let f="";o.setEncoding("utf8"),o.on("data",a=>{f+=a;}),o.on("end",()=>{let a;if(f)try{a=JSON.parse(f);}catch{a=void 0;}this.transport&&this.transport.handleRequest(o,n,a);}),o.on("error",a=>{h.error("HTTP request error",{error:a.message}),u(500,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}}));});}else o.method==="GET"?this.transport&&this.transport.handleRequest(o,n,void 0):u(405,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32601,message:"Method not found"}}));}),this.httpServer.on("error",o=>{h.error("HTTP server error",{error:o.message}),this.info.status=c.ERROR;}),this.httpServer.on("clientError",(o,n)=>{h.warn("HTTP client error",{error:o.message}),n.writable&&n.end(`HTTP/1.1 400 Bad Request\r
|
|
1
|
+
import {b as b$1,a}from'./chunks/chunk-PJM3ON7Z.mjs';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {EventEmitter}from'events';import d from'zod/v4';import q from'http';import {StreamableHTTPServerTransport}from'@modelcontextprotocol/sdk/server/streamableHttp.js';import {Client}from'@modelcontextprotocol/sdk/client/index.js';import {StdioClientTransport}from'@modelcontextprotocol/sdk/client/stdio.js';import {StreamableHTTPClientTransport}from'@modelcontextprotocol/sdk/client/streamableHttp.js';import {SSEClientTransport}from'@modelcontextprotocol/sdk/client/sse.js';import {CallToolResultSchema,ToolListChangedNotificationSchema}from'@modelcontextprotocol/sdk/types.js';import {UnauthorizedError}from'@modelcontextprotocol/sdk/client/auth.js';import {withTimeout}from'@easbot/utils';import v from'zod';var E={STDIO:"stdio",HTTP:"http"},l={STOPPED:"stopped",STARTING:"starting",RUNNING:"running",STOPPING:"stopping",ERROR:"error"};var D=b$1.create({service:"tool-registry"}),R={REGISTERED:"mcp.tool.registered",UNREGISTERED:"mcp.tool.unregistered",CLEARED:"mcp.tool.cleared"},k=class extends EventEmitter{constructor(){super();a(this,"tools",new Map);}register(e){if(!e.name||typeof e.name!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u65E0\u6548\uFF1A\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e.name)){D?.debug("tool already registered, skipping",{tool:e.name});return}this.tools.set(e.name,e),this.emit(R.REGISTERED,e);}unregister(e){return this.tools.has(e)?(this.tools.delete(e),this.emit(R.UNREGISTERED,e),true):false}get(e){return this.tools.get(e)}getAll(){return Array.from(this.tools.values())}getTools(){return Array.from(this.tools.values()).map(({handler:e,...r})=>r)}has(e){return this.tools.has(e)}getSize(){return this.tools.size}clear(){this.tools.clear(),this.emit(R.CLEARED);}},b=new k;var S=b$1.create({service:"mcp.server.stdio"}),w=class{constructor(t){a(this,"config");a(this,"server",null);a(this,"info");a(this,"isStarting",false);a(this,"isStopping",false);a(this,"toolEventCleanup",null);a(this,"handleToolRegistered",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),S.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:l.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now(),enabled:t.enabled};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of b.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),S.info("tool loaded",{tool:t.name});}}subscribeToolEvents(){this.toolEventCleanup=()=>{b.off(R.REGISTERED,this.handleToolRegistered);},b.on(R.REGISTERED,this.handleToolRegistered);}adaptToolHandler(t){return async(e,r)=>{let n={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,n)}}unsubscribeToolEvents(){this.toolEventCleanup&&(this.toolEventCleanup(),this.toolEventCleanup=null);}convertToZodSchema(t){if(t instanceof d.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},n=e.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d.object(f)}if(e.type==="string")return d.string();if(e.type==="number")return d.number();if(e.type==="boolean")return d.boolean();if(e.type==="array"){let r=e.items;return r?d.array(this.jsonSchemaToZod(r)):d.array(d.unknown())}}return d.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return d.string();case "number":return d.number();case "integer":return d.number().int();case "boolean":return d.boolean();case "null":return d.null();case "array":{let r=t.items;return r?d.array(this.jsonSchemaToZod(r)):d.array(d.unknown())}case "object":{let r=t.properties||{},n=t.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d.object(f)}default:return d.unknown()}}async start(){if(this.isStarting){S.warn("server is already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){S.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{S.info("starting stdio mcp server",{id:this.info.id,name:this.info.name,command:this.config.command,args:this.config.args});let t=new StdioServerTransport;this.server=new McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeToolEvents(),await this.server.connect(t),this.info.status=l.RUNNING,this.info.lastActivityAt=Date.now(),S.info("stdio mcp server started successfully",{id:this.info.id,name:this.info.name,toolCount:b.getSize()});}catch(t){throw this.info.status=l.ERROR,S.error("failed to start stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){S.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){S.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{S.info("stopping stdio mcp server",{id:this.info.id,name:this.info.name}),this.unsubscribeToolEvents(),this.server&&(await this.server.close(),this.server=null),this.info.status=l.STOPPED,S.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=l.ERROR,S.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){S.info("restarting stdio mcp server",{id:this.info.id}),await this.stop(),await this.start();}};function Z(s){return new w(s)}async function z(s){let t=new w(s);return await t.start(),t.createInstance()}var g=b$1.create({service:"mcp.server.http"}),P=class{constructor(t){a(this,"config");a(this,"server",null);a(this,"transport",null);a(this,"httpServer",null);a(this,"info");a(this,"isStarting",false);a(this,"isStopping",false);a(this,"toolCleanup",null);a(this,"handleTool",t=>{if(this.server){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool registered",{tool:t.name});}});this.config=t,this.info={id:t.id,name:t.name,version:t.version,transportType:t.transportType,status:l.STOPPED,createdAt:Date.now(),lastActivityAt:Date.now()};}getInfo(){return this.info}getConfig(){return this.config}createInstance(){let t=this;return {info:this.info,get server(){return t.server},start:()=>this.start(),stop:()=>this.stop(),restart:()=>this.restart()}}loadTools(){if(this.server)for(let t of b.getAll()){let e=this.convertToZodSchema(t.inputSchema),r=this.adaptToolHandler(t.handler);this.server.registerTool(t.name,{description:t.description,inputSchema:e},r),g.info("tool loaded",{tool:t.name});}}subscribeTools(){this.toolCleanup=()=>{b.off(R.REGISTERED,this.handleTool);},b.on(R.REGISTERED,this.handleTool);}convertToZodSchema(t){if(t instanceof d.ZodType)return t;if(typeof t=="object"&&t!==null){let e=t;if(e.type==="object"){let r=e.properties||{},n=e.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d.object(f)}if(e.type==="string")return d.string();if(e.type==="number")return d.number();if(e.type==="boolean")return d.boolean();if(e.type==="array"){let r=e.items;return r?d.array(this.jsonSchemaToZod(r)):d.array(d.unknown())}}return d.unknown()}jsonSchemaToZod(t){switch(t.type){case "string":return d.string();case "number":return d.number();case "integer":return d.number().int();case "boolean":return d.boolean();case "null":return d.null();case "array":{let r=t.items;return r?d.array(this.jsonSchemaToZod(r)):d.array(d.unknown())}case "object":{let r=t.properties||{},n=t.required||[],o={};for(let[i,h]of Object.entries(r))o[i]=this.jsonSchemaToZod(h);if(Object.keys(r).filter(i=>!n.includes(i)).length===0)return d.object(o);let f={};for(let[i,h]of Object.entries(r)){let c=o[i];c&&(n.includes(i)?f[i]=c:f[i]=c.optional());}return d.object(f)}default:return d.unknown()}}adaptToolHandler(t){return async(e,r)=>{let n={signal:r.signal,sessionId:r.sessionId,requestId:r.requestId,taskId:r.taskId,_meta:r._meta,authInfo:r.authInfo?{type:"bearer",claims:{clientId:r.authInfo.clientId,scopes:r.authInfo.scopes}}:void 0};return t(e,n)}}unsubscribeTools(){this.toolCleanup&&(this.toolCleanup(),this.toolCleanup=null);}async start(){if(this.isStarting){g.warn("already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){g.debug("already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{g.info("starting",{id:this.info.id,name:this.info.name,url:this.config.url});let t;try{t=new URL(this.config.url);}catch{throw new Error(`\u65E0\u6548\u7684 URL: ${this.config.url}`)}let e=parseInt(t.port||"3000",10),r=t.hostname||"0.0.0.0";if(Number.isNaN(e)||e<1||e>65535)throw new Error(`\u65E0\u6548\u7684\u7AEF\u53E3\u53F7: ${t.port}`);this.transport=new StreamableHTTPServerTransport({sessionIdGenerator:()=>crypto.randomUUID()}),this.server=new McpServer({name:this.config.name,version:this.config.version}),this.loadTools(),this.subscribeTools(),await this.server.connect(this.transport),this.httpServer=q.createServer((n,o)=>{let m=n.headers.origin,f=(h,c,H)=>{o.writeHead(h,c),H?o.end(H):o.end();},i={"Access-Control-Allow-Origin":m||"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, mcpsessionid, mcp-protocol-version","Access-Control-Max-Age":"86400"};if(n.method==="OPTIONS"){f(204,i);return}if(n.method==="POST"){let h="";n.setEncoding("utf8"),n.on("data",c=>{h+=c;}),n.on("end",()=>{let c;if(h)try{c=JSON.parse(h);}catch{c=void 0;}this.transport&&this.transport.handleRequest(n,o,c);}),n.on("error",c=>{g.error("HTTP request error",{error:c.message}),f(500,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32603,message:"Internal error"}}));});}else n.method==="GET"?this.transport&&this.transport.handleRequest(n,o,void 0):f(405,i,JSON.stringify({jsonrpc:"2.0",error:{code:-32601,message:"Method not found"}}));}),this.httpServer.on("error",n=>{g.error("HTTP server error",{error:n.message}),this.info.status=l.ERROR;}),this.httpServer.on("clientError",(n,o)=>{g.warn("HTTP client error",{error:n.message}),o.writable&&o.end(`HTTP/1.1 400 Bad Request\r
|
|
2
2
|
\r
|
|
3
|
-
`);}),this.httpServer.listen(e,r),h.info("HTTP server listening",{hostname:r,port:e}),this.info.status=c.RUNNING,this.info.lastActivityAt=Date.now(),h.info("started",{id:this.info.id,name:this.info.name,toolCount:y.getSize()});}catch(t){throw this.info.status=c.ERROR,h.error("failed to start",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){h.warn("already stopping",{id:this.info.id});return}if(this.info.status!==c.RUNNING&&this.info.status!==c.ERROR){h.debug("not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=c.STOPPING;try{h.info("stopping",{id:this.info.id,name:this.info.name}),this.unsubscribeTools(),this.httpServer&&(await new Promise(t=>{this.httpServer.close(()=>t());}),this.httpServer=null),this.transport&&(await this.transport.close(),this.transport=null),this.server&&(await this.server.close(),this.server=null),this.info.status=c.STOPPED,h.info("stopped",{id:this.info.id});}catch(t){this.info.status=c.ERROR,h.error("failed to stop",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){h.info("restarting",{id:this.info.id}),await this.stop(),await this.start();}};function V(m){return new I(m)}async function B(m){let t=new I(m);return await t.start(),t.createInstance()}var O={version:"0.2.22"};function x(){return O.version}var d=b.create({service:"mcp.client"}),P=3e4,Bt=v.discriminatedUnion("status",[v.object({status:v.literal("connected")}).meta({ref:"MCPStatusConnected"}),v.object({status:v.literal("disconnected")}).meta({ref:"MCPStatusDisconnected"}),v.object({status:v.literal("failed"),error:v.string()}).meta({ref:"MCPStatusFailed"}),v.object({status:v.literal("needs_auth")}).meta({ref:"MCPStatusNeedsAuth"}),v.object({status:v.literal("needs_client_registration"),error:v.string()}).meta({ref:"MCPStatusNeedsClientRegistration"})]),A=class{constructor(){a(this,"id","");a(this,"client",null);a(this,"_info");a(this,"notificationCleanup",null);a(this,"pendingTransport",null);a(this,"oauthState","");a(this,"toolListChangedHandler",null);this._info=this.createInitialInfo();}get info(){return {...this._info}}get status(){return this._info.status}get tools(){return [...this._info.tools]}async connect(t,e){d.info("connecting to MCP server",{id:t,type:e.type}),await this.disconnect(),this.id=t,this._info=this.createInitialInfo(),this._info.id=t,this._info.name=t;try{if(this.client=await this.createClient(e),!this.client)return;this._info.status={status:"connected"},this._info.connectedAt=Date.now(),await this.fetchCapabilities(),d.info("connected to MCP server",{id:t,toolCount:this._info.tools.length});}catch(r){let o=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:o},this._info.error=o,d.error("failed to connect to MCP server",{id:t,error:o});}}async startAuth(){if(!this.pendingTransport)throw new Error("No pending OAuth flow. Please connect to a server that requires authentication first.");return this.oauthState=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(t=>t.toString(16).padStart(2,"0")).join(""),{authorizationUrl:"",state:this.oauthState}}async finishAuth(t){if(!this.pendingTransport)throw new Error("No pending OAuth flow.");t&&await this.pendingTransport.finishAuth?.(t),this.pendingTransport=null,d.info("OAuth completed, reconnecting...",{id:this.id});}async disconnect(){this.notificationCleanup&&(this.notificationCleanup(),this.notificationCleanup=null),this.client&&(await this.client.close().catch(t=>{d.error("Failed to close MCP client",{error:t});}),this.client=null),this.pendingTransport=null,this.toolListChangedHandler=null,this._info.status.status==="connected"&&(this._info.status={status:"disconnected"}),d.info("disconnected from MCP server",{id:this.id});}async listTools(){if(!this.client||this._info.status.status!=="connected")return {};let t={};for(let e of this._info.tools)t[e.name]={name:e.name,description:e.description,inputSchema:e.inputSchema};return t}async callTool(t,e,r){let o=Date.now();if(!this.client||this._info.status.status!=="connected")return {toolName:t,args:e,result:null,success:false,error:"Client not connected",duration:Date.now()-o};try{let n=await withTimeout(this.client.callTool({name:t,arguments:e},CallToolResultSchema,{resetTimeoutOnProgress:!0,timeout:r}),r??P);return {toolName:t,args:e,result:n.content,success:!0,duration:Date.now()-o}}catch(n){return {toolName:t,args:e,result:null,success:false,error:n instanceof Error?n.message:String(n),duration:Date.now()-o}}}async listResources(){return [...this._info.resources]}async readResource(t){if(!this.client||this._info.status.status!=="connected"){d.warn("client not connected for readResource");return}return this.client.readResource({uri:t}).catch(e=>{d.error("failed to read resource",{uri:t,error:e.message});})}async listPrompts(){return [...this._info.prompts]}async getPrompt(t,e){if(!this.client||this._info.status.status!=="connected"){d.warn("client not connected for getPrompt");return}return this.client.getPrompt({name:t,arguments:e}).catch(r=>{d.error("failed to get prompt",{name:t,error:r.message});})}async refreshTools(){if(!(!this.client||this._info.status.status!=="connected"))try{let t=await withTimeout(this.client.listTools(),P);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema})),d.info("tools refreshed",{id:this.id,count:this._info.tools.length});}catch(t){d.error("failed to refresh tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}}async createClient(t){return t.type==="local"?this.createLocalClient(t):t.type==="remote"?this.createRemoteClient(t):null}async fetchCapabilities(){if(this.client){try{let t=await withTimeout(this.client.listTools(),P);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));}catch(t){d.debug("failed to get tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}try{let t=await withTimeout(this.client.listResources(),5e3);this._info.resources=t.resources.map(e=>({name:e.name,uri:e.uri,description:e.description,mimeType:e.mimeType}));}catch{d.debug("failed to get resources",{id:this.id});}try{let t=await withTimeout(this.client.listPrompts(),5e3);this._info.prompts=t.prompts.map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(r=>({name:r.name,description:r.description,required:r.required}))}));}catch{d.debug("failed to get prompts",{id:this.id});}}}async createLocalClient(t){let[e,...r]=t.command;if(!e)return this._info.status={status:"failed",error:"Command is empty"},null;let o=new StdioClientTransport({stderr:"pipe",command:e,args:r.length>0?r:void 0,cwd:process.cwd(),env:Object.fromEntries(Object.entries({...process.env,...t.environment}).filter(([,n])=>n!==void 0))});o.stderr?.on("data",n=>{d.info(`mcp stderr: ${n.toString()}`,{id:this.id});});try{let n=new Client({name:"easbot-mcp",version:x()});return await withTimeout(n.connect(o),t.timeout??P),this.registerNotificationHandler(n),n}catch(n){let b=n instanceof Error?n.message:String(n);return this._info.status={status:"failed",error:b},d.error("local mcp startup failed",{command:[e,...r],error:b}),null}}async createRemoteClient(t){t.oauth===false;let r={headers:t.headers};if((t.transport||"streamable-http")==="sse"){d.info("using SSE transport",{url:t.url});let n=new SSEClientTransport(new URL(t.url),{requestInit:r});return this.connectWithTransport(n,t)}else {d.info("using StreamableHTTP transport",{url:t.url});let n=new StreamableHTTPClientTransport(new URL(t.url),{requestInit:r});return this.connectWithTransport(n,t)}}async connectWithTransport(t,e){try{let r=new Client({name:"easbot-mcp",version:x()});return await withTimeout(r.connect(t),e.timeout??P),this.registerNotificationHandler(r),r}catch(r){if(r instanceof UnauthorizedError){let o=r instanceof Error?r.message:String(r);o.includes("registration")||o.includes("client_id")?this._info.status={status:"needs_client_registration",error:"Server does not support dynamic client registration. Please provide clientId in config."}:(this._info.status={status:"needs_auth"},this.pendingTransport=t);}else {let o=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:o};}return d.error("remote mcp connection failed",{url:e.url,error:this._info.status}),null}}registerToolListChangedHandler(t){this.toolListChangedHandler=t;}registerNotificationHandler(t){let e=async()=>{d.info("tools list changed notification received",{id:this.id}),await this.refreshTools(),this.toolListChangedHandler&&await this.toolListChangedHandler();};t.setNotificationHandler(ToolListChangedNotificationSchema,e),this.notificationCleanup=()=>{t.removeNotificationHandler("notifications/tools/list_changed");};}createInitialInfo(){return {id:"",name:"",status:{status:"disconnected"},tools:[],resources:[],prompts:[]}}};function Kt(){return new A}var $t="0.2.20",Qt="@easbot/mcp";async function Xt(m){let{Log:t}=await import('./chunks/log-2GAL6FAC.mjs'),e=false;await t.init({logDir:m.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:m.print??false,dev:m.dev??e,level:m.level??("INFO")});}export{I as HttpServerAdapter,A as MCPClient,Qt as NAME,c as ServerStatus,N as ServerTransportType,Bt as Status,E as StdioServerAdapter,$t as VERSION,B as createAndStartHttpServer,z as createAndStartStdioServer,V as createHttpServer,Kt as createMCPClient,Z as createStdioServer,x as getVersion,Xt as initLog};
|
|
3
|
+
`);}),this.httpServer.listen(e,r),g.info("HTTP server listening",{hostname:r,port:e}),this.info.status=l.RUNNING,this.info.lastActivityAt=Date.now(),g.info("started",{id:this.info.id,name:this.info.name,toolCount:b.getSize()});}catch(t){throw this.info.status=l.ERROR,g.error("failed to start",{id:this.info.id,error:t instanceof Error?t.message:String(t)}),t}finally{this.isStarting=false;}}async stop(){if(this.isStopping){g.warn("already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){g.debug("not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{g.info("stopping",{id:this.info.id,name:this.info.name}),this.unsubscribeTools(),this.httpServer&&(await new Promise(t=>{this.httpServer.close(()=>t());}),this.httpServer=null),this.transport&&(await this.transport.close(),this.transport=null),this.server&&(await this.server.close(),this.server=null),this.info.status=l.STOPPED,g.info("stopped",{id:this.info.id});}catch(t){this.info.status=l.ERROR,g.error("failed to stop",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){g.info("restarting",{id:this.info.id}),await this.stop(),await this.start();}};function F(s){return new P(s)}async function B(s){let t=new P(s);return await t.start(),t.createInstance()}var O={version:"0.2.23"};function x(){return O.version}var j=b$1.create({service:"mcp.server.factory"});function $(s){return s.type==="local"}function J(s){return s.type==="remote"}function W(s,t){if(!t.command)throw new Error(`MCP server ${s} has no command specified`);return {id:s,name:s,version:"1.0.0",transportType:E.STDIO,enabled:t.enabled,timeout:t.timeout,command:t.command,args:t.args?.length?t.args:void 0,env:t.env}}function Q(s,t){return {id:s,name:s,version:"1.0.0",transportType:E.HTTP,enabled:t.enabled,timeout:t.timeout,url:t.url,headers:t.headers}}async function X(s,t){if(j.debug("creating server from config",{name:s,type:t.type}),$(t)){let e=W(s,t),r=new w(e);return await r.start(),r.createInstance()}if(J(t)){let e=Q(s,t),r=new P(e);return await r.start(),r.createInstance()}throw new Error(`Unsupported MCP config type: ${t.type}`)}async function zt(s){let t={};for(let[e,r]of Object.entries(s))try{let n=await X(e,r);t[e]=n;}catch(n){j.error("failed to create server from config",{name:e,error:n instanceof Error?n.message:String(n)});}return t}var p=b$1.create({service:"mcp.client"}),M=3e4,A=class{constructor(){a(this,"id","");a(this,"client",null);a(this,"_info");a(this,"notificationCleanup",null);a(this,"pendingTransport",null);a(this,"oauthState","");a(this,"capturedRedirectUrl",null);a(this,"oauthConfig");a(this,"toolListChangedHandler",null);a(this,"oauthProvider",null);this._info=this.createInitialInfo();}get info(){return {...this._info}}get status(){return this._info.status}get tools(){return [...this._info.tools]}get resources(){return [...this._info.resources]}get prompts(){return [...this._info.prompts]}get clientId(){return this.id}setToolListChangedHandler(t){this.toolListChangedHandler=t;}setOAuthProvider(t){this.oauthProvider=t;}async connect(t,e){p.info("connecting to MCP server",{id:t,type:e.type}),await this.disconnect(),this.id=t,this._info=this.createInitialInfo(),this._info.id=t,this._info.name=t;try{if(e.type==="remote"&&(this.oauthConfig=e.oauth===!1?void 0:e.oauth??{}),this.client=await this.createClient(e),!this.client)return;this._info.status={status:"connected"},this._info.connectedAt=Date.now(),await this.fetchCapabilities(),p.info("connected to MCP server",{id:t,toolCount:this._info.tools.length});}catch(r){let n=r instanceof Error?r.message:String(r);this._info.status={status:"failed",error:n},this._info.error=n,p.error("failed to connect to MCP server",{id:t,error:n});}}async startAuth(){if(!this.pendingTransport)throw new Error("No pending OAuth flow. Please connect to a server that requires authentication first.");return this.oauthState=Array.from(crypto.getRandomValues(new Uint8Array(32))).map(t=>t.toString(16).padStart(2,"0")).join(""),this.oauthProvider&&await this.oauthProvider.saveState(this.oauthState),{authorizationUrl:this.capturedRedirectUrl?.toString()??"",state:this.oauthState}}async finishAuth(t){if(!this.pendingTransport)throw new Error("No pending OAuth flow.");try{await this.pendingTransport.finishAuth?.(t);}catch(e){throw p.error("failed to finish OAuth",{id:this.id,error:e}),e}this.pendingTransport=null,this.capturedRedirectUrl=null,p.info("OAuth completed, ready to reconnect",{id:this.id});}isAuthRequired(){return this._info.status.status==="needs_auth"}isClientRegistrationRequired(){return this._info.status.status==="needs_client_registration"}getPendingTransport(){return this.pendingTransport}getAuthorizationUrl(){return this.capturedRedirectUrl?.toString()??""}async disconnect(){this.notificationCleanup&&(this.notificationCleanup(),this.notificationCleanup=null),this.client&&(await this.client.close().catch(t=>{p.error("Failed to close MCP client",{id:this.id,error:t});}),this.client=null),this.pendingTransport=null,this.capturedRedirectUrl=null,this.toolListChangedHandler=null,this._info.status.status==="connected"&&(this._info.status={status:"disconnected"}),p.info("disconnected from MCP server",{id:this.id});}async listTools(){if(!this.client||this._info.status.status!=="connected")return {};let t={};for(let e of this._info.tools)t[e.name]={name:e.name,description:e.description,inputSchema:e.inputSchema};return t}async callTool(t,e,r){let n=Date.now();if(!this.client||this._info.status.status!=="connected")return {toolName:t,args:e,content:[],success:false,error:"Client not connected",duration:Date.now()-n};try{let o=await withTimeout(this.client.callTool({name:t,arguments:e},CallToolResultSchema,{resetTimeoutOnProgress:!0,timeout:r}),r??M);return {toolName:t,args:e,content:o.content.map(m=>m.type==="text"?{type:"text",text:m.text}:m.type==="image"?{type:"image",data:m.data,mimeType:m.mimeType}:m.type==="resource"?{type:"resource",resource:m.resource}:{type:"text",text:String(m)}),success:!0,duration:Date.now()-n,metadata:o.metadata}}catch(o){return {toolName:t,args:e,content:[],success:false,error:o instanceof Error?o.message:String(o),duration:Date.now()-n}}}async listResources(){return [...this._info.resources]}async readResource(t){if(!this.client||this._info.status.status!=="connected"){p.warn("client not connected for readResource",{id:this.id});return}return this.client.readResource({uri:t}).catch(e=>{p.error("failed to read resource",{id:this.id,uri:t,error:e.message});})}async listPrompts(){return [...this._info.prompts]}async getPrompt(t,e){if(!this.client||this._info.status.status!=="connected"){p.warn("client not connected for getPrompt",{id:this.id});return}return this.client.getPrompt({name:t,arguments:e}).catch(r=>{p.error("failed to get prompt",{id:this.id,name:t,error:r.message});})}async refreshTools(){if(!(!this.client||this._info.status.status!=="connected"))try{let t=await withTimeout(this.client.listTools(),M);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema})),p.info("tools refreshed",{id:this.id,count:this._info.tools.length});}catch(t){p.error("failed to refresh tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}}async createClient(t){return t.type==="local"?await this.createLocalClient(t):t.type==="remote"?await this.createRemoteClient(t):null}async fetchCapabilities(){if(this.client){try{let t=await withTimeout(this.client.listTools(),M);this._info.tools=t.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));}catch(t){p.debug("failed to get tools",{id:this.id,error:t instanceof Error?t.message:String(t)});}try{let t=await withTimeout(this.client.listResources(),5e3);this._info.resources=t.resources.map(e=>({name:e.name,uri:e.uri,description:e.description,mimeType:e.mimeType}));}catch{p.debug("failed to get resources",{id:this.id});}try{let t=await withTimeout(this.client.listPrompts(),5e3);this._info.prompts=t.prompts.map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(r=>({name:r.name,description:r.description,required:r.required}))}));}catch{p.debug("failed to get prompts",{id:this.id});}}}async createLocalClient(t){let[e,...r]=t.command;if(!e)return this._info.status={status:"failed",error:"Command is empty"},null;let n=new StdioClientTransport({stderr:"pipe",command:e,args:r.length>0?r:void 0,cwd:t.cwd??process.cwd(),env:Object.fromEntries(Object.entries({...process.env,...t.environment}).filter(([,o])=>o!==void 0))});n.stderr?.on("data",o=>{p.info(`mcp stderr: ${o.toString()}`,{id:this.id});});try{let o=new Client({name:"easbot-mcp",version:x()});return await withTimeout(o.connect(n),t.timeout??M),this.registerNotificationHandler(o),o}catch(o){let m=o instanceof Error?o.message:String(o);return this._info.status={status:"failed",error:m},p.error("local mcp startup failed",{id:this.id,command:[e,...r],error:m}),null}}async createRemoteClient(t){let e={headers:t.headers};if((t.transport||"streamable-http")==="sse"){p.info("using SSE transport",{id:this.id,url:t.url});let n=new SSEClientTransport(new URL(t.url),{requestInit:e});return await this.connectWithTransport(n,t)}else {p.info("using StreamableHTTP transport",{id:this.id,url:t.url});let n=new StreamableHTTPClientTransport(new URL(t.url),{requestInit:e});return await this.connectWithTransport(n,t)}}async connectWithTransport(t,e){try{let r=new Client({name:"easbot-mcp",version:x()});return await r.connect(t),this.registerNotificationHandler(r),r}catch(r){return this.handleConnectionError(r,t,e),null}}handleConnectionError(t,e,r){if(t instanceof UnauthorizedError){let n=t instanceof Error?t.message:String(t);n.includes("registration")||n.includes("client_id")?this._info.status={status:"needs_client_registration",error:"Server does not support dynamic client registration. Please provide clientId in config."}:(this._info.status={status:"needs_auth"},this.pendingTransport=e,this.capturedRedirectUrl=this.extractRedirectUrl(t));}else {let n=t instanceof Error?t.message:String(t);this._info.status={status:"failed",error:n};}p.error("remote mcp connection failed",{id:this.id,url:r.url,status:this._info.status});}extractRedirectUrl(t){let r=t.message.match(/https?:\/\/[^\s]+/);if(r)try{return new URL(r[0])}catch{return null}return null}registerNotificationHandler(t){let e=async()=>{p.info("tools list changed notification received",{id:this.id}),await this.refreshTools(),this.toolListChangedHandler&&await this.toolListChangedHandler();};t.setNotificationHandler(ToolListChangedNotificationSchema,e),this.notificationCleanup=()=>{t.removeNotificationHandler("notifications/tools/list_changed");};}createInitialInfo(){return {id:"",name:"",status:{status:"disconnected"},tools:[],resources:[],prompts:[]}}};function it(){return new A}var le=v.discriminatedUnion("status",[v.object({status:v.literal("connected")}).meta({ref:"MCPStatusConnected"}),v.object({status:v.literal("disconnected")}).meta({ref:"MCPStatusDisconnected"}),v.object({status:v.literal("failed"),error:v.string()}).meta({ref:"MCPStatusFailed"}),v.object({status:v.literal("needs_auth")}).meta({ref:"MCPStatusNeedsAuth"}),v.object({status:v.literal("needs_client_registration"),error:v.string()}).meta({ref:"MCPStatusNeedsClientRegistration"}),v.object({status:v.literal("disabled")}).meta({ref:"MCPStatusDisabled"})]);var ge="@easbot/mcp";async function ve(s){let{Log:t}=await import('./chunks/log-2GAL6FAC.mjs'),e=false;await t.init({logDir:s.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:s.print??false,dev:s.dev??e,level:s.level??("INFO")});}export{P as HttpServerAdapter,A as MCPClient,ge as NAME,l as ServerStatus,E as ServerTransportType,le as Status,w as StdioServerAdapter,k as ToolRegistry,R as ToolRegistryEvent,B as createAndStartHttpServer,z as createAndStartStdioServer,F as createHttpServer,it as createMCPClient,X as createServerFromConfig,zt as createServersFromConfigMap,Z as createStdioServer,x as getVersion,ve as initLog,b as tools};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easbot/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "MCP (Model Context Protocol) integration library for EASBOT ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"ai": "^6.0.176",
|
|
45
45
|
"zod": "^4.4.3",
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
47
|
-
"@easbot/types": "0.2.
|
|
48
|
-
"@easbot/utils": "0.2.
|
|
47
|
+
"@easbot/types": "0.2.23",
|
|
48
|
+
"@easbot/utils": "0.2.23"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@biomejs/biome": "^2.4.14",
|