@toolbox-sdk/core
Version:
JavaScript Base SDK for interacting with the Toolbox service
234 lines • 11.4 kB
JavaScript
// Copyright 2026 Google LLC
//
// 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 __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _McpHttpTransportV20260728_instances, _McpHttpTransportV20260728_getMeta, _McpHttpTransportV20260728_checkProtocolNegotiationError, _McpHttpTransportV20260728_sendRequest;
import { AxiosError } from 'axios';
import { McpHttpTransportBase } from '../transportBase.js';
import * as types from './types.js';
import { getSupportedMcpVersions, } from '../../protocol.js';
import { logApiError } from '../../errorUtils.js';
import { warnIfHttpAndHeaders } from '../../utils.js';
import { v4 as uuidv4 } from 'uuid';
import { VERSION } from '../../version.js';
import { ProtocolNegotiationError } from '../../errorUtils.js';
export class McpHttpTransportV20260728 extends McpHttpTransportBase {
constructor() {
super(...arguments);
_McpHttpTransportV20260728_instances.add(this);
}
async initializeSession(
// Required to match McpHttpTransportBase signature, but unused because
// Stateless MCP does not use an initialize handshake.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_headers) { }
async toolsList(toolsetName, headers) {
var _a, _b, _c;
await this.ensureInitialized(headers);
const url = this.appendToolsetPath(toolsetName);
const result = await __classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_sendRequest).call(this, url, types.ListToolsRequest, { _meta: __classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_getMeta).call(this) }, headers);
if (!result) {
const error = new Error('Failed to list tools: No response from server.');
logApiError(`Error listing tools from ${url}`, error);
throw error;
}
const toolsMap = {};
for (const tool of result.tools) {
toolsMap[tool.name] = this.convertToolSchema(tool);
}
const serverVersion = (_c = (_b = (_a = result._meta) === null || _a === void 0 ? void 0 : _a['io.modelcontextprotocol/serverInfo']) === null || _b === void 0 ? void 0 : _b.version) !== null && _c !== void 0 ? _c : '0.0.0';
return {
serverVersion,
tools: toolsMap,
};
}
async toolGet(toolName, headers) {
const manifest = await this.toolsList(undefined, headers);
if (!manifest.tools[toolName]) {
const error = new Error(`Tool '${toolName}' not found.`);
logApiError(`Error getting tool ${toolName}`, error);
throw error;
}
return {
serverVersion: manifest.serverVersion,
tools: {
[toolName]: manifest.tools[toolName],
},
};
}
async toolInvoke(toolName, arguments_, headers) {
await this.ensureInitialized(headers);
if (headers && Object.keys(headers).length > 0) {
warnIfHttpAndHeaders(this._mcpBaseUrl, headers);
}
const params = {
name: toolName,
arguments: arguments_,
_meta: __classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_getMeta).call(this),
};
const result = await __classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_sendRequest).call(this, this._mcpBaseUrl, types.CallToolRequest, params, headers);
if (!result) {
const error = new Error(`Failed to invoke tool '${toolName}': No response from server.`);
logApiError(`Error invoking tool ${toolName}`, error);
throw error;
}
return this.processToolResultContent(result.content);
}
}
_McpHttpTransportV20260728_instances = new WeakSet(), _McpHttpTransportV20260728_getMeta = function _McpHttpTransportV20260728_getMeta() {
const clientInfo = {
name: this._clientName || 'toolbox-core-js',
version: this._clientVersion || VERSION,
};
return {
'io.modelcontextprotocol/protocolVersion': this._protocolVersion,
'io.modelcontextprotocol/clientInfo': clientInfo,
'io.modelcontextprotocol/clientCapabilities': {},
};
}, _McpHttpTransportV20260728_checkProtocolNegotiationError = function _McpHttpTransportV20260728_checkProtocolNegotiationError(errVal) {
var _a;
if (!errVal)
return;
// Check for unsupported protocol version error code (-32022 or -32004)
if (typeof errVal === 'object' &&
errVal !== null &&
'code' in errVal &&
(errVal.code === -32022 ||
errVal.code === -32004)) {
const serverSupported = (((_a = errVal.data) === null || _a === void 0 ? void 0 : _a.supported) || []);
const clientSupported = this.supportedProtocols || getSupportedMcpVersions();
const mutuallySupported = clientSupported.filter(v => serverSupported.includes(v));
if (mutuallySupported.length > 0) {
throw new ProtocolNegotiationError(mutuallySupported[0]);
}
else {
throw new Error(`No mutually supported protocol version. Client supports: ${clientSupported.join(', ')}, Server supports: ${serverSupported.join(', ')}`);
}
}
// Check for legacy fallback (string or object message matching)
const errMsg = typeof errVal === 'string'
? errVal.toLowerCase()
: typeof errVal === 'object' && errVal !== null && 'message' in errVal
? String(errVal.message).toLowerCase()
: '';
const isLegacyError = errMsg.includes('invalid protocol version') ||
errMsg.includes('unsupported protocol version');
if (isLegacyError) {
// Cascading Fallback
const clientSupported = this.supportedProtocols || getSupportedMcpVersions();
const currentIdx = clientSupported.indexOf(this._protocolVersion);
if (currentIdx !== -1 && currentIdx + 1 < clientSupported.length) {
throw new ProtocolNegotiationError(clientSupported[currentIdx + 1]);
}
else {
throw new Error("Server threw 'invalid protocol version' but no fallback versions remain in the user's supported protocols array.");
}
}
}, _McpHttpTransportV20260728_sendRequest = async function _McpHttpTransportV20260728_sendRequest(url, request, paramsOverride, headers) {
var _a;
const params = paramsOverride || request.params;
let payload;
const isNotification = !('getResultModel' in request);
const method = request.method;
if (isNotification) {
payload = {
jsonrpc: '2.0',
method,
params: params,
};
}
else {
payload = {
jsonrpc: '2.0',
id: uuidv4(),
method,
params: params,
};
}
// Inject Protocol Version into headers as required by MCP spec
const reqHeaders = { ...(headers || {}) };
reqHeaders['MCP-Protocol-Version'] = this._protocolVersion;
// Inject SEP-2243 routing headers
reqHeaders['Mcp-Method'] = method;
if (typeof params === 'object' && params !== null) {
if ((method === 'tools/call' || method === 'prompts/get') &&
'name' in params) {
reqHeaders['Mcp-Name'] = String(params.name);
}
else if (method === 'resources/read' && 'uri' in params) {
reqHeaders['Mcp-Name'] = String(params.uri);
}
}
try {
const response = await this._session.post(url, payload, {
headers: reqHeaders,
});
if (response.status !== 200 &&
response.status !== 204 &&
response.status !== 202) {
const errorText = JSON.stringify(response.data);
throw new Error(`API request failed with status ${response.status} (${response.statusText}). Server response: ${errorText}`);
}
if (response.status === 204 || response.status === 202) {
return null;
}
const jsonResp = response.data;
if (jsonResp && typeof jsonResp === 'object' && jsonResp.error) {
const errVal = jsonResp.error;
__classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_checkProtocolNegotiationError).call(this, errVal);
const errResult = types.JSONRPCErrorSchema.safeParse(jsonResp);
let message = `MCP request failed: ${JSON.stringify(jsonResp.error)}`;
let code = 'MCP_ERROR';
if (errResult.success) {
const err = errResult.data.error;
message = `MCP request failed with code ${err.code}: ${err.message}`;
code = String(err.code);
}
throw new AxiosError(message, code, response.config, response.request, response);
}
// Parse Result
if (!isNotification && 'getResultModel' in request) {
const rpcRespResult = types.JSONRPCResponseSchema.safeParse(jsonResp);
if (rpcRespResult.success) {
const resultModel = request.getResultModel();
return resultModel.parse(rpcRespResult.data.result);
}
throw new Error('Failed to parse JSON-RPC response structure');
}
return null;
}
catch (error) {
if (error instanceof ProtocolNegotiationError) {
throw error;
}
if (error instanceof AxiosError) {
const jsonResp = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
if (jsonResp) {
if (typeof jsonResp === 'object' && 'error' in jsonResp) {
const errVal = jsonResp.error;
__classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_checkProtocolNegotiationError).call(this, errVal);
}
else if (typeof jsonResp === 'string') {
__classPrivateFieldGet(this, _McpHttpTransportV20260728_instances, "m", _McpHttpTransportV20260728_checkProtocolNegotiationError).call(this, jsonResp);
}
}
}
logApiError(`Error posting data to ${url}:`, error);
throw error;
}
};
//# sourceMappingURL=mcp.js.map