reasonix 0.11.1 → 0.11.3
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/README.md +136 -4
- package/README.zh-CN.md +118 -3
- package/dist/cli/index.js +459 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +86 -10
- package/dist/index.js +159 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3134,6 +3134,68 @@ declare class SseTransport implements McpTransport {
|
|
|
3134
3134
|
private markClosed;
|
|
3135
3135
|
}
|
|
3136
3136
|
|
|
3137
|
+
/**
|
|
3138
|
+
* Streamable HTTP transport for MCP (spec version 2025-03-26).
|
|
3139
|
+
*
|
|
3140
|
+
* Wire shape (single endpoint, no separate POST URL handshake):
|
|
3141
|
+
*
|
|
3142
|
+
* 1. Client POSTs each outgoing JSON-RPC frame to the endpoint with
|
|
3143
|
+
* `Accept: application/json, text/event-stream`. The server picks
|
|
3144
|
+
* ONE of three responses:
|
|
3145
|
+
* a. `202 Accepted`, no body → notification or response
|
|
3146
|
+
* was accepted; nothing more to deliver.
|
|
3147
|
+
* b. `200 OK`, `Content-Type: application/json` → body is a
|
|
3148
|
+
* single JSON-RPC response (or batch). Connection closes.
|
|
3149
|
+
* c. `200 OK`, `Content-Type: text/event-stream` → an SSE
|
|
3150
|
+
* stream of `event: message` frames carrying responses,
|
|
3151
|
+
* server-initiated requests, and notifications. Stream may
|
|
3152
|
+
* close after the matching response or stay open longer.
|
|
3153
|
+
* 2. The server may include `Mcp-Session-Id: <opaque>` on the response
|
|
3154
|
+
* to `initialize`. Client echoes that header on every subsequent
|
|
3155
|
+
* request. A 404 on a request with a session id means the session
|
|
3156
|
+
* expired — caller must reinitialize.
|
|
3157
|
+
*
|
|
3158
|
+
* Compared to 2024-11-05 HTTP+SSE:
|
|
3159
|
+
* - No two-endpoint dance (no `event: endpoint` handshake).
|
|
3160
|
+
* - Replies arrive on the POST response, not on a separate GET stream.
|
|
3161
|
+
* - Session continuity is explicit (`Mcp-Session-Id`), not implicit.
|
|
3162
|
+
*
|
|
3163
|
+
* Not yet implemented in this transport (acceptable for v1):
|
|
3164
|
+
* - Long-lived GET stream for unsolicited server-initiated frames
|
|
3165
|
+
* (sampling requests, etc.). Most MCP servers we care about today
|
|
3166
|
+
* don't issue server-initiated requests, and POST-only handles
|
|
3167
|
+
* full request/response/notification traffic. Add when a real
|
|
3168
|
+
* server we're integrating against needs it.
|
|
3169
|
+
* - Resumability via `Last-Event-ID` on reconnect.
|
|
3170
|
+
*/
|
|
3171
|
+
|
|
3172
|
+
interface StreamableHttpTransportOptions {
|
|
3173
|
+
/** Streamable HTTP endpoint URL, e.g. `https://mcp.example.com/mcp`. */
|
|
3174
|
+
url: string;
|
|
3175
|
+
/** Extra headers sent on every request (e.g. `Authorization`). */
|
|
3176
|
+
headers?: Record<string, string>;
|
|
3177
|
+
}
|
|
3178
|
+
declare class StreamableHttpTransport implements McpTransport {
|
|
3179
|
+
private readonly url;
|
|
3180
|
+
private readonly extraHeaders;
|
|
3181
|
+
private readonly queue;
|
|
3182
|
+
private readonly waiters;
|
|
3183
|
+
private readonly controller;
|
|
3184
|
+
/** Session id minted by server on (typically) the initialize response. */
|
|
3185
|
+
private sessionId;
|
|
3186
|
+
private closed;
|
|
3187
|
+
/** Background SSE read-loops kicked off by send(); awaited on close(). */
|
|
3188
|
+
private readonly streams;
|
|
3189
|
+
constructor(opts: StreamableHttpTransportOptions);
|
|
3190
|
+
send(message: JsonRpcMessage): Promise<void>;
|
|
3191
|
+
messages(): AsyncIterableIterator<JsonRpcMessage>;
|
|
3192
|
+
close(): Promise<void>;
|
|
3193
|
+
/** Visible for tests — confirm session header round-trip. */
|
|
3194
|
+
getSessionId(): string | null;
|
|
3195
|
+
private consumeStream;
|
|
3196
|
+
private pushMessage;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3137
3199
|
/**
|
|
3138
3200
|
* Bridge: register an MCP server's tools into a Reasonix ToolRegistry.
|
|
3139
3201
|
*
|
|
@@ -3263,11 +3325,13 @@ declare function truncateForModelByTokens(s: string, maxTokens: number): string;
|
|
|
3263
3325
|
* Parse the `--mcp` CLI argument into a transport-tagged spec.
|
|
3264
3326
|
*
|
|
3265
3327
|
* Accepted forms:
|
|
3266
|
-
* "name=command args..."
|
|
3267
|
-
* "command args..."
|
|
3268
|
-
* "name=https://host/sse"
|
|
3269
|
-
* "https://host/sse"
|
|
3270
|
-
*
|
|
3328
|
+
* "name=command args..." → stdio, namespaced (tools prefixed with `name_`)
|
|
3329
|
+
* "command args..." → stdio, anonymous
|
|
3330
|
+
* "name=https://host/sse" → HTTP+SSE (2024-11-05), namespaced
|
|
3331
|
+
* "https://host/sse" → HTTP+SSE (2024-11-05), anonymous
|
|
3332
|
+
* "name=streamable+https://host/mcp" → Streamable HTTP (2025-03-26), namespaced
|
|
3333
|
+
* "streamable+https://host/mcp" → Streamable HTTP (2025-03-26), anonymous
|
|
3334
|
+
* ("http://" / "streamable+http://" also honored — useful for local dev.)
|
|
3271
3335
|
*
|
|
3272
3336
|
* The identifier regex before `=` is deliberately narrow
|
|
3273
3337
|
* (`[a-zA-Z_][a-zA-Z0-9_]*`) so Windows drive letters ("C:\\...") and
|
|
@@ -3276,9 +3340,15 @@ declare function truncateForModelByTokens(s: string, maxTokens: number): string;
|
|
|
3276
3340
|
* with `foo=...` as a bare command, they can wrap it in quotes inside the
|
|
3277
3341
|
* shell command string.
|
|
3278
3342
|
*
|
|
3279
|
-
* Transport
|
|
3280
|
-
*
|
|
3281
|
-
*
|
|
3343
|
+
* Transport selection:
|
|
3344
|
+
* - body starts with `streamable+http(s)://` → Streamable HTTP. The
|
|
3345
|
+
* `streamable+` prefix is stripped from the URL we hand the transport.
|
|
3346
|
+
* - body starts with `http(s)://` → HTTP+SSE (2024-11-05).
|
|
3347
|
+
* Default for plain http URLs to preserve back-compat with users who
|
|
3348
|
+
* already have `--mcp https://...` config entries pointed at SSE
|
|
3349
|
+
* servers; opt into Streamable HTTP explicitly.
|
|
3350
|
+
* - anything else → stdio (including ws://,
|
|
3351
|
+
* which will surface later as a spawn error).
|
|
3282
3352
|
*/
|
|
3283
3353
|
interface StdioMcpSpec {
|
|
3284
3354
|
transport: "stdio";
|
|
@@ -3295,7 +3365,13 @@ interface SseMcpSpec {
|
|
|
3295
3365
|
/** Fully qualified SSE endpoint URL. */
|
|
3296
3366
|
url: string;
|
|
3297
3367
|
}
|
|
3298
|
-
|
|
3368
|
+
interface StreamableHttpMcpSpec {
|
|
3369
|
+
transport: "streamable-http";
|
|
3370
|
+
name: string | null;
|
|
3371
|
+
/** Fully qualified Streamable HTTP endpoint URL (no `streamable+` prefix). */
|
|
3372
|
+
url: string;
|
|
3373
|
+
}
|
|
3374
|
+
type McpSpec = StdioMcpSpec | SseMcpSpec | StreamableHttpMcpSpec;
|
|
3299
3375
|
declare function parseMcpSpec(input: string): McpSpec;
|
|
3300
3376
|
|
|
3301
3377
|
/**
|
|
@@ -3795,4 +3871,4 @@ declare function aggregateUsage(records: UsageRecord[], opts?: AggregateOptions)
|
|
|
3795
3871
|
/** File-size helper for the stats header — "1.2 MB" etc. Returns "" if missing. */
|
|
3796
3872
|
declare function formatLogSize(path?: string): string;
|
|
3797
3873
|
|
|
3798
|
-
export { AT_MENTION_PATTERN, AT_PICKER_PREFIX, type AggregateOptions, AppendOnlyLog, type AppendUsageInput, type ApplyResult, type ApplyStatus, type AtMentionExpansion, type AtMentionOptions, type BranchOptions, type BranchProgress, type BranchResult, type BranchSample, type BranchSelector, type BranchSummary, type BridgeOptions, type BridgeResult, CODE_SYSTEM_PROMPT, CacheFirstLoop, type CacheFirstLoopOptions, type CallToolResult, type ChatMessage, type ChatResponse, type ChoiceOption, ChoiceRequestedError, type ChoiceToolOptions, DEFAULT_AT_MENTION_MAX_BYTES, DEFAULT_MAX_RESULT_CHARS, DEFAULT_MAX_RESULT_TOKENS, DEFAULT_PICKER_IGNORE_DIRS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EditBlock, type EditSnapshot, type EventRole, type FileWithStats, type FilesystemToolsOptions, type FlattenDecision, type FlattenOptions, type GetLatestVersionOptions, type GetPromptResult, HOOK_EVENTS, HOOK_SETTINGS_DIRNAME, HOOK_SETTINGS_FILENAME, type HarvestOptions, type HookConfig, type HookEvent, type HookOutcome, type HookPayload, type HookReport, type HookScope, type HookSettings, type HookSpawnInput, type HookSpawnResult, type HookSpawner, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type InspectionReport, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, LATEST_CACHE_TTL_MS, LATEST_FETCH_TIMEOUT_MS, type ListFilesOptions, type ListPromptsResult, type ListResourcesResult, type ListToolsResult, type LoadHookSettingsOptions, type LoopEvent, MCP_PROTOCOL_VERSION, MEMORY_INDEX_FILE, MEMORY_INDEX_MAX_CHARS, McpClient, type McpClientOptions, type McpContentBlock, type McpProgressHandler, type McpProgressInfo, type McpPrompt, type McpPromptArgument, type McpPromptMessage, type McpPromptResourceBlock, type McpResource, type McpResourceContents, type McpResourceContentsBlob, type McpResourceContentsText, type McpSpec, type McpTool, type McpToolSchema, type McpTransport, type MemoryEntry, type MemoryScope, MemoryStore, type MemoryStoreOptions, type MemoryToolsOptions, type MemoryType, type WriteInput as MemoryWriteInput, NeedsConfirmationError, PROJECT_MEMORY_FILE, PROJECT_MEMORY_MAX_CHARS, type PageContent, type PickerCandidate, PlanCheckpointError, PlanProposedError, PlanRevisionProposedError, type PlanStep, type PlanStepRisk, type PlanToolOptions, type ProgressNotificationParams, type ProjectMemory, type RankPickerOptions, type ReadResourceResult, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type ResolvedHook, type RetryInfo, type RetryOptions, type Role, type RunCommandResult, type RunHooksOptions, type ScavengeOptions, type ScavengeResult, type SearchResult, type SectionResult, type SessionInfo, SessionStats, type SessionSummary, type ShellToolsOptions, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, type StepCompletion, StormBreaker, type StreamChunk, type SubagentEvent, type SubagentSink, type SubagentToolOptions, type ToolCall, type ToolCallContext, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, USER_MEMORY_DIR, Usage, type UsageAggregate, type UsageBucket, type UsageRecord, VERSION, VolatileScratch, type WebFetchOptions, type WebSearchOptions, type WebToolsOptions, aggregateBranchUsage, aggregateUsage, analyzeSchema, appendSessionMessage, appendUsage, applyEditBlock, applyEditBlocks, applyMemoryStack, applyProjectMemory, applyUserMemory, bridgeMcpTools, bucketCacheHitRatio, bucketSavingsFraction, claudeEquivalentCost, codeSystemPrompt, compareVersions, computeReplayStats, costUsd, decideOutcome, defaultConfigPath, defaultSelector, defaultUsageLogPath, deleteSession, detectAtPicker, detectShellOperator, diffTranscripts, emptyPlanState, expandAtMentions, fetchWithRetry, fixToolCallPairing, flattenMcpResult, flattenSchema, forkRegistryExcluding, formatCommandResult, formatHookOutcomeMessage, formatLogSize, formatLoopError, formatSearchResults, getLatestVersion, globalSettingsPath, harvest, healLoadedMessages, healLoadedMessagesByTokens, htmlToText, injectPowerShellUtf8, inputCostUsd, inspectMcpServer, isAllowed, isJsonRpcError, isNpxInstall, isPlanStateEmpty, isPlausibleKey, listFilesSync, listFilesWithStatsSync, listSessions, loadApiKey, loadDotenv, loadHooks, loadSessionMessages, matchesTool, memoryEnabled, nestArguments, openTranscriptFile, outputCostUsd, parseEditBlocks, parseMcpSpec, parseMojeekResults, parseTranscript, prepareSpawn, projectHash, projectSettingsPath, quoteForCmdExe, rankPickerCandidates, readConfig, readProjectMemory, readTranscript, readUsageLog, recordFromLoopEvent, redactKey, registerChoiceTool, registerFilesystemTools, registerMemoryTools, registerPlanTool, registerShellTools, registerSubagentTool, registerWebTools, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, resolveExecutable, restoreSnapshots, runBranches, runCommand, runHooks, sanitizeMemoryName, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, snapshotBeforeEdits, stripHallucinatedToolMarkup, tokenizeCommand, truncateForModel, truncateForModelByTokens, webFetch, webSearch, withUtf8Codepage, writeConfig, writeMeta, writeRecord };
|
|
3874
|
+
export { AT_MENTION_PATTERN, AT_PICKER_PREFIX, type AggregateOptions, AppendOnlyLog, type AppendUsageInput, type ApplyResult, type ApplyStatus, type AtMentionExpansion, type AtMentionOptions, type BranchOptions, type BranchProgress, type BranchResult, type BranchSample, type BranchSelector, type BranchSummary, type BridgeOptions, type BridgeResult, CODE_SYSTEM_PROMPT, CacheFirstLoop, type CacheFirstLoopOptions, type CallToolResult, type ChatMessage, type ChatResponse, type ChoiceOption, ChoiceRequestedError, type ChoiceToolOptions, DEFAULT_AT_MENTION_MAX_BYTES, DEFAULT_MAX_RESULT_CHARS, DEFAULT_MAX_RESULT_TOKENS, DEFAULT_PICKER_IGNORE_DIRS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EditBlock, type EditSnapshot, type EventRole, type FileWithStats, type FilesystemToolsOptions, type FlattenDecision, type FlattenOptions, type GetLatestVersionOptions, type GetPromptResult, HOOK_EVENTS, HOOK_SETTINGS_DIRNAME, HOOK_SETTINGS_FILENAME, type HarvestOptions, type HookConfig, type HookEvent, type HookOutcome, type HookPayload, type HookReport, type HookScope, type HookSettings, type HookSpawnInput, type HookSpawnResult, type HookSpawner, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type InspectionReport, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, LATEST_CACHE_TTL_MS, LATEST_FETCH_TIMEOUT_MS, type ListFilesOptions, type ListPromptsResult, type ListResourcesResult, type ListToolsResult, type LoadHookSettingsOptions, type LoopEvent, MCP_PROTOCOL_VERSION, MEMORY_INDEX_FILE, MEMORY_INDEX_MAX_CHARS, McpClient, type McpClientOptions, type McpContentBlock, type McpProgressHandler, type McpProgressInfo, type McpPrompt, type McpPromptArgument, type McpPromptMessage, type McpPromptResourceBlock, type McpResource, type McpResourceContents, type McpResourceContentsBlob, type McpResourceContentsText, type McpSpec, type McpTool, type McpToolSchema, type McpTransport, type MemoryEntry, type MemoryScope, MemoryStore, type MemoryStoreOptions, type MemoryToolsOptions, type MemoryType, type WriteInput as MemoryWriteInput, NeedsConfirmationError, PROJECT_MEMORY_FILE, PROJECT_MEMORY_MAX_CHARS, type PageContent, type PickerCandidate, PlanCheckpointError, PlanProposedError, PlanRevisionProposedError, type PlanStep, type PlanStepRisk, type PlanToolOptions, type ProgressNotificationParams, type ProjectMemory, type RankPickerOptions, type ReadResourceResult, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type ResolvedHook, type RetryInfo, type RetryOptions, type Role, type RunCommandResult, type RunHooksOptions, type ScavengeOptions, type ScavengeResult, type SearchResult, type SectionResult, type SessionInfo, SessionStats, type SessionSummary, type ShellToolsOptions, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, type StepCompletion, StormBreaker, type StreamChunk, type StreamableHttpMcpSpec, StreamableHttpTransport, type StreamableHttpTransportOptions, type SubagentEvent, type SubagentSink, type SubagentToolOptions, type ToolCall, type ToolCallContext, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, USER_MEMORY_DIR, Usage, type UsageAggregate, type UsageBucket, type UsageRecord, VERSION, VolatileScratch, type WebFetchOptions, type WebSearchOptions, type WebToolsOptions, aggregateBranchUsage, aggregateUsage, analyzeSchema, appendSessionMessage, appendUsage, applyEditBlock, applyEditBlocks, applyMemoryStack, applyProjectMemory, applyUserMemory, bridgeMcpTools, bucketCacheHitRatio, bucketSavingsFraction, claudeEquivalentCost, codeSystemPrompt, compareVersions, computeReplayStats, costUsd, decideOutcome, defaultConfigPath, defaultSelector, defaultUsageLogPath, deleteSession, detectAtPicker, detectShellOperator, diffTranscripts, emptyPlanState, expandAtMentions, fetchWithRetry, fixToolCallPairing, flattenMcpResult, flattenSchema, forkRegistryExcluding, formatCommandResult, formatHookOutcomeMessage, formatLogSize, formatLoopError, formatSearchResults, getLatestVersion, globalSettingsPath, harvest, healLoadedMessages, healLoadedMessagesByTokens, htmlToText, injectPowerShellUtf8, inputCostUsd, inspectMcpServer, isAllowed, isJsonRpcError, isNpxInstall, isPlanStateEmpty, isPlausibleKey, listFilesSync, listFilesWithStatsSync, listSessions, loadApiKey, loadDotenv, loadHooks, loadSessionMessages, matchesTool, memoryEnabled, nestArguments, openTranscriptFile, outputCostUsd, parseEditBlocks, parseMcpSpec, parseMojeekResults, parseTranscript, prepareSpawn, projectHash, projectSettingsPath, quoteForCmdExe, rankPickerCandidates, readConfig, readProjectMemory, readTranscript, readUsageLog, recordFromLoopEvent, redactKey, registerChoiceTool, registerFilesystemTools, registerMemoryTools, registerPlanTool, registerShellTools, registerSubagentTool, registerWebTools, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, resolveExecutable, restoreSnapshots, runBranches, runCommand, runHooks, sanitizeMemoryName, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, snapshotBeforeEdits, stripHallucinatedToolMarkup, tokenizeCommand, truncateForModel, truncateForModelByTokens, webFetch, webSearch, withUtf8Codepage, writeConfig, writeMeta, writeRecord };
|
package/dist/index.js
CHANGED
|
@@ -7325,6 +7325,159 @@ var SseTransport = class {
|
|
|
7325
7325
|
}
|
|
7326
7326
|
};
|
|
7327
7327
|
|
|
7328
|
+
// src/mcp/streamable-http.ts
|
|
7329
|
+
import { createParser as createParser3 } from "eventsource-parser";
|
|
7330
|
+
var SESSION_HEADER = "mcp-session-id";
|
|
7331
|
+
var StreamableHttpTransport = class {
|
|
7332
|
+
url;
|
|
7333
|
+
extraHeaders;
|
|
7334
|
+
queue = [];
|
|
7335
|
+
waiters = [];
|
|
7336
|
+
controller = new AbortController();
|
|
7337
|
+
/** Session id minted by server on (typically) the initialize response. */
|
|
7338
|
+
sessionId = null;
|
|
7339
|
+
closed = false;
|
|
7340
|
+
/** Background SSE read-loops kicked off by send(); awaited on close(). */
|
|
7341
|
+
streams = /* @__PURE__ */ new Set();
|
|
7342
|
+
constructor(opts) {
|
|
7343
|
+
this.url = opts.url;
|
|
7344
|
+
this.extraHeaders = opts.headers ?? {};
|
|
7345
|
+
}
|
|
7346
|
+
async send(message) {
|
|
7347
|
+
if (this.closed) throw new Error("MCP Streamable HTTP transport is closed");
|
|
7348
|
+
const headers = {
|
|
7349
|
+
"content-type": "application/json",
|
|
7350
|
+
// Both accepted — server picks. application/json first signals a
|
|
7351
|
+
// mild preference for the simpler shape when the response is a
|
|
7352
|
+
// single message.
|
|
7353
|
+
accept: "application/json, text/event-stream",
|
|
7354
|
+
...this.extraHeaders
|
|
7355
|
+
};
|
|
7356
|
+
if (this.sessionId !== null) headers["mcp-session-id"] = this.sessionId;
|
|
7357
|
+
let res;
|
|
7358
|
+
try {
|
|
7359
|
+
res = await fetch(this.url, {
|
|
7360
|
+
method: "POST",
|
|
7361
|
+
headers,
|
|
7362
|
+
body: JSON.stringify(message),
|
|
7363
|
+
signal: this.controller.signal
|
|
7364
|
+
});
|
|
7365
|
+
} catch (err) {
|
|
7366
|
+
throw new Error(`MCP Streamable HTTP POST ${this.url} failed: ${err.message}`);
|
|
7367
|
+
}
|
|
7368
|
+
const serverSessionId = res.headers.get(SESSION_HEADER);
|
|
7369
|
+
if (serverSessionId && this.sessionId === null) {
|
|
7370
|
+
this.sessionId = serverSessionId;
|
|
7371
|
+
}
|
|
7372
|
+
if (res.status === 404 && this.sessionId !== null) {
|
|
7373
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7374
|
+
throw new Error(
|
|
7375
|
+
`MCP Streamable HTTP session expired (server returned 404 with Mcp-Session-Id "${this.sessionId}"). Reinitialize the client.`
|
|
7376
|
+
);
|
|
7377
|
+
}
|
|
7378
|
+
if (!res.ok) {
|
|
7379
|
+
const body = await res.text().catch(() => "");
|
|
7380
|
+
throw new Error(
|
|
7381
|
+
`MCP Streamable HTTP POST ${this.url} \u2192 ${res.status} ${res.statusText}${body ? `: ${body}` : ""}`
|
|
7382
|
+
);
|
|
7383
|
+
}
|
|
7384
|
+
if (res.status === 202) {
|
|
7385
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7386
|
+
return;
|
|
7387
|
+
}
|
|
7388
|
+
const ct = (res.headers.get("content-type") ?? "").toLowerCase();
|
|
7389
|
+
if (ct.includes("application/json")) {
|
|
7390
|
+
let parsed;
|
|
7391
|
+
try {
|
|
7392
|
+
parsed = await res.json();
|
|
7393
|
+
} catch (err) {
|
|
7394
|
+
throw new Error(`MCP Streamable HTTP body wasn't valid JSON: ${err.message}`);
|
|
7395
|
+
}
|
|
7396
|
+
if (Array.isArray(parsed)) {
|
|
7397
|
+
for (const item of parsed) this.pushMessage(item);
|
|
7398
|
+
} else {
|
|
7399
|
+
this.pushMessage(parsed);
|
|
7400
|
+
}
|
|
7401
|
+
return;
|
|
7402
|
+
}
|
|
7403
|
+
if (ct.includes("text/event-stream")) {
|
|
7404
|
+
if (!res.body) {
|
|
7405
|
+
throw new Error("MCP Streamable HTTP SSE response had no body");
|
|
7406
|
+
}
|
|
7407
|
+
const stream = this.consumeStream(res.body);
|
|
7408
|
+
this.streams.add(stream);
|
|
7409
|
+
stream.finally(() => this.streams.delete(stream));
|
|
7410
|
+
return;
|
|
7411
|
+
}
|
|
7412
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7413
|
+
}
|
|
7414
|
+
async *messages() {
|
|
7415
|
+
while (true) {
|
|
7416
|
+
if (this.queue.length > 0) {
|
|
7417
|
+
yield this.queue.shift();
|
|
7418
|
+
continue;
|
|
7419
|
+
}
|
|
7420
|
+
if (this.closed) return;
|
|
7421
|
+
const next = await new Promise((resolve9) => {
|
|
7422
|
+
this.waiters.push(resolve9);
|
|
7423
|
+
});
|
|
7424
|
+
if (next === null) return;
|
|
7425
|
+
yield next;
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
async close() {
|
|
7429
|
+
if (this.closed) return;
|
|
7430
|
+
this.closed = true;
|
|
7431
|
+
while (this.waiters.length > 0) this.waiters.shift()(null);
|
|
7432
|
+
try {
|
|
7433
|
+
this.controller.abort();
|
|
7434
|
+
} catch {
|
|
7435
|
+
}
|
|
7436
|
+
await Promise.allSettled(Array.from(this.streams));
|
|
7437
|
+
}
|
|
7438
|
+
/** Visible for tests — confirm session header round-trip. */
|
|
7439
|
+
getSessionId() {
|
|
7440
|
+
return this.sessionId;
|
|
7441
|
+
}
|
|
7442
|
+
// ---------- internals ----------
|
|
7443
|
+
async consumeStream(body) {
|
|
7444
|
+
const parser = createParser3({
|
|
7445
|
+
onEvent: (ev) => {
|
|
7446
|
+
const type = ev.event ?? "message";
|
|
7447
|
+
if (type !== "message") return;
|
|
7448
|
+
try {
|
|
7449
|
+
const parsed = JSON.parse(ev.data);
|
|
7450
|
+
this.pushMessage(parsed);
|
|
7451
|
+
} catch {
|
|
7452
|
+
}
|
|
7453
|
+
}
|
|
7454
|
+
});
|
|
7455
|
+
const decoder = new TextDecoder();
|
|
7456
|
+
try {
|
|
7457
|
+
for await (const chunk of body) {
|
|
7458
|
+
if (this.closed) break;
|
|
7459
|
+
parser.feed(decoder.decode(chunk, { stream: true }));
|
|
7460
|
+
}
|
|
7461
|
+
} catch (err) {
|
|
7462
|
+
if (!this.closed) {
|
|
7463
|
+
this.pushMessage({
|
|
7464
|
+
jsonrpc: "2.0",
|
|
7465
|
+
id: null,
|
|
7466
|
+
error: {
|
|
7467
|
+
code: -32e3,
|
|
7468
|
+
message: `Streamable HTTP stream error: ${err.message}`
|
|
7469
|
+
}
|
|
7470
|
+
});
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
}
|
|
7474
|
+
pushMessage(msg) {
|
|
7475
|
+
const waiter = this.waiters.shift();
|
|
7476
|
+
if (waiter) waiter(msg);
|
|
7477
|
+
else this.queue.push(msg);
|
|
7478
|
+
}
|
|
7479
|
+
};
|
|
7480
|
+
|
|
7328
7481
|
// src/mcp/shell-split.ts
|
|
7329
7482
|
function shellSplit(input) {
|
|
7330
7483
|
const tokens = [];
|
|
@@ -7377,6 +7530,7 @@ function shellSplit(input) {
|
|
|
7377
7530
|
// src/mcp/spec.ts
|
|
7378
7531
|
var NAME_PREFIX = /^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/;
|
|
7379
7532
|
var HTTP_URL = /^https?:\/\//i;
|
|
7533
|
+
var STREAMABLE_PREFIX = /^streamable\+(https?:\/\/.+)$/i;
|
|
7380
7534
|
function parseMcpSpec(input) {
|
|
7381
7535
|
const trimmed = input.trim();
|
|
7382
7536
|
if (!trimmed) {
|
|
@@ -7388,6 +7542,10 @@ function parseMcpSpec(input) {
|
|
|
7388
7542
|
if (!body) {
|
|
7389
7543
|
throw new Error(`MCP spec has name but no command: ${input}`);
|
|
7390
7544
|
}
|
|
7545
|
+
const streamMatch = STREAMABLE_PREFIX.exec(body);
|
|
7546
|
+
if (streamMatch) {
|
|
7547
|
+
return { transport: "streamable-http", name, url: streamMatch[1] };
|
|
7548
|
+
}
|
|
7391
7549
|
if (HTTP_URL.test(body)) {
|
|
7392
7550
|
return { transport: "sse", name, url: body };
|
|
7393
7551
|
}
|
|
@@ -8112,6 +8270,7 @@ export {
|
|
|
8112
8270
|
SseTransport,
|
|
8113
8271
|
StdioTransport,
|
|
8114
8272
|
StormBreaker,
|
|
8273
|
+
StreamableHttpTransport,
|
|
8115
8274
|
ToolCallRepair,
|
|
8116
8275
|
ToolRegistry,
|
|
8117
8276
|
USER_MEMORY_DIR,
|