Skip to main content
Glama

Neo4j MCP Server

routing-table.js10.4 kB
"use strict"; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createValidRoutingTable = void 0; /** * Copyright (c) "Neo4j" * Neo4j Sweden AB [https://neo4j.com] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var neo4j_driver_core_1 = require("neo4j-driver-core"); var _a = neo4j_driver_core_1.internal.constants, WRITE = _a.ACCESS_MODE_WRITE, READ = _a.ACCESS_MODE_READ, ServerAddress = neo4j_driver_core_1.internal.serverAddress.ServerAddress; var PROTOCOL_ERROR = neo4j_driver_core_1.error.PROTOCOL_ERROR; var MIN_ROUTERS = 1; /** * The routing table object used to determine the role of the servers in the driver. */ var RoutingTable = /** @class */ (function () { function RoutingTable(_a) { var _b = _a === void 0 ? {} : _a, database = _b.database, routers = _b.routers, readers = _b.readers, writers = _b.writers, expirationTime = _b.expirationTime, ttl = _b.ttl; this.database = database || null; this.databaseName = database || 'default database'; this.routers = routers || []; this.readers = readers || []; this.writers = writers || []; this.expirationTime = expirationTime || (0, neo4j_driver_core_1.int)(0); this.ttl = ttl; } /** * Create a valid routing table from a raw object * * @param {string} database the database name. It is used for logging purposes * @param {ServerAddress} routerAddress The router address, it is used for loggin purposes * @param {RawRoutingTable} rawRoutingTable Method used to get the raw routing table to be processed * @param {RoutingTable} The valid Routing Table */ RoutingTable.fromRawRoutingTable = function (database, routerAddress, rawRoutingTable) { return createValidRoutingTable(database, routerAddress, rawRoutingTable); }; RoutingTable.prototype.forget = function (address) { // Don't remove it from the set of routers, since that might mean we lose our ability to re-discover, // just remove it from the set of readers and writers, so that we don't use it for actual work without // performing discovery first. this.readers = removeFromArray(this.readers, address); this.writers = removeFromArray(this.writers, address); }; RoutingTable.prototype.forgetRouter = function (address) { this.routers = removeFromArray(this.routers, address); }; RoutingTable.prototype.forgetWriter = function (address) { this.writers = removeFromArray(this.writers, address); }; /** * Check if this routing table is fresh to perform the required operation. * @param {string} accessMode the type of operation. Allowed values are {@link READ} and {@link WRITE}. * @return {boolean} `true` when this table contains servers to serve the required operation, `false` otherwise. */ RoutingTable.prototype.isStaleFor = function (accessMode) { return (this.expirationTime.lessThan(Date.now()) || this.routers.length < MIN_ROUTERS || (accessMode === READ && this.readers.length === 0) || (accessMode === WRITE && this.writers.length === 0)); }; /** * Check if this routing table is expired for specified amount of duration * * @param {Integer} duration amount of duration in milliseconds to check for expiration * @returns {boolean} */ RoutingTable.prototype.isExpiredFor = function (duration) { return this.expirationTime.add(duration).lessThan(Date.now()); }; RoutingTable.prototype.allServers = function () { return __spreadArray(__spreadArray(__spreadArray([], __read(this.routers), false), __read(this.readers), false), __read(this.writers), false); }; RoutingTable.prototype.toString = function () { return ('RoutingTable[' + "database=".concat(this.databaseName, ", ") + "expirationTime=".concat(this.expirationTime, ", ") + "currentTime=".concat(Date.now(), ", ") + "routers=[".concat(this.routers, "], ") + "readers=[".concat(this.readers, "], ") + "writers=[".concat(this.writers, "]]")); }; return RoutingTable; }()); exports.default = RoutingTable; /** * Remove all occurrences of the element in the array. * @param {Array} array the array to filter. * @param {Object} element the element to remove. * @return {Array} new filtered array. */ function removeFromArray(array, element) { return array.filter(function (item) { return item.asKey() !== element.asKey(); }); } /** * Create a valid routing table from a raw object * * @param {string} db the database name. It is used for logging purposes * @param {ServerAddress} routerAddress The router address, it is used for loggin purposes * @param {RawRoutingTable} rawRoutingTable Method used to get the raw routing table to be processed * @param {RoutingTable} The valid Routing Table */ function createValidRoutingTable(database, routerAddress, rawRoutingTable) { var ttl = rawRoutingTable.ttl; var expirationTime = calculateExpirationTime(rawRoutingTable, routerAddress); var _a = parseServers(rawRoutingTable, routerAddress), routers = _a.routers, readers = _a.readers, writers = _a.writers; assertNonEmpty(routers, 'routers', routerAddress); assertNonEmpty(readers, 'readers', routerAddress); return new RoutingTable({ database: database || rawRoutingTable.db, routers: routers, readers: readers, writers: writers, expirationTime: expirationTime, ttl: ttl }); } exports.createValidRoutingTable = createValidRoutingTable; /** * Parse server from the RawRoutingTable. * * @param {RawRoutingTable} rawRoutingTable the raw routing table * @param {string} routerAddress the router address * @returns {Object} The object with the list of routers, readers and writers */ function parseServers(rawRoutingTable, routerAddress) { try { var routers_1 = []; var readers_1 = []; var writers_1 = []; rawRoutingTable.servers.forEach(function (server) { var role = server.role; var addresses = server.addresses; if (role === 'ROUTE') { routers_1 = parseArray(addresses).map(function (address) { return ServerAddress.fromUrl(address); }); } else if (role === 'WRITE') { writers_1 = parseArray(addresses).map(function (address) { return ServerAddress.fromUrl(address); }); } else if (role === 'READ') { readers_1 = parseArray(addresses).map(function (address) { return ServerAddress.fromUrl(address); }); } }); return { routers: routers_1, readers: readers_1, writers: writers_1 }; } catch (error) { throw (0, neo4j_driver_core_1.newError)("Unable to parse servers entry from router ".concat(routerAddress, " from addresses:\n").concat(neo4j_driver_core_1.json.stringify(rawRoutingTable.servers), "\nError message: ").concat(error.message), PROTOCOL_ERROR); } } /** * Call the expiration time using the ttls from the raw routing table and return it * * @param {RawRoutingTable} rawRoutingTable the routing table * @param {string} routerAddress the router address * @returns {number} the ttl */ function calculateExpirationTime(rawRoutingTable, routerAddress) { try { var now = (0, neo4j_driver_core_1.int)(Date.now()); var expires = (0, neo4j_driver_core_1.int)(rawRoutingTable.ttl) .multiply(1000) .add(now); // if the server uses a really big expire time like Long.MAX_VALUE this may have overflowed if (expires.lessThan(now)) { return neo4j_driver_core_1.Integer.MAX_VALUE; } return expires; } catch (error) { throw (0, neo4j_driver_core_1.newError)("Unable to parse TTL entry from router ".concat(routerAddress, " from raw routing table:\n").concat(neo4j_driver_core_1.json.stringify(rawRoutingTable), "\nError message: ").concat(error.message), PROTOCOL_ERROR); } } /** * Assert if serverAddressesArray is not empty, throws and PROTOCOL_ERROR otherwise * * @param {string[]} serverAddressesArray array of addresses * @param {string} serversName the server name * @param {string} routerAddress the router address */ function assertNonEmpty(serverAddressesArray, serversName, routerAddress) { if (serverAddressesArray.length === 0) { throw (0, neo4j_driver_core_1.newError)('Received no ' + serversName + ' from router ' + routerAddress, PROTOCOL_ERROR); } } function parseArray(addresses) { if (!Array.isArray(addresses)) { throw new TypeError('Array expected but got: ' + addresses); } return Array.from(addresses); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tobarrientos2/neo4j-mcpserver'

If you have feedback or need assistance with the MCP directory API, please join our Discord server