reasonix 0.4.3 → 0.4.6

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/dist/index.d.ts CHANGED
@@ -366,7 +366,7 @@ declare class ToolCallRepair {
366
366
  private readonly storm;
367
367
  private readonly opts;
368
368
  constructor(opts: ToolCallRepairOptions);
369
- process(declaredCalls: ToolCall[], reasoningContent: string | null): {
369
+ process(declaredCalls: ToolCall[], reasoningContent: string | null, content?: string | null): {
370
370
  calls: ToolCall[];
371
371
  report: RepairReport;
372
372
  };
@@ -901,8 +901,9 @@ declare function renderMarkdown(report: DiffReport): string;
901
901
  * insulated as long as we keep up with the spec itself.
902
902
  *
903
903
  * Spec reference: https://spec.modelcontextprotocol.io/ (2024-11-05 draft
904
- * at time of writing). Only the subset Reasonix consumes is modeled here —
905
- * tools list/call + init handshake. Resources and prompts are deferred.
904
+ * at time of writing). Reasonix models the subset it consumes: tools
905
+ * list/call, resources list/read, prompts list/get, plus the init
906
+ * handshake. Sampling and progress notifications remain deferred.
906
907
  *
907
908
  * Transport note: the wire format for stdio MCP is **newline-delimited
908
909
  * JSON** (NDJSON), not the LSP-style Content-Length header framing that
@@ -989,6 +990,78 @@ interface CallToolResult {
989
990
  /** True = tool raised an error; the content describes it. */
990
991
  isError?: boolean;
991
992
  }
993
+ /**
994
+ * A resource the server can expose — think "file the model can read."
995
+ * The URI is opaque to the client: servers may use `file://`, custom
996
+ * schemes, or bare strings. Reasonix doesn't interpret them.
997
+ */
998
+ interface McpResource {
999
+ uri: string;
1000
+ name: string;
1001
+ description?: string;
1002
+ /** Hint for the content type (e.g. "text/markdown"). Purely informational. */
1003
+ mimeType?: string;
1004
+ }
1005
+ interface ListResourcesResult {
1006
+ resources: McpResource[];
1007
+ nextCursor?: string;
1008
+ }
1009
+ /**
1010
+ * One resource can return multiple content blobs (e.g. the file + a
1011
+ * side-car). `text` is the common case for UTF-8 content; `blob` is
1012
+ * base64-encoded bytes for binary content. Servers populate exactly
1013
+ * one of the two for each entry.
1014
+ */
1015
+ interface McpResourceContentsText {
1016
+ uri: string;
1017
+ mimeType?: string;
1018
+ text: string;
1019
+ }
1020
+ interface McpResourceContentsBlob {
1021
+ uri: string;
1022
+ mimeType?: string;
1023
+ blob: string;
1024
+ }
1025
+ type McpResourceContents = McpResourceContentsText | McpResourceContentsBlob;
1026
+ interface ReadResourceResult {
1027
+ contents: McpResourceContents[];
1028
+ }
1029
+ /**
1030
+ * A parameterizable prompt template the server exposes. Clients fetch
1031
+ * it with `prompts/get` and pass the result to the model as-is.
1032
+ */
1033
+ interface McpPromptArgument {
1034
+ name: string;
1035
+ description?: string;
1036
+ required?: boolean;
1037
+ }
1038
+ interface McpPrompt {
1039
+ name: string;
1040
+ description?: string;
1041
+ arguments?: McpPromptArgument[];
1042
+ }
1043
+ interface ListPromptsResult {
1044
+ prompts: McpPrompt[];
1045
+ nextCursor?: string;
1046
+ }
1047
+ /**
1048
+ * MCP prompt messages are modeled after chat completions: role + content.
1049
+ * Content can be a text block OR (per the spec) a resource/image block;
1050
+ * Reasonix cares about text in v1, but surfaces the raw array so callers
1051
+ * can render other kinds if they need to.
1052
+ */
1053
+ interface McpPromptMessage {
1054
+ role: "user" | "assistant";
1055
+ content: McpContentBlock | McpPromptResourceBlock;
1056
+ }
1057
+ interface McpPromptResourceBlock {
1058
+ type: "resource";
1059
+ resource: McpResourceContents;
1060
+ }
1061
+ interface GetPromptResult {
1062
+ description?: string;
1063
+ messages: McpPromptMessage[];
1064
+ }
992
1065
  /** Current MCP protocol version Reasonix is coded against. */
