 d7ad321176
			
		
	
	d7ad321176
	
	
	
		
			
			This comprehensive implementation includes: - FastAPI backend with MCP server integration - React/TypeScript frontend with Vite - PostgreSQL database with Redis caching - Grafana/Prometheus monitoring stack - Docker Compose orchestration - Full MCP protocol support for Claude Code integration Features: - Agent discovery and management across network - Visual workflow editor and execution engine - Real-time task coordination and monitoring - Multi-model support with specialized agents - Distributed development task allocation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			377 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { CancelledNotificationSchema, ErrorCode, isJSONRPCError, isJSONRPCRequest, isJSONRPCResponse, isJSONRPCNotification, McpError, PingRequestSchema, ProgressNotificationSchema, } from "../types.js";
 | |
| /**
 | |
|  * The default request timeout, in miliseconds.
 | |
|  */
 | |
| export const DEFAULT_REQUEST_TIMEOUT_MSEC = 60000;
 | |
| /**
 | |
|  * Implements MCP protocol framing on top of a pluggable transport, including
 | |
|  * features like request/response linking, notifications, and progress.
 | |
|  */
 | |
| export class Protocol {
 | |
|     constructor(_options) {
 | |
|         this._options = _options;
 | |
|         this._requestMessageId = 0;
 | |
|         this._requestHandlers = new Map();
 | |
|         this._requestHandlerAbortControllers = new Map();
 | |
|         this._notificationHandlers = new Map();
 | |
|         this._responseHandlers = new Map();
 | |
|         this._progressHandlers = new Map();
 | |
|         this._timeoutInfo = new Map();
 | |
|         this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
 | |
|             const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
 | |
|             controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
 | |
|         });
 | |
|         this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
 | |
|             this._onprogress(notification);
 | |
|         });
 | |
|         this.setRequestHandler(PingRequestSchema, 
 | |
|         // Automatic pong by default.
 | |
|         (_request) => ({}));
 | |
|     }
 | |
|     _setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
 | |
|         this._timeoutInfo.set(messageId, {
 | |
|             timeoutId: setTimeout(onTimeout, timeout),
 | |
|             startTime: Date.now(),
 | |
|             timeout,
 | |
|             maxTotalTimeout,
 | |
|             resetTimeoutOnProgress,
 | |
|             onTimeout
 | |
|         });
 | |
|     }
 | |
|     _resetTimeout(messageId) {
 | |
|         const info = this._timeoutInfo.get(messageId);
 | |
|         if (!info)
 | |
|             return false;
 | |
|         const totalElapsed = Date.now() - info.startTime;
 | |
|         if (info.maxTotalTimeout && totalElapsed >= info.maxTotalTimeout) {
 | |
|             this._timeoutInfo.delete(messageId);
 | |
|             throw new McpError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", { maxTotalTimeout: info.maxTotalTimeout, totalElapsed });
 | |
|         }
 | |
|         clearTimeout(info.timeoutId);
 | |
|         info.timeoutId = setTimeout(info.onTimeout, info.timeout);
 | |
|         return true;
 | |
|     }
 | |
