@runpod/mcp-server 4.3.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +16 -0
- package/dist/{chunk-DDX42UTT.mjs → chunk-4GF3CMSH.mjs} +6 -2
- package/dist/{chunk-DDX42UTT.mjs.map → chunk-4GF3CMSH.mjs.map} +1 -1
- package/dist/http.cjs +198 -5
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +6 -1
- package/dist/http.d.ts +6 -1
- package/dist/http.mjs +197 -5
- package/dist/http.mjs.map +1 -1
- package/dist/stdio.cjs +131 -5
- package/dist/stdio.cjs.map +1 -1
- package/dist/stdio.mjs +127 -6
- package/dist/stdio.mjs.map +1 -1
- package/dist/{wizard-L25AYBNQ.mjs → wizard-KKTBTVXE.mjs} +4 -3
- package/dist/wizard-KKTBTVXE.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/wizard-L25AYBNQ.mjs.map +0 -1
package/dist/http.d.cts
CHANGED
|
@@ -26,6 +26,11 @@ interface RpcSummary {
|
|
|
26
26
|
client?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Extract the bearer token from an HTTP request's Authorization header.
|
|
31
|
+
* Returns null if the header is missing or malformed.
|
|
32
|
+
*/
|
|
33
|
+
declare function extractBearerToken(req: IncomingMessage): string | null;
|
|
29
34
|
declare function getBaseUrl(req: {
|
|
30
35
|
headers: {
|
|
31
36
|
host?: string;
|
|
@@ -59,4 +64,4 @@ declare function summarizeRpc(messages: JSONRPCMessage[]): RpcSummary;
|
|
|
59
64
|
*/
|
|
60
65
|
declare function handleMcpRequest(req: IncomingMessage, res: ServerResponse, opts?: HandleMcpRequestOptions): Promise<void>;
|
|
61
66
|
|
|
62
|
-
export { bodyIsCheckable, defaultCredentialChecker, getBaseUrl, handleMcpRequest, parseMcpMessages, prefersJsonResponse, requestLogSampleRate, summarizeRpc };
|
|
67
|
+
export { bodyIsCheckable, defaultCredentialChecker, extractBearerToken, getBaseUrl, handleMcpRequest, parseMcpMessages, prefersJsonResponse, requestLogSampleRate, summarizeRpc };
|
package/dist/http.d.ts
CHANGED
|
@@ -26,6 +26,11 @@ interface RpcSummary {
|
|
|
26
26
|
client?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Extract the bearer token from an HTTP request's Authorization header.
|
|
31
|
+
* Returns null if the header is missing or malformed.
|
|
32
|
+
*/
|
|
33
|
+
declare function extractBearerToken(req: IncomingMessage): string | null;
|
|
29
34
|
declare function getBaseUrl(req: {
|
|
30
35
|
headers: {
|
|
31
36
|
host?: string;
|
|
@@ -59,4 +64,4 @@ declare function summarizeRpc(messages: JSONRPCMessage[]): RpcSummary;
|
|
|
59
64
|
*/
|
|
60
65
|
declare function handleMcpRequest(req: IncomingMessage, res: ServerResponse, opts?: HandleMcpRequestOptions): Promise<void>;
|
|
61
66
|
|
|
62
|
-
export { bodyIsCheckable, defaultCredentialChecker, getBaseUrl, handleMcpRequest, parseMcpMessages, prefersJsonResponse, requestLogSampleRate, summarizeRpc };
|
|
67
|
+
export { bodyIsCheckable, defaultCredentialChecker, extractBearerToken, getBaseUrl, handleMcpRequest, parseMcpMessages, prefersJsonResponse, requestLogSampleRate, summarizeRpc };
|
package/dist/http.mjs
CHANGED
|
@@ -5695,6 +5695,8 @@ var listHubRepos = {
|
|
|
5695
5695
|
};
|
|
5696
5696
|
var deployHubRepo = {
|
|
5697
5697
|
name: "deploy-hub-repo",
|
|
5698
|
+
// Two sequential upstream calls: together they can outlast a client's request timeout.
|
|
5699
|
+
holdsResponse: true,
|
|
5698
5700
|
annotations: write,
|
|
5699
5701
|
description: "Deploy a Runpod Hub repo's listed release as a new Serverless endpoint (the same as clicking Deploy on the Hub). Identify the repo by `repo` (\"owner/name\" from list-hub-repos) or by `hubReleaseId`. The release supplies the prebuilt image, container disk, CUDA constraints, and env-var defaults; pass `env` to override or fill in values (required keys without a default must be provided \u2014 check list-hub-repos with includeConfig:true for the schema). GPU selection comes from the release config when it specifies one; otherwise pass gpuIds (GPU pool names, e.g. 'ADA_24' or 'ADA_80_PRO,AMPERE_80'). Uses the authenticated GraphQL API (no REST home for Hub deploys yet).",
|
|
5700
5702
|
inputSchema: {
|
|
@@ -6183,6 +6185,7 @@ var runEndpoint = {
|
|
|
6183
6185
|
};
|
|
6184
6186
|
var runsyncEndpoint = {
|
|
6185
6187
|
name: "runsync-endpoint",
|
|
6188
|
+
holdsResponse: true,
|
|
6186
6189
|
annotations: write,
|
|
6187
6190
|
description: "Submit a synchronous job to a Serverless endpoint and wait for the result. Best for fast tasks: if the job outlives the wait, the response returns a job ID and a non-terminal status (IN_QUEUE or IN_PROGRESS) to poll with get-job-status. Max payload 20 MB; results expire after 1 minute. The wait parameter extends the server-side wait" + (HOSTED ? ` \u2014 this server runs behind a 60-second gateway deadline, so waits clamp to ${HTTP_LONG_POLL_BUDGET_MS} ms, which is also the effective default. For longer jobs use run-endpoint + get-job-status.` : " to up to 5 minutes (300000 ms); it defaults to 90000 (90 seconds)."),
|
|
6188
6191
|
inputSchema: {
|
|
@@ -6227,6 +6230,7 @@ var runsyncEndpoint = {
|
|
|
6227
6230
|
};
|
|
6228
6231
|
var getJobStatus = {
|
|
6229
6232
|
name: "get-job-status",
|
|
6233
|
+
holdsResponse: true,
|
|
6230
6234
|
annotations: readOnly,
|
|
6231
6235
|
description: "Check the status of a Serverless job. Returns the current status and output when complete. Job statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT. Pass `wait` (milliseconds, up to " + STATUS_WAIT_MAX_MS + ") to BLOCK server-side, polling until the job reaches a terminal status or the budget expires \u2014 use it to ride out a cold start (a first job on a fresh worker pulls the image and loads the model, commonly 1\u20135+ minutes) in a single call instead of returning on the first IN_QUEUE and tight-looping the tool. Without `wait` it returns the current status immediately (a single check). If the budget expires before a terminal status, it returns the latest non-terminal status with pollingTimedOut:true \u2014 call again (with `wait`) to keep blocking. IMPORTANT: a job stuck IN_QUEUE does not necessarily mean a capacity shortage \u2014 a worker may have spun up and crash-looped. When the job is IN_QUEUE this tool attaches a workerHealth summary and a hint. To dig deeper call list-endpoint-workers, then read stream-worker-logs regardless of the status a worker reports: a container failing to start loops while its worker still shows RUNNING or THROTTLED and unhealthy stays 0, so UNHEALTHY is one symptom of a crash loop and not a test for it. The logs are the authority.",
|
|
6232
6236
|
inputSchema: {
|
|
@@ -6275,6 +6279,7 @@ var getJobStatus = {
|
|
|
6275
6279
|
};
|
|
6276
6280
|
var streamJob = {
|
|
6277
6281
|
name: "stream-job",
|
|
6282
|
+
holdsResponse: true,
|
|
6278
6283
|
annotations: readOnly,
|
|
6279
6284
|
description: `Retrieve streaming output from a Serverless job. The worker must support streaming output. Polls /stream/{jobId} and collects chunks until the status is COMPLETED, FAILED, CANCELLED, or TIMED_OUT, for up to ${formatBudget(STREAM_BUDGET_MS)}. If the budget expires first, returns the chunks collected so far with pollingTimedOut: true \u2014 call stream-job again to resume where it left off, or get-job-status to check without streaming.`,
|
|
6280
6285
|
inputSchema: {
|
|
@@ -6507,6 +6512,9 @@ function publicGraphqlBase(env) {
|
|
|
6507
6512
|
function authedGraphqlBase(env) {
|
|
6508
6513
|
return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
|
|
6509
6514
|
}
|
|
6515
|
+
function knowledgeSearchBase(env) {
|
|
6516
|
+
return pick(env.KNOWLEDGE_SEARCH_URL, "") || void 0;
|
|
6517
|
+
}
|
|
6510
6518
|
|
|
6511
6519
|
// node_modules/.pnpm/@runpod+typescript-api-sdk@0.3.0/node_modules/@runpod/typescript-api-sdk/dist/index.js
|
|
6512
6520
|
var PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
@@ -7912,6 +7920,7 @@ function logParams(args) {
|
|
|
7912
7920
|
}
|
|
7913
7921
|
var streamPodLogs = {
|
|
7914
7922
|
name: "stream-pod-logs",
|
|
7923
|
+
holdsResponse: true,
|
|
7915
7924
|
annotations: readOnly,
|
|
7916
7925
|
description: "Read a bounded snapshot of a Pod's logs (container and/or system source). Holds the live stream open for maxWaitMs and returns the parsed log lines; `truncated: true` means the byte cap cut the output. Use `since` to resume from a timestamp.",
|
|
7917
7926
|
inputSchema: {
|
|
@@ -7934,6 +7943,7 @@ var streamPodLogs = {
|
|
|
7934
7943
|
};
|
|
7935
7944
|
var streamWorkerLogs = {
|
|
7936
7945
|
name: "stream-worker-logs",
|
|
7946
|
+
holdsResponse: true,
|
|
7937
7947
|
annotations: readOnly,
|
|
7938
7948
|
description: "Read a bounded snapshot of a Serverless worker's logs (container and/or system source). Holds the live stream open for maxWaitMs and returns the parsed log lines; `truncated: true` means the byte cap cut the output. Get worker IDs from list-endpoint-workers. Use this whenever a job stays IN_QUEUE while workers exist, whatever status they report \u2014 a crash-looping container often still shows RUNNING or THROTTLED with unhealthy 0, so these logs, not the worker status, are what identify a crash loop.",
|
|
7939
7949
|
inputSchema: {
|
|
@@ -8527,7 +8537,7 @@ function words2(name) {
|
|
|
8527
8537
|
|
|
8528
8538
|
// src/server.ts
|
|
8529
8539
|
var SERVER_NAME = "Runpod API Server";
|
|
8530
|
-
var SERVER_VERSION = true ? "4.
|
|
8540
|
+
var SERVER_VERSION = true ? "4.4.0" : "dev";
|
|
8531
8541
|
|
|
8532
8542
|
// src/specgen/analytics.ts
|
|
8533
8543
|
import { createHmac } from "crypto";
|
|
@@ -8857,6 +8867,177 @@ function createAlpTools(opts) {
|
|
|
8857
8867
|
return [reportFeedback, saveToJournal, askQuestion, readJournalTool];
|
|
8858
8868
|
}
|
|
8859
8869
|
|
|
8870
|
+
// src/search/knowledge.ts
|
|
8871
|
+
var SEARCH_NAMESPACES = ["docs", "knowledge", "blog", "site"];
|
|
8872
|
+
var MAX_QUERY_CHARS = 2e3;
|
|
8873
|
+
var MAX_SEARCH_LIMIT = 20;
|
|
8874
|
+
var ATTEMPTS = 7;
|
|
8875
|
+
var BASE_DELAY_MS = 250;
|
|
8876
|
+
var ATTEMPT_TIMEOUT_MS = 1e4;
|
|
8877
|
+
var RETRY_DEADLINE_MS = 3e4;
|
|
8878
|
+
var PLATFORM_LIMIT = /TooManyConcurrentRequests|Too many concurrent requests/;
|
|
8879
|
+
var AT_CAPACITY = {
|
|
8880
|
+
status: 503,
|
|
8881
|
+
body: {
|
|
8882
|
+
error: "Runpod knowledge search is at capacity.",
|
|
8883
|
+
hint: "Retry the same call in a few seconds."
|
|
8884
|
+
}
|
|
8885
|
+
};
|
|
8886
|
+
var UNREACHABLE = {
|
|
8887
|
+
status: 504,
|
|
8888
|
+
body: {
|
|
8889
|
+
error: "Runpod knowledge search did not respond.",
|
|
8890
|
+
hint: "Retry the same call once."
|
|
8891
|
+
}
|
|
8892
|
+
};
|
|
8893
|
+
function searchConfigured(env = process.env) {
|
|
8894
|
+
return Boolean(knowledgeSearchBase(env) && env.RUNPOD_ASSISTANT_API_KEY);
|
|
8895
|
+
}
|
|
8896
|
+
function parseSearchRequest(raw) {
|
|
8897
|
+
if (typeof raw.query !== "string" || !raw.query.trim()) {
|
|
8898
|
+
return { error: "query must be a non-empty string." };
|
|
8899
|
+
}
|
|
8900
|
+
if (raw.query.length > MAX_QUERY_CHARS) {
|
|
8901
|
+
return { error: `query exceeds ${MAX_QUERY_CHARS} characters.` };
|
|
8902
|
+
}
|
|
8903
|
+
const request = { query: raw.query };
|
|
8904
|
+
if (raw.namespaces !== void 0) {
|
|
8905
|
+
if (!Array.isArray(raw.namespaces) || raw.namespaces.length === 0 || !raw.namespaces.every(
|
|
8906
|
+
(ns) => SEARCH_NAMESPACES.includes(ns)
|
|
8907
|
+
)) {
|
|
8908
|
+
return {
|
|
8909
|
+
error: `namespaces must be a non-empty list of: ${SEARCH_NAMESPACES.join(", ")}.`
|
|
8910
|
+
};
|
|
8911
|
+
}
|
|
8912
|
+
request.namespaces = raw.namespaces;
|
|
8913
|
+
}
|
|
8914
|
+
if (raw.limit !== void 0) {
|
|
8915
|
+
if (typeof raw.limit !== "number" || !Number.isInteger(raw.limit) || raw.limit < 1 || raw.limit > MAX_SEARCH_LIMIT) {
|
|
8916
|
+
return {
|
|
8917
|
+
error: `limit must be an integer from 1 to ${MAX_SEARCH_LIMIT}.`
|
|
8918
|
+
};
|
|
8919
|
+
}
|
|
8920
|
+
request.limit = raw.limit;
|
|
8921
|
+
}
|
|
8922
|
+
return { request };
|
|
8923
|
+
}
|
|
8924
|
+
async function searchKnowledge(request, opts = {}) {
|
|
8925
|
+
const env = opts.env ?? process.env;
|
|
8926
|
+
const doFetch = opts.fetch ?? fetch;
|
|
8927
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
8928
|
+
const now = opts.now ?? Date.now;
|
|
8929
|
+
if (!searchConfigured(env)) {
|
|
8930
|
+
return {
|
|
8931
|
+
status: 503,
|
|
8932
|
+
body: { error: "Knowledge search is not configured on this server." }
|
|
8933
|
+
};
|
|
8934
|
+
}
|
|
8935
|
+
const url = `${knowledgeSearchBase(env)}/v1/search`;
|
|
8936
|
+
const init = {
|
|
8937
|
+
method: "POST",
|
|
8938
|
+
headers: {
|
|
8939
|
+
Authorization: `Bearer ${env.RUNPOD_ASSISTANT_API_KEY}`,
|
|
8940
|
+
"Content-Type": "application/json"
|
|
8941
|
+
},
|
|
8942
|
+
body: JSON.stringify({ ...request, source: "runpod-mcp" })
|
|
8943
|
+
};
|
|
8944
|
+
const startedAt = now();
|
|
8945
|
+
for (let attempt = 1; ; attempt++) {
|
|
8946
|
+
try {
|
|
8947
|
+
const res = await doFetch(url, {
|
|
8948
|
+
...init,
|
|
8949
|
+
signal: AbortSignal.timeout(ATTEMPT_TIMEOUT_MS)
|
|
8950
|
+
});
|
|
8951
|
+
if (res.ok) {
|
|
8952
|
+
const data = await res.json().catch(() => null);
|
|
8953
|
+
if (!data) {
|
|
8954
|
+
console.warn("knowledge_search_failed status=200 invalid_json");
|
|
8955
|
+
return {
|
|
8956
|
+
status: 502,
|
|
8957
|
+
body: { error: "Runpod knowledge search failed." }
|
|
8958
|
+
};
|
|
8959
|
+
}
|
|
8960
|
+
return {
|
|
8961
|
+
status: 200,
|
|
8962
|
+
body: {
|
|
8963
|
+
text: String(data.text ?? ""),
|
|
8964
|
+
totalResults: Number(data.totalResults ?? 0),
|
|
8965
|
+
failedNamespaces: Array.isArray(data.failedNamespaces) ? data.failedNamespaces : []
|
|
8966
|
+
}
|
|
8967
|
+
};
|
|
8968
|
+
}
|
|
8969
|
+
const text = await res.text();
|
|
8970
|
+
const retryable = res.status === 503 || res.status === 429 || PLATFORM_LIMIT.test(text);
|
|
8971
|
+
if (!retryable) {
|
|
8972
|
+
console.warn(`knowledge_search_failed status=${res.status}`);
|
|
8973
|
+
return res.status === 400 ? { status: 400, body: { error: errorField(text) } } : { status: 502, body: { error: "Runpod knowledge search failed." } };
|
|
8974
|
+
}
|
|
8975
|
+
} catch (error) {
|
|
8976
|
+
console.warn(
|
|
8977
|
+
`knowledge_search_unreachable ${error instanceof Error ? error.name : "error"}`
|
|
8978
|
+
);
|
|
8979
|
+
return UNREACHABLE;
|
|
8980
|
+
}
|
|
8981
|
+
const delay = Math.random() * BASE_DELAY_MS * 2 ** (attempt - 1);
|
|
8982
|
+
if (attempt >= ATTEMPTS || now() - startedAt + delay > RETRY_DEADLINE_MS) {
|
|
8983
|
+
return AT_CAPACITY;
|
|
8984
|
+
}
|
|
8985
|
+
await sleep2(delay);
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
function errorField(text) {
|
|
8989
|
+
try {
|
|
8990
|
+
const parsed = JSON.parse(text);
|
|
8991
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
8992
|
+
} catch {
|
|
8993
|
+
}
|
|
8994
|
+
return "Invalid search request.";
|
|
8995
|
+
}
|
|
8996
|
+
|
|
8997
|
+
// src/specgen/tools/search.ts
|
|
8998
|
+
function createSearchDocsTool(search) {
|
|
8999
|
+
return {
|
|
9000
|
+
name: "search-docs",
|
|
9001
|
+
annotations: readOnly,
|
|
9002
|
+
recordedArguments: ["limit"],
|
|
9003
|
+
description: 'Search Runpod documentation, curated support knowledge, the Runpod blog and runpod.io for passages that answer a question, for example "how do I attach a network volume to a Serverless endpoint". Returns ranked passages with their source URLs. Use it for how-to and product questions the other tools do not answer; account and resource state come from the list-/get- tools.',
|
|
9004
|
+
inputSchema: {
|
|
9005
|
+
type: "object",
|
|
9006
|
+
properties: {
|
|
9007
|
+
query: {
|
|
9008
|
+
type: "string",
|
|
9009
|
+
maxLength: MAX_QUERY_CHARS,
|
|
9010
|
+
description: "The question, in natural language."
|
|
9011
|
+
},
|
|
9012
|
+
namespaces: {
|
|
9013
|
+
type: "array",
|
|
9014
|
+
items: { type: "string", enum: [...SEARCH_NAMESPACES] },
|
|
9015
|
+
minItems: 1,
|
|
9016
|
+
description: "Sources to search: docs (docs.runpod.io), knowledge (curated support answers), blog, site (runpod.io pages). Default: docs, knowledge, blog."
|
|
9017
|
+
},
|
|
9018
|
+
limit: {
|
|
9019
|
+
type: "integer",
|
|
9020
|
+
minimum: 1,
|
|
9021
|
+
maximum: MAX_SEARCH_LIMIT,
|
|
9022
|
+
description: "Most passages to return. Default 8."
|
|
9023
|
+
}
|
|
9024
|
+
},
|
|
9025
|
+
required: ["query"],
|
|
9026
|
+
additionalProperties: false
|
|
9027
|
+
},
|
|
9028
|
+
handler: async (ctx, args) => {
|
|
9029
|
+
const parsed = parseSearchRequest(args);
|
|
9030
|
+
if ("error" in parsed) return badRequest(parsed.error);
|
|
9031
|
+
const outcome = await search(parsed.request, ctx.apiKey);
|
|
9032
|
+
return {
|
|
9033
|
+
ok: outcome.status === 200,
|
|
9034
|
+
status: outcome.status,
|
|
9035
|
+
payload: outcome.body
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
};
|
|
9039
|
+
}
|
|
9040
|
+
|
|
8860
9041
|
// src/specgen/ops.ts
|
|
8861
9042
|
import { createHash, randomBytes } from "crypto";
|
|
8862
9043
|
var SALT = randomBytes(16).toString("hex");
|
|
@@ -8881,6 +9062,9 @@ var curatedTools = [
|
|
|
8881
9062
|
listPublicEndpoints,
|
|
8882
9063
|
...knowledgeTools
|
|
8883
9064
|
];
|
|
9065
|
+
var responseHoldingTools = new Set(
|
|
9066
|
+
curatedTools.filter((tool) => tool.holdsResponse).map((tool) => tool.name)
|
|
9067
|
+
);
|
|
8884
9068
|
var SERVER_INSTRUCTIONS = `These tools cover the Runpod v2 REST surface: compute catalog (GPUs, CPUs, data centers, capacity), pods, serverless endpoints and jobs, templates, network volumes, container registries, billing, public endpoints, and the Hub.
|
|
8885
9069
|
|
|
8886
9070
|
Answer from live reads, as facts. Account and availability questions can only be answered from tool data: call the relevant list-/get- tool and quote the figures, names, and ids it returns verbatim. State stock and status definitively from the read you just made \u2014 never "probably" or "check later". When the user names a resource loosely ("my comfyui pod"), resolve it with a list- tool; ask only on genuine ambiguity. If nothing exists (no pods, zero spend), say exactly that \u2014 an honest empty answer is complete.
|
|
@@ -8904,9 +9088,10 @@ CONTRIBUTING BACK IS OPTIONAL. Four tools feed Runpod's agent-learning pipeline,
|
|
|
8904
9088
|
function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
8905
9089
|
const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
|
|
8906
9090
|
const caller = callerId(ctx.apiKey);
|
|
8907
|
-
const configuredCuratedTools = opts.alp ? [...curatedTools, ...createAlpTools(opts.alp)] : curatedTools;
|
|
8908
9091
|
const servedCuratedTools = [
|
|
8909
|
-
...
|
|
9092
|
+
...curatedTools,
|
|
9093
|
+
...opts.search ? [createSearchDocsTool(opts.search)] : [],
|
|
9094
|
+
...opts.alp ? createAlpTools(opts.alp) : [],
|
|
8910
9095
|
createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
|
|
8911
9096
|
];
|
|
8912
9097
|
const callShapeOnlyTools = new Set(
|
|
@@ -9531,9 +9716,12 @@ function earlyCredentialCheckSkip(req) {
|
|
|
9531
9716
|
if (credentialCheckMayBeWrongEnvironment()) return "skip_env_mismatch";
|
|
9532
9717
|
return null;
|
|
9533
9718
|
}
|
|
9534
|
-
var
|
|
9719
|
+
var callsResponseHoldingTool = (message) => {
|
|
9720
|
+
const call = CallToolRequestSchema2.safeParse(message);
|
|
9721
|
+
return call.success && responseHoldingTools.has(call.data.params.name);
|
|
9722
|
+
};
|
|
9535
9723
|
function prefersJsonResponse(messages) {
|
|
9536
|
-
return messages.length > 0 && !messages.some(
|
|
9724
|
+
return messages.length > 0 && !messages.some(callsResponseHoldingTool);
|
|
9537
9725
|
}
|
|
9538
9726
|
var DEFAULT_REQUEST_LOG_SAMPLE_RATE = 0.1;
|
|
9539
9727
|
function requestLogSampleRate(env = process.env) {
|
|
@@ -9718,6 +9906,9 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
9718
9906
|
harnessSource: "user_agent"
|
|
9719
9907
|
}
|
|
9720
9908
|
} : {},
|
|
9909
|
+
// search-docs: listed only where the deployment holds the assistant's
|
|
9910
|
+
// service key; the search runs in-process with it.
|
|
9911
|
+
...searchConfigured() ? { search: (request) => searchKnowledge(request) } : {},
|
|
9721
9912
|
...notFoundLimiter ? {
|
|
9722
9913
|
rateLimiter: notFoundLimiter.rateLimiter,
|
|
9723
9914
|
onToolResult: notFoundLimiter.onToolResult
|
|
@@ -9746,6 +9937,7 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
9746
9937
|
export {
|
|
9747
9938
|
bodyIsCheckable,
|
|
9748
9939
|
defaultCredentialChecker,
|
|
9940
|
+
extractBearerToken,
|
|
9749
9941
|
getBaseUrl,
|
|
9750
9942
|
handleMcpRequest,
|
|
9751
9943
|
parseMcpMessages,
|