@easbot/mcp 0.2.24 → 0.2.26
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 +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +2 -2
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var chunkDQPEZFOV_cjs=require('./chunks/chunk-DQPEZFOV.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=chunkDQPEZFOV_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();chunkDQPEZFOV_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=chunkDQPEZFOV_cjs.b.create({service:"mcp.server.stdio"}),R=class{constructor(t){chunkDQPEZFOV_cjs.a(this,"config");chunkDQPEZFOV_cjs.a(this,"server",null);chunkDQPEZFOV_cjs.a(this,"info");chunkDQPEZFOV_cjs.a(this,"isStarting",false);chunkDQPEZFOV_cjs.a(this,"isStopping",false);chunkDQPEZFOV_cjs.a(this,"toolEventCleanup",null);chunkDQPEZFOV_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=chunkDQPEZFOV_cjs.b.create({service:"mcp.server.http"}),w=class{constructor(t){chunkDQPEZFOV_cjs.a(this,"config");chunkDQPEZFOV_cjs.a(this,"server",null);chunkDQPEZFOV_cjs.a(this,"transport",null);chunkDQPEZFOV_cjs.a(this,"httpServer",null);chunkDQPEZFOV_cjs.a(this,"info");chunkDQPEZFOV_cjs.a(this,"isStarting",false);chunkDQPEZFOV_cjs.a(this,"isStopping",false);chunkDQPEZFOV_cjs.a(this,"toolCleanup",null);chunkDQPEZFOV_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
|
|
1
|
+
'use strict';var chunkDQPEZFOV_cjs=require('./chunks/chunk-DQPEZFOV.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=chunkDQPEZFOV_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();chunkDQPEZFOV_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 y=chunkDQPEZFOV_cjs.b.create({service:"mcp.server.stdio"}),R=class{constructor(t){chunkDQPEZFOV_cjs.a(this,"config");chunkDQPEZFOV_cjs.a(this,"server",null);chunkDQPEZFOV_cjs.a(this,"info");chunkDQPEZFOV_cjs.a(this,"isStarting",false);chunkDQPEZFOV_cjs.a(this,"isStopping",false);chunkDQPEZFOV_cjs.a(this,"toolEventCleanup",null);chunkDQPEZFOV_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),y.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),y.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){y.warn("server is already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){y.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{y.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(),y.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,y.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){y.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){y.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{y.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,y.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=l.ERROR,y.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){y.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=chunkDQPEZFOV_cjs.b.create({service:"mcp.server.http"}),w=class{constructor(t){chunkDQPEZFOV_cjs.a(this,"config");chunkDQPEZFOV_cjs.a(this,"server",null);chunkDQPEZFOV_cjs.a(this,"transport",null);chunkDQPEZFOV_cjs.a(this,"httpServer",null);chunkDQPEZFOV_cjs.a(this,"info");chunkDQPEZFOV_cjs.a(this,"isStarting",false);chunkDQPEZFOV_cjs.a(this,"isStopping",false);chunkDQPEZFOV_cjs.a(this,"toolCleanup",null);chunkDQPEZFOV_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),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.24"};function E(){return H.version}var O=chunkDQPEZFOV_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=chunkDQPEZFOV_cjs.b.create({service:"mcp.client"}),x=3e4,M=class{constructor(){chunkDQPEZFOV_cjs.a(this,"id","");chunkDQPEZFOV_cjs.a(this,"client",null);chunkDQPEZFOV_cjs.a(this,"_info");chunkDQPEZFOV_cjs.a(this,"notificationCleanup",null);chunkDQPEZFOV_cjs.a(this,"pendingTransport",null);chunkDQPEZFOV_cjs.a(this,"oauthState","");chunkDQPEZFOV_cjs.a(this,"capturedRedirectUrl",null);chunkDQPEZFOV_cjs.a(this,"oauthConfig");chunkDQPEZFOV_cjs.a(this,"toolListChangedHandler",null);chunkDQPEZFOV_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-P5KGMDMW.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;
|
|
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.26"};function E(){return H.version}var O=chunkDQPEZFOV_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=chunkDQPEZFOV_cjs.b.create({service:"mcp.client"}),x=3e4,M=class{constructor(){chunkDQPEZFOV_cjs.a(this,"id","");chunkDQPEZFOV_cjs.a(this,"client",null);chunkDQPEZFOV_cjs.a(this,"_info");chunkDQPEZFOV_cjs.a(this,"notificationCleanup",null);chunkDQPEZFOV_cjs.a(this,"pendingTransport",null);chunkDQPEZFOV_cjs.a(this,"oauthState","");chunkDQPEZFOV_cjs.a(this,"capturedRedirectUrl",null);chunkDQPEZFOV_cjs.a(this,"oauthConfig");chunkDQPEZFOV_cjs.a(this,"toolListChangedHandler",null);chunkDQPEZFOV_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-P5KGMDMW.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
package/dist/index.d.ts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {b as b$1,a}from'./chunks/chunk-VHCOYGSJ.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
|
|
1
|
+
import {b as b$1,a}from'./chunks/chunk-VHCOYGSJ.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 y=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),y.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),y.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){y.warn("server is already starting",{id:this.info.id});return}if(this.info.status===l.RUNNING){y.debug("server is already running",{id:this.info.id});return}this.isStarting=true,this.info.status=l.STARTING;try{y.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(),y.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,y.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){y.warn("server is already stopping",{id:this.info.id});return}if(this.info.status!==l.RUNNING&&this.info.status!==l.ERROR){y.debug("server is not running",{id:this.info.id,status:this.info.status});return}this.isStopping=true,this.info.status=l.STOPPING;try{y.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,y.info("stdio mcp server stopped",{id:this.info.id,name:this.info.name});}catch(t){this.info.status=l.ERROR,y.error("error stopping stdio mcp server",{id:this.info.id,error:t instanceof Error?t.message:String(t)});}finally{this.isStopping=false;}}async restart(){y.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),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.24"};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-WIKXQDPJ.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};
|
|
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.26"};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-WIKXQDPJ.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.26",
|
|
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.26",
|
|
48
|
+
"@easbot/utils": "0.2.26"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@biomejs/biome": "^2.4.14",
|