|     _cleanupTimeout(messageId) {
 | |
|         const info = this._timeoutInfo.get(messageId);
 | |
|         if (info) {
 | |
|             clearTimeout(info.timeoutId);
 | |
|             this._timeoutInfo.delete(messageId);
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Attaches to the given transport, starts it, and starts listening for messages.
 | |
|      *
 | |
|      * The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
 | |
|      */
 | |
|     async connect(transport) {
 | |
|         var _a, _b, _c;
 | |
|         this._transport = transport;
 | |
|         const _onclose = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.onclose;
 | |
|         this._transport.onclose = () => {
 | |
|             _onclose === null || _onclose === void 0 ? void 0 : _onclose();
 | |
|             this._onclose();
 | |
|         };
 | |
|         const _onerror = (_b = this.transport) === null || _b === void 0 ? void 0 : _b.onerror;
 | |
|         this._transport.onerror = (error) => {
 | |
|             _onerror === null || _onerror === void 0 ? void 0 : _onerror(error);
 | |
|             this._onerror(error);
 | |
|         };
 | |
|         const _onmessage = (_c = this._transport) === null || _c === void 0 ? void 0 : _c.onmessage;
 | |
|         this._transport.onmessage = (message, extra) => {
 | |
|             _onmessage === null || _onmessage === void 0 ? void 0 : _onmessage(message, extra);
 | |
|             if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
 | |
|                 this._onresponse(message);
 | |
|             }
 | |
|             else if (isJSONRPCRequest(message)) {
 | |
|                 this._onrequest(message, extra);
 | |
|             }
 | |
|             else if (isJSONRPCNotification(message)) {
 | |
|                 this._onnotification(message);
 | |
|             }
 | |
|             else {
 | |
|                 this._onerror(new Error(`Unknown message type: ${JSON.stringify(message)}`));
 | |
|             }
 | |
|         };
 | |
|         await this._transport.start();
 | |
|     }
 | |
|     _onclose() {
 | |
|         var _a;
 | |
|         const responseHandlers = this._responseHandlers;
 | |
|         this._responseHandlers = new Map();
 | |
|         this._progressHandlers.clear();
 | |
|         this._transport = undefined;
 | |
|         (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
 | |
|         const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
 | |
|         for (const handler of responseHandlers.values()) {
 | |
|             handler(error);
 | |
|         }
 | |
|     }
 | |
|     _onerror(error) {
 | |
|         var _a;
 | |
|         (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
 | |
|     }
 | |
|     _onnotification(notification) {
 | |
|         var _a;
 | |
|         const handler = (_a = this._notificationHandlers.get(notification.method)) !== null && _a !== void 0 ? _a : this.fallbackNotificationHandler;
 | |
|         // Ignore notifications not being subscribed to.
 | |
|         if (handler === undefined) {
 | |
|             return;
 | |
|         }
 | |
|         // Starting with Promise.resolve() puts any synchronous errors into the monad as well.
 | |
|         Promise.resolve()
 | |
|             .then(() => handler(notification))
 | |
|             .catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
 | |
|     }
 | |
|     _onrequest(request, extra) {
 | |
|         var _a, _b, _c, _d;
 | |
|         const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
 | |
|         if (handler === undefined) {
 | |
|             (_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
 | |
|                 jsonrpc: "2.0",
 | |
|                 id: request.id,
 | |
|                 error: {
 | |
|                     code: ErrorCode.MethodNotFound,
 | |
|                     message: "Method not found",
 | |
|                 },
 | |
|             }).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
 | |
|             return;
 | |
|         }
 | |
|         const abortController = new AbortController();
 | |
|         this._requestHandlerAbortControllers.set(request.id, abortController);
 | |
|         const fullExtra = {
 | |
|             signal: abortController.signal,
 | |
|             sessionId: (_c = this._transport) === null || _c === void 0 ? void 0 : _c.sessionId,
 | |
|             _meta: (_d = request.params) === null || _d === void 0 ? void 0 : _d._meta,
 | |
|             sendNotification: (notification) => this.notification(notification, { relatedRequestId: request.id }),
 | |
|             sendRequest: (r, resultSchema, options) => this.request(r, resultSchema, { ...options, relatedRequestId: request.id }),
 | |
|             authInfo: extra === null || extra === void 0 ? void 0 : extra.authInfo,
 | |
|             requestId: request.id,
 | |
|             requestInfo: extra === null || extra === void 0 ? void 0 : extra.requestInfo
 | |
|         };
 | |
|         // Starting with Promise.resolve() puts any synchronous errors into the monad as well.
 | |
|         Promise.resolve()
 | |
|             .then(() => handler(request, fullExtra))
 | |
|             .then((result) => {
 | |
|             var _a;
 | |
|             if (abortController.signal.aborted) {
 | |
|                 return;
 | |
|             }
 | |
|             return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
 | |
|                 result,
 | |
|                 jsonrpc: "2.0",
 | |
|                 id: request.id,
 | |
|             });
 | |
|         }, (error) => {
 | |
|             var _a, _b;
 | |
|             if (abortController.signal.aborted) {
 | |
|                 return;
 | |
|             }
 | |
|             return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
 | |
|                 jsonrpc: "2.0",
 | |
|                 id: request.id,
 | |
|                 error: {
 | |
|                     code: Number.isSafeInteger(error["code"])
 | |
|                         ? error["code"]
 | |
|                         : ErrorCode.InternalError,
 | |
|                     message: (_b = error.message) !== null && _b !== void 0 ? _b : "Internal error",
 | |
|                 },
 | |
|             });
 | |
|         })
 | |
