mcp-use
Version:
Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents, Clients and Servers with support for ChatGPT Apps, Code Mode, OAuth, Notifications, Sampling, Observability and more.
524 lines (519 loc) • 15 kB
JavaScript
import {
ElicitationValidationError
} from "./chunk-KUEVOU4M.js";
import {
Telemetry
} from "./chunk-QQO5WIVJ.js";
import {
__name
} from "./chunk-3GQAWCBQ.js";
// src/server/tools/tool-execution-helpers.ts
import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";
// src/server/utils/runtime.ts
var isDeno = typeof globalThis.Deno !== "undefined";
function getEnv(key) {
if (isDeno) {
return globalThis.Deno.env.get(key);
}
return process.env[key];
}
__name(getEnv, "getEnv");
function getCwd() {
if (isDeno) {
return globalThis.Deno.cwd();
}
return process.cwd();
}
__name(getCwd, "getCwd");
var fsHelpers = {
async readFileSync(path, encoding = "utf8") {
if (isDeno) {
return await globalThis.Deno.readTextFile(path);
}
const { readFileSync } = await import("fs");
const result = readFileSync(path, encoding);
return typeof result === "string" ? result : result.toString(encoding);
},
async readFile(path) {
if (isDeno) {
const data = await globalThis.Deno.readFile(path);
return data.buffer;
}
const { readFileSync } = await import("fs");
const buffer = readFileSync(path);
return buffer.buffer.slice(
buffer.byteOffset,
buffer.byteOffset + buffer.byteLength
);
},
async existsSync(path) {
if (isDeno) {
try {
await globalThis.Deno.stat(path);
return true;
} catch {
return false;
}
}
const { existsSync } = await import("fs");
return existsSync(path);
},
async readdirSync(path) {
if (isDeno) {
const entries = [];
for await (const entry of globalThis.Deno.readDir(path)) {
entries.push(entry.name);
}
return entries;
}
const { readdirSync } = await import("fs");
return readdirSync(path);
}
};
var pathHelpers = {
join(...paths) {
if (isDeno) {
return paths.join("/").replace(/\/+/g, "/");
}
return paths.join("/").replace(/\/+/g, "/");
},
relative(from, to) {
const fromParts = from.split("/").filter((p) => p);
const toParts = to.split("/").filter((p) => p);
let i = 0;
while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {
i++;
}
const upCount = fromParts.length - i;
const relativeParts = [...Array(upCount).fill(".."), ...toParts.slice(i)];
return relativeParts.join("/");
}
};
function generateUUID() {
return globalThis.crypto.randomUUID();
}
__name(generateUUID, "generateUUID");
// src/server/tools/tool-execution-helpers.ts
function findSessionContext(sessions, initialRequestContext, extraProgressToken, extraSendNotification) {
let requestContext = initialRequestContext;
let session;
let progressToken = extraProgressToken;
let sendNotification = extraSendNotification;
if (!requestContext) {
for (const [, s] of sessions.entries()) {
if (s.context) {
requestContext = s.context;
break;
}
}
}
if (!progressToken || !sendNotification) {
if (requestContext) {
for (const [, s] of sessions.entries()) {
if (s.context === requestContext) {
session = s;
break;
}
}
} else {
const firstSession = sessions.values().next().value;
if (firstSession) {
session = firstSession;
}
}
if (session) {
if (!progressToken && session.progressToken) {
progressToken = session.progressToken;
}
if (!sendNotification && session.sendNotification) {
sendNotification = session.sendNotification;
}
}
}
return { requestContext, session, progressToken, sendNotification };
}
__name(findSessionContext, "findSessionContext");
async function sendProgressNotification(sendNotification, progressToken, progress, total, message) {
if (sendNotification && progressToken !== void 0) {
try {
await sendNotification({
method: "notifications/progress",
params: {
progressToken,
progress,
total,
message
}
});
} catch {
}
}
}
__name(sendProgressNotification, "sendProgressNotification");
async function withTimeout(promise, timeout, errorMessage) {
if (timeout && timeout !== Infinity) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(errorMessage)), timeout);
});
return await Promise.race([promise, timeoutPromise]);
}
return await promise;
}
__name(withTimeout, "withTimeout");
function parseElicitParams(messageOrParams, schemaOrUrlOrOptions, maybeOptions) {
let sdkParams;
let zodSchema = null;
let options;
if (typeof messageOrParams === "string") {
const message = messageOrParams;
if (typeof schemaOrUrlOrOptions === "string") {
options = maybeOptions;
const elicitationId = `elicit-${generateUUID()}`;
sdkParams = {
mode: "url",
message,
url: schemaOrUrlOrOptions,
elicitationId
};
} else if (schemaOrUrlOrOptions && typeof schemaOrUrlOrOptions === "object" && "_def" in schemaOrUrlOrOptions) {
options = maybeOptions;
zodSchema = schemaOrUrlOrOptions;
const jsonSchema = toJsonSchemaCompat(schemaOrUrlOrOptions);
sdkParams = {
mode: "form",
message,
requestedSchema: jsonSchema
};
} else {
throw new Error(
"Invalid elicit signature: second parameter must be a Zod schema or URL string"
);
}
} else {
options = schemaOrUrlOrOptions;
const params = messageOrParams;
if (params.mode === "url") {
const elicitationId = `elicit-${generateUUID()}`;
sdkParams = {
mode: "url",
message: params.message,
url: params.url,
elicitationId
};
} else {
sdkParams = {
mode: "form",
message: params.message,
requestedSchema: params.requestedSchema
};
}
}
return { sdkParams, zodSchema, options };
}
__name(parseElicitParams, "parseElicitParams");
function createSampleMethod(createMessage, progressToken, sendNotification) {
return async (promptOrParams, options) => {
let sampleParams;
if (typeof promptOrParams === "string") {
sampleParams = {
messages: [
{
role: "user",
content: {
type: "text",
text: promptOrParams
}
}
],
maxTokens: options?.maxTokens || 1e3,
...options?.modelPreferences && {
modelPreferences: options.modelPreferences
},
...options?.systemPrompt && { systemPrompt: options.systemPrompt },
...options?.temperature !== void 0 && {
temperature: options.temperature
},
...options?.stopSequences && { stopSequences: options.stopSequences },
...options?.metadata && { metadata: options.metadata }
};
} else {
sampleParams = promptOrParams;
}
const { timeout, progressIntervalMs = 5e3, onProgress } = options ?? {};
let progressCount = 0;
let completed = false;
let progressInterval = null;
if (progressToken !== void 0 && sendNotification) {
progressInterval = setInterval(async () => {
if (completed) return;
progressCount++;
const progressData = {
progress: progressCount,
total: void 0,
message: `Waiting for LLM response... (${progressCount * Math.round(progressIntervalMs / 1e3)}s elapsed)`
};
if (onProgress) {
try {
onProgress(progressData);
} catch {
}
}
await sendProgressNotification(
sendNotification,
progressToken,
progressData.progress,
progressData.total,
progressData.message
);
}, progressIntervalMs);
}
try {
console.log("[SAMPLING DEBUG] Calling createMessage...");
const sdkTimeout = timeout && timeout !== Infinity ? timeout : 2147483647;
const samplePromise = createMessage(sampleParams, {
timeout: sdkTimeout
});
console.log("[SAMPLING DEBUG] Waiting for response...");
const result = await withTimeout(
samplePromise,
timeout,
`Sampling timed out after ${timeout}ms`
);
console.log("[SAMPLING DEBUG] Got result:", result);
Telemetry.getInstance().trackServerContext({
contextType: "sample"
}).catch((e) => console.debug(`Failed to track sample context: ${e}`));
return result;
} catch (error) {
console.error("[SAMPLING DEBUG] Error during sampling:", error);
throw error;
} finally {
completed = true;
if (progressInterval) {
clearInterval(progressInterval);
}
}
};
}
__name(createSampleMethod, "createSampleMethod");
function createElicitMethod(elicitInput) {
return async (messageOrParams, schemaOrUrlOrOptions, maybeOptions) => {
const { sdkParams, zodSchema, options } = parseElicitParams(
messageOrParams,
schemaOrUrlOrOptions,
maybeOptions
);
const { timeout } = options ?? {};
const sdkTimeout = timeout && timeout !== Infinity ? timeout : 2147483647;
const result = await elicitInput(sdkParams, { timeout: sdkTimeout });
Telemetry.getInstance().trackServerContext({
contextType: "elicit"
}).catch((e) => console.debug(`Failed to track elicit context: ${e}`));
if (zodSchema && result.action === "accept" && result.data) {
try {
const validatedData = zodSchema.parse(result.data);
return {
...result,
data: validatedData
};
} catch (error) {
const err = error;
throw new ElicitationValidationError(
`Elicitation data validation failed: ${err.message}`,
err
);
}
}
return result;
};
}
__name(createElicitMethod, "createElicitMethod");
function createReportProgressMethod(progressToken, sendNotification) {
if (progressToken !== void 0 && sendNotification) {
return async (progress, total, message) => {
await sendProgressNotification(
sendNotification,
progressToken,
progress,
total,
message
);
};
}
return void 0;
}
__name(createReportProgressMethod, "createReportProgressMethod");
var LOG_LEVELS = {
debug: 0,
info: 1,
notice: 2,
warning: 3,
error: 4,
critical: 5,
alert: 6,
emergency: 7
};
var VALID_LOG_LEVELS = [
"debug",
"info",
"notice",
"warning",
"error",
"critical",
"alert",
"emergency"
];
function isValidLogLevel(level) {
return VALID_LOG_LEVELS.includes(level);
}
__name(isValidLogLevel, "isValidLogLevel");
function shouldLogMessage(messageLevel, minLevel) {
if (!minLevel) {
return true;
}
if (!isValidLogLevel(messageLevel) || !isValidLogLevel(minLevel)) {
return true;
}
return LOG_LEVELS[messageLevel] >= LOG_LEVELS[minLevel];
}
__name(shouldLogMessage, "shouldLogMessage");
function createLogMethod(sendNotification, minLogLevel) {
if (!sendNotification) {
return void 0;
}
return async (level, message, logger) => {
if (!shouldLogMessage(level, minLogLevel)) {
return;
}
await sendNotification({
method: "notifications/message",
params: {
level,
data: message,
logger: logger || "tool"
}
});
Telemetry.getInstance().trackServerContext({
contextType: "notification",
notificationType: "message"
}).catch(
(e) => console.debug(`Failed to track notification context: ${e}`)
);
};
}
__name(createLogMethod, "createLogMethod");
function createClientCapabilityChecker(clientCapabilities) {
const caps = clientCapabilities || {};
return {
can(capability) {
return capability in caps;
},
capabilities() {
return { ...caps };
}
};
}
__name(createClientCapabilityChecker, "createClientCapabilityChecker");
function createSendNotificationMethod(sessionId, sessions) {
if (!sessionId || !sessions) {
return void 0;
}
return async (method, params) => {
const session = sessions.get(sessionId);
if (!session?.sendNotification) {
console.warn(
`[MCP] Cannot send notification to session ${sessionId} - no sendNotification function`
);
return;
}
try {
await session.sendNotification({
method,
params: params || {}
});
} catch (error) {
console.error(
`[MCP] Error sending notification to session ${sessionId}:`,
error
);
}
};
}
__name(createSendNotificationMethod, "createSendNotificationMethod");
function createSendNotificationToSessionMethod(sessions) {
if (!sessions) {
return void 0;
}
return async (sessionId, method, params) => {
const session = sessions.get(sessionId);
if (!session?.sendNotification) {
return false;
}
try {
await session.sendNotification({
method,
params: params || {}
});
return true;
} catch (error) {
console.error(
`[MCP] Error sending notification to session ${sessionId}:`,
error
);
return false;
}
};
}
__name(createSendNotificationToSessionMethod, "createSendNotificationToSessionMethod");
function createEnhancedContext(baseContext, createMessage, elicitInput, progressToken, sendNotification, minLogLevel, clientCapabilities, sessionId, sessions) {
const enhancedContext = baseContext ? Object.create(baseContext) : {};
enhancedContext.sample = createSampleMethod(
createMessage,
progressToken,
sendNotification
);
enhancedContext.elicit = createElicitMethod(elicitInput);
enhancedContext.reportProgress = createReportProgressMethod(
progressToken,
sendNotification
);
enhancedContext.log = createLogMethod(sendNotification, minLogLevel);
enhancedContext.client = createClientCapabilityChecker(clientCapabilities);
if (sessionId) {
enhancedContext.session = {
sessionId
};
}
const sendNotificationMethod = createSendNotificationMethod(
sessionId,
sessions
);
if (sendNotificationMethod) {
enhancedContext.sendNotification = sendNotificationMethod;
}
const sendNotificationToSessionMethod = createSendNotificationToSessionMethod(sessions);
if (sendNotificationToSessionMethod) {
enhancedContext.sendNotificationToSession = sendNotificationToSessionMethod;
}
return enhancedContext;
}
__name(createEnhancedContext, "createEnhancedContext");
export {
isDeno,
getEnv,
getCwd,
fsHelpers,
pathHelpers,
generateUUID,
findSessionContext,
sendProgressNotification,
withTimeout,
parseElicitParams,
createSampleMethod,
createElicitMethod,
createReportProgressMethod,
VALID_LOG_LEVELS,
isValidLogLevel,
shouldLogMessage,
createEnhancedContext
};