@oh-my-pi/pi-coding-agent 6.2.0 → 6.7.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 +46 -0
- package/docs/sdk.md +1 -1
- package/package.json +5 -5
- package/scripts/generate-template.ts +6 -6
- package/src/cli/args.ts +3 -0
- package/src/core/agent-session.ts +39 -0
- package/src/core/bash-executor.ts +3 -3
- package/src/core/cursor/exec-bridge.ts +95 -88
- package/src/core/custom-commands/bundled/review/index.ts +142 -145
- package/src/core/custom-commands/bundled/wt/index.ts +68 -66
- package/src/core/custom-commands/loader.ts +4 -6
- package/src/core/custom-tools/index.ts +2 -2
- package/src/core/custom-tools/loader.ts +66 -61
- package/src/core/custom-tools/types.ts +4 -4
- package/src/core/custom-tools/wrapper.ts +61 -25
- package/src/core/event-bus.ts +19 -47
- package/src/core/extensions/index.ts +8 -4
- package/src/core/extensions/loader.ts +160 -120
- package/src/core/extensions/types.ts +4 -4
- package/src/core/extensions/wrapper.ts +149 -100
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/tool-wrapper.ts +96 -70
- package/src/core/hooks/types.ts +1 -2
- package/src/core/index.ts +1 -0
- package/src/core/mcp/index.ts +6 -2
- package/src/core/mcp/json-rpc.ts +88 -0
- package/src/core/mcp/loader.ts +22 -4
- package/src/core/mcp/manager.ts +202 -48
- package/src/core/mcp/tool-bridge.ts +143 -55
- package/src/core/mcp/tool-cache.ts +122 -0
- package/src/core/python-executor.ts +3 -9
- package/src/core/sdk.ts +33 -32
- package/src/core/session-manager.ts +30 -0
- package/src/core/settings-manager.ts +34 -1
- package/src/core/ssh/ssh-executor.ts +6 -84
- package/src/core/streaming-output.ts +107 -53
- package/src/core/tools/ask.ts +92 -93
- package/src/core/tools/bash.ts +103 -94
- package/src/core/tools/calculator.ts +41 -26
- package/src/core/tools/complete.ts +76 -66
- package/src/core/tools/context.ts +22 -24
- package/src/core/tools/exa/index.ts +1 -1
- package/src/core/tools/exa/mcp-client.ts +56 -101
- package/src/core/tools/find.ts +250 -253
- package/src/core/tools/git.ts +39 -33
- package/src/core/tools/grep.ts +440 -427
- package/src/core/tools/index.ts +62 -61
- package/src/core/tools/ls.ts +119 -114
- package/src/core/tools/lsp/clients/biome-client.ts +5 -7
- package/src/core/tools/lsp/clients/index.ts +4 -4
- package/src/core/tools/lsp/clients/lsp-linter-client.ts +5 -7
- package/src/core/tools/lsp/config.ts +2 -2
- package/src/core/tools/lsp/index.ts +604 -578
- package/src/core/tools/notebook.ts +121 -119
- package/src/core/tools/output.ts +163 -147
- package/src/core/tools/patch/applicator.ts +1100 -0
- package/src/core/tools/patch/diff.ts +362 -0
- package/src/core/tools/patch/fuzzy.ts +647 -0
- package/src/core/tools/patch/index.ts +430 -0
- package/src/core/tools/patch/normalize.ts +220 -0
- package/src/core/tools/patch/normative.ts +49 -0
- package/src/core/tools/patch/parser.ts +528 -0
- package/src/core/tools/patch/shared.ts +228 -0
- package/src/core/tools/patch/types.ts +244 -0
- package/src/core/tools/python.ts +139 -136
- package/src/core/tools/read.ts +237 -216
- package/src/core/tools/render-utils.ts +196 -77
- package/src/core/tools/renderers.ts +1 -1
- package/src/core/tools/ssh.ts +99 -80
- package/src/core/tools/task/executor.ts +11 -7
- package/src/core/tools/task/index.ts +352 -343
- package/src/core/tools/task/worker.ts +13 -23
- package/src/core/tools/todo-write.ts +74 -59
- package/src/core/tools/web-fetch.ts +54 -47
- package/src/core/tools/web-search/index.ts +27 -16
- package/src/core/tools/write.ts +73 -44
- package/src/core/ttsr.ts +106 -152
- package/src/core/voice.ts +49 -39
- package/src/index.ts +16 -12
- package/src/lib/worktree/index.ts +1 -9
- package/src/modes/interactive/components/diff.ts +15 -8
- package/src/modes/interactive/components/settings-defs.ts +24 -0
- package/src/modes/interactive/components/tool-execution.ts +34 -6
- package/src/modes/interactive/controllers/event-controller.ts +6 -19
- package/src/modes/interactive/controllers/input-controller.ts +1 -1
- package/src/modes/interactive/utils/ui-helpers.ts +5 -1
- package/src/modes/rpc/rpc-mode.ts +99 -81
- package/src/prompts/tools/patch.md +76 -0
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/{edit.md → replace.md} +1 -0
- package/src/utils/shell.ts +0 -40
- package/src/core/tools/edit-diff.ts +0 -574
- package/src/core/tools/edit.ts +0 -345
package/src/core/hooks/index.ts
CHANGED
|
@@ -11,6 +11,6 @@ export {
|
|
|
11
11
|
type SendMessageHandler,
|
|
12
12
|
} from "./loader";
|
|
13
13
|
export { execCommand, HookRunner, type HookErrorListener } from "./runner";
|
|
14
|
-
export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper";
|
|
14
|
+
export { HookToolWrapper, wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper";
|
|
15
15
|
export * from "./types";
|
|
16
16
|
export type { UsageStatistics, ReadonlySessionManager } from "../session-manager";
|
|
@@ -7,93 +7,119 @@ import type { HookRunner } from "./runner";
|
|
|
7
7
|
import type { ToolCallEventResult, ToolResultEventResult } from "./types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Wraps an AgentTool with hook callbacks for interception.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
11
13
|
* - Emits tool_call event before execution (can block)
|
|
12
14
|
* - Emits tool_result event after execution (can modify result)
|
|
13
15
|
* - Forwards onUpdate callback to wrapped tool for progress streaming
|
|
14
16
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
export class HookToolWrapper<T> implements AgentTool<any, T> {
|
|
18
|
+
name: string;
|
|
19
|
+
label: string;
|
|
20
|
+
description: string;
|
|
21
|
+
parameters: unknown;
|
|
22
|
+
renderCall?: AgentTool["renderCall"];
|
|
23
|
+
renderResult?: AgentTool["renderResult"];
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
private tool: AgentTool<any, T>,
|
|
27
|
+
private hookRunner: HookRunner,
|
|
28
|
+
) {
|
|
29
|
+
this.name = tool.name;
|
|
30
|
+
this.label = tool.label ?? "";
|
|
31
|
+
this.description = tool.description;
|
|
32
|
+
this.parameters = tool.parameters;
|
|
33
|
+
this.renderCall = tool.renderCall;
|
|
34
|
+
this.renderResult = tool.renderResult;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async execute(
|
|
38
|
+
toolCallId: string,
|
|
39
|
+
params: Record<string, unknown>,
|
|
40
|
+
signal?: AbortSignal,
|
|
41
|
+
onUpdate?: AgentToolUpdateCallback<T>,
|
|
42
|
+
context?: AgentToolContext,
|
|
43
|
+
) {
|
|
44
|
+
// Emit tool_call event - hooks can block execution
|
|
45
|
+
// If hook errors/times out, block by default (fail-safe)
|
|
46
|
+
if (this.hookRunner.hasHandlers("tool_call")) {
|
|
47
|
+
try {
|
|
48
|
+
const callResult = (await this.hookRunner.emitToolCall({
|
|
49
|
+
type: "tool_call",
|
|
50
|
+
toolName: this.tool.name,
|
|
51
|
+
toolCallId,
|
|
52
|
+
input: params,
|
|
53
|
+
})) as ToolCallEventResult | undefined;
|
|
35
54
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
} catch (err) {
|
|
41
|
-
// Hook error or block - throw to mark as error
|
|
42
|
-
if (err instanceof Error) {
|
|
43
|
-
throw err;
|
|
44
|
-
}
|
|
45
|
-
throw new Error(`Hook failed, blocking execution: ${String(err)}`);
|
|
55
|
+
if (callResult?.block) {
|
|
56
|
+
const reason = callResult.reason || "Tool execution was blocked by a hook";
|
|
57
|
+
throw new Error(reason);
|
|
46
58
|
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
// Hook error or block - throw to mark as error
|
|
61
|
+
if (err instanceof Error) {
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Hook failed, blocking execution: ${String(err)}`);
|
|
47
65
|
}
|
|
66
|
+
}
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
// Execute the actual tool, forwarding onUpdate for progress streaming
|
|
69
|
+
try {
|
|
70
|
+
const result = await this.tool.execute(toolCallId, params, signal, onUpdate, context);
|
|
52
71
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
// Emit tool_result event - hooks can modify the result
|
|
73
|
+
if (this.hookRunner.hasHandlers("tool_result")) {
|
|
74
|
+
const resultResult = (await this.hookRunner.emit({
|
|
75
|
+
type: "tool_result",
|
|
76
|
+
toolName: this.tool.name,
|
|
77
|
+
toolCallId,
|
|
78
|
+
input: params,
|
|
79
|
+
content: result.content,
|
|
80
|
+
details: result.details,
|
|
81
|
+
isError: false,
|
|
82
|
+
})) as ToolResultEventResult | undefined;
|
|
64
83
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
84
|
+
// Apply modifications if any
|
|
85
|
+
if (resultResult) {
|
|
86
|
+
return {
|
|
87
|
+
content: resultResult.content ?? result.content,
|
|
88
|
+
details: (resultResult.details ?? result.details) as T,
|
|
89
|
+
};
|
|
72
90
|
}
|
|
91
|
+
}
|
|
73
92
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
throw err; // Re-throw original error for agent-loop
|
|
93
|
+
return result;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
// Emit tool_result event for errors so hooks can observe failures
|
|
96
|
+
if (this.hookRunner.hasHandlers("tool_result")) {
|
|
97
|
+
await this.hookRunner.emit({
|
|
98
|
+
type: "tool_result",
|
|
99
|
+
toolName: this.tool.name,
|
|
100
|
+
toolCallId,
|
|
101
|
+
input: params,
|
|
102
|
+
content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
|
|
103
|
+
details: undefined,
|
|
104
|
+
isError: true,
|
|
105
|
+
});
|
|
89
106
|
}
|
|
90
|
-
|
|
91
|
-
|
|
107
|
+
throw err; // Re-throw original error for agent-loop
|
|
108
|
+
}
|
|
109
|
+
}
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
/**
|
|
95
113
|
* Wrap all tools with hook callbacks.
|
|
96
114
|
*/
|
|
97
115
|
export function wrapToolsWithHooks<T>(tools: AgentTool<any, T>[], hookRunner: HookRunner): AgentTool<any, T>[] {
|
|
98
|
-
return tools.map((tool) =>
|
|
116
|
+
return tools.map((tool) => new HookToolWrapper(tool, hookRunner));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Backward compatibility alias - use HookToolWrapper directly.
|
|
121
|
+
* @deprecated Use HookToolWrapper class instead
|
|
122
|
+
*/
|
|
123
|
+
export function wrapToolWithHooks<T>(tool: AgentTool<any, T>, hookRunner: HookRunner): AgentTool<any, T> {
|
|
124
|
+
return new HookToolWrapper(tool, hookRunner);
|
|
99
125
|
}
|
package/src/core/hooks/types.ts
CHANGED
|
@@ -21,9 +21,8 @@ import type {
|
|
|
21
21
|
SessionEntry,
|
|
22
22
|
SessionManager,
|
|
23
23
|
} from "../session-manager";
|
|
24
|
-
|
|
25
|
-
import type { EditToolDetails } from "../tools/edit";
|
|
26
24
|
import type { BashToolDetails, FindToolDetails, GrepToolDetails, LsToolDetails, ReadToolDetails } from "../tools/index";
|
|
25
|
+
import type { EditToolDetails } from "../tools/patch";
|
|
27
26
|
|
|
28
27
|
// Re-export for backward compatibility
|
|
29
28
|
export type { ExecOptions, ExecResult } from "../exec";
|
package/src/core/index.ts
CHANGED
package/src/core/mcp/index.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
// Client
|
|
9
9
|
export { callTool, connectToServer, disconnectServer, listTools, serverSupportsTools } from "./client";
|
|
10
|
-
|
|
11
10
|
// Config
|
|
12
11
|
export type { ExaFilterResult, LoadMCPConfigsOptions, LoadMCPConfigsResult } from "./config";
|
|
13
12
|
export {
|
|
@@ -17,6 +16,9 @@ export {
|
|
|
17
16
|
loadAllMCPConfigs,
|
|
18
17
|
validateServerConfig,
|
|
19
18
|
} from "./config";
|
|
19
|
+
// JSON-RPC (lightweight HTTP-based MCP calls)
|
|
20
|
+
export type { JsonRpcResponse } from "./json-rpc";
|
|
21
|
+
export { callMCP, parseSSE } from "./json-rpc";
|
|
20
22
|
// Loader (for SDK integration)
|
|
21
23
|
export type { MCPToolsLoadOptions, MCPToolsLoadResult } from "./loader";
|
|
22
24
|
export { discoverAndLoadMCPTools } from "./loader";
|
|
@@ -25,7 +27,9 @@ export type { MCPDiscoverOptions, MCPLoadResult } from "./manager";
|
|
|
25
27
|
export { createMCPManager, MCPManager } from "./manager";
|
|
26
28
|
// Tool bridge
|
|
27
29
|
export type { MCPToolDetails } from "./tool-bridge";
|
|
28
|
-
export {
|
|
30
|
+
export { createMCPToolName, DeferredMCPTool, MCPTool, parseMCPToolName } from "./tool-bridge";
|
|
31
|
+
// Tool cache
|
|
32
|
+
export { MCPToolCache } from "./tool-cache";
|
|
29
33
|
// Transports
|
|
30
34
|
export { createHttpTransport, HttpTransport } from "./transports/http";
|
|
31
35
|
export { createStdioTransport, StdioTransport } from "./transports/stdio";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP JSON-RPC 2.0 over HTTPS.
|
|
3
|
+
*
|
|
4
|
+
* Lightweight utilities for calling MCP servers directly via HTTP
|
|
5
|
+
* without maintaining persistent connections.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { logger } from "../logger";
|
|
9
|
+
|
|
10
|
+
/** Parse SSE response format (lines starting with "data: ") */
|
|
11
|
+
export function parseSSE(text: string): unknown {
|
|
12
|
+
const lines = text.split("\n");
|
|
13
|
+
for (const line of lines) {
|
|
14
|
+
if (line.startsWith("data: ")) {
|
|
15
|
+
const data = line.slice(6).trim();
|
|
16
|
+
if (data === "[DONE]") continue;
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(data);
|
|
19
|
+
} catch {
|
|
20
|
+
// Try next line
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Fallback: try parsing entire response as JSON
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(text);
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** JSON-RPC 2.0 response structure */
|
|
33
|
+
export interface JsonRpcResponse<T = unknown> {
|
|
34
|
+
jsonrpc: "2.0";
|
|
35
|
+
id: string | number;
|
|
36
|
+
result?: T;
|
|
37
|
+
error?: {
|
|
38
|
+
code: number;
|
|
39
|
+
message: string;
|
|
40
|
+
data?: unknown;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Call an MCP server with JSON-RPC 2.0 over HTTPS.
|
|
46
|
+
*
|
|
47
|
+
* @param url - Full MCP server URL (including any query parameters)
|
|
48
|
+
* @param method - JSON-RPC method name (e.g., "tools/list", "tools/call")
|
|
49
|
+
* @param params - Method parameters
|
|
50
|
+
* @returns Parsed JSON-RPC response
|
|
51
|
+
*/
|
|
52
|
+
export async function callMCP<T = unknown>(
|
|
53
|
+
url: string,
|
|
54
|
+
method: string,
|
|
55
|
+
params?: Record<string, unknown>,
|
|
56
|
+
): Promise<JsonRpcResponse<T>> {
|
|
57
|
+
const body = {
|
|
58
|
+
jsonrpc: "2.0",
|
|
59
|
+
id: Math.random().toString(36).slice(2),
|
|
60
|
+
method,
|
|
61
|
+
params: params ?? {},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const response = await fetch(url, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
Accept: "application/json, text/event-stream",
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify(body),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const errorMsg = `MCP request failed: ${response.status} ${response.statusText}`;
|
|
75
|
+
logger.error(errorMsg, { url, method, params });
|
|
76
|
+
throw new Error(errorMsg);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const text = await response.text();
|
|
80
|
+
const result = parseSSE(text) as JsonRpcResponse<T> | null;
|
|
81
|
+
|
|
82
|
+
if (!result) {
|
|
83
|
+
logger.error("Failed to parse MCP response", { url, method, responseText: text.slice(0, 500) });
|
|
84
|
+
throw new Error("Failed to parse MCP response");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result;
|
|
88
|
+
}
|
package/src/core/mcp/loader.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
* Integrates MCP tool discovery with the custom tools system.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { AgentStorage } from "../agent-storage";
|
|
7
8
|
import type { LoadedCustomTool } from "../custom-tools/types";
|
|
9
|
+
import { logger } from "../logger";
|
|
8
10
|
import { type MCPLoadResult, MCPManager } from "./manager";
|
|
9
11
|
import { parseMCPToolName } from "./tool-bridge";
|
|
12
|
+
import { MCPToolCache } from "./tool-cache";
|
|
10
13
|
|
|
11
14
|
/** Result from loading MCP tools */
|
|
12
15
|
export interface MCPToolsLoadResult {
|
|
@@ -30,6 +33,19 @@ export interface MCPToolsLoadOptions {
|
|
|
30
33
|
enableProjectConfig?: boolean;
|
|
31
34
|
/** Whether to filter out Exa MCP servers (default: true) */
|
|
32
35
|
filterExa?: boolean;
|
|
36
|
+
/** SQLite storage for MCP tool cache (null disables cache) */
|
|
37
|
+
cacheStorage?: AgentStorage | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolveToolCache(storage: AgentStorage | null | undefined): MCPToolCache | null {
|
|
41
|
+
if (storage === null) return null;
|
|
42
|
+
try {
|
|
43
|
+
const resolved = storage ?? AgentStorage.open();
|
|
44
|
+
return new MCPToolCache(resolved);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.warn("MCP tool cache unavailable", { error: String(error) });
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
33
49
|
}
|
|
34
50
|
|
|
35
51
|
/**
|
|
@@ -40,7 +56,8 @@ export interface MCPToolsLoadOptions {
|
|
|
40
56
|
* @returns MCP tools in LoadedCustomTool format for integration
|
|
41
57
|
*/
|
|
42
58
|
export async function discoverAndLoadMCPTools(cwd: string, options?: MCPToolsLoadOptions): Promise<MCPToolsLoadResult> {
|
|
43
|
-
const
|
|
59
|
+
const toolCache = resolveToolCache(options?.cacheStorage);
|
|
60
|
+
const manager = new MCPManager(cwd, toolCache);
|
|
44
61
|
|
|
45
62
|
let result: MCPLoadResult;
|
|
46
63
|
try {
|
|
@@ -69,12 +86,13 @@ export async function discoverAndLoadMCPTools(cwd: string, options?: MCPToolsLoa
|
|
|
69
86
|
|
|
70
87
|
// Get provider info from manager's connection if available
|
|
71
88
|
const connection = serverName ? manager.getConnection(serverName) : undefined;
|
|
72
|
-
const
|
|
89
|
+
const source = serverName ? manager.getSource(serverName) : undefined;
|
|
90
|
+
const providerName =
|
|
91
|
+
connection?._source?.providerName ?? source?.providerName ?? connection?._source?.provider ?? source?.provider;
|
|
73
92
|
|
|
74
93
|
// Format path with provider info if available
|
|
75
94
|
// Format: "mcp:serverName via providerName" (e.g., "mcp:agentx via Claude Code")
|
|
76
|
-
const path =
|
|
77
|
-
provider && serverName ? `mcp:${serverName} via ${connection._source!.providerName}` : `mcp:${tool.name}`;
|
|
95
|
+
const path = serverName && providerName ? `mcp:${serverName} via ${providerName}` : `mcp:${tool.name}`;
|
|
78
96
|
|
|
79
97
|
return {
|
|
80
98
|
path,
|