@yolk-sdk/mcp 0.0.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/client/client.d.mts +40 -0
  4. package/dist/client/client.d.mts.map +1 -0
  5. package/dist/client/client.mjs +225 -0
  6. package/dist/client/client.mjs.map +1 -0
  7. package/dist/client/config.d.mts +29 -0
  8. package/dist/client/config.d.mts.map +1 -0
  9. package/dist/client/config.mjs +13 -0
  10. package/dist/client/config.mjs.map +1 -0
  11. package/dist/client/errors.d.mts +14 -0
  12. package/dist/client/errors.d.mts.map +1 -0
  13. package/dist/client/errors.mjs +22 -0
  14. package/dist/client/errors.mjs.map +1 -0
  15. package/dist/client/index.d.mts +5 -0
  16. package/dist/client/index.mjs +5 -0
  17. package/dist/client/node.d.mts +16 -0
  18. package/dist/client/node.d.mts.map +1 -0
  19. package/dist/client/node.mjs +13 -0
  20. package/dist/client/node.mjs.map +1 -0
  21. package/dist/client/protocol.d.mts +175 -0
  22. package/dist/client/protocol.d.mts.map +1 -0
  23. package/dist/client/protocol.mjs +225 -0
  24. package/dist/client/protocol.mjs.map +1 -0
  25. package/dist/index.d.mts +1 -0
  26. package/dist/index.mjs +1 -0
  27. package/dist/server/errors.d.mts +11 -0
  28. package/dist/server/errors.d.mts.map +1 -0
  29. package/dist/server/errors.mjs +16 -0
  30. package/dist/server/errors.mjs.map +1 -0
  31. package/dist/server/index.d.mts +4 -0
  32. package/dist/server/index.mjs +4 -0
  33. package/dist/server/server.d.mts +22 -0
  34. package/dist/server/server.d.mts.map +1 -0
  35. package/dist/server/server.mjs +180 -0
  36. package/dist/server/server.mjs.map +1 -0
  37. package/dist/server/stdio.d.mts +8 -0
  38. package/dist/server/stdio.d.mts.map +1 -0
  39. package/dist/server/stdio.mjs +18 -0
  40. package/dist/server/stdio.mjs.map +1 -0
  41. package/package.json +77 -0
  42. package/src/client/README.md +24 -0
  43. package/src/client/client.ts +494 -0
  44. package/src/client/config.ts +37 -0
  45. package/src/client/errors.ts +20 -0
  46. package/src/client/index.ts +48 -0
  47. package/src/client/node.ts +32 -0
  48. package/src/client/protocol.ts +364 -0
  49. package/src/index.ts +2 -0
  50. package/src/server/README.md +22 -0
  51. package/src/server/errors.ts +6 -0
  52. package/src/server/index.ts +4 -0
  53. package/src/server/server.ts +331 -0
  54. package/src/server/stdio.ts +37 -0