993
1066
  declare const MCP_PROTOCOL_VERSION = "2024-11-05";
994
1067
  /** Type guard — success vs error response. */
@@ -1079,9 +1152,18 @@ declare class McpClient {
1079
1152
  private readerStarted;
1080
1153
  private initialized;
1081
1154
  private _serverCapabilities;
1155
+ private _serverInfo;
1156
+ private _protocolVersion;
1157
+ private _instructions;
1082
1158
  constructor(opts: McpClientOptions);
1083
1159
  /** Server's advertised capabilities, available after initialize(). */
1084
1160
  get serverCapabilities(): InitializeResult["capabilities"];
1161
+ /** Server's self-reported name + version, available after initialize(). */
1162
+ get serverInfo(): InitializeResult["serverInfo"];
1163
+ /** Protocol version the server agreed to during the handshake. */
1164
+ get protocolVersion(): string;
1165
+ /** Optional free-form instructions the server provides at handshake. */
1166
+ get serverInstructions(): string | undefined;
1085
1167
  /**
1086
1168
  * Complete the initialize → initialized handshake. Must be called
1087
1169
  * before any other method (otherwise compliant servers reject).
@@ -1091,6 +1173,24 @@ declare class McpClient {
1091
1173
  listTools(): Promise<ListToolsResult>;
1092
1174
  /** Invoke a tool by name. Returns the raw MCP result (caller unwraps content). */
1093
1175
  callTool(name: string, args?: Record<string, unknown>): Promise<CallToolResult>;
1176
+ /**
1177
+ * List resources the server exposes. Supports a pagination cursor;
1178
+ * callers interested in the full set should loop on `nextCursor`.
1179
+ * Servers that don't support resources respond with method-not-found
1180
+ * (−32601) — we surface that as a thrown Error so callers can gate
1181
+ * on the `serverCapabilities.resources` field first.
1182
+ */
1183
+ listResources(cursor?: string): Promise<ListResourcesResult>;
1184
+ /** Read the contents of a resource by URI. */
1185
+ readResource(uri: string): Promise<ReadResourceResult>;
1186
+ /** List prompt templates the server exposes. */
1187
+ listPrompts(cursor?: string): Promise<ListPromptsResult>;
1188
+ /**
1189
+ * Fetch a rendered prompt by name. `args` supplies values for any
1190
+ * required template arguments; the server validates. Returns messages
1191
+ * ready to prepend to the model's input.
1192
+ */
1193
+ getPrompt(name: string, args?: Record<string, string>): Promise<GetPromptResult>;
1094
1194
  /** Close the transport and reject any outstanding requests. */
1095
1195
  close(): Promise<void>;
1096
1196
  private assertInitialized;
@@ -1279,6 +1379,44 @@ interface SseMcpSpec {
1279
1379
  type McpSpec = StdioMcpSpec | SseMcpSpec;
1280
1380
  declare function parseMcpSpec(input: string): McpSpec;
1281
1381
 
1382
+ /**
1383
+ * Gather a full inspection report from an initialized MCP client:
1384
+ * server info, capabilities, tools, resources, prompts. Methods the
1385
+ * server doesn't support come back as `{ supported: false }` instead
1386
+ * of throwing, so a CLI or UI can render a consistent "what this
1387
+ * server exposes" summary even against minimal implementations.
1388
+ *
1389
+ * Pure with respect to I/O beyond the passed-in client — the CLI
1390
+ * layer owns argument parsing, connection setup, and printing.
1391
+ */
1392
+
1393
+ interface InspectionReport {
1394
+ protocolVersion: string;
1395
+ serverInfo: {
1396
+ name: string;
1397
+ version: string;
1398
+ };
1399
+ capabilities: Record<string, unknown>;
1400
+ instructions?: string;
1401
+ tools: SectionResult<McpTool>;
1402
+ resources: SectionResult<McpResource>;
1403
+ prompts: SectionResult<McpPrompt>;
1404
+ }
1405
+ type SectionResult<T> = {
1406
+ supported: true;
1407
+ items: T[];
1408
+ } | {
1409
+ supported: false;
1410
+ reason: string;
1411
+ };
1412
+ /**
1413
+ * Run an inspection against a **already-initialized** client. Caller
1414
+ * is responsible for `initialize()` before this and `close()` after.
1415
+ * We keep this pure so unit tests can feed in a FakeMcpTransport and
1416
+ * verify the aggregate shape without spinning up a real process.
1417
+ */
1418
+ declare function inspectMcpServer(client: McpClient): Promise<InspectionReport>;
1419
+
1282
1420
  /**
1283
1421
  * Aider-style SEARCH/REPLACE edit blocks.
1284
1422
  *
@@ -1441,4 +1579,4 @@ declare function redactKey(key: string): string;
1441
1579
 
1442
1580
  declare const VERSION = "0.4.3";
1443
1581
 
1444
- export { AppendOnlyLog, type ApplyResult, type ApplyStatus, 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, DEFAULT_MAX_RESULT_CHARS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EditBlock, type EditSnapshot, type EventRole, type FlattenDecision, type FlattenOptions, type HarvestOptions, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, type ListToolsResult, type LoopEvent, MCP_PROTOCOL_VERSION, McpClient, type McpClientOptions, type McpContentBlock, type McpSpec, type McpTool, type McpToolSchema, type McpTransport, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, type SessionInfo, SessionStats, type SessionSummary, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, aggregateBranchUsage, analyzeSchema, appendSessionMessage, applyEditBlock, applyEditBlocks, bridgeMcpTools, claudeEquivalentCost, codeSystemPrompt, computeReplayStats, costUsd, defaultConfigPath, defaultSelector, deleteSession, diffTranscripts, emptyPlanState, fetchWithRetry, flattenMcpResult, flattenSchema, formatLoopError, harvest, healLoadedMessages, isJsonRpcError, isPlanStateEmpty, isPlausibleKey, listSessions, loadApiKey, loadDotenv, loadSessionMessages, nestArguments, openTranscriptFile, parseEditBlocks, parseMcpSpec, parseTranscript, readConfig, readTranscript, recordFromLoopEvent, redactKey, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, restoreSnapshots, runBranches, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, snapshotBeforeEdits, stripHallucinatedToolMarkup, truncateForModel, writeConfig, writeMeta, writeRecord };
1582
+ export { AppendOnlyLog, type ApplyResult, type ApplyStatus, 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, DEFAULT_MAX_RESULT_CHARS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EditBlock, type EditSnapshot, type EventRole, type FlattenDecision, type FlattenOptions, type GetPromptResult, type HarvestOptions, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type InspectionReport, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, type ListPromptsResult, type ListResourcesResult, type ListToolsResult, type LoopEvent, MCP_PROTOCOL_VERSION, McpClient, type McpClientOptions, type McpContentBlock, 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 ReadResourceResult, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, type SectionResult, type SessionInfo, SessionStats, type SessionSummary, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, aggregateBranchUsage, analyzeSchema, appendSessionMessage, applyEditBlock, applyEditBlocks, bridgeMcpTools, claudeEquivalentCost, codeSystemPrompt, computeReplayStats, costUsd, defaultConfigPath, defaultSelector, deleteSession, diffTranscripts, emptyPlanState, fetchWithRetry, flattenMcpResult, flattenSchema, formatLoopError, harvest, healLoadedMessages, inspectMcpServer, isJsonRpcError, isPlanStateEmpty, isPlausibleKey, listSessions, loadApiKey, loadDotenv, loadSessionMessages, nestArguments, openTranscriptFile, parseEditBlocks, parseMcpSpec, parseTranscript, readConfig, readTranscript, recordFromLoopEvent, redactKey, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, restoreSnapshots, runBranches, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, snapshotBeforeEdits, stripHallucinatedToolMarkup, truncateForModel, writeConfig, writeMeta, writeRecord };
package/dist/index.js CHANGED
@@ -673,7 +673,19 @@ function scavengeToolCalls(reasoningContent, opts) {
673
673
  const max = opts.maxCalls ?? 4;
674
674
  const notes = [];
675
675
  const out = [];
676
- for (const candidate of iterateJsonObjects(reasoningContent)) {
676
+ for (const invoke of iterateDsmlInvokes(reasoningContent)) {
677
+ if (out.length >= max) break;
678
+ if (!opts.allowedNames.has(invoke.name)) continue;
679
+ out.push({
680
+ function: {
681
+ name: invoke.name,
682
+ arguments: JSON.stringify(invoke.args)
683
+ }
684
+ });
685
+ notes.push(`scavenged DSML call: ${invoke.name}`);
686
+ }
687
+ const nonDsml = stripDsmlBlocks(reasoningContent);
688
+ for (const candidate of iterateJsonObjects(nonDsml)) {
677
689
  if (out.length >= max) break;
678
690
  const call = coerceToToolCall(candidate, opts.allowedNames);
679
691
  if (call) {
@@ -683,6 +695,40 @@ function scavengeToolCalls(reasoningContent, opts) {
683
695
  }
684
696
  return { calls: out, notes };
685
697
  }
698
+ function stripDsmlBlocks(text) {
699
+ let out = text;
700
+ out = out.replace(/<[||]DSML[||]function_calls>[\s\S]*?<\/?[||]DSML[||]function_calls>/g, "");
701
+ out = out.replace(/<[||]DSML[||]invoke\s+[^>]*>[\s\S]*?<\/[||]DSML[||]invoke>/g, "");
702
+ return out;
703
+ }
704
+ function* iterateDsmlInvokes(text) {
705
+ const INVOKE_RE = /<[||]DSML[||]invoke\s+name="([^"]+)">([\s\S]*?)<\/[||]DSML[||]invoke>/g;
706
+ for (const match of text.matchAll(INVOKE_RE)) {
707
+ const name = match[1];
708
+ const body = match[2];
709
+ if (!name || body === void 0) continue;
710
+ yield { name, args: parseDsmlParameters(body) };
711
+ }
712
+ }
713
+ function parseDsmlParameters(body) {
714
+ const PARAM_RE = /<[||]DSML[||]parameter\s+name="([^"]+)"(?:\s+string="(true|false)")?\s*>([\s\S]*?)<\/[||]DSML[||]parameter>/g;
715
+ const args = {};
716
+ for (const m of body.matchAll(PARAM_RE)) {
717
+ const key = m[1];
718
+ const stringFlag = m[2];
719
+ const raw = (m[3] ?? "").trim();
720
+ if (!key) continue;
721
+ if (stringFlag === "false") {
722
+ try {
723
+ args[key] = JSON.parse(raw);
724
+ continue;
725
+ } catch {
726
+ }
727
+ }
728
+ args[key] = raw;
729
+ }
730
+ return args;
731
+ }
686
732
  function* iterateJsonObjects(text) {
687
733
  for (let i = 0; i < text.length; i++) {
688
734
  if (text[i] !== "{") continue;
@@ -868,14 +914,15 @@ var ToolCallRepair = class {
868
914
  this.opts = opts;
869
915
  this.storm = new StormBreaker(opts.stormWindow ?? 6, opts.stormThreshold ?? 3);
870
916
  }
871
- process(declaredCalls, reasoningContent) {
917
+ process(declaredCalls, reasoningContent, content = null) {
872
918
  const report = {
873
919
  scavenged: 0,
874
920
  truncationsFixed: 0,
875
921
  stormsBroken: 0,
876
922
  notes: []
877
923
  };
878
- const scavenged = scavengeToolCalls(reasoningContent, {
924
+ const combined = [reasoningContent ?? "", content ?? ""].filter(Boolean).join("\n");
925
+ const scavenged = scavengeToolCalls(combined || null, {
879
926
  allowedNames: this.opts.allowedToolNames,
880
927
  maxCalls: this.opts.maxScavenge ?? 4
881
928
  });
@@ -1453,7 +1500,8 @@ var CacheFirstLoop = class {
1453
1500
  const planState = preHarvestedPlanState ? preHarvestedPlanState : this.harvestEnabled ? await harvest(reasoningContent || null, this.client, this.harvestOptions) : emptyPlanState();
1454
1501
  const { calls: repairedCalls, report } = this.repair.process(
1455
1502
  toolCalls,
1456
- reasoningContent || null
1503
+ reasoningContent || null,
1504
+ assistantContent || null
1457
1505
  );
1458
1506
  this.appendAndPersist(this.assistantMessage(assistantContent, repairedCalls));
1459
1507
  yield {
@@ -2148,6 +2196,9 @@ var McpClient = class {
2148
2196
  readerStarted = false;
2149
2197
  initialized = false;
2150
2198
  _serverCapabilities = {};
2199
+ _serverInfo = { name: "", version: "" };
2200
+ _protocolVersion = "";
2201
+ _instructions;
2151
2202
  constructor(opts) {
2152
2203
  this.transport = opts.transport;
2153
2204
  this.clientInfo = opts.clientInfo ?? { name: "reasonix", version: "0.3.0-dev" };
@@ -2157,6 +2208,18 @@ var McpClient = class {
2157
2208
  get serverCapabilities() {
2158
2209
  return this._serverCapabilities;
2159
2210
  }
2211
+ /** Server's self-reported name + version, available after initialize(). */
2212
+ get serverInfo() {
2213
+ return this._serverInfo;
2214
+ }
2215
+ /** Protocol version the server agreed to during the handshake. */
2216
+ get protocolVersion() {
2217
+ return this._protocolVersion;
2218
+ }
2219
+ /** Optional free-form instructions the server provides at handshake. */
2220
+ get serverInstructions() {
2221
+ return this._instructions;
2222
+ }
2160
2223
  /**
2161
2224
  * Complete the initialize → initialized handshake. Must be called
2162
2225
  * before any other method (otherwise compliant servers reject).
@@ -2166,10 +2229,18 @@ var McpClient = class {
2166
2229
  this.startReaderIfNeeded();
2167
2230
  const result = await this.request("initialize", {
2168
2231
  protocolVersion: MCP_PROTOCOL_VERSION,
2169
- capabilities: { tools: {} },
2232
+ // Advertise every method the client can consume so servers know
2233
+ // they can send listChanged notifications etc. Sub-feature flags
2234
+ // (e.g. `resources.subscribe`) are omitted — we don't implement
2235
+ // those yet and the empty object means "method-level support, no
2236
+ // sub-features."
2237
+ capabilities: { tools: {}, resources: {}, prompts: {} },
2170
2238
  clientInfo: this.clientInfo
2171
2239
  });
2172
2240
  this._serverCapabilities = result.capabilities ?? {};
2241
+ this._serverInfo = result.serverInfo ?? { name: "", version: "" };
2242
+ this._protocolVersion = result.protocolVersion ?? "";
2243
+ this._instructions = result.instructions;
2173
2244
  await this.transport.send({
2174
2245
  jsonrpc: "2.0",
2175
2246
  method: "notifications/initialized"
@@ -2190,6 +2261,45 @@ var McpClient = class {
2190
2261
  arguments: args ?? {}
2191
2262
  });
2192
2263
  }
2264
+ /**
2265
+ * List resources the server exposes. Supports a pagination cursor;
2266
+ * callers interested in the full set should loop on `nextCursor`.
2267
+ * Servers that don't support resources respond with method-not-found
2268
+ * (−32601) — we surface that as a thrown Error so callers can gate
2269
+ * on the `serverCapabilities.resources` field first.
2270
+ */
2271
+ async listResources(cursor) {
2272
+ this.assertInitialized();
2273
+ return this.request("resources/list", {
2274
+ ...cursor ? { cursor } : {}
2275
+ });
2276
+ }
2277
+ /** Read the contents of a resource by URI. */
2278
+ async readResource(uri) {
2279
+ this.assertInitialized();
2280
+ return this.request("resources/read", {
2281
+ uri
2282
+ });
2283
+ }
2284
+ /** List prompt templates the server exposes. */
2285
+ async listPrompts(cursor) {
2286
+ this.assertInitialized();
2287
+ return this.request("prompts/list", {
2288
+ ...cursor ? { cursor } : {}
2289
+ });
2290
+ }
2291
+ /**
2292
+ * Fetch a rendered prompt by name. `args` supplies values for any
2293
+ * required template arguments; the server validates. Returns messages
2294
+ * ready to prepend to the model's input.
2295
+ */
2296
+ async getPrompt(name, args) {
2297
+ this.assertInitialized();
2298
+ return this.request("prompts/get", {
2299
+ name,
2300
+ ...args ? { arguments: args } : {}
2301
+ });
2302
+ }
2193
2303
  /** Close the transport and reject any outstanding requests. */
2194
2304
  async close() {
2195
2305
  for (const [, pending] of this.pending) {
@@ -2578,6 +2688,36 @@ function parseMcpSpec(input) {
2578
2688
  return { transport: "stdio", name, command, args };
2579
2689
  }
2580
2690
 
2691
+ // src/mcp/inspect.ts
2692
+ async function inspectMcpServer(client) {
2693
+ const tools = await trySection(() => client.listTools().then((r) => r.tools));
2694
+ const resources = await trySection(
2695
+ () => client.listResources().then((r) => r.resources)
2696
+ );
2697
+ const prompts = await trySection(() => client.listPrompts().then((r) => r.prompts));
2698
+ return {
2699
+ protocolVersion: client.protocolVersion || "(unknown)",
2700
+ serverInfo: client.serverInfo,
2701
+ capabilities: client.serverCapabilities ?? {},
2702
+ instructions: client.serverInstructions,
2703
+ tools,
2704
+ resources,
2705
+ prompts
2706
+ };
2707
+ }
2708
+ async function trySection(load) {
2709
+ try {
2710
+ const items = await load();
2711
+ return { supported: true, items };
2712
+ } catch (err) {
2713
+ const msg = err.message ?? String(err);
2714
+ if (/-32601/.test(msg) || /method not found/i.test(msg)) {
2715
+ return { supported: false, reason: "method not found (-32601)" };
2716
+ }
2717
+ return { supported: false, reason: msg };
2718
+ }
2719
+ }
2720
+
2581
2721
  // src/code/edit-blocks.ts
2582
2722
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
2583
2723
  import { dirname as dirname2, resolve as resolve2 } from "path";
@@ -2861,6 +3001,7 @@ export {
2861
3001
  formatLoopError,
2862
3002
  harvest,
2863
3003
  healLoadedMessages,
3004
+ inspectMcpServer,
2864
3005
  isJsonRpcError,
2865
3006
  isPlanStateEmpty,
2866
3007
  isPlausibleKey,