Skip to main content
Glama

Neo4j MCP Server

handshake.js7.59 kB
"use strict"; /** * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); var channel_1 = require("../channel"); var neo4j_driver_core_1 = require("neo4j-driver-core"); var BOLT_MAGIC_PREAMBLE = 0x6060b017; var AVAILABLE_BOLT_PROTOCOLS = ['5.8', '5.7', '5.6', '5.4', '5.3', '5.2', '5.1', '5.0', '4.4', '4.3', '4.2', '3.0']; // bolt protocols the client will accept, ordered by preference var DESIRED_CAPABILITES = 0; function version(major, minor) { return { major: major, minor: minor }; } function createHandshakeMessage(versions) { if (versions.length > 4) { throw (0, neo4j_driver_core_1.newError)('It should not have more than 4 versions of the protocol'); } var handshakeBuffer = (0, channel_1.alloc)(5 * 4); handshakeBuffer.writeInt32(BOLT_MAGIC_PREAMBLE); versions.forEach(function (version) { if (version instanceof Array) { var _a = version[0], major = _a.major, minor = _a.minor; var minMinor = version[1].minor; var range = minor - minMinor; handshakeBuffer.writeInt32((range << 16) | (minor << 8) | major); } else { var major = version.major, minor = version.minor; handshakeBuffer.writeInt32((minor << 8) | major); } }); handshakeBuffer.reset(); return handshakeBuffer; } function parseNegotiatedResponse(buffer, log) { var h = [ buffer.readUInt8(), buffer.readUInt8(), buffer.readUInt8(), buffer.readUInt8() ]; if (h[0] === 0x48 && h[1] === 0x54 && h[2] === 0x54 && h[3] === 0x50) { log.error('Handshake failed since server responded with HTTP.'); throw (0, neo4j_driver_core_1.newError)('Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' + '(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)'); } return Number(h[3] + '.' + h[2]); } function handshakeNegotiationV2(channel, buffer, log) { var numVersions = buffer.readVarInt(); var versions = []; for (var i = 0; i < numVersions; i++) { var versionRange = [ buffer.readUInt8(), buffer.readUInt8(), buffer.readUInt8(), buffer.readUInt8() ]; versions = versions.concat(getVersions(versionRange)); } var capabilityBitMask = buffer.readVarInt(); var capabilites = selectCapabilites(capabilityBitMask); var major = 0; var minor = 0; versions.sort(function (a, b) { if (Number(a.major) !== Number(b.major)) { return Number(b.major) - Number(a.major); } else { return Number(b.minor) - Number(a.minor); } }); for (var i = 0; i < versions.length; i++) { var version_1 = versions[i]; if (AVAILABLE_BOLT_PROTOCOLS.includes(version_1.major + '.' + version_1.minor)) { major = version_1.major; minor = version_1.minor; break; } } return new Promise(function (resolve, reject) { try { var selectionBuffer = (0, channel_1.alloc)(5); selectionBuffer.writeInt32((minor << 8) | major); selectionBuffer.writeVarInt(capabilites); channel.write(selectionBuffer); resolve({ protocolVersion: Number(major + '.' + minor), capabilites: capabilites, consumeRemainingBuffer: function (consumer) { if (buffer.hasRemaining()) { consumer(buffer.readSlice(buffer.remaining())); } } }); } catch (e) { reject(e); } }); } /** * @return {BaseBuffer} * @private */ function newHandshakeBuffer() { return createHandshakeMessage([ version(255, 1), [version(5, 8), version(5, 0)], [version(4, 4), version(4, 2)], version(3, 0) ]); } /** * This callback is displayed as a global member. * @callback BufferConsumerCallback * @param {buffer} buffer the remaining buffer */ /** * @typedef HandshakeResult * @property {number} protocolVersion The protocol version negotiated in the handshake * @property {number} capabilites A bitmask representing the capabilities negotiated in the handshake * @property {function(BufferConsumerCallback)} consumeRemainingBuffer A function to consume the remaining buffer if it exists */ /** * Shake hands using the channel and return the protocol version * * @param {Channel} channel the channel use to shake hands * @param {Logger} log the log object * @returns {Promise<HandshakeResult>} Promise of protocol version and consumeRemainingBuffer */ function handshake(channel, log) { return initialHandshake(channel, log).then(function (result) { if (result.protocolVersion === 255.1) { return handshakeNegotiationV2(channel, result.buffer, log); } else { return result; } }); } exports.default = handshake; /** * Shake hands using the channel and return the protocol version, or the improved handshake protocol if communicating with a newer server. * * @param {Channel} channel the channel use to shake hands * @param {Logger} log the log object * @returns {Promise<HandshakeResult>} Promise of protocol version and consumeRemainingBuffer */ function initialHandshake(channel, log) { var _this = this; return new Promise(function (resolve, reject) { var handshakeErrorHandler = function (error) { reject(error); }; channel.onerror = handshakeErrorHandler.bind(_this); if (channel._error) { handshakeErrorHandler(channel._error); } channel.onmessage = function (buffer) { try { // read the response buffer and initialize the protocol var protocolVersion = parseNegotiatedResponse(buffer, log); resolve({ protocolVersion: protocolVersion, capabilites: 0, buffer: buffer, consumeRemainingBuffer: function (consumer) { if (buffer.hasRemaining()) { consumer(buffer.readSlice(buffer.remaining())); } } }); } catch (e) { reject(e); } }; channel.write(newHandshakeBuffer()); }); } function getVersions(versionArray) { var resultArr = []; var major = versionArray[3]; var minor = versionArray[2]; for (var i = 0; i <= versionArray[1]; i++) { resultArr.push({ major: major, minor: minor - i }); } return resultArr; } function selectCapabilites(capabilityBitMask) { return DESIRED_CAPABILITES; // capabilites are currently unused and will always be 0. }

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