@@ -0,0 +1,494 @@
1
+ import { Duration, Effect, Option, Stream } from 'effect'
2
+ import { HttpClient, HttpClientRequest } from 'effect/unstable/http'
3
+ import { ChildProcess } from 'effect/unstable/process'
4
+ import type { ChildProcessSpawner } from 'effect/unstable/process'
5
+ import type { ToolResult } from '@yolk-sdk/agent/protocol'
6
+ import type {
7
+ McpClientInfo,
8
+ McpLocalServerConfig,
9
+ McpRemoteServerConfig,
10
+ McpSecurityPolicy,
11
+ McpServerConfig
12
+ } from './config.ts'
13
+ import { defaultMcpClientInfo, defaultMcpSecurityPolicy } from './config.ts'
14
+ import { McpError } from './errors.ts'
15
+ import {
16
+ decodeJsonRpcResponseFromJson,
17
+ decodeToolCallResult,
18
+ decodeToolsListResult,
19
+ encodeJsonRpcMessage,
20
+ jsonRpcErrorToMcpError,
21
+ makeInitializedNotification,
22
+ makeInitializeParams,
23
+ makeJsonRpcRequest,
24
+ mcpToolToToolDef,
25
+ toolCallResultToToolResult,
26
+ type JsonRpcNotification,
27
+ type JsonRpcRequest,
28
+ type JsonRpcResponse
29
+ } from './protocol.ts'
30
+
31
+ const defaultRequestTimeoutMs = 30_000
32
+
33
+ export type McpClientOptions = {
34
+ readonly clientInfo?: McpClientInfo
35
+ readonly securityPolicy?: McpSecurityPolicy
36
+ readonly timeoutMs?: number
37
+ }
38
+
39
+ export type McpResolvedTool = {
40
+ readonly serverName: string
41
+ readonly mcpToolName: string
42
+ readonly def: ReturnType<typeof mcpToolToToolDef>
43
+ }
44
+
45
+ const unknownToMessage = (error: unknown) =>
46
+ error instanceof Error ? error.message : String(error)
47
+
48
+ const timeoutMs = (options?: McpClientOptions) => options?.timeoutMs ?? defaultRequestTimeoutMs
49
+
50
+ const clientInfo = (options?: McpClientOptions) => options?.clientInfo ?? defaultMcpClientInfo
51
+
52
+ const securityPolicy = (options?: McpClientOptions) =>
53
+ options?.securityPolicy ?? defaultMcpSecurityPolicy
54
+
55
+ const fail = (server: string, message: string, cause: McpError['cause']) =>
56
+ Effect.fail(new McpError({ server, message, cause }))
57
+
58
+ const validateRemoteUrl = (config: McpRemoteServerConfig, policy: McpSecurityPolicy) =>
59
+ Effect.gen(function* () {
60
+ const url = yield* Effect.try({
61
+ try: () => new URL(config.url),
62
+ catch: error =>
63
+ new McpError({
64
+ server: config.name,
65
+ message: `Invalid MCP server URL: ${unknownToMessage(error)}`,
66
+ cause: 'validation'
67
+ })
68
+ })
69
+
70
+ if (url.protocol === 'https:') {
71
+ return url.toString()
72
+ }
73
+
74
+ if (
75
+ policy.allowDevHttpLocalhost &&
76
+ url.protocol === 'http:' &&
77
+ (url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]')
78
+ ) {
79
+ return url.toString()
80
+ }
81
+
82
+ return yield* fail(config.name, 'Remote MCP requires https: URL', 'security')
83
+ })
84
+
85
+ const validateLocal = (config: McpLocalServerConfig, policy: McpSecurityPolicy) =>
86
+ Effect.gen(function* () {
87
+ if (!policy.allowLocalServers) {
88
+ return yield* fail(config.name, 'Local MCP servers are disabled by policy', 'security')
89
+ }
90
+
91
+ if (config.command.length === 0) {
92
+ return yield* fail(config.name, 'Local MCP command must not be empty', 'validation')
93
+ }
94
+ })
95
+
96
+ const parseSseJsonRpcResponse = (server: string, body: string) =>
97
+ Effect.gen(function* () {
98
+ const candidates = [
99
+ body,
100
+ ...body
101
+ .split('\n')
102
+ .filter(line => line.startsWith('data: '))
103
+ .map(line => line.substring('data: '.length))
104
+ ]
105
+ const parsed = yield* Effect.forEach(candidates, candidate =>
106
+ decodeJsonRpcResponseFromJson(server, candidate).pipe(Effect.option)
107
+ ).pipe(Effect.map(Option.firstSomeOf))
108
+
109
+ if (Option.isSome(parsed)) {
110
+ return parsed.value
111
+ }
112
+
113
+ return yield* fail(server, 'MCP response did not contain a JSON-RPC message', 'protocol')
114
+ })
115
+
116
+ const unwrapResponse = (server: string, response: JsonRpcResponse) =>
117
+ 'error' in response
118
+ ? Effect.fail(jsonRpcErrorToMcpError(server, response.error))
119
+ : Effect.succeed(response.result)
120
+
121
+ const mapUnknownToMcpError =
122
+ (server: string, message: string, cause: McpError['cause']) => (error: unknown) =>
123
+ error instanceof McpError
124
+ ? error
125
+ : new McpError({
126
+ server,
127
+ message: `${message}: ${unknownToMessage(error)}`,
128
+ cause
129
+ })
130
+
131
+ const findDuplicateToolName = (tools: ReadonlyArray<McpResolvedTool>) => {
132
+ const names = tools.map(tool => tool.def.name)
133
+ return Option.fromNullishOr(names.find((name, index) => names.indexOf(name) !== index))
134
+ }
135
+
136
+ const requestRemote = (
137
+ config: McpRemoteServerConfig,
138
+ request: JsonRpcRequest,
139
+ options?: McpClientOptions
140
+ ) =>
141
+ Effect.gen(function* () {
142
+ const policy = securityPolicy(options)
143
+ const url = yield* validateRemoteUrl(config, policy)
144
+ const http = yield* HttpClient.HttpClient
145
+ const body = yield* encodeJsonRpcMessage(config.name, request)
146
+ const encoded = HttpClientRequest.post(url).pipe(
147
+ HttpClientRequest.accept('application/json, text/event-stream'),
148
+ HttpClientRequest.setHeaders(config.headers ?? {}),
149
+ HttpClientRequest.bodyText(body, 'application/json')
150
+ )
151
+ const response = yield* HttpClient.filterStatusOk(http)
152
+ .execute(encoded)
153
+ .pipe(
154
+ Effect.mapError(
155
+ error =>
156
+ new McpError({
157
+ server: config.name,
158
+ message: `MCP request failed: ${unknownToMessage(error)}`,
159
+ cause: 'transport'
160
+ })
161
+ ),
162
+ Effect.timeoutOrElse({
163
+ duration: Duration.millis(timeoutMs(options)),
164
+ orElse: () => fail(config.name, 'MCP request timed out', 'timeout')
165
+ })
166
+ )
167
+ const text = yield* response.text.pipe(
168
+ Effect.mapError(
169
+ error =>
170
+ new McpError({
171
+ server: config.name,
172
+ message: `Could not read MCP response: ${unknownToMessage(error)}`,
173
+ cause: 'transport'
174
+ })
175
+ )
176
+ )
177
+ const decoded = yield* parseSseJsonRpcResponse(config.name, text)
178
+
179
+ return yield* unwrapResponse(config.name, decoded)
180
+ })
181
+
182
+ const notifyRemote = (
183
+ config: McpRemoteServerConfig,
184
+ notification: JsonRpcNotification,
185
+ options?: McpClientOptions
186
+ ) =>
187
+ Effect.gen(function* () {
188
+ const policy = securityPolicy(options)
189
+ const url = yield* validateRemoteUrl(config, policy)
190
+ const http = yield* HttpClient.HttpClient
191
+ const body = yield* encodeJsonRpcMessage(config.name, notification)
192
+ const encoded = HttpClientRequest.post(url).pipe(
193
+ HttpClientRequest.accept('application/json, text/event-stream'),
194
+ HttpClientRequest.setHeaders(config.headers ?? {}),
195
+ HttpClientRequest.bodyText(body, 'application/json')
196
+ )
197
+ yield* HttpClient.filterStatusOk(http)
198
+ .execute(encoded)
199
+ .pipe(
200
+ Effect.mapError(
201
+ error =>
202
+ new McpError({
203
+ server: config.name,
204
+ message: `MCP notification failed: ${unknownToMessage(error)}`,
205
+ cause: 'transport'
206
+ })
207
+ ),
208
+ Effect.timeoutOrElse({
209
+ duration: Duration.millis(timeoutMs(options)),
210
+ orElse: () => fail(config.name, 'MCP notification timed out', 'timeout')
211
+ })
212
+ )
213
+ })
214
+
215
+ const requestRemoteSession = (
216
+ config: McpRemoteServerConfig,
217
+ request: JsonRpcRequest,
218
+ options?: McpClientOptions
219
+ ) =>
220
+ Effect.gen(function* () {
221
+ yield* requestRemote(config, initializeRequest(options), options)
222
+ yield* notifyRemote(config, makeInitializedNotification(), options)
223
+ return yield* requestRemote(config, request, options)
224
+ })
225
+
226
+ type EncodedLocalMessage = {
227
+ readonly message: JsonRpcRequest | JsonRpcNotification
228
+ readonly line: string
229
+ }
230
+
231
+ const requestLocalEncoded = (
232
+ config: McpLocalServerConfig,
233
+ messages: ReadonlyArray<EncodedLocalMessage>,
234
+ expectedResponses: number,
235
+ options?: McpClientOptions
236
+ ) => {
237
+ const policy = securityPolicy(options)
238
+ if (!policy.allowLocalServers) {
239
+ return fail(config.name, 'Local MCP servers are disabled by policy', 'security')
240
+ }
241
+
242
+ const command = config.command[0]
243
+ if (command === undefined) {
244
+ return fail(config.name, 'Local MCP command must not be empty', 'validation')
245
+ }
246
+
247
+ return Effect.gen(function* () {
248
+ const stdin = Stream.fromIterable(messages.map(message => `${message.line}\n`)).pipe(
249
+ Stream.encodeText
250
+ )
251
+ const child = yield* ChildProcess.make(command, config.command.slice(1), {
252
+ env: config.environment ?? {},
253
+ extendEnv: false,
254
+ stdin: { stream: stdin, endOnDone: true },
255
+ stderr: 'ignore'
256
+ })
257
+ const lines = yield* child.stdout.pipe(
258
+ Stream.decodeText,
259
+ Stream.splitLines,
260
+ Stream.filter(line => line.length > 0),
261
+ Stream.take(expectedResponses),
262
+ Stream.runCollect
263
+ )
264
+ const responses = yield* Effect.forEach(lines, line =>
265
+ decodeJsonRpcResponseFromJson(config.name, line)
266
+ )
267
+
268
+ if (responses.length < expectedResponses) {
269
+ return yield* fail(config.name, 'Local MCP did not return expected response', 'protocol')
270
+ }
271
+
272
+ return responses
273
+ }).pipe(
274
+ Effect.scoped,
275
+ Effect.timeoutOrElse({
276
+ duration: Duration.millis(timeoutMs(options)),
277
+ orElse: () => fail(config.name, 'Local MCP request timed out', 'timeout')
278
+ }),
279
+ Effect.mapError(mapUnknownToMcpError(config.name, 'Local MCP request failed', 'transport'))
280
+ )
281
+ }
282
+
283
+ const requestLocal = (
284
+ config: McpLocalServerConfig,
285
+ requests: ReadonlyArray<JsonRpcRequest | JsonRpcNotification>,
286
+ expectedResponses: number,
287
+ options?: McpClientOptions
288
+ ) =>
289
+ Effect.gen(function* () {
290
+ const messages = yield* Effect.forEach(requests, request =>
291
+ encodeJsonRpcMessage(config.name, request).pipe(
292
+ Effect.map(line => ({ message: request, line }))
293
+ )
294
+ )
295
+
296
+ return yield* requestLocalEncoded(config, messages, expectedResponses, options)
297
+ })
298
+
299
+ const initializeRequest = (options?: McpClientOptions) =>
300
+ makeJsonRpcRequest({
301
+ id: 1,
302
+ method: 'initialize',
303
+ params: makeInitializeParams(clientInfo(options))
304
+ })
305
+
306
+ const listToolsRequest = () => makeJsonRpcRequest({ id: 2, method: 'tools/list' })
307
+
308
+ const callToolRequest = (input: { readonly toolName: string; readonly params: unknown }) =>
309
+ makeJsonRpcRequest({
310
+ id: 3,
311
+ method: 'tools/call',
312
+ params: { name: input.toolName, arguments: input.params }
313
+ })
314
+
315
+ const responseById = (responses: ReadonlyArray<JsonRpcResponse>, id: string | number) =>
316
+ Option.fromNullishOr(responses.find(response => response.id === id))
317
+
318
+ const requestLocalSession = (
319
+ config: McpLocalServerConfig,
320
+ request: JsonRpcRequest,
321
+ options?: McpClientOptions
322
+ ) =>
323
+ Effect.gen(function* () {
324
+ const initialize = initializeRequest(options)
325
+ const responses = yield* requestLocal(
326
+ config,
327
+ [initialize, makeInitializedNotification(), request],
328
+ 2,
329
+ options
330
+ )
331
+ const initializeResponse = responseById(responses, initialize.id)
332
+ if (Option.isNone(initializeResponse)) {
333
+ return yield* fail(config.name, 'Local MCP did not return initialize response', 'protocol')
334
+ }
335
+ yield* unwrapResponse(config.name, initializeResponse.value)
336
+
337
+ return responses
338
+ }).pipe(
339
+ Effect.flatMap(responses => {
340
+ const response = responseById(responses, request.id)
341
+ return Option.isNone(response)
342
+ ? fail(config.name, 'Local MCP did not return expected response', 'protocol')
343
+ : unwrapResponse(config.name, response.value)
344
+ })
345
+ )
346
+
347
+ const resolveMcpTools = (config: McpServerConfig, result: unknown) =>
348
+ Effect.gen(function* () {
349
+ const tools = yield* decodeToolsListResult(result).pipe(
350
+ Effect.mapError(
351
+ error =>
352
+ new McpError({
353
+ server: config.name,
354
+ message: `Invalid tools/list result: ${unknownToMessage(error)}`,
355
+ cause: 'validation'
356
+ })
357
+ )
358
+ )
359
+
360
+ return tools.tools.map(tool => ({
361
+ serverName: config.name,
362
+ mcpToolName: tool.name,
363
+ def: mcpToolToToolDef({ serverName: config.name, tool })
364
+ }))
365
+ })
366
+
367
+ export const listRemoteMcpServerTools = (
368
+ config: McpRemoteServerConfig,
369
+ options?: McpClientOptions
370
+ ): Effect.Effect<ReadonlyArray<McpResolvedTool>, McpError, HttpClient.HttpClient> =>
371
+ Effect.gen(function* () {
372
+ if (config.enabled === false) {
373
+ return []
374
+ }
375
+
376
+ const result = yield* requestRemoteSession(config, listToolsRequest(), options)
377
+ return yield* resolveMcpTools(config, result)
378
+ })
379
+
380
+ export const listLocalMcpServerTools = (
381
+ config: McpLocalServerConfig,
382
+ options?: McpClientOptions
383
+ ): Effect.Effect<
384
+ ReadonlyArray<McpResolvedTool>,
385
+ McpError,
386
+ ChildProcessSpawner.ChildProcessSpawner
387
+ > =>
388
+ Effect.gen(function* () {
389
+ if (config.enabled === false) {
390
+ return []
391
+ }
392
+
393
+ yield* validateLocal(config, securityPolicy(options))
394
+ const result = yield* requestLocalSession(config, listToolsRequest(), options)
395
+ return yield* resolveMcpTools(config, result)
396
+ })
397
+
398
+ export const listMcpServerTools = (config: McpServerConfig, options?: McpClientOptions) =>
399
+ Effect.gen(function* () {
400
+ if (config.enabled === false) {
401
+ return []
402
+ }
403
+
404
+ if (config.type === 'local') {
405
+ return yield* listLocalMcpServerTools(config, options)
406
+ }
407
+
408
+ return yield* listRemoteMcpServerTools(config, options)
409
+ })
410
+
411
+ export type CallMcpServerToolInput = {
412
+ readonly config: McpServerConfig
413
+ readonly mcpToolName: string
414
+ readonly toolCallId: string
415
+ readonly params: unknown
416
+ readonly options?: McpClientOptions
417
+ }
418
+
419
+ const resolveMcpToolResult = (input: CallMcpServerToolInput, result: unknown) =>
420
+ Effect.gen(function* () {
421
+ const toolCallResult = yield* decodeToolCallResult(result).pipe(
422
+ Effect.mapError(
423
+ error =>
424
+ new McpError({
425
+ server: input.config.name,
426
+ message: `Invalid tools/call result: ${unknownToMessage(error)}`,
427
+ cause: 'validation'
428
+ })
429
+ )
430
+ )
431
+
432
+ return toolCallResultToToolResult({ toolCallId: input.toolCallId, result: toolCallResult })
433
+ })
434
+
435
+ export const callRemoteMcpServerTool = (
436
+ input: Omit<CallMcpServerToolInput, 'config'> & { readonly config: McpRemoteServerConfig }
437
+ ): Effect.Effect<ToolResult, McpError, HttpClient.HttpClient> =>
438
+ Effect.gen(function* () {
439
+ const result = yield* requestRemoteSession(
440
+ input.config,
441
+ callToolRequest({ toolName: input.mcpToolName, params: input.params }),
442
+ input.options
443
+ )
444
+ return yield* resolveMcpToolResult(input, result)
445
+ })
446
+
447
+ export const callLocalMcpServerTool = (
448
+ input: Omit<CallMcpServerToolInput, 'config'> & { readonly config: McpLocalServerConfig }
449
+ ): Effect.Effect<ToolResult, McpError, ChildProcessSpawner.ChildProcessSpawner> =>
450
+ Effect.gen(function* () {
451
+ const result = yield* requestLocalSession(
452
+ input.config,
453
+ callToolRequest({ toolName: input.mcpToolName, params: input.params }),
454
+ input.options
455
+ )
456
+ return yield* resolveMcpToolResult(input, result)
457
+ })
458
+
459
+ export const callMcpServerTool = (
460
+ input: CallMcpServerToolInput
461
+ ): Effect.Effect<
462
+ ToolResult,
463
+ McpError,
464
+ ChildProcessSpawner.ChildProcessSpawner | HttpClient.HttpClient
465
+ > =>
466
+ input.config.type === 'local'
467
+ ? callLocalMcpServerTool({
468
+ config: input.config,
469
+ mcpToolName: input.mcpToolName,
470
+ toolCallId: input.toolCallId,
471
+ params: input.params,
472
+ options: input.options
473
+ })
474
+ : callRemoteMcpServerTool({
475
+ config: input.config,
476
+ mcpToolName: input.mcpToolName,
477
+ toolCallId: input.toolCallId,
478
+ params: input.params,
479
+ options: input.options
480
+ })
481
+
482
+ export const listMcpTools = (configs: ReadonlyArray<McpServerConfig>, options?: McpClientOptions) =>
483
+ Effect.flatMap(
484
+ Effect.forEach(configs, config => listMcpServerTools(config, options)),
485
+ tools => {
486
+ const resolved = tools.flat()
487
+ const duplicate = findDuplicateToolName(resolved)
488
+ if (Option.isSome(duplicate)) {
489
+ return fail('mcp', `Duplicate MCP tool name: ${duplicate.value}`, 'validation')
490
+ }
491
+
492
+ return Effect.succeed(resolved)
493
+ }
494
+ )
@@ -0,0 +1,37 @@
1
+ export type McpRemoteServerConfig = {
2
+ readonly name: string
3
+ readonly type: 'remote'
4
+ readonly url: string
5
+ readonly headers?: Readonly<Record<string, string>>
6
+ readonly enabled?: boolean
7
+ }
8
+
9
+ export type McpLocalServerConfig = {
10
+ readonly name: string
11
+ readonly type: 'local'
12
+ readonly command: ReadonlyArray<string>
13
+ readonly environment?: Readonly<Record<string, string>>
14
+ readonly enabled?: boolean
15
+ }
16
+
17
+ export type McpServerConfig = McpRemoteServerConfig | McpLocalServerConfig
18
+
19
+ export type McpClientInfo = {
20
+ readonly name: string
21
+ readonly version: string
22
+ }
23
+
24
+ export type McpSecurityPolicy = {
25
+ readonly allowLocalServers: boolean
26
+ readonly allowDevHttpLocalhost: boolean
27
+ }
28
+
29
+ export const defaultMcpClientInfo: McpClientInfo = {
30
+ name: 'yolk',
31
+ version: '0.1.0'
32
+ }
33
+
34
+ export const defaultMcpSecurityPolicy: McpSecurityPolicy = {
35
+ allowLocalServers: false,
36
+ allowDevHttpLocalhost: false
37
+ }
@@ -0,0 +1,20 @@
1
+ import * as Schema from 'effect/Schema'
2
+
3
+ export const McpErrorCause = Schema.Literals([
4
+ 'disabled',
5
+ 'security',
6
+ 'transport',
7
+ 'protocol',
8
+ 'parse',
9
+ 'encoding',
10
+ 'timeout',
11
+ 'validation',
12
+ 'tool_error'
13
+ ])
14
+ export type McpErrorCause = typeof McpErrorCause.Type
15
+
16
+ export class McpError extends Schema.TaggedErrorClass<McpError>()('McpError', {
17
+ server: Schema.String,
18
+ message: Schema.String,
19
+ cause: McpErrorCause
20
+ }) {}
@@ -0,0 +1,48 @@
1
+ export { defaultMcpClientInfo, defaultMcpSecurityPolicy } from './config.ts'
2
+ export type {
3
+ McpClientInfo,
4
+ McpLocalServerConfig,
5
+ McpRemoteServerConfig,
6
+ McpSecurityPolicy,
7
+ McpServerConfig
8
+ } from './config.ts'
9
+ export {
10
+ callLocalMcpServerTool,
11
+ callMcpServerTool,
12
+ callRemoteMcpServerTool,
13
+ listLocalMcpServerTools,
14
+ listMcpServerTools,
15
+ listMcpTools,
16
+ listRemoteMcpServerTools
17
+ } from './client.ts'
18
+ export type { CallMcpServerToolInput, McpClientOptions, McpResolvedTool } from './client.ts'
19
+ export { McpError, McpErrorCause } from './errors.ts'
20
+ export {
21
+ decodeJsonRpcMessageFromJson,
22
+ decodeJsonRpcResponse,
23
+ decodeJsonRpcResponseFromJson,
24
+ decodeToolCallResult,
25
+ decodeToolsListResult,
26
+ encodeJsonRpcMessage,
27
+ GenericContentBlock,
28
+ JsonRpcErrorObject,
29
+ JsonRpcErrorResponse,
30
+ JsonRpcMessage,
31
+ JsonRpcNotification,
32
+ JsonRpcRequest,
33
+ JsonRpcResponse,
34
+ JsonRpcSuccessResponse,
35
+ jsonRpcErrorToMcpError,
36
+ latestMcpProtocolVersion,
37
+ makeInitializedNotification,
38
+ makeInitializeParams,
39
+ makeJsonRpcRequest,
40
+ McpTool,
41
+ mcpToolToToolDef,
42
+ sanitizeMcpName,
43
+ TextContentBlock,
44
+ ToolCallResult,
45
+ toolCallResultToToolResult,
46
+ ToolsListResult
47
+ } from './protocol.ts'
48
+ export type { JsonRpcMessage as JsonRpcMessageType } from './protocol.ts'
@@ -0,0 +1,32 @@
1
+ import { Effect } from 'effect'
2
+ import { NodeServices } from '@effect/platform-node'
3
+ import type { McpLocalServerConfig, McpServerConfig } from './config.ts'
4
+ import {
5
+ callLocalMcpServerTool,
6
+ callMcpServerTool,
7
+ listLocalMcpServerTools,
8
+ listMcpServerTools,
9
+ listMcpTools,
10
+ type CallMcpServerToolInput,
11
+ type McpClientOptions
12
+ } from './client.ts'
13
+
14
+ export const listLocalMcpServerToolsNode = (
15
+ config: McpLocalServerConfig,
16
+ options?: McpClientOptions
17
+ ) => listLocalMcpServerTools(config, options).pipe(Effect.provide(NodeServices.layer))
18
+
19
+ export const listMcpServerToolsNode = (config: McpServerConfig, options?: McpClientOptions) =>
20
+ listMcpServerTools(config, options).pipe(Effect.provide(NodeServices.layer))
21
+
22
+ export const listMcpToolsNode = (
23
+ configs: ReadonlyArray<McpServerConfig>,
24
+ options?: McpClientOptions
25
+ ) => listMcpTools(configs, options).pipe(Effect.provide(NodeServices.layer))
26
+
27
+ export const callLocalMcpServerToolNode = (
28
+ input: Omit<CallMcpServerToolInput, 'config'> & { readonly config: McpLocalServerConfig }
29
+ ) => callLocalMcpServerTool(input).pipe(Effect.provide(NodeServices.layer))
30
+
31
+ export const callMcpServerToolNode = (input: CallMcpServerToolInput) =>
32
+ callMcpServerTool(input).pipe(Effect.provide(NodeServices.layer))