@smthrs/mcp 0.0.0-stage → 1.0.0-rc.4

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 (128) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +21 -0
  3. package/README.md +111 -2
  4. package/dist/cjs/Diagnostics.d.ts +46 -0
  5. package/dist/cjs/Diagnostics.d.ts.map +1 -0
  6. package/dist/cjs/Diagnostics.js +29 -0
  7. package/dist/cjs/Diagnostics.js.map +7 -0
  8. package/dist/cjs/McpClient.d.ts +304 -0
  9. package/dist/cjs/McpClient.d.ts.map +1 -0
  10. package/dist/cjs/McpClient.js +622 -0
  11. package/dist/cjs/McpClient.js.map +7 -0
  12. package/dist/cjs/McpError.d.ts +44 -0
  13. package/dist/cjs/McpError.d.ts.map +1 -0
  14. package/dist/cjs/McpError.js +41 -0
  15. package/dist/cjs/McpError.js.map +7 -0
  16. package/dist/cjs/McpFlows.d.ts +113 -0
  17. package/dist/cjs/McpFlows.d.ts.map +1 -0
  18. package/dist/cjs/McpFlows.js +127 -0
  19. package/dist/cjs/McpFlows.js.map +7 -0
  20. package/dist/cjs/index.d.ts +39 -0
  21. package/dist/cjs/index.d.ts.map +1 -0
  22. package/dist/cjs/index.js +41 -0
  23. package/dist/cjs/index.js.map +7 -0
  24. package/dist/cjs/internal/DiagnosticReporter.d.ts +17 -0
  25. package/dist/cjs/internal/DiagnosticReporter.d.ts.map +1 -0
  26. package/dist/cjs/internal/DiagnosticReporter.js +56 -0
  27. package/dist/cjs/internal/DiagnosticReporter.js.map +7 -0
  28. package/dist/cjs/internal/HttpTransport.d.ts +67 -0
  29. package/dist/cjs/internal/HttpTransport.d.ts.map +1 -0
  30. package/dist/cjs/internal/HttpTransport.js +298 -0
  31. package/dist/cjs/internal/HttpTransport.js.map +7 -0
  32. package/dist/cjs/internal/JsonLimits.d.ts +29 -0
  33. package/dist/cjs/internal/JsonLimits.d.ts.map +1 -0
  34. package/dist/cjs/internal/JsonLimits.js +51 -0
  35. package/dist/cjs/internal/JsonLimits.js.map +7 -0
  36. package/dist/cjs/internal/Limits.d.ts +36 -0
  37. package/dist/cjs/internal/Limits.d.ts.map +1 -0
  38. package/dist/cjs/internal/Limits.js +34 -0
  39. package/dist/cjs/internal/Limits.js.map +7 -0
  40. package/dist/cjs/internal/Rpc.d.ts +141 -0
  41. package/dist/cjs/internal/Rpc.d.ts.map +1 -0
  42. package/dist/cjs/internal/Rpc.js +92 -0
  43. package/dist/cjs/internal/Rpc.js.map +7 -0
  44. package/dist/cjs/internal/StdioTransport.d.ts +78 -0
  45. package/dist/cjs/internal/StdioTransport.d.ts.map +1 -0
  46. package/dist/cjs/internal/StdioTransport.js +310 -0
  47. package/dist/cjs/internal/StdioTransport.js.map +7 -0
  48. package/dist/cjs/internal/Transport.d.ts +87 -0
  49. package/dist/cjs/internal/Transport.d.ts.map +1 -0
  50. package/dist/cjs/internal/Transport.js +116 -0
  51. package/dist/cjs/internal/Transport.js.map +7 -0
  52. package/dist/cjs/package.json +1 -0
  53. package/dist/esm/Diagnostics.d.ts +46 -0
  54. package/dist/esm/Diagnostics.d.ts.map +1 -0
  55. package/dist/esm/Diagnostics.js +26 -0
  56. package/dist/esm/Diagnostics.js.map +1 -0
  57. package/dist/esm/McpClient.d.ts +304 -0
  58. package/dist/esm/McpClient.d.ts.map +1 -0
  59. package/dist/esm/McpClient.js +671 -0
  60. package/dist/esm/McpClient.js.map +1 -0
  61. package/dist/esm/McpError.d.ts +44 -0
  62. package/dist/esm/McpError.d.ts.map +1 -0
  63. package/dist/esm/McpError.js +43 -0
  64. package/dist/esm/McpError.js.map +1 -0
  65. package/dist/esm/McpFlows.d.ts +113 -0
  66. package/dist/esm/McpFlows.d.ts.map +1 -0
  67. package/dist/esm/McpFlows.js +168 -0
  68. package/dist/esm/McpFlows.js.map +1 -0
  69. package/dist/esm/index.d.ts +39 -0
  70. package/dist/esm/index.d.ts.map +1 -0
  71. package/dist/esm/index.js +39 -0
  72. package/dist/esm/index.js.map +1 -0
  73. package/dist/esm/internal/DiagnosticReporter.d.ts +17 -0
  74. package/dist/esm/internal/DiagnosticReporter.d.ts.map +1 -0
  75. package/dist/esm/internal/DiagnosticReporter.js +44 -0
  76. package/dist/esm/internal/DiagnosticReporter.js.map +1 -0
  77. package/dist/esm/internal/HttpTransport.d.ts +67 -0
  78. package/dist/esm/internal/HttpTransport.d.ts.map +1 -0
  79. package/dist/esm/internal/HttpTransport.js +266 -0
  80. package/dist/esm/internal/HttpTransport.js.map +1 -0
  81. package/dist/esm/internal/JsonLimits.d.ts +29 -0
  82. package/dist/esm/internal/JsonLimits.d.ts.map +1 -0
  83. package/dist/esm/internal/JsonLimits.js +55 -0
  84. package/dist/esm/internal/JsonLimits.js.map +1 -0
  85. package/dist/esm/internal/Limits.d.ts +36 -0
  86. package/dist/esm/internal/Limits.d.ts.map +1 -0
  87. package/dist/esm/internal/Limits.js +41 -0
  88. package/dist/esm/internal/Limits.js.map +1 -0
  89. package/dist/esm/internal/Rpc.d.ts +141 -0
  90. package/dist/esm/internal/Rpc.d.ts.map +1 -0
  91. package/dist/esm/internal/Rpc.js +129 -0
  92. package/dist/esm/internal/Rpc.js.map +1 -0
  93. package/dist/esm/internal/StdioTransport.d.ts +78 -0
  94. package/dist/esm/internal/StdioTransport.d.ts.map +1 -0
  95. package/dist/esm/internal/StdioTransport.js +332 -0
  96. package/dist/esm/internal/StdioTransport.js.map +1 -0
  97. package/dist/esm/internal/Transport.d.ts +87 -0
  98. package/dist/esm/internal/Transport.d.ts.map +1 -0
  99. package/dist/esm/internal/Transport.js +146 -0
  100. package/dist/esm/internal/Transport.js.map +1 -0
  101. package/docs/README.md +139 -0
  102. package/docs/api.md +469 -0
  103. package/docs/concepts/the-session.md +135 -0
  104. package/docs/concepts/tools-as-flows.md +116 -0
  105. package/docs/guides/bound-an-untrusted-server.md +158 -0
  106. package/docs/guides/configure-servers-for-the-cli.md +167 -0
  107. package/docs/guides/connect-a-server.md +161 -0
  108. package/docs/guides/grant-authority-to-mcp-tools.md +130 -0
  109. package/docs/guides/handle-a-failed-tool-call.md +125 -0
  110. package/docs/guides/select-the-tools-a-run-sees.md +92 -0
  111. package/docs/guides/testing.md +132 -0
  112. package/docs/guides/validate-structured-output.md +103 -0
  113. package/docs/installation.md +117 -0
  114. package/docs/quickstart.md +200 -0
  115. package/docs/troubleshooting.md +316 -0
  116. package/package.json +157 -3
  117. package/src/Diagnostics.ts +47 -0
  118. package/src/McpClient.ts +985 -0
  119. package/src/McpError.ts +52 -0
  120. package/src/McpFlows.ts +211 -0
  121. package/src/index.ts +42 -0
  122. package/src/internal/DiagnosticReporter.ts +47 -0
  123. package/src/internal/HttpTransport.ts +400 -0
  124. package/src/internal/JsonLimits.ts +53 -0
  125. package/src/internal/Limits.ts +48 -0
  126. package/src/internal/Rpc.ts +219 -0
  127. package/src/internal/StdioTransport.ts +491 -0
  128. package/src/internal/Transport.ts +178 -0
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var Limits_exports = {};
20
+ __export(Limits_exports, {
21
+ checkPositiveIntegers: () => checkPositiveIntegers,
22
+ isPositiveInteger: () => isPositiveInteger,
23
+ protocolError: () => protocolError
24
+ });
25
+ module.exports = __toCommonJS(Limits_exports);
26
+ var import_effect = require("effect");
27
+ var import_McpError = require("../McpError.js");
28
+ const protocolError = (server, message) => new import_McpError.McpError({ code: "protocol_error", message, server });
29
+ const isPositiveInteger = (value) => Number.isSafeInteger(value) && value > 0;
30
+ const checkPositiveIntegers = (server, entries) => {
31
+ const invalid = entries.find(([, value]) => !isPositiveInteger(value));
32
+ return invalid === void 0 ? import_effect.Effect.void : import_effect.Effect.fail(protocolError(server, `MCP option "${invalid[0]}" must be a positive integer`));
33
+ };
34
+ //# sourceMappingURL=Limits.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/internal/Limits.ts"],
4
+ "sourcesContent": ["/**\n * Positive-integer option bounds shared by the transport and the client.\n *\n * Both `connect` functions resolve their defaults and then reject the first\n * option that is not a positive safe integer, before any process is spawned.\n * The check and its error prose live here so the two option lists cannot\n * drift in wording or in semantics.\n *\n * @since 1.0.0-rc.0\n */\n\nimport { Effect } from \"effect\"\nimport { McpError } from \"../McpError.ts\"\n\n/**\n * Builds the `protocol_error` failure both modules report for malformed\n * options and frames.\n *\n * @category errors\n * @since 1.0.0-rc.0\n */\nexport const protocolError = (server: string, message: string): McpError =>\n new McpError({ code: \"protocol_error\", message, server })\n\n/**\n * Whether a value is a positive safe integer.\n *\n * @category validation\n * @since 1.0.0-rc.0\n */\nexport const isPositiveInteger = (value: number): boolean => Number.isSafeInteger(value) && value > 0\n\n/**\n * Fails with `protocol_error` naming the first option whose resolved value is\n * not a positive safe integer. Entries are checked in the order given.\n *\n * @category validation\n * @since 1.0.0-rc.0\n */\nexport const checkPositiveIntegers = (\n server: string,\n entries: ReadonlyArray<readonly [name: string, value: number]>\n): Effect.Effect<void, McpError> => {\n const invalid = entries.find(([, value]) => !isPositiveInteger(value))\n return invalid === undefined\n ? Effect.void\n : Effect.fail(protocolError(server, `MCP option \"${invalid[0]}\" must be a positive integer`))\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,oBAAuB;AACvB,sBAAyB;AASlB,MAAM,gBAAgB,CAAC,QAAgB,YAC5C,IAAI,yBAAS,EAAE,MAAM,kBAAkB,SAAS,OAAO,CAAC;AAQnD,MAAM,oBAAoB,CAAC,UAA2B,OAAO,cAAc,KAAK,KAAK,QAAQ;AAS7F,MAAM,wBAAwB,CACnC,QACA,YACkC;AAClC,QAAM,UAAU,QAAQ,KAAK,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,kBAAkB,KAAK,CAAC;AACrE,SAAO,YAAY,SACf,qBAAO,OACP,qBAAO,KAAK,cAAc,QAAQ,eAAe,QAAQ,CAAC,CAAC,8BAA8B,CAAC;AAChG;",
6
+ "names": []
7
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * JSON-RPC 2.0 envelope encoding for the MCP stdio transport.
3
+ *
4
+ * MCP's stdio transport frames every message as exactly one line of JSON on
5
+ * standard input or output, so this module is pure line-shaped codec: no
6
+ * process, no scheduling, no retry policy. {@link StdioTransport} owns those.
7
+ *
8
+ * @since 1.0.0-rc.0
9
+ */
10
+ /**
11
+ * A JSON-RPC call this client sends. Omitting `id` sends a notification, for
12
+ * which the server never replies.
13
+ *
14
+ * @category models
15
+ * @since 1.0.0-rc.0
16
+ */
17
+ export interface Outbound {
18
+ readonly jsonrpc: "2.0";
19
+ readonly id?: number | undefined;
20
+ readonly method: string;
21
+ readonly params?: unknown;
22
+ }
23
+ /**
24
+ * Any outbound wire message, including replies to server requests. A reply
25
+ * preserves the server's exact id type rather than normalizing it as a
26
+ * correlation id in the client's pending-request map.
27
+ *
28
+ * @category models
29
+ * @since 1.0.0-rc.0
30
+ */
31
+ export type OutboundMessage = Outbound | {
32
+ readonly jsonrpc: "2.0";
33
+ readonly id: string | number;
34
+ readonly result: unknown;
35
+ } | {
36
+ readonly jsonrpc: "2.0";
37
+ readonly id: string | number;
38
+ readonly error: {
39
+ readonly code: number;
40
+ readonly message: string;
41
+ };
42
+ };
43
+ /**
44
+ * A JSON object from server stdout that claims JSON-RPC by carrying its own
45
+ * `jsonrpc` property. Validation happens after parsing so an incorrect version
46
+ * cannot be mistaken for ordinary stdout noise.
47
+ *
48
+ * @category models
49
+ * @since 1.0.0-rc.0
50
+ */
51
+ export interface Inbound {
52
+ readonly jsonrpc: unknown;
53
+ readonly id?: unknown;
54
+ readonly method?: unknown;
55
+ readonly params?: unknown;
56
+ readonly result?: unknown;
57
+ readonly error?: unknown;
58
+ }
59
+ /**
60
+ * A validated JSON-RPC reply, normalized to the numeric request id this
61
+ * client uses for correlation, or an error whose null id cannot be correlated.
62
+ *
63
+ * @category models
64
+ * @since 1.0.0-rc.0
65
+ */
66
+ export type Reply = {
67
+ readonly _tag: "Result";
68
+ readonly id: number;
69
+ readonly result: unknown;
70
+ } | {
71
+ readonly _tag: "Error";
72
+ readonly id: number;
73
+ readonly code: number;
74
+ readonly message: string;
75
+ readonly data: unknown;
76
+ } | {
77
+ readonly _tag: "UncorrelatedError";
78
+ readonly code: number;
79
+ readonly message: string;
80
+ readonly data: unknown;
81
+ } | {
82
+ readonly _tag: "Malformed";
83
+ readonly reason: string;
84
+ };
85
+ /**
86
+ * The transport-relevant classification of one parsed JSON-RPC object.
87
+ * Server request ids belong to the opposite direction and must never be
88
+ * looked up in the client's pending-request map.
89
+ *
90
+ * @category models
91
+ * @since 1.0.0-rc.0
92
+ */
93
+ export type Classification = {
94
+ readonly _tag: "Notification";
95
+ } | {
96
+ readonly _tag: "Request";
97
+ readonly id: string | number;
98
+ readonly method: string;
99
+ readonly params: unknown;
100
+ } | Reply;
101
+ /**
102
+ * Encodes one outbound message as a newline-terminated UTF-8 frame.
103
+ *
104
+ * @category conversions
105
+ * @since 1.0.0-rc.0
106
+ */
107
+ export declare const encode: (message: OutboundMessage) => Uint8Array;
108
+ /**
109
+ * Parses one line of server output. A blank line, invalid JSON, a non-object,
110
+ * or an object with no own `jsonrpc` property returns `undefined`. MCP servers
111
+ * commonly log to stdout, so output that does not claim to be JSON-RPC is
112
+ * noise rather than a protocol violation. Tagged objects are preserved for
113
+ * {@link classify}, including objects that claim the wrong version.
114
+ *
115
+ * @category conversions
116
+ * @since 1.0.0-rc.0
117
+ */
118
+ export declare const parse: (line: string) => Inbound | undefined;
119
+ /**
120
+ * Validates and normalizes a parsed inbound object as a reply.
121
+ *
122
+ * Digit-string ids are accepted only in their canonical ASCII decimal form,
123
+ * then converted back to the safe integer id used by the pending-request map.
124
+ * A reply must carry an own id and exactly one own `result` or `error`
125
+ * property. A null id is accepted only for a valid error, which cannot settle
126
+ * any particular request.
127
+ *
128
+ * @category conversions
129
+ * @since 1.0.0-rc.0
130
+ */
131
+ export declare const replyOf: (message: Inbound) => Reply;
132
+ /**
133
+ * Classifies a parsed JSON-RPC object for the stdio reader. A wrong version is
134
+ * malformed; a valid own `method` with an own id is a server request, without
135
+ * an id a notification. Every remaining object must satisfy {@link replyOf}.
136
+ *
137
+ * @category conversions
138
+ * @since 1.0.0-rc.0
139
+ */
140
+ export declare const classify: (message: Inbound) => Classification;
141
+ //# sourceMappingURL=Rpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Rpc.d.ts","sourceRoot":"","sources":["../../../src/internal/Rpc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var Rpc_exports = {};
20
+ __export(Rpc_exports, {
21
+ classify: () => classify,
22
+ encode: () => encode,
23
+ parse: () => parse,
24
+ replyOf: () => replyOf
25
+ });
26
+ module.exports = __toCommonJS(Rpc_exports);
27
+ const encoder = new TextEncoder();
28
+ const encode = (message) => encoder.encode(`${JSON.stringify(message)}
29
+ `);
30
+ const parse = (line) => {
31
+ const trimmed = line.trim();
32
+ if (trimmed === "") return void 0;
33
+ let value;
34
+ try {
35
+ value = JSON.parse(trimmed);
36
+ } catch {
37
+ return void 0;
38
+ }
39
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
40
+ if (!Object.hasOwn(value, "jsonrpc")) return void 0;
41
+ return value;
42
+ };
43
+ const malformed = (reason) => ({ _tag: "Malformed", reason });
44
+ const replyOf = (message) => {
45
+ if (!Object.hasOwn(message, "id")) return malformed("a reply carried no id");
46
+ const rawId = message.id;
47
+ const id = typeof rawId === "number" ? rawId : typeof rawId === "string" && /^(0|[1-9][0-9]*)$/.test(rawId) ? Number(rawId) : Number.NaN;
48
+ if (rawId !== null && !Number.isSafeInteger(id)) return malformed("a reply id must be a JSON-RPC integer");
49
+ const hasResult = Object.hasOwn(message, "result");
50
+ const hasError = Object.hasOwn(message, "error");
51
+ if (!hasResult && !hasError) return malformed("a reply carried neither result nor error");
52
+ if (hasResult && hasError) return malformed("a reply carried both result and error");
53
+ if (hasResult) {
54
+ if (rawId === null) return malformed("a reply id must be a JSON-RPC integer");
55
+ return { _tag: "Result", id, result: message.result };
56
+ }
57
+ const error = message.error;
58
+ if (typeof error !== "object" || error === null || Array.isArray(error) || !Number.isInteger(error.code) || typeof error.message !== "string") {
59
+ return malformed("a reply carried a malformed error object");
60
+ }
61
+ const record = error;
62
+ if (rawId === null) {
63
+ return { _tag: "UncorrelatedError", code: record.code, message: record.message, data: record.data };
64
+ }
65
+ return {
66
+ _tag: "Error",
67
+ id,
68
+ code: record.code,
69
+ message: record.message,
70
+ data: record.data
71
+ };
72
+ };
73
+ const classify = (message) => {
74
+ if (message.jsonrpc !== "2.0") {
75
+ return malformed('a JSON-RPC message must carry jsonrpc "2.0"');
76
+ }
77
+ if (Object.hasOwn(message, "method")) {
78
+ if (typeof message.method !== "string") return malformed("a method must be a string");
79
+ if (Object.hasOwn(message, "result") || Object.hasOwn(message, "error")) {
80
+ return malformed("a method-bearing message cannot also carry result or error");
81
+ }
82
+ if (Object.hasOwn(message, "params") && (typeof message.params !== "object" || message.params === null || Array.isArray(message.params))) return malformed("MCP method params must be an object");
83
+ if (!Object.hasOwn(message, "id")) return { _tag: "Notification" };
84
+ const id = message.id;
85
+ if (typeof id !== "string" && (typeof id !== "number" || !Number.isSafeInteger(id))) {
86
+ return malformed("a server request id must be a string or safe integer");
87
+ }
88
+ return { _tag: "Request", id, method: message.method, params: message.params };
89
+ }
90
+ return replyOf(message);
91
+ };
92
+ //# sourceMappingURL=Rpc.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/internal/Rpc.ts"],
4
+ "sourcesContent": ["/**\n * JSON-RPC 2.0 envelope encoding for the MCP stdio transport.\n *\n * MCP's stdio transport frames every message as exactly one line of JSON on\n * standard input or output, so this module is pure line-shaped codec: no\n * process, no scheduling, no retry policy. {@link StdioTransport} owns those.\n *\n * @since 1.0.0-rc.0\n */\n\n/**\n * A JSON-RPC call this client sends. Omitting `id` sends a notification, for\n * which the server never replies.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Outbound {\n readonly jsonrpc: \"2.0\"\n readonly id?: number | undefined\n readonly method: string\n readonly params?: unknown\n}\n\n/**\n * Any outbound wire message, including replies to server requests. A reply\n * preserves the server's exact id type rather than normalizing it as a\n * correlation id in the client's pending-request map.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type OutboundMessage = Outbound | {\n readonly jsonrpc: \"2.0\"\n readonly id: string | number\n readonly result: unknown\n} | {\n readonly jsonrpc: \"2.0\"\n readonly id: string | number\n readonly error: { readonly code: number; readonly message: string }\n}\n\n/**\n * A JSON object from server stdout that claims JSON-RPC by carrying its own\n * `jsonrpc` property. Validation happens after parsing so an incorrect version\n * cannot be mistaken for ordinary stdout noise.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Inbound {\n readonly jsonrpc: unknown\n readonly id?: unknown\n readonly method?: unknown\n readonly params?: unknown\n readonly result?: unknown\n readonly error?: unknown\n}\n\n/**\n * A validated JSON-RPC reply, normalized to the numeric request id this\n * client uses for correlation, or an error whose null id cannot be correlated.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Reply = {\n readonly _tag: \"Result\"\n readonly id: number\n readonly result: unknown\n} | {\n readonly _tag: \"Error\"\n readonly id: number\n readonly code: number\n readonly message: string\n readonly data: unknown\n} | {\n readonly _tag: \"UncorrelatedError\"\n readonly code: number\n readonly message: string\n readonly data: unknown\n} | {\n readonly _tag: \"Malformed\"\n readonly reason: string\n}\n\n/**\n * The transport-relevant classification of one parsed JSON-RPC object.\n * Server request ids belong to the opposite direction and must never be\n * looked up in the client's pending-request map.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Classification = { readonly _tag: \"Notification\" } | {\n readonly _tag: \"Request\"\n readonly id: string | number\n readonly method: string\n readonly params: unknown\n} | Reply\n\nconst encoder = new TextEncoder()\n\n/**\n * Encodes one outbound message as a newline-terminated UTF-8 frame.\n *\n * @category conversions\n * @since 1.0.0-rc.0\n */\nexport const encode = (message: OutboundMessage): Uint8Array => encoder.encode(`${JSON.stringify(message)}\\n`)\n\n/**\n * Parses one line of server output. A blank line, invalid JSON, a non-object,\n * or an object with no own `jsonrpc` property returns `undefined`. MCP servers\n * commonly log to stdout, so output that does not claim to be JSON-RPC is\n * noise rather than a protocol violation. Tagged objects are preserved for\n * {@link classify}, including objects that claim the wrong version.\n *\n * @category conversions\n * @since 1.0.0-rc.0\n */\nexport const parse = (line: string): Inbound | undefined => {\n const trimmed = line.trim()\n if (trimmed === \"\") return undefined\n let value: unknown\n try {\n value = JSON.parse(trimmed)\n } catch {\n return undefined\n }\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined\n if (!Object.hasOwn(value, \"jsonrpc\")) return undefined\n return value as Inbound\n}\n\nconst malformed = (reason: string): Reply => ({ _tag: \"Malformed\", reason })\n\n/**\n * Validates and normalizes a parsed inbound object as a reply.\n *\n * Digit-string ids are accepted only in their canonical ASCII decimal form,\n * then converted back to the safe integer id used by the pending-request map.\n * A reply must carry an own id and exactly one own `result` or `error`\n * property. A null id is accepted only for a valid error, which cannot settle\n * any particular request.\n *\n * @category conversions\n * @since 1.0.0-rc.0\n */\nexport const replyOf = (message: Inbound): Reply => {\n if (!Object.hasOwn(message, \"id\")) return malformed(\"a reply carried no id\")\n const rawId = message.id\n const id = typeof rawId === \"number\"\n ? rawId\n : typeof rawId === \"string\" && /^(0|[1-9][0-9]*)$/.test(rawId)\n ? Number(rawId)\n : Number.NaN\n if (rawId !== null && !Number.isSafeInteger(id)) return malformed(\"a reply id must be a JSON-RPC integer\")\n\n const hasResult = Object.hasOwn(message, \"result\")\n const hasError = Object.hasOwn(message, \"error\")\n if (!hasResult && !hasError) return malformed(\"a reply carried neither result nor error\")\n if (hasResult && hasError) return malformed(\"a reply carried both result and error\")\n if (hasResult) {\n if (rawId === null) return malformed(\"a reply id must be a JSON-RPC integer\")\n return { _tag: \"Result\", id, result: message.result }\n }\n\n const error = message.error\n if (\n typeof error !== \"object\" || error === null || Array.isArray(error) ||\n !Number.isInteger((error as { readonly code?: unknown }).code) ||\n typeof (error as { readonly message?: unknown }).message !== \"string\"\n ) {\n return malformed(\"a reply carried a malformed error object\")\n }\n const record = error as { readonly code: number; readonly message: string; readonly data?: unknown }\n if (rawId === null) {\n return { _tag: \"UncorrelatedError\", code: record.code, message: record.message, data: record.data }\n }\n return {\n _tag: \"Error\",\n id,\n code: record.code,\n message: record.message,\n data: record.data\n }\n}\n\n/**\n * Classifies a parsed JSON-RPC object for the stdio reader. A wrong version is\n * malformed; a valid own `method` with an own id is a server request, without\n * an id a notification. Every remaining object must satisfy {@link replyOf}.\n *\n * @category conversions\n * @since 1.0.0-rc.0\n */\nexport const classify = (message: Inbound): Classification => {\n if (message.jsonrpc !== \"2.0\") {\n return malformed(\"a JSON-RPC message must carry jsonrpc \\\"2.0\\\"\")\n }\n if (Object.hasOwn(message, \"method\")) {\n if (typeof message.method !== \"string\") return malformed(\"a method must be a string\")\n if (Object.hasOwn(message, \"result\") || Object.hasOwn(message, \"error\")) {\n return malformed(\"a method-bearing message cannot also carry result or error\")\n }\n if (\n Object.hasOwn(message, \"params\") &&\n (typeof message.params !== \"object\" || message.params === null || Array.isArray(message.params))\n ) return malformed(\"MCP method params must be an object\")\n if (!Object.hasOwn(message, \"id\")) return { _tag: \"Notification\" }\n const id = message.id\n if (typeof id !== \"string\" && (typeof id !== \"number\" || !Number.isSafeInteger(id))) {\n return malformed(\"a server request id must be a string or safe integer\")\n }\n return { _tag: \"Request\", id, method: message.method, params: message.params }\n }\n return replyOf(message)\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Newline-delimited JSON-RPC transport over a spawned MCP server's stdio.
3
+ *
4
+ * This module owns exactly the connection lifecycle and request/reply
5
+ * correlation an MCP session needs: spawn once, write frames in, read frames
6
+ * out, match replies to the request that asked for them. It knows nothing
7
+ * about `initialize`, `tools/list`, or `tools/call`. It answers the protocol's
8
+ * liveness `ping` with an empty result, and unsupported server requests with
9
+ * method-not-found. {@link McpClient} owns feature negotiation and tool calls.
10
+ *
11
+ * Server-initiated notifications are received and dropped. A future caller
12
+ * that needs `notifications/*` (for example a progress stream) is the reason
13
+ * to add a subscription surface here rather than threading one more parameter
14
+ * through every constructor now.
15
+ *
16
+ * @since 1.0.0-rc.0
17
+ */
18
+ import { Effect } from "effect";
19
+ import type { Scope } from "effect";
20
+ import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
21
+ import { McpError } from "../McpError.ts";
22
+ import * as Transport from "./Transport.ts";
23
+ /**
24
+ * Options accepted by {@link connect}.
25
+ *
26
+ * @category models
27
+ * @since 1.0.0-rc.0
28
+ */
29
+ export interface ConnectOptions {
30
+ /** The name this server is known by, for error messages only. */
31
+ readonly server: string;
32
+ readonly command: string;
33
+ readonly args: ReadonlyArray<string>;
34
+ readonly cwd?: string | undefined;
35
+ /** Values merged into the bootstrap allowlist rather than the full host environment. */
36
+ readonly env?: Record<string, string | undefined> | undefined;
37
+ /** Default deadline for a request/reply exchange. See {@link Transport.defaultRequestTimeoutMs}. */
38
+ readonly requestTimeoutMs?: number | undefined;
39
+ /** Maximum number of frames waiting to be written. See {@link defaultQueueCapacity}. */
40
+ readonly queueCapacity?: number | undefined;
41
+ /** Maximum UTF-8 bytes accepted in one inbound JSON-RPC frame. See {@link Transport.defaultMaxFrameBytes}. */
42
+ readonly maxFrameBytes?: number | undefined;
43
+ /** Maximum UTF-8 bytes emitted in one JSON-RPC frame. See {@link Transport.defaultMaxOutboundFrameBytes}. */
44
+ readonly maxOutboundFrameBytes?: number | undefined;
45
+ /** Maximum diagnostic stderr bytes retained in memory. See {@link defaultMaxStderrBytes}. */
46
+ readonly maxStderrBytes?: number | undefined;
47
+ }
48
+ /**
49
+ * Default number of outbound frames allowed to wait in memory.
50
+ *
51
+ * @category constants
52
+ * @since 1.0.0-rc.0
53
+ */
54
+ export declare const defaultQueueCapacity = 64;
55
+ /**
56
+ * Default maximum child-stderr tail retained for connection diagnostics.
57
+ *
58
+ * @category constants
59
+ * @since 1.0.0-rc.0
60
+ */
61
+ export declare const defaultMaxStderrBytes = 2048;
62
+ /**
63
+ * Spawns an MCP server over stdio and returns a live {@link Transport}.
64
+ *
65
+ * The connection is scoped: the writer and reader loops are daemon fibers
66
+ * forked into the calling scope, and closing that scope tears the process
67
+ * down with it. Every request pending when the connection closes fails with
68
+ * `connection_closed` instead of hanging forever.
69
+ *
70
+ * Stdout that does not claim JSON-RPC is ignored because servers commonly log
71
+ * there. Once an object carries its own `jsonrpc` property, a malformed version
72
+ * or reply closes the connection with `protocol_error`.
73
+ *
74
+ * @category constructors
75
+ * @since 1.0.0-rc.0
76
+ */
77
+ export declare const connect: (options: ConnectOptions) => Effect.Effect<Transport.Transport, McpError, ChildProcessSpawner | Scope.Scope>;
78
+ //# sourceMappingURL=StdioTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdioTransport.d.ts","sourceRoot":"","sources":["../../../src/internal/StdioTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAY,MAAM,EAAoD,MAAM,QAAQ,CAAA;AAC3F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAEnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAA;AACtF,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAKzC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAuD3C;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,wFAAwF;IACxF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC7D,oGAAoG;IACpG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9C,wFAAwF;IACxF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3C,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3C,6GAA6G;IAC7G,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnD,6FAA6F;IAC7F,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7C;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAA;AAsCzC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,GAClB,SAAS,cAAc,KACtB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,mBAAmB,GAAG,KAAK,CAAC,KAAK,CAuT7E,CAAA"}