-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathclient.ts
More file actions
154 lines (137 loc) · 4.06 KB
/
client.ts
File metadata and controls
154 lines (137 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* MCP Client Wrapper - Manage MCP client lifecycle and capabilities
*
* This module wraps the MCP SDK Client for React usage, handling:
* - Client creation with proper capabilities
* - Connection lifecycle (connect/disconnect)
* - Server info extraction
*
* Usage:
* import { createMcpClient, connectClient } from '@/lib/mcp/client';
*
* const client = createMcpClient();
* const transport = createHttpTransport(url);
* await connectClient(client, transport);
*/
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
import type { Implementation, ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';
/**
* Client configuration options.
*/
export interface McpClientOptions {
/** Client name shown to servers */
name?: string;
/** Client version */
version?: string;
/** Enable sampling capability (receive LLM requests from server) */
enableSampling?: boolean;
/** Enable roots capability (expose filesystem paths to server) */
enableRoots?: boolean;
}
/**
* Information about a connected MCP server.
*/
export interface ServerInfo {
/** Server name */
name: string;
/** Server version */
version: string;
/** Server capabilities */
capabilities: ServerCapabilities;
/** Server instructions (if provided) */
instructions?: string;
}
const DEFAULT_CLIENT_NAME = 'MCP Inspector';
const DEFAULT_CLIENT_VERSION = '2.0.0';
/**
* Create a new MCP client with Inspector capabilities.
*
* @param options - Client configuration options
* @returns Configured MCP Client instance
*/
export function createMcpClient(options: McpClientOptions = {}): Client {
const {
name = DEFAULT_CLIENT_NAME,
version = DEFAULT_CLIENT_VERSION,
enableSampling = true,
enableRoots = true,
} = options;
const clientInfo: Implementation = {
name,
version,
};
// Build capabilities based on options
const capabilities: Record<string, unknown> = {};
if (enableSampling) {
// Declare sampling capability with tool support (per MCP 2025-11-25 spec)
capabilities.sampling = { tools: {} };
}
if (enableRoots) {
// Declare roots capability
capabilities.roots = { listChanged: true };
}
return new Client(clientInfo, { capabilities });
}
/**
* Connect an MCP client to a server via transport.
*
* @param client - MCP Client instance
* @param transport - Transport to connect through
* @returns Server information on successful connection
* @throws Error if connection fails
*/
export async function connectClient(
client: Client,
transport: Transport
): Promise<ServerInfo> {
await client.connect(transport);
const serverVersion = client.getServerVersion();
const serverCapabilities = client.getServerCapabilities();
const instructions = client.getInstructions();
if (!serverVersion) {
throw new Error('Failed to get server version after connection');
}
return {
name: serverVersion.name,
version: serverVersion.version,
capabilities: serverCapabilities ?? {},
instructions: instructions ?? undefined,
};
}
/**
* Disconnect an MCP client and clean up resources.
*
* @param client - MCP Client instance to disconnect
*/
export async function disconnectClient(client: Client): Promise<void> {
await client.close();
}
/**
* Check if a client is currently connected.
*
* @param client - MCP Client instance
* @returns true if connected
*/
export function isClientConnected(client: Client): boolean {
// The SDK client doesn't expose connection state directly,
// but we can check if server version is available
try {
return client.getServerVersion() !== undefined;
} catch {
return false;
}
}
/**
* Check if server supports a specific capability.
*
* @param serverInfo - Server info from connection
* @param capability - Capability name to check
* @returns true if capability is supported
*/
export function serverSupports(
serverInfo: ServerInfo,
capability: keyof ServerCapabilities
): boolean {
return serverInfo.capabilities[capability] !== undefined;
}