|             .catch((error) => this._onerror(new Error(`Failed to send response: ${error}`)))
 | |
|             .finally(() => {
 | |
|             this._requestHandlerAbortControllers.delete(request.id);
 | |
|         });
 | |
|     }
 | |
|     _onprogress(notification) {
 | |
|         const { progressToken, ...params } = notification.params;
 | |
|         const messageId = Number(progressToken);
 | |
|         const handler = this._progressHandlers.get(messageId);
 | |
|         if (!handler) {
 | |
|             this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
 | |
|             return;
 | |
|         }
 | |
|         const responseHandler = this._responseHandlers.get(messageId);
 | |
|         const timeoutInfo = this._timeoutInfo.get(messageId);
 | |
|         if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) {
 | |
|             try {
 | |
|                 this._resetTimeout(messageId);
 | |
|             }
 | |
|             catch (error) {
 | |
|                 responseHandler(error);
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         handler(params);
 | |
|     }
 | |
|     _onresponse(response) {
 | |
|         const messageId = Number(response.id);
 | |
|         const handler = this._responseHandlers.get(messageId);
 | |
|         if (handler === undefined) {
 | |
|             this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
 | |
|             return;
 | |
|         }
 | |
|         this._responseHandlers.delete(messageId);
 | |
|         this._progressHandlers.delete(messageId);
 | |
|         this._cleanupTimeout(messageId);
 | |
|         if (isJSONRPCResponse(response)) {
 | |
|             handler(response);
 | |
|         }
 | |
|         else {
 | |
|             const error = new McpError(response.error.code, response.error.message, response.error.data);
 | |
|             handler(error);
 | |
|         }
 | |
|     }
 | |
|     get transport() {
 | |
|         return this._transport;
 | |
|     }
 | |
|     /**
 | |
|      * Closes the connection.
 | |
|      */
 | |
|     async close() {
 | |
|         var _a;
 | |
|         await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
 | |
|     }
 | |
|     /**
 | |
|      * Sends a request and wait for a response.
 | |
|      *
 | |
|      * Do not use this method to emit notifications! Use notification() instead.
 | |
|      */
 | |
|     request(request, resultSchema, options) {
 | |
|         const { relatedRequestId, resumptionToken, onresumptiontoken } = options !== null && options !== void 0 ? options : {};
 | |
|         return new Promise((resolve, reject) => {
 | |
|             var _a, _b, _c, _d, _e, _f;
 | |
|             if (!this._transport) {
 | |
|                 reject(new Error("Not connected"));
 | |
|                 return;
 | |
|             }
 | |
|             if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.enforceStrictCapabilities) === true) {
 | |
|                 this.assertCapabilityForMethod(request.method);
 | |
|             }
 | |
|             (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
 | |
|             const messageId = this._requestMessageId++;
 | |
|             const jsonrpcRequest = {
 | |
|                 ...request,
 | |
|                 jsonrpc: "2.0",
 | |
|                 id: messageId,
 | |
|             };
 | |
|             if (options === null || options === void 0 ? void 0 : options.onprogress) {
 | |
|                 this._progressHandlers.set(messageId, options.onprogress);
 | |
|                 jsonrpcRequest.params = {
 | |
|                     ...request.params,
 | |
|                     _meta: {
 | |
|                         ...(((_c = request.params) === null || _c === void 0 ? void 0 : _c._meta) || {}),
 | |
|                         progressToken: messageId
 | |
|                     },
 | |
|                 };
 | |
|             }
 | |
|             const cancel = (reason) => {
 | |
|                 var _a;
 | |
|                 this._responseHandlers.delete(messageId);
 | |
|                 this._progressHandlers.delete(messageId);
 | |
|                 this._cleanupTimeout(messageId);
 | |
|                 (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
 | |
|                     jsonrpc: "2.0",
 | |
|                     method: "notifications/cancelled",
 | |
|                     params: {
 | |
|                         requestId: messageId,
 | |
|                         reason: String(reason),
 | |
|                     },
 | |
|                 }, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
 | |
|                 reject(reason);
 | |
|             };
 | |
|             this._responseHandlers.set(messageId, (response) => {
 | |
|                 var _a;
 | |
|                 if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
 | |
|                     return;
 | |
|                 }
 | |
|                 if (response instanceof Error) {
 | |
|                     return reject(response);
 | |
|                 }
 | |
|                 try {
 | |
|                     const result = resultSchema.parse(response.result);
 | |
|                     resolve(result);
 | |
|                 }
 | |
|                 catch (error) {
 | |
|                     reject(error);
 | |
|                 }
 | |
|             });
 | |
|             (_d = options === null || options === void 0 ? void 0 : options.signal) === null || _d === void 0 ? void 0 : _d.addEventListener("abort", () => {
 | |
|                 var _a;
 | |
|                 cancel((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.reason);
 | |
|             });
 | |
|             const timeout = (_e = options === null || options === void 0 ? void 0 : options.timeout) !== null && _e !== void 0 ? _e : DEFAULT_REQUEST_TIMEOUT_MSEC;
 | |
|             const timeoutHandler = () => cancel(new McpError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
 | |
|             this._setupTimeout(messageId, timeout, options === null || options === void 0 ? void 0 : options.maxTotalTimeout, timeoutHandler, (_f = options === null || options === void 0 ? void 0 : options.resetTimeoutOnProgress) !== null && _f !== void 0 ? _f : false);
 | |
|             this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error) => {
 | |
|                 this._cleanupTimeout(messageId);
 | |
|                 reject(error);
 | |
|             });
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Emits a notification, which is a one-way message that does not expect a response.
 | |
|      */
 | |
|     async notification(notification, options) {
 | |
|         if (!this._transport) {
 | |
|             throw new Error("Not connected");
 | |
|         }
 | |
|         this.assertNotificationCapability(notification.method);
 | |
|         const jsonrpcNotification = {
 | |
|             ...notification,
 | |
|             jsonrpc: "2.0",
 | |
|         };
 | |
|         await this._transport.send(jsonrpcNotification, options);
 | |
|     }
 | |
|     /**
 | |
|      * Registers a handler to invoke when this protocol object receives a request with the given method.
 | |
|      *
 | |
|      * Note that this will replace any previous request handler for the same method.
 | |
|      */
 | |
|     setRequestHandler(requestSchema, handler) {
 | |
|         const method = requestSchema.shape.method.value;
 | |
|         this.assertRequestHandlerCapability(method);
 | |
|         this._requestHandlers.set(method, (request, extra) => {
 | |
|             return Promise.resolve(handler(requestSchema.parse(request), extra));
 | |
|         });
 | |
|     }
 | |
|     /**
 | |
|      * Removes the request handler for the given method.
 | |
|      */
 | |
|     removeRequestHandler(method) {
 | |
|         this._requestHandlers.delete(method);
 | |
|     }
 | |
|     /**
 | |
|      * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
 | |
|      */
 | |
|     assertCanSetRequestHandler(method) {
 | |
|         if (this._requestHandlers.has(method)) {
 | |
|             throw new Error(`A request handler for ${method} already exists, which would be overridden`);
 | |
|         }
 | |
|     }
 | |
|     /**
 | |
|      * Registers a handler to invoke when this protocol object receives a notification with the given method.
 | |
|      *
 | |
|      * Note that this will replace any previous notification handler for the same method.
 | |
|      */
 | |
|     setNotificationHandler(notificationSchema, handler) {
 | |
|         this._notificationHandlers.set(notificationSchema.shape.method.value, (notification) => Promise.resolve(handler(notificationSchema.parse(notification))));
 | |
|     }
 | |
|     /**
 | |
|      * Removes the notification handler for the given method.
 | |
|      */
 | |
|     removeNotificationHandler(method) {
 | |
|         this._notificationHandlers.delete(method);
 | |
|     }
 | |
| }
 | |
| export function mergeCapabilities(base, additional) {
 | |
|     return Object.entries(additional).reduce((acc, [key, value]) => {
 | |
|         if (value && typeof value === "object") {
 | |
|             acc[key] = acc[key] ? { ...acc[key], ...value } : value;
 | |
|         }
 | |
|         else {
 | |
|             acc[key] = value;
 | |
|         }
 | |
|         return acc;
 | |
|     }, { ...base });
 | |
| }
 | |
| //# sourceMappingURL=protocol.js.map
 |