@mcp-z/client 2.0.0 → 2.0.1
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/cjs/client-helpers.d.cts +5 -6
- package/dist/cjs/client-helpers.d.ts +5 -6
- package/dist/cjs/client-helpers.js +8 -8
- package/dist/cjs/client-helpers.js.map +1 -1
- package/dist/cjs/connection/connect-client.d.cts +1 -2
- package/dist/cjs/connection/connect-client.d.ts +1 -2
- package/dist/cjs/connection/connect-client.js +6 -9
- package/dist/cjs/connection/connect-client.js.map +1 -1
- package/dist/cjs/connection/existing-process-transport.d.cts +1 -2
- package/dist/cjs/connection/existing-process-transport.d.ts +1 -2
- package/dist/cjs/connection/existing-process-transport.js +3 -3
- package/dist/cjs/connection/existing-process-transport.js.map +1 -1
- package/dist/cjs/response-wrappers.d.cts +1 -1
- package/dist/cjs/response-wrappers.d.ts +1 -1
- package/dist/cjs/response-wrappers.js.map +1 -1
- package/dist/cjs/search/search.d.cts +1 -1
- package/dist/cjs/search/search.d.ts +1 -1
- package/dist/cjs/search/search.js.map +1 -1
- package/dist/esm/client-helpers.d.ts +5 -6
- package/dist/esm/client-helpers.js +8 -8
- package/dist/esm/client-helpers.js.map +1 -1
- package/dist/esm/connection/connect-client.d.ts +1 -2
- package/dist/esm/connection/connect-client.js +2 -5
- package/dist/esm/connection/connect-client.js.map +1 -1
- package/dist/esm/connection/existing-process-transport.d.ts +1 -2
- package/dist/esm/connection/existing-process-transport.js +1 -1
- package/dist/esm/connection/existing-process-transport.js.map +1 -1
- package/dist/esm/response-wrappers.d.ts +1 -1
- package/dist/esm/response-wrappers.js.map +1 -1
- package/dist/esm/search/search.d.ts +1 -1
- package/dist/esm/search/search.js.map +1 -1
- package/package.json +3 -2
- package/dist/cjs/monkey-patches.d.cts +0 -6
- package/dist/cjs/monkey-patches.d.ts +0 -6
- package/dist/cjs/monkey-patches.js +0 -233
- package/dist/cjs/monkey-patches.js.map +0 -1
- package/dist/esm/monkey-patches.d.ts +0 -6
- package/dist/esm/monkey-patches.js +0 -32
- package/dist/esm/monkey-patches.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["buildCapabilityIndex","search","searchCapabilities","DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","Object","entries","propName","prop","join","extractArgumentsText","args","Array","isArray","map","arg","name","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","tool","prompt","resource","Promise","all","listTools","catch","listPrompts","listResources","tools","type","server","schemaText","prompts","argumentsText","arguments","resources","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/client';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["buildCapabilityIndex","search","searchCapabilities","DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","Object","entries","propName","prop","join","extractArgumentsText","args","Array","isArray","map","arg","name","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","tool","prompt","resource","Promise","all","listTools","catch","listPrompts","listResources","tools","type","server","schemaText","prompts","argumentsText","arguments","resources","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { Client } from '@modelcontextprotocol/
|
|
2
|
-
import type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
1
|
+
import type { Client } from '@modelcontextprotocol/client';
|
|
3
2
|
import type { ToolArguments } from './connection/types.js';
|
|
4
3
|
import { PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } from './response-wrappers.js';
|
|
5
4
|
export type PromptArguments = Record<string, string>;
|
|
@@ -33,10 +32,10 @@ export type ManagedClient = Omit<Client, 'callTool' | 'getPrompt' | 'readResourc
|
|
|
33
32
|
readonly serverName: string;
|
|
34
33
|
/** Underlying MCP SDK client for advanced scenarios. */
|
|
35
34
|
readonly nativeClient: Client;
|
|
36
|
-
callTool(toolName: string, args?: ToolArguments, requestOptions?:
|
|
37
|
-
callTool(invocation: NativeCallToolParams[0],
|
|
38
|
-
callToolRaw(toolName: string, args?: ToolArguments, requestOptions?:
|
|
39
|
-
callToolRaw(invocation: NativeCallToolParams[0],
|
|
35
|
+
callTool(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;
|
|
36
|
+
callTool(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;
|
|
37
|
+
callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;
|
|
38
|
+
callToolRaw(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;
|
|
40
39
|
getPrompt(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;
|
|
41
40
|
getPrompt(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;
|
|
42
41
|
getPromptRaw(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;
|
|
@@ -17,23 +17,23 @@ import { PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } f
|
|
|
17
17
|
});
|
|
18
18
|
const nativeCallTool = client.callTool.bind(client);
|
|
19
19
|
const wrapCallTool = (promise)=>promise.then((payload)=>new ToolResponseWrapper(payload));
|
|
20
|
-
enhanced.callTool = (nameOrInvocation,
|
|
20
|
+
enhanced.callTool = (nameOrInvocation, argsOrOptions, requestOptions)=>{
|
|
21
21
|
if (typeof nameOrInvocation === 'string') {
|
|
22
22
|
return wrapCallTool(nativeCallTool({
|
|
23
23
|
name: nameOrInvocation,
|
|
24
|
-
arguments:
|
|
25
|
-
},
|
|
24
|
+
arguments: argsOrOptions !== null && argsOrOptions !== void 0 ? argsOrOptions : {}
|
|
25
|
+
}, requestOptions));
|
|
26
26
|
}
|
|
27
|
-
return wrapCallTool(nativeCallTool(nameOrInvocation,
|
|
27
|
+
return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrOptions));
|
|
28
28
|
};
|
|
29
|
-
enhanced.callToolRaw = (nameOrInvocation,
|
|
29
|
+
enhanced.callToolRaw = (nameOrInvocation, argsOrOptions, requestOptions)=>{
|
|
30
30
|
if (typeof nameOrInvocation === 'string') {
|
|
31
31
|
return nativeCallTool({
|
|
32
32
|
name: nameOrInvocation,
|
|
33
|
-
arguments:
|
|
34
|
-
},
|
|
33
|
+
arguments: argsOrOptions !== null && argsOrOptions !== void 0 ? argsOrOptions : {}
|
|
34
|
+
}, requestOptions);
|
|
35
35
|
}
|
|
36
|
-
return nativeCallTool(nameOrInvocation,
|
|
36
|
+
return nativeCallTool(nameOrInvocation, argsOrOptions);
|
|
37
37
|
};
|
|
38
38
|
const nativeGetPrompt = client.getPrompt.bind(client);
|
|
39
39
|
const wrapPrompt = (promise)=>promise.then((payload)=>new PromptResponseWrapper(payload));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/client-helpers.ts"],"sourcesContent":["import type { Client } from '@modelcontextprotocol/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/client-helpers.ts"],"sourcesContent":["import type { Client } from '@modelcontextprotocol/client';\nimport type { ToolArguments } from './connection/types.ts';\nimport { type NativeCallToolResponse, type NativeGetPromptResponse, type NativeReadResourceResponse, PromptResponseWrapper, ResourceResponseWrapper, ToolResponseWrapper } from './response-wrappers.ts';\n\nexport type PromptArguments = Record<string, string>;\n\ntype NativeCallToolParams = Parameters<Client['callTool']>;\ntype NativeCallToolReturn = ReturnType<Client['callTool']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.callTool()`.\n * @public\n */\nexport type WrappedCallToolReturn = Promise<ToolResponseWrapper>;\n\ntype NativeGetPromptParams = Parameters<Client['getPrompt']>;\ntype NativeGetPromptReturn = ReturnType<Client['getPrompt']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.getPrompt()`.\n * @public\n */\nexport type WrappedGetPromptReturn = Promise<PromptResponseWrapper>;\n\ntype NativeReadResourceParams = Parameters<Client['readResource']>;\ntype NativeReadResourceReturn = ReturnType<Client['readResource']>;\n/**\n * Fetch-style wrapper returned by `ManagedClient.readResource()`.\n * @public\n */\nexport type WrappedReadResourceReturn = Promise<ResourceResponseWrapper>;\n\n/**\n * Client returned by registry.connect() with convenience overloads for\n * calling tools, reading resources, and getting prompts using simple arguments.\n */\nexport type ManagedClient = Omit<Client, 'callTool' | 'getPrompt' | 'readResource'> & {\n /** Name of the server this client is connected to. */\n readonly serverName: string;\n /** Underlying MCP SDK client for advanced scenarios. */\n readonly nativeClient: Client;\n\n callTool(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;\n callTool(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): WrappedCallToolReturn;\n callToolRaw(toolName: string, args?: ToolArguments, requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;\n callToolRaw(invocation: NativeCallToolParams[0], requestOptions?: NativeCallToolParams[1]): NativeCallToolReturn;\n\n getPrompt(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPrompt(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): WrappedGetPromptReturn;\n getPromptRaw(name: string, args?: PromptArguments, requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n getPromptRaw(invocation: NativeGetPromptParams[0], requestOptions?: NativeGetPromptParams[1]): NativeGetPromptReturn;\n\n readResource(uri: string, requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResource(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): WrappedReadResourceReturn;\n readResourceRaw(uri: string, requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n readResourceRaw(request: NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]): NativeReadResourceReturn;\n};\n\n/**\n * Enhance an MCP SDK client with convenience overloads.\n */\nexport function decorateClient(client: Client, metadata: { serverName: string }): ManagedClient {\n const enhanced = client as unknown as ManagedClient;\n\n Object.defineProperty(enhanced, 'serverName', {\n value: metadata.serverName,\n enumerable: true,\n configurable: false,\n writable: false,\n });\n Object.defineProperty(enhanced, 'nativeClient', {\n value: client,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n\n const nativeCallTool = client.callTool.bind(client);\n const wrapCallTool = (promise: NativeCallToolReturn): WrappedCallToolReturn => promise.then((payload) => new ToolResponseWrapper(payload as NativeCallToolResponse));\n\n enhanced.callTool = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrOptions?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[1]) => {\n if (typeof nameOrInvocation === 'string') {\n return wrapCallTool(nativeCallTool({ name: nameOrInvocation, arguments: (argsOrOptions as ToolArguments) ?? {} }, requestOptions));\n }\n return wrapCallTool(nativeCallTool(nameOrInvocation, argsOrOptions as NativeCallToolParams[1]));\n }) as ManagedClient['callTool'];\n\n enhanced.callToolRaw = ((nameOrInvocation: string | NativeCallToolParams[0], argsOrOptions?: ToolArguments | NativeCallToolParams[1], requestOptions?: NativeCallToolParams[1]) => {\n if (typeof nameOrInvocation === 'string') {\n return nativeCallTool({ name: nameOrInvocation, arguments: (argsOrOptions as ToolArguments) ?? {} }, requestOptions);\n }\n return nativeCallTool(nameOrInvocation, argsOrOptions as NativeCallToolParams[1]);\n }) as ManagedClient['callToolRaw'];\n\n const nativeGetPrompt = client.getPrompt.bind(client);\n const wrapPrompt = (promise: NativeGetPromptReturn): WrappedGetPromptReturn => promise.then((payload) => new PromptResponseWrapper(payload as NativeGetPromptResponse));\n\n enhanced.getPrompt = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return wrapPrompt(nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions));\n }\n return wrapPrompt(nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]));\n }) as ManagedClient['getPrompt'];\n\n enhanced.getPromptRaw = ((nameOrParams: string | NativeGetPromptParams[0], argsOrOptions?: PromptArguments | NativeGetPromptParams[1], requestOptions?: NativeGetPromptParams[1]) => {\n if (typeof nameOrParams === 'string') {\n return nativeGetPrompt({ name: nameOrParams, ...(argsOrOptions ? { arguments: argsOrOptions as PromptArguments } : {}) }, requestOptions);\n }\n return nativeGetPrompt(nameOrParams, argsOrOptions as NativeGetPromptParams[1]);\n }) as ManagedClient['getPromptRaw'];\n\n const nativeReadResource = client.readResource.bind(client);\n const wrapResource = (promise: NativeReadResourceReturn): WrappedReadResourceReturn => promise.then((payload) => new ResourceResponseWrapper(payload as NativeReadResourceResponse));\n\n enhanced.readResource = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return wrapResource(nativeReadResource({ uri: uriOrRequest }, requestOptions));\n }\n return wrapResource(nativeReadResource(uriOrRequest, requestOptions));\n }) as ManagedClient['readResource'];\n\n enhanced.readResourceRaw = ((uriOrRequest: string | NativeReadResourceParams[0], requestOptions?: NativeReadResourceParams[1]) => {\n if (typeof uriOrRequest === 'string') {\n return nativeReadResource({ uri: uriOrRequest }, requestOptions);\n }\n return nativeReadResource(uriOrRequest, requestOptions);\n }) as ManagedClient['readResourceRaw'];\n\n return enhanced;\n}\n"],"names":["PromptResponseWrapper","ResourceResponseWrapper","ToolResponseWrapper","decorateClient","client","metadata","enhanced","Object","defineProperty","value","serverName","enumerable","configurable","writable","nativeCallTool","callTool","bind","wrapCallTool","promise","then","payload","nameOrInvocation","argsOrOptions","requestOptions","name","arguments","callToolRaw","nativeGetPrompt","getPrompt","wrapPrompt","nameOrParams","getPromptRaw","nativeReadResource","readResource","wrapResource","uriOrRequest","uri","readResourceRaw"],"mappings":"AAEA,SAAqGA,qBAAqB,EAAEC,uBAAuB,EAAEC,mBAAmB,QAAQ,yBAAyB;AAsDzM;;CAEC,GACD,OAAO,SAASC,eAAeC,MAAc,EAAEC,QAAgC;IAC7E,MAAMC,WAAWF;IAEjBG,OAAOC,cAAc,CAACF,UAAU,cAAc;QAC5CG,OAAOJ,SAASK,UAAU;QAC1BC,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IACAN,OAAOC,cAAc,CAACF,UAAU,gBAAgB;QAC9CG,OAAOL;QACPO,YAAY;QACZC,cAAc;QACdC,UAAU;IACZ;IAEA,MAAMC,iBAAiBV,OAAOW,QAAQ,CAACC,IAAI,CAACZ;IAC5C,MAAMa,eAAe,CAACC,UAAyDA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIlB,oBAAoBkB;IAEjId,SAASS,QAAQ,GAAI,CAACM,kBAAoDC,eAAyDC;QACjI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOJ,aAAaH,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGC;QACpH;QACA,OAAON,aAAaH,eAAeO,kBAAkBC;IACvD;IAEAhB,SAASoB,WAAW,GAAI,CAACL,kBAAoDC,eAAyDC;QACpI,IAAI,OAAOF,qBAAqB,UAAU;YACxC,OAAOP,eAAe;gBAAEU,MAAMH;gBAAkBI,SAAS,EAAGH,0BAAAA,2BAAAA,gBAAmC,CAAC;YAAE,GAAGC;QACvG;QACA,OAAOT,eAAeO,kBAAkBC;IAC1C;IAEA,MAAMK,kBAAkBvB,OAAOwB,SAAS,CAACZ,IAAI,CAACZ;IAC9C,MAAMyB,aAAa,CAACX,UAA2DA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAIpB,sBAAsBoB;IAEnId,SAASsB,SAAS,GAAI,CAACE,cAAiDR,eAA4DC;QAClI,IAAI,OAAOO,iBAAiB,UAAU;YACpC,OAAOD,WAAWF,gBAAgB;gBAAEH,MAAMM;gBAAc,GAAIR,gBAAgB;oBAAEG,WAAWH;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGC;QACvI;QACA,OAAOM,WAAWF,gBAAgBG,cAAcR;IAClD;IAEAhB,SAASyB,YAAY,GAAI,CAACD,cAAiDR,eAA4DC;QACrI,IAAI,OAAOO,iBAAiB,UAAU;YACpC,OAAOH,gBAAgB;gBAAEH,MAAMM;gBAAc,GAAIR,gBAAgB;oBAAEG,WAAWH;gBAAiC,IAAI,CAAC,CAAC;YAAE,GAAGC;QAC5H;QACA,OAAOI,gBAAgBG,cAAcR;IACvC;IAEA,MAAMU,qBAAqB5B,OAAO6B,YAAY,CAACjB,IAAI,CAACZ;IACpD,MAAM8B,eAAe,CAAChB,UAAiEA,QAAQC,IAAI,CAAC,CAACC,UAAY,IAAInB,wBAAwBmB;IAE7Id,SAAS2B,YAAY,GAAI,CAACE,cAAoDZ;QAC5E,IAAI,OAAOY,iBAAiB,UAAU;YACpC,OAAOD,aAAaF,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGZ;QAChE;QACA,OAAOW,aAAaF,mBAAmBG,cAAcZ;IACvD;IAEAjB,SAAS+B,eAAe,GAAI,CAACF,cAAoDZ;QAC/E,IAAI,OAAOY,iBAAiB,UAAU;YACpC,OAAOH,mBAAmB;gBAAEI,KAAKD;YAAa,GAAGZ;QACnD;QACA,OAAOS,mBAAmBG,cAAcZ;IAC1C;IAEA,OAAOjB;AACT"}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Helper to connect MCP SDK clients to servers with intelligent transport inference.
|
|
5
5
|
* Automatically detects transport type from URL protocol or type field.
|
|
6
6
|
*/
|
|
7
|
-
import '
|
|
8
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
7
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
9
8
|
import { type DcrAuthenticatorOptions } from '../dcr/index.js';
|
|
10
9
|
import type { ServerProcess } from '../spawn/spawn-server.js';
|
|
11
10
|
import type { ServersConfig } from '../spawn/spawn-servers.js';
|
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Helper to connect MCP SDK clients to servers with intelligent transport inference.
|
|
5
5
|
* Automatically detects transport type from URL protocol or type field.
|
|
6
|
-
*/ import '
|
|
7
|
-
import {
|
|
8
|
-
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
9
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
10
|
-
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
6
|
+
*/ import { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
|
|
7
|
+
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
|
|
11
8
|
import getPort from 'get-port';
|
|
12
9
|
import { probeAuthCapabilities } from '../auth/index.js';
|
|
13
10
|
import { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport '../monkey-patches.ts';\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Extract the \"server base\" by removing a trailing `/mcp` path segment if present.\n * Examples:\n * - https://example.com/mcp -> https://example.com\n * - https://example.com/sheets/mcp -> https://example.com/sheets\n * - https://example.com/sheets/mcp/ -> https://example.com/sheets\n * - https://example.com/sheets -> https://example.com/sheets\n */\nexport function extractBaseUrl(mcpUrl: string): string {\n const url = new URL(mcpUrl);\n\n // Ignore query/hash for base URL purposes\n url.search = '';\n url.hash = '';\n\n // Normalize path segments (removes empty segments from leading/trailing slashes)\n const segments = url.pathname.split('/').filter(Boolean);\n\n // If last segment is exactly \"mcp\", drop it\n if (segments[segments.length - 1] === 'mcp') {\n segments.pop();\n }\n\n // Rebuild pathname; empty means root\n url.pathname = segments.length ? `/${segments.join('/')}` : '';\n\n // Return without trailing slash (except root origin)\n const out = url.origin + url.pathname;\n return out === url.origin ? out : out.replace(/\\/+$/, '');\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n const baseUrl = extractBaseUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(baseUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(baseUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["Client","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","getPort","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","DcrAuthenticator","logger","defaultLogger","ExistingProcessTransport","waitForHttpReady","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","extractBaseUrl","mcpUrl","url","URL","search","hash","segments","pathname","split","filter","Boolean","length","pop","join","out","origin","replace","inferTransportType","config","type","protocol","connectMcpClient","registryOrConfig","serverName","options","isRegistry","servers","Map","serversConfig","registry","undefined","serverConfig","available","Object","keys","transportType","client","name","version","capabilities","serverHandle","get","transport","process","connect","command","args","env","isSpawnedHttp","has","debug","baseUrl","authToken","supportsDcr","port","redirectUri","authenticator","headless","dcrAuthenticator","tokens","ensureAuthenticated","accessToken","staticHeaders","headers","dcrHeaders","Authorization","mergedHeaders","transportOptions","requestInit","error","errorMessage","message","String","cause","isConnectionRefused","code","includes","close","catch","shouldFallback","warn","sseClient","sseTransportOptions","sseTransport","sseError","all"],"mappings":"AAAA;;;;;CAKC,GAED,OAAO,uBAAuB;AAE9B,SAASA,MAAM,QAAQ,4CAA4C;AACnE,SAASC,kBAAkB,QAAQ,0CAA0C;AAC7E,SAASC,oBAAoB,QAAQ,4CAA4C;AACjF,SAASC,6BAA6B,QAAQ,qDAAqD;AAEnG,OAAOC,aAAa,WAAW;AAC/B,SAASC,qBAAqB,QAAQ,mBAAmB;AACzD,SAASC,+BAA+B,QAAQ,kBAAkB;AAClE,SAASC,gBAAgB,QAAsC,kBAAkB;AAcjF,SAASC,UAAUC,aAAa,QAAqB,qBAAqB;AAC1E,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,gBAAgB,QAAQ,2BAA2B;AAE5D;;;;;;;CAOC,GACD,eAAeC,YAAeC,OAAmB,EAAEC,EAAU,EAAEC,SAAiB;IAC9E,IAAIC;IAEJ,OAAOC,QAAQC,IAAI,CAAC;QAClBL,QAAQM,OAAO,CAAC,IAAMC,aAAaJ;QACnC,IAAIC,QAAW,CAACI,GAAGC;YACjBN,YAAYO,WAAW,IAAMD,OAAO,IAAIE,MAAM,CAAC,cAAc,EAAEV,GAAG,IAAI,EAAEC,WAAW,IAAID;QACzF;KACD;AACH;AAEA;;;;;;;CAOC,GACD,OAAO,SAASW,eAAeC,MAAc;IAC3C,MAAMC,MAAM,IAAIC,IAAIF;IAEpB,0CAA0C;IAC1CC,IAAIE,MAAM,GAAG;IACbF,IAAIG,IAAI,GAAG;IAEX,iFAAiF;IACjF,MAAMC,WAAWJ,IAAIK,QAAQ,CAACC,KAAK,CAAC,KAAKC,MAAM,CAACC;IAEhD,4CAA4C;IAC5C,IAAIJ,QAAQ,CAACA,SAASK,MAAM,GAAG,EAAE,KAAK,OAAO;QAC3CL,SAASM,GAAG;IACd;IAEA,qCAAqC;IACrCV,IAAIK,QAAQ,GAAGD,SAASK,MAAM,GAAG,CAAC,CAAC,EAAEL,SAASO,IAAI,CAAC,MAAM,GAAG;IAE5D,qDAAqD;IACrD,MAAMC,MAAMZ,IAAIa,MAAM,GAAGb,IAAIK,QAAQ;IACrC,OAAOO,QAAQZ,IAAIa,MAAM,GAAGD,MAAMA,IAAIE,OAAO,CAAC,QAAQ;AACxD;AAEA;;;;;;;;;;;CAWC,GACD,SAASC,mBAAmBC,MAAsB;IAChD,kCAAkC;IAClC,IAAIA,OAAOC,IAAI,EAAE;QACf,gDAAgD;QAChD,IAAID,OAAOhB,GAAG,EAAE;YACd,MAAMA,MAAM,IAAIC,IAAIe,OAAOhB,GAAG;YAC9B,MAAMkB,WAAWlB,IAAIkB,QAAQ;YAE7B,IAAI,AAACA,CAAAA,aAAa,WAAWA,aAAa,QAAO,KAAMF,OAAOC,IAAI,KAAK,UAAUD,OAAOC,IAAI,KAAK,WAAW;gBAC1G,MAAM,IAAIpB,MAAM,CAAC,qCAAqC,EAAEqB,SAAS,iCAAiC,EAAEF,OAAOC,IAAI,CAAC,CAAC,CAAC;YACpH;QACF;QAEA,yBAAyB;QACzB,IAAID,OAAOC,IAAI,KAAK,UAAUD,OAAOC,IAAI,KAAK,WAAW,OAAO;QAChE,IAAID,OAAOC,IAAI,KAAK,SAAS,OAAO;QAEpC,MAAM,IAAIpB,MAAM,CAAC,4BAA4B,EAAEmB,OAAOC,IAAI,EAAE;IAC9D;IAEA,sCAAsC;IACtC,IAAID,OAAOhB,GAAG,EAAE;QACd,MAAMA,MAAM,IAAIC,IAAIe,OAAOhB,GAAG;QAC9B,MAAMkB,WAAWlB,IAAIkB,QAAQ;QAE7B,IAAIA,aAAa,WAAWA,aAAa,UAAU;YACjD,OAAO;QACT;QACA,MAAM,IAAIrB,MAAM,CAAC,0BAA0B,EAAEqB,UAAU;IACzD;IAEA,+BAA+B;IAC/B,OAAO;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GACD,OAAO,eAAeC,iBACpBC,gBAA8C,EAC9CC,UAAkB,EAClBC,OAGC;;IAED,gEAAgE;IAChE,MAAMC,aAAa,aAAaH,oBAAoBA,iBAAiBI,OAAO,YAAYC;IACxF,MAAMC,gBAA+BH,aAAa,AAACH,iBAAkCJ,MAAM,GAAII;IAC/F,MAAMO,WAAWJ,aAAcH,mBAAoCQ;IACnE,MAAM/C,iBAASyC,oBAAAA,8BAAAA,QAASzC,MAAM,uCAAIC;IAElC,MAAM+C,eAAeH,aAAa,CAACL,WAAW;IAE9C,IAAI,CAACQ,cAAc;QACjB,MAAMC,YAAYC,OAAOC,IAAI,CAACN,eAAef,IAAI,CAAC;QAClD,MAAM,IAAId,MAAM,CAAC,QAAQ,EAAEwB,WAAW,0CAA0C,EAAES,aAAa,QAAQ;IACzG;IAEA,uCAAuC;IACvC,MAAMG,gBAAgBlB,mBAAmBc;IAEzC,oBAAoB;IACpB,MAAMK,SAAS,IAAI7D,OAAO;QAAE8D,MAAM;QAAkBC,SAAS;IAAQ,GAAG;QAAEC,cAAc,CAAC;IAAE;IAE3F,sCAAsC;IACtC,IAAIJ,kBAAkB,SAAS;QAC7B,qDAAqD;QACrD,MAAMK,eAAeX,qBAAAA,+BAAAA,SAAUH,OAAO,CAACe,GAAG,CAAClB;QAE3C,IAAIiB,cAAc;YAChB,oCAAoC;YACpC,MAAME,YAAY,IAAIzD,yBAAyBuD,aAAaG,OAAO;YACnE,MAAMP,OAAOQ,OAAO,CAACF;QACvB,OAAO;YACL,qEAAqE;YACrE,oEAAoE;YACpE,IAAI,CAACX,aAAac,OAAO,EAAE;gBACzB,MAAM,IAAI9C,MAAM,CAAC,QAAQ,EAAEwB,WAAW,iDAAiD,CAAC;YAC1F;YAEA,MAAMmB,YAAY,IAAIjE,qBAAqB;gBACzCoE,SAASd,aAAac,OAAO;gBAC7BC,MAAMf,aAAae,IAAI,IAAI,EAAE;gBAC7BC,KAAKhB,aAAagB,GAAG,IAAI,CAAC;YAC5B;YAEA,qFAAqF;YACrF,MAAMX,OAAOQ,OAAO,CAACF;QACvB;IACF,OAAO,IAAIP,kBAAkB,QAAQ;QACnC,IAAI,CAAE,CAAA,SAASJ,YAAW,KAAM,CAACA,aAAa7B,GAAG,EAAE;YACjD,MAAM,IAAIH,MAAM,CAAC,QAAQ,EAAEwB,WAAW,4CAA4C,CAAC;QACrF;QAEA,iEAAiE;QACjE,iEAAiE;QACjE,MAAMyB,gBAAgBnB,qBAAAA,+BAAAA,SAAUH,OAAO,CAACuB,GAAG,CAAC1B;QAE5C,IAAIyB,eAAe;YACjBjE,OAAOmE,KAAK,CAAC,CAAC,4CAA4C,EAAE3B,WAAW,KAAK,EAAEQ,aAAa7B,GAAG,EAAE;YAChG,MAAMhB,iBAAiB6C,aAAa7B,GAAG;YACvCnB,OAAOmE,KAAK,CAAC,CAAC,gCAAgC,EAAE3B,WAAW,OAAO,CAAC;QACrE;QAEA,MAAMrB,MAAM,IAAIC,IAAI4B,aAAa7B,GAAG;QAEpC,gEAAgE;QAChE,MAAMiD,UAAUnD,eAAe+B,aAAa7B,GAAG;QAC/C,MAAMqC,eAAe,MAAMpD,YAAYP,sBAAsBuE,UAAUtE,iCAAiC;QAExG,IAAIuE;QAEJ,IAAIb,aAAac,WAAW,EAAE;YAC5BtE,OAAOmE,KAAK,CAAC,CAAC,WAAW,EAAE3B,WAAW,6BAA6B,CAAC;YAEpE,8DAA8D;YAC9D,MAAM+B,OAAO,MAAM3E;YACnB,MAAM4E,cAAc,CAAC,iBAAiB,EAAED,KAAK,SAAS,CAAC;YAEvD,+EAA+E;YAC/E,MAAME,gBAAgB,IAAI1E,iBAAiB;gBACzC2E,UAAU;gBACVF;gBACAxE;mBACGyC,oBAAAA,8BAAAA,QAASkC,gBAAgB,AAA5B;YACF;YAEA,+DAA+D;YAC/D,MAAMC,SAAS,MAAMH,cAAcI,mBAAmB,CAACT,SAASZ;YAChEa,YAAYO,OAAOE,WAAW;YAE9B9E,OAAOmE,KAAK,CAAC,CAAC,+BAA+B,EAAE3B,WAAW,CAAC,CAAC;QAC9D,OAAO;YACLxC,OAAOmE,KAAK,CAAC,CAAC,YAAY,EAAE3B,WAAW,0DAA0D,CAAC;QACpG;QAEA,IAAI;YACF,iEAAiE;YACjE,8FAA8F;YAC9F,MAAMuC,gBAAgB/B,aAAagC,OAAO,IAAI,CAAC;YAC/C,MAAMC,aAAaZ,YAAY;gBAAEa,eAAe,CAAC,OAAO,EAAEb,WAAW;YAAC,IAAI,CAAC;YAC3E,MAAMc,gBAAgB;gBAAE,GAAGJ,aAAa;gBAAE,GAAGE,UAAU;YAAC;YAExD,MAAMG,mBACJlC,OAAOC,IAAI,CAACgC,eAAevD,MAAM,GAAG,IAChC;gBACEyD,aAAa;oBACXL,SAASG;gBACX;YACF,IACApC;YAEN,MAAMY,YAAY,IAAIhE,8BAA8BwB,KAAKiE;YACzD,+FAA+F;YAC/F,gEAAgE;YAChE,MAAMhF,YAAYiD,OAAOQ,OAAO,CAACF,YAAoC,OAAO;QAC9E,EAAE,OAAO2B,OAAO;YACd,+DAA+D;YAC/D,iFAAiF;YACjF,MAAMC,eAAeD,iBAAiBtE,QAAQsE,MAAME,OAAO,GAAGC,OAAOH;YAErE,0EAA0E;YAC1E,wFAAwF;YACxF,MAAMI,QAAQJ,iBAAiBtE,QAAQ,AAACsE,MAAgDI,KAAK,GAAG3C;YAChG,MAAM4C,sBAAsBD,CAAAA,kBAAAA,4BAAAA,MAAOE,IAAI,MAAK,kBAAkBL,aAAaM,QAAQ,CAAC;YAEpF,IAAIF,qBAAqB;gBACvB,4CAA4C;gBAC5C,MAAMtC,OAAOyC,KAAK,GAAGC,KAAK,CAAC,KAAO;gBAClC,MAAM,IAAI/E,MAAM,CAAC,sBAAsB,EAAEG,KAAK;YAChD;YAEA,8DAA8D;YAC9D,MAAM6E,iBACJT,aAAaM,QAAQ,CAAC,yBAAyB,mBAAmB;YAClEN,aAAaM,QAAQ,CAAC,UAAU,+CAA+C;YAC/EN,aAAaM,QAAQ,CAAC,QAAQ,qBAAqB;YAErD,IAAIG,gBAAgB;gBAClBhG,OAAOiG,IAAI,CAAC,CAAC,wBAAwB,EAAEV,aAAa,gCAAgC,CAAC;YACvF,OAAO;gBACLvF,OAAOiG,IAAI,CAAC;YACd;YAEA,iEAAiE;YACjE,MAAMC,YAAY,IAAI1G,OAAO;gBAAE8D,MAAM;gBAAkBC,SAAS;YAAQ,GAAG;gBAAEC,cAAc,CAAC;YAAE;YAE9F,wDAAwD;YACxD,yDAAyD;YACzD,MAAMuB,gBAAgB/B,aAAagC,OAAO,IAAI,CAAC;YAC/C,MAAMC,aAAaZ,YAAY;gBAAEa,eAAe,CAAC,OAAO,EAAEb,WAAW;YAAC,IAAI,CAAC;YAC3E,MAAMc,gBAAgB;gBAAE,GAAGJ,aAAa;gBAAE,GAAGE,UAAU;YAAC;YAExD,MAAMkB,sBACJjD,OAAOC,IAAI,CAACgC,eAAevD,MAAM,GAAG,IAChC;gBACEyD,aAAa;oBACXL,SAASG;gBACX;YACF,IACApC;YAEN,MAAMqD,eAAe,IAAI3G,mBAAmB0B,KAAKgF;YAEjD,IAAI;gBACF,MAAM/F,YAAY8F,UAAUrC,OAAO,CAACuC,eAAe,OAAO;gBAC1D,wCAAwC;gBACxC,OAAOF;YACT,EAAE,OAAOG,UAAU;gBACjB,gEAAgE;gBAChE,MAAM5F,QAAQ6F,GAAG,CAAC;oBAACjD,OAAOyC,KAAK,GAAGC,KAAK,CAAC,KAAO;oBAAIG,UAAUJ,KAAK,GAAGC,KAAK,CAAC,KAAO;iBAAG;gBACrF,MAAMM;YACR;QACF;IACF;IAEA,OAAOhD,QAAQ,iCAAiC;AAClD"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/connect-client.ts"],"sourcesContent":["/**\n * connect-mcp-client.ts\n *\n * Helper to connect MCP SDK clients to servers with intelligent transport inference.\n * Automatically detects transport type from URL protocol or type field.\n */\n\nimport type { Transport } from '@modelcontextprotocol/client';\nimport { Client, SSEClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';\nimport { StdioClientTransport } from '@modelcontextprotocol/client/stdio';\nimport getPort from 'get-port';\nimport { probeAuthCapabilities } from '../auth/index.ts';\nimport { DCR_CAPABILTY_DISCOVERY_TIMEOUT } from '../constants.ts';\nimport { DcrAuthenticator, type DcrAuthenticatorOptions } from '../dcr/index.ts';\nimport type { ServerProcess } from '../spawn/spawn-server.ts';\nimport type { ServersConfig } from '../spawn/spawn-servers.ts';\n\n/**\n * Minimal interface for connecting to servers.\n * Only needs config and servers map for connection logic.\n */\ninterface RegistryLike {\n config: ServersConfig;\n servers: Map<string, ServerProcess>;\n}\n\nimport type { McpServerEntry, TransportType } from '../types.ts';\nimport { logger as defaultLogger, type Logger } from '../utils/logger.ts';\nimport { ExistingProcessTransport } from './existing-process-transport.ts';\nimport { waitForHttpReady } from './wait-for-http-ready.ts';\n\n/**\n * Wrap promise with timeout - throws if promise takes too long\n * Clears timeout when promise completes to prevent hanging event loop\n * @param promise - Promise to wrap\n * @param ms - Timeout in milliseconds\n * @param operation - Description of operation for error message\n * @returns Promise result or timeout error\n */\nasync function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n return Promise.race([\n promise.finally(() => clearTimeout(timeoutId)),\n new Promise<T>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Timeout after ${ms}ms: ${operation}`)), ms);\n }),\n ]);\n}\n\n/**\n * Extract the \"server base\" by removing a trailing `/mcp` path segment if present.\n * Examples:\n * - https://example.com/mcp -> https://example.com\n * - https://example.com/sheets/mcp -> https://example.com/sheets\n * - https://example.com/sheets/mcp/ -> https://example.com/sheets\n * - https://example.com/sheets -> https://example.com/sheets\n */\nexport function extractBaseUrl(mcpUrl: string): string {\n const url = new URL(mcpUrl);\n\n // Ignore query/hash for base URL purposes\n url.search = '';\n url.hash = '';\n\n // Normalize path segments (removes empty segments from leading/trailing slashes)\n const segments = url.pathname.split('/').filter(Boolean);\n\n // If last segment is exactly \"mcp\", drop it\n if (segments[segments.length - 1] === 'mcp') {\n segments.pop();\n }\n\n // Rebuild pathname; empty means root\n url.pathname = segments.length ? `/${segments.join('/')}` : '';\n\n // Return without trailing slash (except root origin)\n const out = url.origin + url.pathname;\n return out === url.origin ? out : out.replace(/\\/+$/, '');\n}\n\n/**\n * Infer transport type from server configuration with validation.\n *\n * Priority:\n * 1. Explicit type field (if present)\n * 2. URL protocol (if URL present): http://, https://\n * 3. Default to 'stdio' (if neither present)\n *\n * @param config - Server configuration\n * @returns Transport type\n * @throws Error if configuration is invalid or has conflicts\n */\nfunction inferTransportType(config: McpServerEntry): TransportType {\n // Priority 1: Explicit type field\n if (config.type) {\n // Validate consistency with URL if both present\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if ((protocol === 'http:' || protocol === 'https:') && config.type !== 'http' && config.type !== 'sse-ide') {\n throw new Error(`Conflicting transport: URL protocol '${protocol}' requires type 'http', but got '${config.type}'`);\n }\n }\n\n // Return normalized type\n if (config.type === 'http' || config.type === 'sse-ide') return 'http';\n if (config.type === 'stdio') return 'stdio';\n\n throw new Error(`Unsupported transport type: ${config.type}`);\n }\n\n // Priority 2: Infer from URL protocol\n if (config.url) {\n const url = new URL(config.url);\n const protocol = url.protocol;\n\n if (protocol === 'http:' || protocol === 'https:') {\n return 'http';\n }\n throw new Error(`Unsupported URL protocol: ${protocol}`);\n }\n\n // Priority 3: Default to stdio\n return 'stdio';\n}\n\n/**\n * Connect MCP SDK client to server with full readiness handling.\n * @internal - Use registry.connect() instead\n *\n * **Completely handles readiness**: transport availability + MCP protocol handshake.\n *\n * Transport is intelligently inferred and handled:\n * - **Stdio servers**: Direct MCP connect (fast for spawned processes)\n * - **HTTP servers**: Transport polling (/mcp endpoint) + MCP connect\n * - **Registry result**: Handles both spawned and external servers\n *\n * Returns only when server is fully MCP-ready (initialize handshake complete).\n *\n * @param registryOrConfig - Result from createServerRegistry() or servers config object\n * @param serverName - Server name from servers config\n * @returns Connected MCP SDK Client (guaranteed ready)\n *\n * @example\n * // Using registry (recommended)\n * const registry = createServerRegistry({ echo: { command: 'node', args: ['server.ts'] } });\n * const client = await registry.connect('echo');\n * // Server is fully ready - transport available + MCP handshake complete\n *\n * @example\n * // HTTP server readiness (waits for /mcp polling + MCP handshake)\n * const registry = createServerRegistry(\n * { http: { type: 'http', url: 'http://localhost:3000/mcp', start: {...} } },\n * { dialects: ['start'] }\n * );\n * const client = await registry.connect('http');\n * // 1. Waits for HTTP server to respond on /mcp\n * // 2. Performs MCP initialize handshake\n * // 3. Returns ready client\n */\nexport async function connectMcpClient(\n registryOrConfig: RegistryLike | ServersConfig,\n serverName: string,\n options?: {\n dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;\n logger?: Logger;\n }\n): Promise<Client> {\n // Detect whether we have a RegistryLike instance or just config\n const isRegistry = 'servers' in registryOrConfig && registryOrConfig.servers instanceof Map;\n const serversConfig: ServersConfig = isRegistry ? (registryOrConfig as RegistryLike).config : (registryOrConfig as ServersConfig);\n const registry = isRegistry ? (registryOrConfig as RegistryLike) : undefined;\n const logger = options?.logger ?? defaultLogger;\n\n const serverConfig = serversConfig[serverName];\n\n if (!serverConfig) {\n const available = Object.keys(serversConfig).join(', ');\n throw new Error(`Server '${serverName}' not found in config. Available servers: ${available || 'none'}`);\n }\n\n // Infer transport type with validation\n const transportType = inferTransportType(serverConfig);\n\n // Create MCP client\n const client = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // Connect based on inferred transport\n if (transportType === 'stdio') {\n // Check if we have a spawned process in the registry\n const serverHandle = registry?.servers.get(serverName);\n\n if (serverHandle) {\n // Reuse the already-spawned process\n const transport = new ExistingProcessTransport(serverHandle.process);\n await client.connect(transport);\n } else {\n // No registry or server not in registry - spawn new process directly\n // This is the standard fallback when process management is not used\n if (!serverConfig.command) {\n throw new Error(`Server '${serverName}' has stdio transport but missing 'command' field`);\n }\n\n const transport = new StdioClientTransport({\n command: serverConfig.command,\n args: serverConfig.args || [],\n env: serverConfig.env || {},\n });\n\n // client.connect() performs initialize handshake - when it resolves, server is ready\n await client.connect(transport);\n }\n } else if (transportType === 'http') {\n if (!('url' in serverConfig) || !serverConfig.url) {\n throw new Error(`Server '${serverName}' has http transport but missing 'url' field`);\n }\n\n // Check if this is a freshly spawned HTTP server (from registry)\n // that might not be ready yet - transport readiness check needed\n const isSpawnedHttp = registry?.servers.has(serverName);\n\n if (isSpawnedHttp) {\n logger.debug(`[connectMcpClient] waiting for HTTP server '${serverName}' at ${serverConfig.url}`);\n await waitForHttpReady(serverConfig.url);\n logger.debug(`[connectMcpClient] HTTP server '${serverName}' ready`);\n }\n\n const url = new URL(serverConfig.url);\n\n // Check for DCR support and handle authentication automatically\n const baseUrl = extractBaseUrl(serverConfig.url);\n const capabilities = await withTimeout(probeAuthCapabilities(baseUrl), DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery');\n\n let authToken: string | undefined;\n\n if (capabilities.supportsDcr) {\n logger.debug(`🔐 Server '${serverName}' supports DCR authentication`);\n\n // Get available port and create the exact redirect URI to use\n const port = await getPort();\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Handle authentication using DcrAuthenticator with fully resolved redirectUri\n const authenticator = new DcrAuthenticator({\n headless: false,\n redirectUri,\n logger,\n ...options?.dcrAuthenticator,\n });\n\n // Ensure we have valid tokens (performs DCR + OAuth if needed)\n const tokens = await authenticator.ensureAuthenticated(baseUrl, capabilities);\n authToken = tokens.accessToken;\n\n logger.debug(`✅ Authentication complete for '${serverName}'`);\n } else {\n logger.debug(`ℹ️ Server '${serverName}' does not support DCR - connecting without authentication`);\n }\n\n try {\n // Try modern Streamable HTTP first (protocol version 2025-03-26)\n // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const transportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const transport = new StreamableHTTPClientTransport(url, transportOptions);\n // Type assertion: SDK transport has sessionId: string | undefined but Transport expects string\n // This is safe at runtime - the undefined is valid per MCP spec\n await withTimeout(client.connect(transport as unknown as Transport), 30000, 'StreamableHTTP connection');\n } catch (error) {\n // Fall back to SSE transport (MCP protocol version 2024-11-05)\n // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Fast-fail: Don't try SSE if connection was refused (server not running)\n // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)\n const cause = error instanceof Error ? (error as Error & { cause?: { code?: string } }).cause : undefined;\n const isConnectionRefused = cause?.code === 'ECONNREFUSED' || errorMessage.includes('Connection refused');\n\n if (isConnectionRefused) {\n // Clean up client resources before throwing\n await client.close().catch(() => {});\n throw new Error(`Server not running at ${url}`);\n }\n\n // Check for known errors that indicate SSE fallback is needed\n const shouldFallback =\n errorMessage.includes('Missing session ID') || // FastMCP specific\n errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint\n errorMessage.includes('405'); // Method not allowed\n\n if (shouldFallback) {\n logger.warn(`Streamable HTTP failed (${errorMessage}), falling back to SSE transport`);\n } else {\n logger.warn('Streamable HTTP connection failed, trying SSE transport as fallback');\n }\n\n // Create new client for SSE transport (required per SDK pattern)\n const sseClient = new Client({ name: 'mcp-cli-client', version: '1.0.0' }, { capabilities: {} });\n\n // SSE transport with merged headers (static + DCR auth)\n // Reuse the same header merging logic as Streamable HTTP\n const staticHeaders = serverConfig.headers || {};\n const dcrHeaders = authToken ? { Authorization: `Bearer ${authToken}` } : {};\n const mergedHeaders = { ...staticHeaders, ...dcrHeaders };\n\n const sseTransportOptions =\n Object.keys(mergedHeaders).length > 0\n ? {\n requestInit: {\n headers: mergedHeaders,\n },\n }\n : undefined;\n\n const sseTransport = new SSEClientTransport(url, sseTransportOptions);\n\n try {\n await withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection');\n // Return SSE client instead of original\n return sseClient;\n } catch (sseError) {\n // SSE connection failed - clean up both clients before throwing\n await Promise.all([client.close().catch(() => {}), sseClient.close().catch(() => {})]);\n throw sseError;\n }\n }\n }\n\n return client; // Guaranteed ready when returned\n}\n"],"names":["Client","SSEClientTransport","StreamableHTTPClientTransport","StdioClientTransport","getPort","probeAuthCapabilities","DCR_CAPABILTY_DISCOVERY_TIMEOUT","DcrAuthenticator","logger","defaultLogger","ExistingProcessTransport","waitForHttpReady","withTimeout","promise","ms","operation","timeoutId","Promise","race","finally","clearTimeout","_","reject","setTimeout","Error","extractBaseUrl","mcpUrl","url","URL","search","hash","segments","pathname","split","filter","Boolean","length","pop","join","out","origin","replace","inferTransportType","config","type","protocol","connectMcpClient","registryOrConfig","serverName","options","isRegistry","servers","Map","serversConfig","registry","undefined","serverConfig","available","Object","keys","transportType","client","name","version","capabilities","serverHandle","get","transport","process","connect","command","args","env","isSpawnedHttp","has","debug","baseUrl","authToken","supportsDcr","port","redirectUri","authenticator","headless","dcrAuthenticator","tokens","ensureAuthenticated","accessToken","staticHeaders","headers","dcrHeaders","Authorization","mergedHeaders","transportOptions","requestInit","error","errorMessage","message","String","cause","isConnectionRefused","code","includes","close","catch","shouldFallback","warn","sseClient","sseTransportOptions","sseTransport","sseError","all"],"mappings":"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"}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* MCP transport that wraps an existing child process for stdio communication.
|
|
5
5
|
* Used when connecting to servers already spawned by initServers().
|
|
6
6
|
*/
|
|
7
|
-
import type { Transport } from '@modelcontextprotocol/
|
|
8
|
-
import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/client';
|
|
9
8
|
import type { ChildProcess } from 'child_process';
|
|
10
9
|
/**
|
|
11
10
|
* Transport that communicates with an existing child process via stdio.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* MCP transport that wraps an existing child process for stdio communication.
|
|
5
5
|
* Used when connecting to servers already spawned by initServers().
|
|
6
|
-
*/ import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/
|
|
6
|
+
*/ import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/client';
|
|
7
7
|
/**
|
|
8
8
|
* Transport that communicates with an existing child process via stdio.
|
|
9
9
|
* Does NOT spawn a new process - uses the one provided.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/existing-process-transport.ts"],"sourcesContent":["/**\n * existing-process-transport.ts\n *\n * MCP transport that wraps an existing child process for stdio communication.\n * Used when connecting to servers already spawned by initServers().\n */\n\nimport {
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/connection/existing-process-transport.ts"],"sourcesContent":["/**\n * existing-process-transport.ts\n *\n * MCP transport that wraps an existing child process for stdio communication.\n * Used when connecting to servers already spawned by initServers().\n */\n\nimport type { JSONRPCMessage, Transport } from '@modelcontextprotocol/client';\nimport { ReadBuffer, serializeMessage } from '@modelcontextprotocol/client';\nimport type { ChildProcess } from 'child_process';\n\n/**\n * Transport that communicates with an existing child process via stdio.\n * Does NOT spawn a new process - uses the one provided.\n */\nexport class ExistingProcessTransport implements Transport {\n private _process: ChildProcess;\n private _readBuffer: ReadBuffer;\n private _dataHandler: ((chunk: Buffer) => void) | null = null;\n private _errorHandler: ((error: Error) => void) | null = null;\n\n // Transport interface callbacks\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(process: ChildProcess) {\n if (!process.stdin || !process.stdout) {\n throw new Error('Child process must have stdin and stdout pipes');\n }\n\n this._process = process;\n this._readBuffer = new ReadBuffer();\n }\n\n /**\n * Start the transport - sets up stdio listeners on existing process.\n */\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n // Listen for process events\n this._process.on('error', (error) => {\n this.onerror?.(error);\n reject(error);\n });\n\n this._process.on('close', () => {\n this.onclose?.();\n });\n\n // Create and save data handler for close\n this._dataHandler = (chunk: Buffer) => {\n this._readBuffer.append(chunk);\n this.processReadBuffer();\n };\n\n // Create and save error handler for close\n this._errorHandler = (error: Error) => {\n this.onerror?.(error);\n };\n\n // Listen for stdout data (MCP messages)\n this._process.stdout?.on('data', this._dataHandler);\n this._process.stdout?.on('error', this._errorHandler);\n this._process.stdin?.on('error', this._errorHandler);\n\n // Process is already running - resolve immediately\n resolve();\n });\n }\n\n /**\n * Process buffered messages from stdout.\n */\n private processReadBuffer(): void {\n while (true) {\n try {\n const message = this._readBuffer.readMessage();\n if (message === null) {\n break;\n }\n this.onmessage?.(message);\n } catch (error) {\n this.onerror?.(error as Error);\n }\n }\n }\n\n /**\n * Close the transport - close without killing the shared process.\n * The process is managed by the cluster and may have other active connections.\n */\n async close(): Promise<void> {\n if (this._dataHandler) {\n this._process.stdout?.off('data', this._dataHandler);\n this._dataHandler = null;\n }\n\n if (this._errorHandler) {\n this._process.stdout?.off('error', this._errorHandler);\n this._process.stdin?.off('error', this._errorHandler);\n this._errorHandler = null;\n }\n\n this._readBuffer.clear();\n }\n\n /**\n * Send a message to the server via stdin.\n */\n async send(message: JSONRPCMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this._process.stdin) {\n reject(new Error('stdin is not available'));\n return;\n }\n\n const json = serializeMessage(message);\n\n if (this._process.stdin.write(json)) {\n resolve();\n } else {\n this._process.stdin.once('drain', resolve);\n }\n });\n }\n}\n"],"names":["ReadBuffer","serializeMessage","ExistingProcessTransport","start","Promise","resolve","reject","_process","on","error","onerror","onclose","_dataHandler","chunk","_readBuffer","append","processReadBuffer","_errorHandler","stdout","stdin","message","readMessage","onmessage","close","off","clear","send","Error","json","write","once","process"],"mappings":"AAAA;;;;;CAKC,GAGD,SAASA,UAAU,EAAEC,gBAAgB,QAAQ,+BAA+B;AAG5E;;;CAGC,GACD,OAAO,MAAMC;IAoBX;;GAEC,GACD,MAAMC,QAAuB;QAC3B,OAAO,IAAIC,QAAQ,CAACC,SAASC;gBAsB3B,wCAAwC;YACxC,uBACA,wBACA;YAxBA,4BAA4B;YAC5B,IAAI,CAACC,QAAQ,CAACC,EAAE,CAAC,SAAS,CAACC;oBACzB,eAAA;iBAAA,gBAAA,CAAA,QAAA,IAAI,EAACC,OAAO,cAAZ,oCAAA,mBAAA,OAAeD;gBACfH,OAAOG;YACT;YAEA,IAAI,CAACF,QAAQ,CAACC,EAAE,CAAC,SAAS;oBACxB,eAAA;iBAAA,gBAAA,CAAA,QAAA,IAAI,EAACG,OAAO,cAAZ,oCAAA,mBAAA;YACF;YAEA,yCAAyC;YACzC,IAAI,CAACC,YAAY,GAAG,CAACC;gBACnB,IAAI,CAACC,WAAW,CAACC,MAAM,CAACF;gBACxB,IAAI,CAACG,iBAAiB;YACxB;YAEA,0CAA0C;YAC1C,IAAI,CAACC,aAAa,GAAG,CAACR;oBACpB,eAAA;iBAAA,gBAAA,CAAA,QAAA,IAAI,EAACC,OAAO,cAAZ,oCAAA,mBAAA,OAAeD;YACjB;aAGA,wBAAA,IAAI,CAACF,QAAQ,CAACW,MAAM,cAApB,4CAAA,sBAAsBV,EAAE,CAAC,QAAQ,IAAI,CAACI,YAAY;aAClD,yBAAA,IAAI,CAACL,QAAQ,CAACW,MAAM,cAApB,6CAAA,uBAAsBV,EAAE,CAAC,SAAS,IAAI,CAACS,aAAa;aACpD,uBAAA,IAAI,CAACV,QAAQ,CAACY,KAAK,cAAnB,2CAAA,qBAAqBX,EAAE,CAAC,SAAS,IAAI,CAACS,aAAa;YAEnD,mDAAmD;YACnDZ;QACF;IACF;IAEA;;GAEC,GACD,AAAQW,oBAA0B;QAChC,MAAO,KAAM;YACX,IAAI;oBAKF,iBAAA;gBAJA,MAAMI,UAAU,IAAI,CAACN,WAAW,CAACO,WAAW;gBAC5C,IAAID,YAAY,MAAM;oBACpB;gBACF;iBACA,kBAAA,CAAA,QAAA,IAAI,EAACE,SAAS,cAAd,sCAAA,qBAAA,OAAiBF;YACnB,EAAE,OAAOX,OAAO;oBACd,eAAA;iBAAA,gBAAA,CAAA,SAAA,IAAI,EAACC,OAAO,cAAZ,oCAAA,mBAAA,QAAeD;YACjB;QACF;IACF;IAEA;;;GAGC,GACD,MAAMc,QAAuB;QAC3B,IAAI,IAAI,CAACX,YAAY,EAAE;gBACrB;aAAA,wBAAA,IAAI,CAACL,QAAQ,CAACW,MAAM,cAApB,4CAAA,sBAAsBM,GAAG,CAAC,QAAQ,IAAI,CAACZ,YAAY;YACnD,IAAI,CAACA,YAAY,GAAG;QACtB;QAEA,IAAI,IAAI,CAACK,aAAa,EAAE;gBACtB,wBACA;aADA,yBAAA,IAAI,CAACV,QAAQ,CAACW,MAAM,cAApB,6CAAA,uBAAsBM,GAAG,CAAC,SAAS,IAAI,CAACP,aAAa;aACrD,uBAAA,IAAI,CAACV,QAAQ,CAACY,KAAK,cAAnB,2CAAA,qBAAqBK,GAAG,CAAC,SAAS,IAAI,CAACP,aAAa;YACpD,IAAI,CAACA,aAAa,GAAG;QACvB;QAEA,IAAI,CAACH,WAAW,CAACW,KAAK;IACxB;IAEA;;GAEC,GACD,MAAMC,KAAKN,OAAuB,EAAiB;QACjD,OAAO,IAAIhB,QAAQ,CAACC,SAASC;YAC3B,IAAI,CAAC,IAAI,CAACC,QAAQ,CAACY,KAAK,EAAE;gBACxBb,OAAO,IAAIqB,MAAM;gBACjB;YACF;YAEA,MAAMC,OAAO3B,iBAAiBmB;YAE9B,IAAI,IAAI,CAACb,QAAQ,CAACY,KAAK,CAACU,KAAK,CAACD,OAAO;gBACnCvB;YACF,OAAO;gBACL,IAAI,CAACE,QAAQ,CAACY,KAAK,CAACW,IAAI,CAAC,SAASzB;YACpC;QACF;IACF;IAnGA,YAAY0B,OAAqB,CAAE;aAR3BnB,eAAiD;aACjDK,gBAAiD;QAQvD,IAAI,CAACc,QAAQZ,KAAK,IAAI,CAACY,QAAQb,MAAM,EAAE;YACrC,MAAM,IAAIS,MAAM;QAClB;QAEA,IAAI,CAACpB,QAAQ,GAAGwB;QAChB,IAAI,CAACjB,WAAW,GAAG,IAAId;IACzB;AA6FF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Client } from '@modelcontextprotocol/
|
|
1
|
+
import type { Client } from '@modelcontextprotocol/client';
|
|
2
2
|
export type NativeCallToolResponse = Awaited<ReturnType<Client['callTool']>>;
|
|
3
3
|
export type NativeGetPromptResponse = Awaited<ReturnType<Client['getPrompt']>>;
|
|
4
4
|
export type NativeReadResourceResponse = Awaited<ReturnType<Client['readResource']>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/response-wrappers.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { ContentBlock, PromptMessage, TextContent } from '@modelcontextprotocol/sdk/types.js';\n\nexport type NativeCallToolResponse = Awaited<ReturnType<Client['callTool']>>;\nexport type NativeGetPromptResponse = Awaited<ReturnType<Client['getPrompt']>>;\nexport type NativeReadResourceResponse = Awaited<ReturnType<Client['readResource']>>;\n\nexport type JsonValidator<T> = (value: unknown) => asserts value is T;\n\nexport class ToolResponseError extends Error {\n readonly response: NativeCallToolResponse;\n\n constructor(message: string, response: NativeCallToolResponse) {\n super(message);\n this.name = 'ToolResponseError';\n this.response = response;\n }\n}\n\nexport class ToolResponseWrapper {\n private readonly payload: NativeCallToolResponse;\n\n constructor(payload: NativeCallToolResponse) {\n this.payload = payload;\n }\n\n raw(): NativeCallToolResponse {\n return this.payload;\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const value = this.resolveJsonPayload();\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(value);\n }\n return value as T;\n }\n\n text(): string {\n if (isCompatibilityResult(this.payload)) {\n if (typeof this.payload.toolResult === 'string') {\n return this.payload.toolResult;\n }\n throw new ToolResponseError('Compatibility tool result is not text', this.payload);\n }\n\n this.throwIfError();\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include text content', this.payload);\n }\n\n return textBlock.text;\n }\n\n private resolveJsonPayload(): unknown {\n if (isCompatibilityResult(this.payload)) {\n return this.payload.toolResult;\n }\n\n this.throwIfError();\n\n if (hasStructuredContent(this.payload)) {\n return this.payload.structuredContent;\n }\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include structuredContent or text content', this.payload);\n }\n\n try {\n return JSON.parse(textBlock.text) as unknown;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ToolResponseError(`Failed to parse tool text content as JSON: ${reason}`, this.payload);\n }\n }\n\n private throwIfError(): void {\n if ('isError' in this.payload && this.payload.isError) {\n let detail = typeof this.payload.error === 'object' && this.payload.error && 'message' in this.payload.error ? String((this.payload.error as { message?: unknown }).message ?? '') : '';\n if (!detail) {\n const textBlock = findFirstTextBlock((this.payload.content ?? []) as ContentBlock[]);\n if (textBlock?.text) {\n detail = textBlock.text;\n }\n }\n const message = detail ? `Tool invocation returned an error result: ${detail}` : 'Tool invocation returned an error result';\n throw new ToolResponseError(message, this.payload);\n }\n }\n}\n\nexport class PromptResponseError extends Error {\n readonly response: NativeGetPromptResponse;\n\n constructor(message: string, response: NativeGetPromptResponse) {\n super(message);\n this.name = 'PromptResponseError';\n this.response = response;\n }\n}\n\nexport class PromptResponseWrapper {\n private readonly payload: NativeGetPromptResponse;\n\n constructor(payload: NativeGetPromptResponse) {\n this.payload = payload;\n }\n\n raw(): NativeGetPromptResponse {\n return this.payload;\n }\n\n text(): string {\n const segments = collectPromptText(this.payload.messages);\n if (!segments.length) {\n throw new PromptResponseError('Prompt response did not include text content', this.payload);\n }\n return segments.join('\\n\\n');\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new PromptResponseError(`Failed to parse prompt text as JSON: ${reason}`, this.payload);\n }\n }\n}\n\nexport class ResourceResponseError extends Error {\n readonly response: NativeReadResourceResponse;\n\n constructor(message: string, response: NativeReadResourceResponse) {\n super(message);\n this.name = 'ResourceResponseError';\n this.response = response;\n }\n}\n\nexport class ResourceResponseWrapper {\n private readonly payload: NativeReadResourceResponse;\n\n constructor(payload: NativeReadResourceResponse) {\n this.payload = payload;\n }\n\n raw(): NativeReadResourceResponse {\n return this.payload;\n }\n\n text(): string {\n const entry = this.firstEntry();\n if ('text' in entry && typeof entry.text === 'string') {\n return entry.text;\n }\n if ('blob' in entry && typeof entry.blob === 'string') {\n try {\n return Buffer.from(entry.blob, 'base64').toString('utf8');\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to decode resource blob as UTF-8 text: ${reason}`, this.payload);\n }\n }\n throw new ResourceResponseError('Resource content does not include text or blob data', this.payload);\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to parse resource text as JSON: ${reason}`, this.payload);\n }\n }\n\n private firstEntry(): NativeReadResourceResponse['contents'][number] {\n const [entry] = this.payload.contents ?? [];\n if (!entry) {\n throw new ResourceResponseError('Resource response did not include any contents', this.payload);\n }\n return entry;\n }\n}\n\nfunction hasStructuredContent(response: NativeCallToolResponse): response is NativeCallToolResponse & { structuredContent: Record<string, unknown> } {\n return Boolean((response as { structuredContent?: unknown }).structuredContent);\n}\n\nfunction isCompatibilityResult(response: NativeCallToolResponse): response is NativeCallToolResponse & { toolResult: unknown } {\n return hasOwn(response, 'toolResult');\n}\n\nfunction findFirstTextBlock(blocks: ContentBlock[] | undefined): TextContent | undefined {\n if (!Array.isArray(blocks)) {\n return undefined;\n }\n return blocks.find(isTextContent);\n}\n\nfunction collectPromptText(messages: PromptMessage[]): string[] {\n const segments: string[] = [];\n for (const message of messages) {\n const textBlock = isTextContent(message.content) ? message.content : undefined;\n if (textBlock) {\n segments.push(textBlock.text);\n }\n }\n return segments;\n}\n\nfunction isTextContent(block: unknown): block is TextContent {\n return Boolean(block) && typeof block === 'object' && (block as { type?: string }).type === 'text';\n}\n\nconst protoHasOwn = Object.prototype.hasOwnProperty;\n\nfunction hasOwn(target: object, key: PropertyKey): boolean {\n return protoHasOwn.call(target, key);\n}\n\nfunction formatErrorReason(error: unknown): string {\n if (error instanceof Error && typeof error.message === 'string') {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n"],"names":["Buffer","ToolResponseError","Error","message","response","name","ToolResponseWrapper","raw","payload","json","validator","value","resolveJsonPayload","assertValid","text","isCompatibilityResult","toolResult","throwIfError","textBlock","findFirstTextBlock","content","hasStructuredContent","structuredContent","JSON","parse","error","reason","formatErrorReason","isError","detail","String","PromptResponseError","PromptResponseWrapper","segments","collectPromptText","messages","length","join","textValue","parsed","ResourceResponseError","ResourceResponseWrapper","entry","firstEntry","blob","from","toString","contents","Boolean","hasOwn","blocks","Array","isArray","undefined","find","isTextContent","push","block","type","protoHasOwn","Object","prototype","hasOwnProperty","target","key","call","stringify"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAc;AAUrC,OAAO,MAAMC,0BAA0BC;IAGrC,YAAYC,OAAe,EAAEC,QAAgC,CAAE;QAC7D,KAAK,CAACD;QACN,IAAI,CAACE,IAAI,GAAG;QACZ,IAAI,CAACD,QAAQ,GAAGA;IAClB;AACF;AAEA,OAAO,MAAME;IAOXC,MAA8B;QAC5B,OAAO,IAAI,CAACC,OAAO;IACrB;IAEAC,KAAkBC,SAA4B,EAAK;QACjD,MAAMC,QAAQ,IAAI,CAACC,kBAAkB;QACrC,IAAIF,WAAW;YACb,MAAMG,cAAgCH;YACtCG,YAAYF;QACd;QACA,OAAOA;IACT;IAEAG,OAAe;YAUwB;QATrC,IAAIC,sBAAsB,IAAI,CAACP,OAAO,GAAG;YACvC,IAAI,OAAO,IAAI,CAACA,OAAO,CAACQ,UAAU,KAAK,UAAU;gBAC/C,OAAO,IAAI,CAACR,OAAO,CAACQ,UAAU;YAChC;YACA,MAAM,IAAIf,kBAAkB,yCAAyC,IAAI,CAACO,OAAO;QACnF;QAEA,IAAI,CAACS,YAAY;QAEjB,MAAMC,YAAYC,oBAAmB,wBAAA,IAAI,CAACX,OAAO,CAACY,OAAO,cAApB,mCAAA,wBAAwB,EAAE;QAC/D,IAAI,CAACF,WAAW;YACd,MAAM,IAAIjB,kBAAkB,8CAA8C,IAAI,CAACO,OAAO;QACxF;QAEA,OAAOU,UAAUJ,IAAI;IACvB;IAEQF,qBAA8B;YAWC;QAVrC,IAAIG,sBAAsB,IAAI,CAACP,OAAO,GAAG;YACvC,OAAO,IAAI,CAACA,OAAO,CAACQ,UAAU;QAChC;QAEA,IAAI,CAACC,YAAY;QAEjB,IAAII,qBAAqB,IAAI,CAACb,OAAO,GAAG;YACtC,OAAO,IAAI,CAACA,OAAO,CAACc,iBAAiB;QACvC;QAEA,MAAMJ,YAAYC,oBAAmB,wBAAA,IAAI,CAACX,OAAO,CAACY,OAAO,cAApB,mCAAA,wBAAwB,EAAE;QAC/D,IAAI,CAACF,WAAW;YACd,MAAM,IAAIjB,kBAAkB,mEAAmE,IAAI,CAACO,OAAO;QAC7G;QAEA,IAAI;YACF,OAAOe,KAAKC,KAAK,CAACN,UAAUJ,IAAI;QAClC,EAAE,OAAOW,OAAO;YACd,MAAMC,SAASC,kBAAkBF;YACjC,MAAM,IAAIxB,kBAAkB,CAAC,2CAA2C,EAAEyB,QAAQ,EAAE,IAAI,CAAClB,OAAO;QAClG;IACF;IAEQS,eAAqB;QAC3B,IAAI,aAAa,IAAI,CAACT,OAAO,IAAI,IAAI,CAACA,OAAO,CAACoB,OAAO,EAAE;gBACiE;YAAtH,IAAIC,SAAS,OAAO,IAAI,CAACrB,OAAO,CAACiB,KAAK,KAAK,YAAY,IAAI,CAACjB,OAAO,CAACiB,KAAK,IAAI,aAAa,IAAI,CAACjB,OAAO,CAACiB,KAAK,GAAGK,QAAO,8BAAA,AAAC,IAAI,CAACtB,OAAO,CAACiB,KAAK,CAA2BtB,OAAO,cAArD,yCAAA,8BAAyD,MAAM;YACrL,IAAI,CAAC0B,QAAQ;oBAC2B;gBAAtC,MAAMX,YAAYC,oBAAoB,wBAAA,IAAI,CAACX,OAAO,CAACY,OAAO,cAApB,mCAAA,wBAAwB,EAAE;gBAChE,IAAIF,sBAAAA,gCAAAA,UAAWJ,IAAI,EAAE;oBACnBe,SAASX,UAAUJ,IAAI;gBACzB;YACF;YACA,MAAMX,UAAU0B,SAAS,CAAC,0CAA0C,EAAEA,QAAQ,GAAG;YACjF,MAAM,IAAI5B,kBAAkBE,SAAS,IAAI,CAACK,OAAO;QACnD;IACF;IAvEA,YAAYA,OAA+B,CAAE;QAC3C,IAAI,CAACA,OAAO,GAAGA;IACjB;AAsEF;AAEA,OAAO,MAAMuB,4BAA4B7B;IAGvC,YAAYC,OAAe,EAAEC,QAAiC,CAAE;QAC9D,KAAK,CAACD;QACN,IAAI,CAACE,IAAI,GAAG;QACZ,IAAI,CAACD,QAAQ,GAAGA;IAClB;AACF;AAEA,OAAO,MAAM4B;IAOXzB,MAA+B;QAC7B,OAAO,IAAI,CAACC,OAAO;IACrB;IAEAM,OAAe;QACb,MAAMmB,WAAWC,kBAAkB,IAAI,CAAC1B,OAAO,CAAC2B,QAAQ;QACxD,IAAI,CAACF,SAASG,MAAM,EAAE;YACpB,MAAM,IAAIL,oBAAoB,gDAAgD,IAAI,CAACvB,OAAO;QAC5F;QACA,OAAOyB,SAASI,IAAI,CAAC;IACvB;IAEA5B,KAAkBC,SAA4B,EAAK;QACjD,MAAM4B,YAAY,IAAI,CAACxB,IAAI;QAC3B,IAAI;YACF,MAAMyB,SAAShB,KAAKC,KAAK,CAACc;YAC1B,IAAI5B,WAAW;gBACb,MAAMG,cAAgCH;gBACtCG,YAAY0B;YACd;YACA,OAAOA;QACT,EAAE,OAAOd,OAAO;YACd,MAAMC,SAASC,kBAAkBF;YACjC,MAAM,IAAIM,oBAAoB,CAAC,qCAAqC,EAAEL,QAAQ,EAAE,IAAI,CAAClB,OAAO;QAC9F;IACF;IA7BA,YAAYA,OAAgC,CAAE;QAC5C,IAAI,CAACA,OAAO,GAAGA;IACjB;AA4BF;AAEA,OAAO,MAAMgC,8BAA8BtC;IAGzC,YAAYC,OAAe,EAAEC,QAAoC,CAAE;QACjE,KAAK,CAACD;QACN,IAAI,CAACE,IAAI,GAAG;QACZ,IAAI,CAACD,QAAQ,GAAGA;IAClB;AACF;AAEA,OAAO,MAAMqC;IAOXlC,MAAkC;QAChC,OAAO,IAAI,CAACC,OAAO;IACrB;IAEAM,OAAe;QACb,MAAM4B,QAAQ,IAAI,CAACC,UAAU;QAC7B,IAAI,UAAUD,SAAS,OAAOA,MAAM5B,IAAI,KAAK,UAAU;YACrD,OAAO4B,MAAM5B,IAAI;QACnB;QACA,IAAI,UAAU4B,SAAS,OAAOA,MAAME,IAAI,KAAK,UAAU;YACrD,IAAI;gBACF,OAAO5C,OAAO6C,IAAI,CAACH,MAAME,IAAI,EAAE,UAAUE,QAAQ,CAAC;YACpD,EAAE,OAAOrB,OAAO;gBACd,MAAMC,SAASC,kBAAkBF;gBACjC,MAAM,IAAIe,sBAAsB,CAAC,8CAA8C,EAAEd,QAAQ,EAAE,IAAI,CAAClB,OAAO;YACzG;QACF;QACA,MAAM,IAAIgC,sBAAsB,uDAAuD,IAAI,CAAChC,OAAO;IACrG;IAEAC,KAAkBC,SAA4B,EAAK;QACjD,MAAM4B,YAAY,IAAI,CAACxB,IAAI;QAC3B,IAAI;YACF,MAAMyB,SAAShB,KAAKC,KAAK,CAACc;YAC1B,IAAI5B,WAAW;gBACb,MAAMG,cAAgCH;gBACtCG,YAAY0B;YACd;YACA,OAAOA;QACT,EAAE,OAAOd,OAAO;YACd,MAAMC,SAASC,kBAAkBF;YACjC,MAAM,IAAIe,sBAAsB,CAAC,uCAAuC,EAAEd,QAAQ,EAAE,IAAI,CAAClB,OAAO;QAClG;IACF;IAEQmC,aAA6D;YACnD;QAAhB,MAAM,CAACD,MAAM,IAAG,yBAAA,IAAI,CAAClC,OAAO,CAACuC,QAAQ,cAArB,oCAAA,yBAAyB,EAAE;QAC3C,IAAI,CAACL,OAAO;YACV,MAAM,IAAIF,sBAAsB,kDAAkD,IAAI,CAAChC,OAAO;QAChG;QACA,OAAOkC;IACT;IA7CA,YAAYlC,OAAmC,CAAE;QAC/C,IAAI,CAACA,OAAO,GAAGA;IACjB;AA4CF;AAEA,SAASa,qBAAqBjB,QAAgC;IAC5D,OAAO4C,QAAQ,AAAC5C,SAA6CkB,iBAAiB;AAChF;AAEA,SAASP,sBAAsBX,QAAgC;IAC7D,OAAO6C,OAAO7C,UAAU;AAC1B;AAEA,SAASe,mBAAmB+B,MAAkC;IAC5D,IAAI,CAACC,MAAMC,OAAO,CAACF,SAAS;QAC1B,OAAOG;IACT;IACA,OAAOH,OAAOI,IAAI,CAACC;AACrB;AAEA,SAASrB,kBAAkBC,QAAyB;IAClD,MAAMF,WAAqB,EAAE;IAC7B,KAAK,MAAM9B,WAAWgC,SAAU;QAC9B,MAAMjB,YAAYqC,cAAcpD,QAAQiB,OAAO,IAAIjB,QAAQiB,OAAO,GAAGiC;QACrE,IAAInC,WAAW;YACbe,SAASuB,IAAI,CAACtC,UAAUJ,IAAI;QAC9B;IACF;IACA,OAAOmB;AACT;AAEA,SAASsB,cAAcE,KAAc;IACnC,OAAOT,QAAQS,UAAU,OAAOA,UAAU,YAAY,AAACA,MAA4BC,IAAI,KAAK;AAC9F;AAEA,MAAMC,cAAcC,OAAOC,SAAS,CAACC,cAAc;AAEnD,SAASb,OAAOc,MAAc,EAAEC,GAAgB;IAC9C,OAAOL,YAAYM,IAAI,CAACF,QAAQC;AAClC;AAEA,SAASrC,kBAAkBF,KAAc;IACvC,IAAIA,iBAAiBvB,SAAS,OAAOuB,MAAMtB,OAAO,KAAK,UAAU;QAC/D,OAAOsB,MAAMtB,OAAO;IACtB;IACA,IAAI,OAAOsB,UAAU,UAAU;QAC7B,OAAOA;IACT;IACA,IAAI;QACF,OAAOF,KAAK2C,SAAS,CAACzC;IACxB,EAAE,OAAM;QACN,OAAOK,OAAOL;IAChB;AACF"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/response-wrappers.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type { Client, ContentBlock, PromptMessage, TextContent } from '@modelcontextprotocol/client';\n\nexport type NativeCallToolResponse = Awaited<ReturnType<Client['callTool']>>;\nexport type NativeGetPromptResponse = Awaited<ReturnType<Client['getPrompt']>>;\nexport type NativeReadResourceResponse = Awaited<ReturnType<Client['readResource']>>;\n\nexport type JsonValidator<T> = (value: unknown) => asserts value is T;\n\nexport class ToolResponseError extends Error {\n readonly response: NativeCallToolResponse;\n\n constructor(message: string, response: NativeCallToolResponse) {\n super(message);\n this.name = 'ToolResponseError';\n this.response = response;\n }\n}\n\nexport class ToolResponseWrapper {\n private readonly payload: NativeCallToolResponse;\n\n constructor(payload: NativeCallToolResponse) {\n this.payload = payload;\n }\n\n raw(): NativeCallToolResponse {\n return this.payload;\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const value = this.resolveJsonPayload();\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(value);\n }\n return value as T;\n }\n\n text(): string {\n if (isCompatibilityResult(this.payload)) {\n if (typeof this.payload.toolResult === 'string') {\n return this.payload.toolResult;\n }\n throw new ToolResponseError('Compatibility tool result is not text', this.payload);\n }\n\n this.throwIfError();\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include text content', this.payload);\n }\n\n return textBlock.text;\n }\n\n private resolveJsonPayload(): unknown {\n if (isCompatibilityResult(this.payload)) {\n return this.payload.toolResult;\n }\n\n this.throwIfError();\n\n if (hasStructuredContent(this.payload)) {\n return this.payload.structuredContent;\n }\n\n const textBlock = findFirstTextBlock(this.payload.content ?? []);\n if (!textBlock) {\n throw new ToolResponseError('Tool response did not include structuredContent or text content', this.payload);\n }\n\n try {\n return JSON.parse(textBlock.text) as unknown;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ToolResponseError(`Failed to parse tool text content as JSON: ${reason}`, this.payload);\n }\n }\n\n private throwIfError(): void {\n if ('isError' in this.payload && this.payload.isError) {\n let detail = typeof this.payload.error === 'object' && this.payload.error && 'message' in this.payload.error ? String((this.payload.error as { message?: unknown }).message ?? '') : '';\n if (!detail) {\n const textBlock = findFirstTextBlock((this.payload.content ?? []) as ContentBlock[]);\n if (textBlock?.text) {\n detail = textBlock.text;\n }\n }\n const message = detail ? `Tool invocation returned an error result: ${detail}` : 'Tool invocation returned an error result';\n throw new ToolResponseError(message, this.payload);\n }\n }\n}\n\nexport class PromptResponseError extends Error {\n readonly response: NativeGetPromptResponse;\n\n constructor(message: string, response: NativeGetPromptResponse) {\n super(message);\n this.name = 'PromptResponseError';\n this.response = response;\n }\n}\n\nexport class PromptResponseWrapper {\n private readonly payload: NativeGetPromptResponse;\n\n constructor(payload: NativeGetPromptResponse) {\n this.payload = payload;\n }\n\n raw(): NativeGetPromptResponse {\n return this.payload;\n }\n\n text(): string {\n const segments = collectPromptText(this.payload.messages);\n if (!segments.length) {\n throw new PromptResponseError('Prompt response did not include text content', this.payload);\n }\n return segments.join('\\n\\n');\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new PromptResponseError(`Failed to parse prompt text as JSON: ${reason}`, this.payload);\n }\n }\n}\n\nexport class ResourceResponseError extends Error {\n readonly response: NativeReadResourceResponse;\n\n constructor(message: string, response: NativeReadResourceResponse) {\n super(message);\n this.name = 'ResourceResponseError';\n this.response = response;\n }\n}\n\nexport class ResourceResponseWrapper {\n private readonly payload: NativeReadResourceResponse;\n\n constructor(payload: NativeReadResourceResponse) {\n this.payload = payload;\n }\n\n raw(): NativeReadResourceResponse {\n return this.payload;\n }\n\n text(): string {\n const entry = this.firstEntry();\n if ('text' in entry && typeof entry.text === 'string') {\n return entry.text;\n }\n if ('blob' in entry && typeof entry.blob === 'string') {\n try {\n return Buffer.from(entry.blob, 'base64').toString('utf8');\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to decode resource blob as UTF-8 text: ${reason}`, this.payload);\n }\n }\n throw new ResourceResponseError('Resource content does not include text or blob data', this.payload);\n }\n\n json<T = unknown>(validator?: JsonValidator<T>): T {\n const textValue = this.text();\n try {\n const parsed = JSON.parse(textValue) as unknown;\n if (validator) {\n const assertValid: JsonValidator<T> = validator;\n assertValid(parsed);\n }\n return parsed as T;\n } catch (error) {\n const reason = formatErrorReason(error);\n throw new ResourceResponseError(`Failed to parse resource text as JSON: ${reason}`, this.payload);\n }\n }\n\n private firstEntry(): NativeReadResourceResponse['contents'][number] {\n const [entry] = this.payload.contents ?? [];\n if (!entry) {\n throw new ResourceResponseError('Resource response did not include any contents', this.payload);\n }\n return entry;\n }\n}\n\nfunction hasStructuredContent(response: NativeCallToolResponse): response is NativeCallToolResponse & { structuredContent: Record<string, unknown> } {\n return Boolean((response as { structuredContent?: unknown }).structuredContent);\n}\n\nfunction isCompatibilityResult(response: NativeCallToolResponse): response is NativeCallToolResponse & { toolResult: unknown } {\n return hasOwn(response, 'toolResult');\n}\n\nfunction findFirstTextBlock(blocks: ContentBlock[] | undefined): TextContent | undefined {\n if (!Array.isArray(blocks)) {\n return undefined;\n }\n return blocks.find(isTextContent);\n}\n\nfunction collectPromptText(messages: PromptMessage[]): string[] {\n const segments: string[] = [];\n for (const message of messages) {\n const textBlock = isTextContent(message.content) ? message.content : undefined;\n if (textBlock) {\n segments.push(textBlock.text);\n }\n }\n return segments;\n}\n\nfunction isTextContent(block: unknown): block is TextContent {\n return Boolean(block) && typeof block === 'object' && (block as { type?: string }).type === 'text';\n}\n\nconst protoHasOwn = Object.prototype.hasOwnProperty;\n\nfunction hasOwn(target: object, key: PropertyKey): boolean {\n return protoHasOwn.call(target, key);\n}\n\nfunction formatErrorReason(error: unknown): string {\n if (error instanceof Error && typeof error.message === 'string') {\n return error.message;\n }\n if (typeof error === 'string') {\n return error;\n }\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n"],"names":["Buffer","ToolResponseError","Error","message","response","name","ToolResponseWrapper","raw","payload","json","validator","value","resolveJsonPayload","assertValid","text","isCompatibilityResult","toolResult","throwIfError","textBlock","findFirstTextBlock","content","hasStructuredContent","structuredContent","JSON","parse","error","reason","formatErrorReason","isError","detail","String","PromptResponseError","PromptResponseWrapper","segments","collectPromptText","messages","length","join","textValue","parsed","ResourceResponseError","ResourceResponseWrapper","entry","firstEntry","blob","from","toString","contents","Boolean","hasOwn","blocks","Array","isArray","undefined","find","isTextContent","push","block","type","protoHasOwn","Object","prototype","hasOwnProperty","target","key","call","stringify"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides text-based search across tools, prompts, and resources
|
|
5
5
|
* from connected MCP servers.
|
|
6
6
|
*/
|
|
7
|
-
import type { Client } from '@modelcontextprotocol/
|
|
7
|
+
import type { Client } from '@modelcontextprotocol/client';
|
|
8
8
|
import type { CapabilityIndex, SearchOptions, SearchResponse } from './types.js';
|
|
9
9
|
export type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;
|
|
10
10
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","propName","prop","Object","entries","join","extractArgumentsText","args","Array","isArray","map","arg","name","buildCapabilityIndex","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","Promise","all","listTools","catch","listPrompts","listResources","tools","tool","type","server","schemaText","prompts","prompt","argumentsText","arguments","resources","resource","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","searchCapabilities","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice","search"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/search/search.ts"],"sourcesContent":["/**\n * Search implementation for MCP capability discovery\n *\n * Provides text-based search across tools, prompts, and resources\n * from connected MCP servers.\n */\n\nimport type { Client } from '@modelcontextprotocol/client';\nimport type { PromptArgument } from '../connection/types.ts';\nimport type { CapabilityIndex, CapabilityType, IndexedCapability, IndexedPrompt, IndexedResource, IndexedTool, SearchField, SearchOptions, SearchResponse, SearchResult } from './types.ts';\n\nexport type CapabilityClient = Pick<Client, 'listTools' | 'listPrompts' | 'listResources'>;\n\nconst DEFAULT_LIMIT = 20;\nconst DEFAULT_THRESHOLD = 0;\nconst DEFAULT_TYPES: CapabilityType[] = ['tool', 'prompt', 'resource'];\nconst DEFAULT_SEARCH_FIELDS: SearchField[] = ['name', 'description', 'schema'];\n\n/**\n * Extract searchable text from a JSON Schema's property descriptions\n */\nfunction extractSchemaText(inputSchema: unknown): string {\n if (!inputSchema || typeof inputSchema !== 'object') {\n return '';\n }\n\n const schema = inputSchema as {\n properties?: Record<string, { description?: string; name?: string }>;\n description?: string;\n };\n\n const parts: string[] = [];\n\n // Add schema-level description if present\n if (schema.description) {\n parts.push(schema.description);\n }\n\n // Add property names and descriptions\n if (schema.properties) {\n for (const [propName, prop] of Object.entries(schema.properties)) {\n parts.push(propName);\n if (prop && typeof prop === 'object' && prop.description) {\n parts.push(prop.description);\n }\n }\n }\n\n return parts.join(' ');\n}\n\n/**\n * Extract searchable text from prompt arguments\n */\nfunction extractArgumentsText(args: PromptArgument[] | undefined): string {\n if (!args || !Array.isArray(args)) {\n return '';\n }\n\n return args\n .map((arg) => {\n const parts = [arg.name];\n if (arg.description) {\n parts.push(arg.description);\n }\n return parts.join(' ');\n })\n .join(' ');\n}\n\n/**\n * Build an index of capabilities from connected MCP clients\n */\nexport async function buildCapabilityIndex(clients: Map<string, CapabilityClient>): Promise<CapabilityIndex> {\n const capabilities: IndexedCapability[] = [];\n const servers: string[] = [];\n\n for (const [serverName, client] of clients) {\n servers.push(serverName);\n\n // Fetch all capabilities in parallel, handling errors gracefully\n const [toolsResult, promptsResult, resourcesResult] = await Promise.all([client.listTools().catch(() => null), client.listPrompts().catch(() => null), client.listResources().catch(() => null)]);\n\n // Index tools\n if (toolsResult?.tools) {\n for (const tool of toolsResult.tools) {\n capabilities.push({\n type: 'tool',\n server: serverName,\n name: tool.name,\n description: tool.description,\n schemaText: extractSchemaText(tool.inputSchema),\n } satisfies IndexedTool);\n }\n }\n\n // Index prompts\n if (promptsResult?.prompts) {\n for (const prompt of promptsResult.prompts) {\n capabilities.push({\n type: 'prompt',\n server: serverName,\n name: prompt.name,\n description: prompt.description,\n argumentsText: extractArgumentsText(prompt.arguments as PromptArgument[] | undefined),\n arguments: prompt.arguments as PromptArgument[] | undefined,\n } satisfies IndexedPrompt);\n }\n }\n\n // Index resources\n if (resourcesResult?.resources) {\n for (const resource of resourcesResult.resources) {\n capabilities.push({\n type: 'resource',\n server: serverName,\n name: resource.name,\n description: resource.description,\n uri: resource.uri,\n mimeType: resource.mimeType,\n } satisfies IndexedResource);\n }\n }\n }\n\n return {\n capabilities,\n servers,\n indexedAt: new Date(),\n };\n}\n\n/**\n * Calculate relevance score and matched fields for a capability against a query\n */\nfunction scoreCapability(capability: IndexedCapability, queryTerms: string[], searchFields: SearchField[]): { score: number; matchedOn: string[] } {\n const matchedOn: string[] = [];\n let totalScore = 0;\n\n // Weights for different match types\n const EXACT_NAME_WEIGHT = 1.0;\n const PARTIAL_NAME_WEIGHT = 0.8;\n const DESCRIPTION_WEIGHT = 0.6;\n const SCHEMA_WEIGHT = 0.4;\n const SERVER_WEIGHT = 0.3;\n\n const nameLower = capability.name.toLowerCase();\n const descLower = (capability.description || '').toLowerCase();\n const serverLower = capability.server.toLowerCase();\n\n // Get schema/arguments text based on type\n let schemaTextLower = '';\n if (capability.type === 'tool') {\n schemaTextLower = capability.schemaText.toLowerCase();\n } else if (capability.type === 'prompt') {\n schemaTextLower = capability.argumentsText.toLowerCase();\n } else if (capability.type === 'resource') {\n // For resources, include URI and mimeType in searchable text\n schemaTextLower = `${capability.uri} ${capability.mimeType || ''}`.toLowerCase();\n }\n\n for (const term of queryTerms) {\n const termLower = term.toLowerCase();\n\n // Check name matches\n if (searchFields.includes('name')) {\n if (nameLower === termLower) {\n totalScore += EXACT_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n } else if (nameLower.includes(termLower)) {\n totalScore += PARTIAL_NAME_WEIGHT;\n if (!matchedOn.includes('name')) matchedOn.push('name');\n }\n }\n\n // Check description matches\n if (searchFields.includes('description') && descLower.includes(termLower)) {\n totalScore += DESCRIPTION_WEIGHT;\n if (!matchedOn.includes('description')) matchedOn.push('description');\n }\n\n // Check schema/arguments matches\n if (searchFields.includes('schema') && schemaTextLower.includes(termLower)) {\n totalScore += SCHEMA_WEIGHT;\n const fieldName = capability.type === 'tool' ? 'inputSchema' : capability.type === 'prompt' ? 'arguments' : 'uri';\n if (!matchedOn.includes(fieldName)) matchedOn.push(fieldName);\n }\n\n // Check server name matches\n if (searchFields.includes('server') && serverLower.includes(termLower)) {\n totalScore += SERVER_WEIGHT;\n if (!matchedOn.includes('server')) matchedOn.push('server');\n }\n }\n\n // Normalize score to 0-1 range based on number of terms\n const normalizedScore = queryTerms.length > 0 ? Math.min(1, totalScore / queryTerms.length) : 0;\n\n return { score: normalizedScore, matchedOn };\n}\n\n/**\n * Search for capabilities matching a query string\n */\nexport function searchCapabilities(index: CapabilityIndex, query: string, options: SearchOptions = {}): SearchResponse {\n const { types = DEFAULT_TYPES, servers, searchFields = DEFAULT_SEARCH_FIELDS, limit = DEFAULT_LIMIT, threshold = DEFAULT_THRESHOLD } = options;\n\n // Tokenize query into search terms\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n\n // If empty query, return empty results\n if (queryTerms.length === 0) {\n return { query, results: [], total: 0 };\n }\n\n // Filter and score capabilities\n const scoredResults: Array<{ capability: IndexedCapability; score: number; matchedOn: string[] }> = [];\n\n for (const capability of index.capabilities) {\n // Filter by type\n if (!types.includes(capability.type)) {\n continue;\n }\n\n // Filter by server\n if (servers && servers.length > 0 && !servers.includes(capability.server)) {\n continue;\n }\n\n // Score the capability\n const { score, matchedOn } = scoreCapability(capability, queryTerms, searchFields);\n\n // Apply threshold filter\n if (score >= threshold && matchedOn.length > 0) {\n scoredResults.push({ capability, score, matchedOn });\n }\n }\n\n // Sort by score descending\n scoredResults.sort((a, b) => b.score - a.score);\n\n // Get total before limiting\n const total = scoredResults.length;\n\n // Apply limit and transform to SearchResult\n const results: SearchResult[] = scoredResults.slice(0, limit).map(({ capability, score, matchedOn }) => ({\n type: capability.type,\n server: capability.server,\n name: capability.name,\n description: capability.description,\n matchedOn,\n score,\n }));\n\n return { query, results, total };\n}\n\n/**\n * Convenience function to search directly from connected clients\n * Builds index and performs search in one call\n */\nexport async function search(clients: Map<string, CapabilityClient>, query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n const index = await buildCapabilityIndex(clients);\n return searchCapabilities(index, query, options);\n}\n"],"names":["DEFAULT_LIMIT","DEFAULT_THRESHOLD","DEFAULT_TYPES","DEFAULT_SEARCH_FIELDS","extractSchemaText","inputSchema","schema","parts","description","push","properties","propName","prop","Object","entries","join","extractArgumentsText","args","Array","isArray","map","arg","name","buildCapabilityIndex","clients","capabilities","servers","serverName","client","toolsResult","promptsResult","resourcesResult","Promise","all","listTools","catch","listPrompts","listResources","tools","tool","type","server","schemaText","prompts","prompt","argumentsText","arguments","resources","resource","uri","mimeType","indexedAt","Date","scoreCapability","capability","queryTerms","searchFields","matchedOn","totalScore","EXACT_NAME_WEIGHT","PARTIAL_NAME_WEIGHT","DESCRIPTION_WEIGHT","SCHEMA_WEIGHT","SERVER_WEIGHT","nameLower","toLowerCase","descLower","serverLower","schemaTextLower","term","termLower","includes","fieldName","normalizedScore","length","Math","min","score","searchCapabilities","index","query","options","types","limit","threshold","split","filter","results","total","scoredResults","sort","a","b","slice","search"],"mappings":"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"}
|