@smithery/api 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.24.0 (2026-01-21)
4
+
5
+ Full Changelog: [v0.23.0...v0.24.0](https://github.com/smithery-ai/typescript-api/compare/v0.23.0...v0.24.0)
6
+
7
+ ### Features
8
+
9
+ * add SmitheryConnectTransport for MCP SDK integration [SMI-1270] ([#39](https://github.com/smithery-ai/typescript-api/issues/39)) ([e607f59](https://github.com/smithery-ai/typescript-api/commit/e607f596a85ab4f25920781ae74a8e6c8e2237f5))
10
+
3
11
  ## 0.23.0 (2026-01-21)
4
12
 
5
13
  Full Changelog: [v0.22.0...v0.23.0](https://github.com/smithery-ai/typescript-api/compare/v0.22.0...v0.23.0)
@@ -0,0 +1,97 @@
1
+ /**
2
+ * SmitheryConnectTransport - An MCP Transport that routes JSON-RPC messages through Smithery Connect.
3
+ *
4
+ * This allows you to use the official MCP SDK's Client class with Smithery Connect as the transport layer.
5
+ *
6
+ * **Important:** Smithery Connect handles MCP initialization server-side when a connection is created.
7
+ * This transport lazily fetches/creates the connection on first message and uses its server info
8
+ * to satisfy the MCP SDK's initialization flow without re-initializing the already-established connection.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
13
+ * import Smithery from '@smithery/api';
14
+ * import { SmitheryConnectTransport } from '@smithery/api/mcp';
15
+ *
16
+ * const smithery = new Smithery({ apiKey: process.env.SMITHERY_API_KEY });
17
+ * // Option 1: Let Smithery generate a connection ID
18
+ * const transport = new SmitheryConnectTransport({
19
+ * client: smithery,
20
+ * namespace: 'my-namespace',
21
+ * mcpUrl: 'https://mcp.example.com/sse',
22
+ * });
23
+ *
24
+ * // Option 2: Use a specific connection ID (retrieves existing or creates new)
25
+ * const transport2 = new SmitheryConnectTransport({
26
+ * client: smithery,
27
+ * namespace: 'my-namespace',
28
+ * connectionId: 'my-connection',
29
+ * mcpUrl: 'https://mcp.example.com/sse',
30
+ * });
31
+ *
32
+ * const mcpClient = new Client({ name: 'my-app', version: '1.0.0' }, { capabilities: {} });
33
+ * await mcpClient.connect(transport);
34
+ *
35
+ * // Now use the MCP SDK's ergonomic API
36
+ * const { tools } = await mcpClient.listTools();
37
+ * const result = await mcpClient.callTool({ name: 'my-tool', arguments: {} });
38
+ * ```
39
+ */
40
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
41
+ import type { JSONRPCMessage, ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';
42
+ import type { Smithery } from "../client.mjs";
43
+ export interface SmitheryConnectTransportOptions {
44
+ /**
45
+ * The Smithery client instance to use for making RPC calls.
46
+ */
47
+ client: Smithery;
48
+ /**
49
+ * The namespace for the Smithery Connect connection.
50
+ */
51
+ namespace: string;
52
+ /**
53
+ * The connection ID for the Smithery Connect connection.
54
+ * If not provided, a new connection will be created with an auto-generated ID.
55
+ */
56
+ connectionId?: string;
57
+ /**
58
+ * The MCP server URL. Required when creating a new connection.
59
+ * If connectionId is provided, this is used to create the connection if it doesn't exist.
60
+ * If connectionId is not provided, this is required and a new connection will be created.
61
+ */
62
+ mcpUrl?: string;
63
+ /**
64
+ * Optional server capabilities for the initialize response.
65
+ * If not provided, defaults to advertising tools, resources, and prompts support.
66
+ */
67
+ capabilities?: ServerCapabilities;
68
+ }
69
+ export declare class SmitheryConnectTransport implements Transport {
70
+ private _client;
71
+ private _namespace;
72
+ private _connectionId;
73
+ private _mcpUrl;
74
+ private _started;
75
+ private _closed;
76
+ private _capabilities;
77
+ private _connection;
78
+ onmessage?: (message: JSONRPCMessage) => void;
79
+ onerror?: (error: Error) => void;
80
+ onclose?: () => void;
81
+ sessionId?: string;
82
+ /**
83
+ * Returns the connection ID. If no connectionId was provided in options,
84
+ * this returns the auto-generated ID after the first message is sent.
85
+ */
86
+ get connectionId(): string | undefined;
87
+ constructor(options: SmitheryConnectTransportOptions);
88
+ start(): Promise<void>;
89
+ /**
90
+ * Lazily ensures the Smithery Connect connection exists.
91
+ * Called on first message to defer network IO until actually needed.
92
+ */
93
+ private _ensureConnection;
94
+ send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
95
+ close(): Promise<void>;
96
+ }
97
+ //# sourceMappingURL=mcp-transport.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-transport.d.mts","sourceRoot":"","sources":["../src/lib/mcp-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;OAEI,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,+CAA+C;OAC7F,KAAK,EAAE,cAAc,EAAmB,kBAAkB,EAAE,MAAM,oCAAoC;OACtG,KAAK,EAAE,QAAQ,EAAE;AAGxB,MAAM,WAAW,+BAA+B;IAC9C;;OAEG;IACH,MAAM,EAAE,QAAQ,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAKD,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,WAAW,CAA2B;IAE9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;gBAEW,OAAO,EAAE,+BAA+B;IAoB9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B;;;OAGG;YACW,iBAAiB;IAiCzB,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkG7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * SmitheryConnectTransport - An MCP Transport that routes JSON-RPC messages through Smithery Connect.
3
+ *
4
+ * This allows you to use the official MCP SDK's Client class with Smithery Connect as the transport layer.
5
+ *
6
+ * **Important:** Smithery Connect handles MCP initialization server-side when a connection is created.
7
+ * This transport lazily fetches/creates the connection on first message and uses its server info
8
+ * to satisfy the MCP SDK's initialization flow without re-initializing the already-established connection.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
13
+ * import Smithery from '@smithery/api';
14
+ * import { SmitheryConnectTransport } from '@smithery/api/mcp';
15
+ *
16
+ * const smithery = new Smithery({ apiKey: process.env.SMITHERY_API_KEY });
17
+ * // Option 1: Let Smithery generate a connection ID
18
+ * const transport = new SmitheryConnectTransport({
19
+ * client: smithery,
20
+ * namespace: 'my-namespace',
21
+ * mcpUrl: 'https://mcp.example.com/sse',
22
+ * });
23
+ *
24
+ * // Option 2: Use a specific connection ID (retrieves existing or creates new)
25
+ * const transport2 = new SmitheryConnectTransport({
26
+ * client: smithery,
27
+ * namespace: 'my-namespace',
28
+ * connectionId: 'my-connection',
29
+ * mcpUrl: 'https://mcp.example.com/sse',
30
+ * });
31
+ *
32
+ * const mcpClient = new Client({ name: 'my-app', version: '1.0.0' }, { capabilities: {} });
33
+ * await mcpClient.connect(transport);
34
+ *
35
+ * // Now use the MCP SDK's ergonomic API
36
+ * const { tools } = await mcpClient.listTools();
37
+ * const result = await mcpClient.callTool({ name: 'my-tool', arguments: {} });
38
+ * ```
39
+ */
40
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
41
+ import type { JSONRPCMessage, ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';
42
+ import type { Smithery } from "../client.js";
43
+ export interface SmitheryConnectTransportOptions {
44
+ /**
45
+ * The Smithery client instance to use for making RPC calls.
46
+ */
47
+ client: Smithery;
48
+ /**
49
+ * The namespace for the Smithery Connect connection.
50
+ */
51
+ namespace: string;
52
+ /**
53
+ * The connection ID for the Smithery Connect connection.
54
+ * If not provided, a new connection will be created with an auto-generated ID.
55
+ */
56
+ connectionId?: string;
57
+ /**
58
+ * The MCP server URL. Required when creating a new connection.
59
+ * If connectionId is provided, this is used to create the connection if it doesn't exist.
60
+ * If connectionId is not provided, this is required and a new connection will be created.
61
+ */
62
+ mcpUrl?: string;
63
+ /**
64
+ * Optional server capabilities for the initialize response.
65
+ * If not provided, defaults to advertising tools, resources, and prompts support.
66
+ */
67
+ capabilities?: ServerCapabilities;
68
+ }
69
+ export declare class SmitheryConnectTransport implements Transport {
70
+ private _client;
71
+ private _namespace;
72
+ private _connectionId;
73
+ private _mcpUrl;
74
+ private _started;
75
+ private _closed;
76
+ private _capabilities;
77
+ private _connection;
78
+ onmessage?: (message: JSONRPCMessage) => void;
79
+ onerror?: (error: Error) => void;
80
+ onclose?: () => void;
81
+ sessionId?: string;
82
+ /**
83
+ * Returns the connection ID. If no connectionId was provided in options,
84
+ * this returns the auto-generated ID after the first message is sent.
85
+ */
86
+ get connectionId(): string | undefined;
87
+ constructor(options: SmitheryConnectTransportOptions);
88
+ start(): Promise<void>;
89
+ /**
90
+ * Lazily ensures the Smithery Connect connection exists.
91
+ * Called on first message to defer network IO until actually needed.
92
+ */
93
+ private _ensureConnection;
94
+ send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
95
+ close(): Promise<void>;
96
+ }
97
+ //# sourceMappingURL=mcp-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-transport.d.ts","sourceRoot":"","sources":["../src/lib/mcp-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;OAEI,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,+CAA+C;OAC7F,KAAK,EAAE,cAAc,EAAmB,kBAAkB,EAAE,MAAM,oCAAoC;OACtG,KAAK,EAAE,QAAQ,EAAE;AAGxB,MAAM,WAAW,+BAA+B;IAC9C;;OAEG;IACH,MAAM,EAAE,QAAQ,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAKD,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,WAAW,CAA2B;IAE9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;gBAEW,OAAO,EAAE,+BAA+B;IAoB9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B;;;OAGG;YACW,iBAAiB;IAiCzB,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkG7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /**
3
+ * SmitheryConnectTransport - An MCP Transport that routes JSON-RPC messages through Smithery Connect.
4
+ *
5
+ * This allows you to use the official MCP SDK's Client class with Smithery Connect as the transport layer.
6
+ *
7
+ * **Important:** Smithery Connect handles MCP initialization server-side when a connection is created.
8
+ * This transport lazily fetches/creates the connection on first message and uses its server info
9
+ * to satisfy the MCP SDK's initialization flow without re-initializing the already-established connection.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
14
+ * import Smithery from '@smithery/api';
15
+ * import { SmitheryConnectTransport } from '@smithery/api/mcp';
16
+ *
17
+ * const smithery = new Smithery({ apiKey: process.env.SMITHERY_API_KEY });
18
+ * // Option 1: Let Smithery generate a connection ID
19
+ * const transport = new SmitheryConnectTransport({
20
+ * client: smithery,
21
+ * namespace: 'my-namespace',
22
+ * mcpUrl: 'https://mcp.example.com/sse',
23
+ * });
24
+ *
25
+ * // Option 2: Use a specific connection ID (retrieves existing or creates new)
26
+ * const transport2 = new SmitheryConnectTransport({
27
+ * client: smithery,
28
+ * namespace: 'my-namespace',
29
+ * connectionId: 'my-connection',
30
+ * mcpUrl: 'https://mcp.example.com/sse',
31
+ * });
32
+ *
33
+ * const mcpClient = new Client({ name: 'my-app', version: '1.0.0' }, { capabilities: {} });
34
+ * await mcpClient.connect(transport);
35
+ *
36
+ * // Now use the MCP SDK's ergonomic API
37
+ * const { tools } = await mcpClient.listTools();
38
+ * const result = await mcpClient.callTool({ name: 'my-tool', arguments: {} });
39
+ * ```
40
+ */
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.SmitheryConnectTransport = void 0;
43
+ // MCP protocol version
44
+ const LATEST_PROTOCOL_VERSION = '2024-11-05';
45
+ class SmitheryConnectTransport {
46
+ /**
47
+ * Returns the connection ID. If no connectionId was provided in options,
48
+ * this returns the auto-generated ID after the first message is sent.
49
+ */
50
+ get connectionId() {
51
+ return this._connectionId;
52
+ }
53
+ constructor(options) {
54
+ this._started = false;
55
+ this._closed = false;
56
+ this._connection = null;
57
+ this._client = options.client;
58
+ this._namespace = options.namespace;
59
+ this._connectionId = options.connectionId;
60
+ this._mcpUrl = options.mcpUrl;
61
+ // Validate: mcpUrl is required if connectionId is not provided
62
+ if (!this._connectionId && !this._mcpUrl) {
63
+ throw new Error('mcpUrl is required when connectionId is not provided');
64
+ }
65
+ this._capabilities = options.capabilities ?? {
66
+ // Default to advertising common capabilities
67
+ // The actual MCP server behind Smithery Connect will handle the real capabilities
68
+ tools: {},
69
+ resources: {},
70
+ prompts: {},
71
+ };
72
+ }
73
+ async start() {
74
+ if (this._started) {
75
+ throw new Error('SmitheryConnectTransport already started! If using Client class, note that connect() calls start() automatically.');
76
+ }
77
+ if (this._closed) {
78
+ throw new Error('Transport has been closed');
79
+ }
80
+ this._started = true;
81
+ }
82
+ /**
83
+ * Lazily ensures the Smithery Connect connection exists.
84
+ * Called on first message to defer network IO until actually needed.
85
+ */
86
+ async _ensureConnection() {
87
+ if (this._connection) {
88
+ return;
89
+ }
90
+ if (this._connectionId) {
91
+ // Connection ID provided: try to retrieve, or create if mcpUrl is provided
92
+ try {
93
+ this._connection = await this._client.beta.connect.connections.retrieve(this._connectionId, {
94
+ namespace: this._namespace,
95
+ });
96
+ }
97
+ catch (error) {
98
+ // If connection doesn't exist and we have mcpUrl, create it with the specified ID
99
+ if (this._mcpUrl) {
100
+ this._connection = await this._client.beta.connect.connections.set(this._connectionId, {
101
+ namespace: this._namespace,
102
+ mcpUrl: this._mcpUrl,
103
+ });
104
+ }
105
+ else {
106
+ throw error;
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ // No connection ID: create a new connection with auto-generated ID
112
+ // mcpUrl is guaranteed to be present (validated in constructor)
113
+ this._connection = await this._client.beta.connect.connections.create(this._namespace, {
114
+ mcpUrl: this._mcpUrl,
115
+ });
116
+ // Store the generated connection ID for subsequent RPC calls
117
+ this._connectionId = this._connection.connectionId;
118
+ }
119
+ }
120
+ async send(message, _options) {
121
+ if (!this._started) {
122
+ throw new Error('Transport not started');
123
+ }
124
+ if (this._closed) {
125
+ throw new Error('Transport has been closed');
126
+ }
127
+ // Only handle outgoing requests and notifications (messages with a method)
128
+ if (!('method' in message)) {
129
+ return;
130
+ }
131
+ // Lazily ensure connection exists before processing any message
132
+ await this._ensureConnection();
133
+ // Intercept 'initialize' request - Smithery Connect handles initialization server-side
134
+ // Return the real serverInfo from the connection
135
+ if (message.method === 'initialize' && 'id' in message && message.id !== undefined) {
136
+ if (this.onmessage) {
137
+ const serverInfo = this._connection?.serverInfo ?? {
138
+ name: 'smithery-connect',
139
+ version: '1.0.0',
140
+ };
141
+ const initializeResponse = {
142
+ jsonrpc: '2.0',
143
+ id: message.id,
144
+ result: {
145
+ protocolVersion: LATEST_PROTOCOL_VERSION,
146
+ serverInfo: {
147
+ name: serverInfo.name,
148
+ version: serverInfo.version,
149
+ },
150
+ capabilities: this._capabilities,
151
+ },
152
+ };
153
+ // Use setTimeout to make this async and match real transport behavior
154
+ setTimeout(() => this.onmessage(initializeResponse), 0);
155
+ }
156
+ return;
157
+ }
158
+ // Intercept 'notifications/initialized' - no response needed, just acknowledge
159
+ if (message.method === 'notifications/initialized') {
160
+ return;
161
+ }
162
+ try {
163
+ // Build the RPC call params, only including id if it's defined
164
+ const rpcParams = {
165
+ namespace: this._namespace,
166
+ jsonrpc: '2.0',
167
+ method: message.method,
168
+ };
169
+ // Only add id if present (for requests, not notifications)
170
+ if ('id' in message && message.id !== undefined) {
171
+ rpcParams.id = message.id;
172
+ }
173
+ // Only add params if present
174
+ if ('params' in message && message.params !== undefined) {
175
+ rpcParams.params = message.params;
176
+ }
177
+ const response = await this._client.beta.connect.rpc.call(this._connectionId, rpcParams);
178
+ // Route the response back via onmessage callback for requests (messages with an id)
179
+ if ('id' in message && message.id !== undefined && this.onmessage) {
180
+ const jsonRpcResponse = {
181
+ jsonrpc: '2.0',
182
+ id: response.id,
183
+ result: response.result,
184
+ };
185
+ this.onmessage(jsonRpcResponse);
186
+ }
187
+ }
188
+ catch (error) {
189
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
190
+ // For requests, send an error response via onmessage
191
+ if ('id' in message && message.id !== undefined && this.onmessage) {
192
+ const errorResponse = {
193
+ jsonrpc: '2.0',
194
+ id: message.id,
195
+ error: {
196
+ code: -32603, // Internal error
197
+ message: normalizedError.message,
198
+ },
199
+ };
200
+ this.onmessage(errorResponse);
201
+ }
202
+ // Also report via onerror callback
203
+ this.onerror?.(normalizedError);
204
+ }
205
+ }
206
+ async close() {
207
+ this._closed = true;
208
+ this._started = false;
209
+ this.onclose?.();
210
+ }
211
+ }
212
+ exports.SmitheryConnectTransport = SmitheryConnectTransport;
213
+ //# sourceMappingURL=mcp-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-transport.js","sourceRoot":"","sources":["../src/lib/mcp-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * SmitheryConnectTransport - An MCP Transport that routes JSON-RPC messages through Smithery Connect.
3
+ *
4
+ * This allows you to use the official MCP SDK's Client class with Smithery Connect as the transport layer.
5
+ *
6
+ * **Important:** Smithery Connect handles MCP initialization server-side when a connection is created.
7
+ * This transport lazily fetches/creates the connection on first message and uses its server info
8
+ * to satisfy the MCP SDK's initialization flow without re-initializing the already-established connection.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
13
+ * import Smithery from '@smithery/api';
14
+ * import { SmitheryConnectTransport } from '@smithery/api/mcp';
15
+ *
16
+ * const smithery = new Smithery({ apiKey: process.env.SMITHERY_API_KEY });
17
+ * // Option 1: Let Smithery generate a connection ID
18
+ * const transport = new SmitheryConnectTransport({
19
+ * client: smithery,
20
+ * namespace: 'my-namespace',
21
+ * mcpUrl: 'https://mcp.example.com/sse',
22
+ * });
23
+ *
24
+ * // Option 2: Use a specific connection ID (retrieves existing or creates new)
25
+ * const transport2 = new SmitheryConnectTransport({
26
+ * client: smithery,
27
+ * namespace: 'my-namespace',
28
+ * connectionId: 'my-connection',
29
+ * mcpUrl: 'https://mcp.example.com/sse',
30
+ * });
31
+ *
32
+ * const mcpClient = new Client({ name: 'my-app', version: '1.0.0' }, { capabilities: {} });
33
+ * await mcpClient.connect(transport);
34
+ *
35
+ * // Now use the MCP SDK's ergonomic API
36
+ * const { tools } = await mcpClient.listTools();
37
+ * const result = await mcpClient.callTool({ name: 'my-tool', arguments: {} });
38
+ * ```
39
+ */
40
+ // MCP protocol version
41
+ const LATEST_PROTOCOL_VERSION = '2024-11-05';
42
+ export class SmitheryConnectTransport {
43
+ /**
44
+ * Returns the connection ID. If no connectionId was provided in options,
45
+ * this returns the auto-generated ID after the first message is sent.
46
+ */
47
+ get connectionId() {
48
+ return this._connectionId;
49
+ }
50
+ constructor(options) {
51
+ this._started = false;
52
+ this._closed = false;
53
+ this._connection = null;
54
+ this._client = options.client;
55
+ this._namespace = options.namespace;
56
+ this._connectionId = options.connectionId;
57
+ this._mcpUrl = options.mcpUrl;
58
+ // Validate: mcpUrl is required if connectionId is not provided
59
+ if (!this._connectionId && !this._mcpUrl) {
60
+ throw new Error('mcpUrl is required when connectionId is not provided');
61
+ }
62
+ this._capabilities = options.capabilities ?? {
63
+ // Default to advertising common capabilities
64
+ // The actual MCP server behind Smithery Connect will handle the real capabilities
65
+ tools: {},
66
+ resources: {},
67
+ prompts: {},
68
+ };
69
+ }
70
+ async start() {
71
+ if (this._started) {
72
+ throw new Error('SmitheryConnectTransport already started! If using Client class, note that connect() calls start() automatically.');
73
+ }
74
+ if (this._closed) {
75
+ throw new Error('Transport has been closed');
76
+ }
77
+ this._started = true;
78
+ }
79
+ /**
80
+ * Lazily ensures the Smithery Connect connection exists.
81
+ * Called on first message to defer network IO until actually needed.
82
+ */
83
+ async _ensureConnection() {
84
+ if (this._connection) {
85
+ return;
86
+ }
87
+ if (this._connectionId) {
88
+ // Connection ID provided: try to retrieve, or create if mcpUrl is provided
89
+ try {
90
+ this._connection = await this._client.beta.connect.connections.retrieve(this._connectionId, {
91
+ namespace: this._namespace,
92
+ });
93
+ }
94
+ catch (error) {
95
+ // If connection doesn't exist and we have mcpUrl, create it with the specified ID
96
+ if (this._mcpUrl) {
97
+ this._connection = await this._client.beta.connect.connections.set(this._connectionId, {
98
+ namespace: this._namespace,
99
+ mcpUrl: this._mcpUrl,
100
+ });
101
+ }
102
+ else {
103
+ throw error;
104
+ }
105
+ }
106
+ }
107
+ else {
108
+ // No connection ID: create a new connection with auto-generated ID
109
+ // mcpUrl is guaranteed to be present (validated in constructor)
110
+ this._connection = await this._client.beta.connect.connections.create(this._namespace, {
111
+ mcpUrl: this._mcpUrl,
112
+ });
113
+ // Store the generated connection ID for subsequent RPC calls
114
+ this._connectionId = this._connection.connectionId;
115
+ }
116
+ }
117
+ async send(message, _options) {
118
+ if (!this._started) {
119
+ throw new Error('Transport not started');
120
+ }
121
+ if (this._closed) {
122
+ throw new Error('Transport has been closed');
123
+ }
124
+ // Only handle outgoing requests and notifications (messages with a method)
125
+ if (!('method' in message)) {
126
+ return;
127
+ }
128
+ // Lazily ensure connection exists before processing any message
129
+ await this._ensureConnection();
130
+ // Intercept 'initialize' request - Smithery Connect handles initialization server-side
131
+ // Return the real serverInfo from the connection
132
+ if (message.method === 'initialize' && 'id' in message && message.id !== undefined) {
133
+ if (this.onmessage) {
134
+ const serverInfo = this._connection?.serverInfo ?? {
135
+ name: 'smithery-connect',
136
+ version: '1.0.0',
137
+ };
138
+ const initializeResponse = {
139
+ jsonrpc: '2.0',
140
+ id: message.id,
141
+ result: {
142
+ protocolVersion: LATEST_PROTOCOL_VERSION,
143
+ serverInfo: {
144
+ name: serverInfo.name,
145
+ version: serverInfo.version,
146
+ },
147
+ capabilities: this._capabilities,
148
+ },
149
+ };
150
+ // Use setTimeout to make this async and match real transport behavior
151
+ setTimeout(() => this.onmessage(initializeResponse), 0);
152
+ }
153
+ return;
154
+ }
155
+ // Intercept 'notifications/initialized' - no response needed, just acknowledge
156
+ if (message.method === 'notifications/initialized') {
157
+ return;
158
+ }
159
+ try {
160
+ // Build the RPC call params, only including id if it's defined
161
+ const rpcParams = {
162
+ namespace: this._namespace,
163
+ jsonrpc: '2.0',
164
+ method: message.method,
165
+ };
166
+ // Only add id if present (for requests, not notifications)
167
+ if ('id' in message && message.id !== undefined) {
168
+ rpcParams.id = message.id;
169
+ }
170
+ // Only add params if present
171
+ if ('params' in message && message.params !== undefined) {
172
+ rpcParams.params = message.params;
173
+ }
174
+ const response = await this._client.beta.connect.rpc.call(this._connectionId, rpcParams);
175
+ // Route the response back via onmessage callback for requests (messages with an id)
176
+ if ('id' in message && message.id !== undefined && this.onmessage) {
177
+ const jsonRpcResponse = {
178
+ jsonrpc: '2.0',
179
+ id: response.id,
180
+ result: response.result,
181
+ };
182
+ this.onmessage(jsonRpcResponse);
183
+ }
184
+ }
185
+ catch (error) {
186
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
187
+ // For requests, send an error response via onmessage
188
+ if ('id' in message && message.id !== undefined && this.onmessage) {
189
+ const errorResponse = {
190
+ jsonrpc: '2.0',
191
+ id: message.id,
192
+ error: {
193
+ code: -32603, // Internal error
194
+ message: normalizedError.message,
195
+ },
196
+ };
197
+ this.onmessage(errorResponse);
198
+ }
199
+ // Also report via onerror callback
200
+ this.onerror?.(normalizedError);
201
+ }
202
+ }
203
+ async close() {
204
+ this._closed = true;
205
+ this._started = false;
206
+ this.onclose?.();
207
+ }
208
+ }
209
+ //# sourceMappingURL=mcp-transport.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-transport.mjs","sourceRoot":"","sources":["../src/lib/mcp-transport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smithery/api",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "The official TypeScript library for the Smithery API",
5
5
  "author": "Smithery <contact@smithery.ai>",
6
6
  "types": "./index.d.ts",
@@ -15,7 +15,6 @@
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
18
- "dependencies": {},
19
18
  "exports": {
20
19
  ".": {
21
20
  "require": {
@@ -75,6 +74,16 @@
75
74
  "./index.mjs": {
76
75
  "default": "./index.mjs"
77
76
  },
77
+ "./lib/*.mjs": {
78
+ "default": "./lib/*.mjs"
79
+ },
80
+ "./lib/*.js": {
81
+ "default": "./lib/*.js"
82
+ },
83
+ "./lib/*": {
84
+ "import": "./lib/*.mjs",
85
+ "require": "./lib/*.js"
86
+ },
78
87
  "./pagination": {
79
88
  "import": "./pagination.mjs",
80
89
  "require": "./pagination.js"
@@ -134,6 +143,29 @@
134
143
  },
135
144
  "./version.mjs": {
136
145
  "default": "./version.mjs"
146
+ },
147
+ "./mcp": {
148
+ "require": {
149
+ "types": "./lib/mcp-transport.d.ts",
150
+ "default": "./lib/mcp-transport.js"
151
+ },
152
+ "types": "./lib/mcp-transport.d.mts",
153
+ "default": "./lib/mcp-transport.mjs"
154
+ }
155
+ },
156
+ "peerDependencies": {
157
+ "@modelcontextprotocol/sdk": ">=1.0.0"
158
+ },
159
+ "peerDependenciesMeta": {
160
+ "@modelcontextprotocol/sdk": {
161
+ "optional": true
162
+ }
163
+ },
164
+ "typesVersions": {
165
+ "*": {
166
+ "mcp": [
167
+ "./lib/mcp-transport.d.ts"
168
+ ]
137
169
  }
138
170
  },
139
171
  "scripts": {
@@ -0,0 +1,277 @@
1
+ /**
2
+ * SmitheryConnectTransport - An MCP Transport that routes JSON-RPC messages through Smithery Connect.
3
+ *
4
+ * This allows you to use the official MCP SDK's Client class with Smithery Connect as the transport layer.
5
+ *
6
+ * **Important:** Smithery Connect handles MCP initialization server-side when a connection is created.
7
+ * This transport lazily fetches/creates the connection on first message and uses its server info
8
+ * to satisfy the MCP SDK's initialization flow without re-initializing the already-established connection.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
13
+ * import Smithery from '@smithery/api';
14
+ * import { SmitheryConnectTransport } from '@smithery/api/mcp';
15
+ *
16
+ * const smithery = new Smithery({ apiKey: process.env.SMITHERY_API_KEY });
17
+ * // Option 1: Let Smithery generate a connection ID
18
+ * const transport = new SmitheryConnectTransport({
19
+ * client: smithery,
20
+ * namespace: 'my-namespace',
21
+ * mcpUrl: 'https://mcp.example.com/sse',
22
+ * });
23
+ *
24
+ * // Option 2: Use a specific connection ID (retrieves existing or creates new)
25
+ * const transport2 = new SmitheryConnectTransport({
26
+ * client: smithery,
27
+ * namespace: 'my-namespace',
28
+ * connectionId: 'my-connection',
29
+ * mcpUrl: 'https://mcp.example.com/sse',
30
+ * });
31
+ *
32
+ * const mcpClient = new Client({ name: 'my-app', version: '1.0.0' }, { capabilities: {} });
33
+ * await mcpClient.connect(transport);
34
+ *
35
+ * // Now use the MCP SDK's ergonomic API
36
+ * const { tools } = await mcpClient.listTools();
37
+ * const result = await mcpClient.callTool({ name: 'my-tool', arguments: {} });
38
+ * ```
39
+ */
40
+
41
+ import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
42
+ import type { JSONRPCMessage, JSONRPCResponse, ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';
43
+ import type { Smithery } from '../client';
44
+ import type { Connection } from '../resources/beta/connect/connections';
45
+
46
+ export interface SmitheryConnectTransportOptions {
47
+ /**
48
+ * The Smithery client instance to use for making RPC calls.
49
+ */
50
+ client: Smithery;
51
+
52
+ /**
53
+ * The namespace for the Smithery Connect connection.
54
+ */
55
+ namespace: string;
56
+
57
+ /**
58
+ * The connection ID for the Smithery Connect connection.
59
+ * If not provided, a new connection will be created with an auto-generated ID.
60
+ */
61
+ connectionId?: string;
62
+
63
+ /**
64
+ * The MCP server URL. Required when creating a new connection.
65
+ * If connectionId is provided, this is used to create the connection if it doesn't exist.
66
+ * If connectionId is not provided, this is required and a new connection will be created.
67
+ */
68
+ mcpUrl?: string;
69
+
70
+ /**
71
+ * Optional server capabilities for the initialize response.
72
+ * If not provided, defaults to advertising tools, resources, and prompts support.
73
+ */
74
+ capabilities?: ServerCapabilities;
75
+ }
76
+
77
+ // MCP protocol version
78
+ const LATEST_PROTOCOL_VERSION = '2024-11-05';
79
+
80
+ export class SmitheryConnectTransport implements Transport {
81
+ private _client: Smithery;
82
+ private _namespace: string;
83
+ private _connectionId: string | undefined;
84
+ private _mcpUrl: string | undefined;
85
+ private _started = false;
86
+ private _closed = false;
87
+ private _capabilities: ServerCapabilities;
88
+ private _connection: Connection | null = null;
89
+
90
+ onmessage?: (message: JSONRPCMessage) => void;
91
+ onerror?: (error: Error) => void;
92
+ onclose?: () => void;
93
+
94
+ sessionId?: string;
95
+
96
+ /**
97
+ * Returns the connection ID. If no connectionId was provided in options,
98
+ * this returns the auto-generated ID after the first message is sent.
99
+ */
100
+ get connectionId(): string | undefined {
101
+ return this._connectionId;
102
+ }
103
+
104
+ constructor(options: SmitheryConnectTransportOptions) {
105
+ this._client = options.client;
106
+ this._namespace = options.namespace;
107
+ this._connectionId = options.connectionId;
108
+ this._mcpUrl = options.mcpUrl;
109
+
110
+ // Validate: mcpUrl is required if connectionId is not provided
111
+ if (!this._connectionId && !this._mcpUrl) {
112
+ throw new Error('mcpUrl is required when connectionId is not provided');
113
+ }
114
+
115
+ this._capabilities = options.capabilities ?? {
116
+ // Default to advertising common capabilities
117
+ // The actual MCP server behind Smithery Connect will handle the real capabilities
118
+ tools: {},
119
+ resources: {},
120
+ prompts: {},
121
+ };
122
+ }
123
+
124
+ async start(): Promise<void> {
125
+ if (this._started) {
126
+ throw new Error(
127
+ 'SmitheryConnectTransport already started! If using Client class, note that connect() calls start() automatically.',
128
+ );
129
+ }
130
+ if (this._closed) {
131
+ throw new Error('Transport has been closed');
132
+ }
133
+
134
+ this._started = true;
135
+ }
136
+
137
+ /**
138
+ * Lazily ensures the Smithery Connect connection exists.
139
+ * Called on first message to defer network IO until actually needed.
140
+ */
141
+ private async _ensureConnection(): Promise<void> {
142
+ if (this._connection) {
143
+ return;
144
+ }
145
+
146
+ if (this._connectionId) {
147
+ // Connection ID provided: try to retrieve, or create if mcpUrl is provided
148
+ try {
149
+ this._connection = await this._client.beta.connect.connections.retrieve(this._connectionId, {
150
+ namespace: this._namespace,
151
+ });
152
+ } catch (error) {
153
+ // If connection doesn't exist and we have mcpUrl, create it with the specified ID
154
+ if (this._mcpUrl) {
155
+ this._connection = await this._client.beta.connect.connections.set(this._connectionId, {
156
+ namespace: this._namespace,
157
+ mcpUrl: this._mcpUrl,
158
+ });
159
+ } else {
160
+ throw error;
161
+ }
162
+ }
163
+ } else {
164
+ // No connection ID: create a new connection with auto-generated ID
165
+ // mcpUrl is guaranteed to be present (validated in constructor)
166
+ this._connection = await this._client.beta.connect.connections.create(this._namespace, {
167
+ mcpUrl: this._mcpUrl!,
168
+ });
169
+ // Store the generated connection ID for subsequent RPC calls
170
+ this._connectionId = this._connection.connectionId;
171
+ }
172
+ }
173
+
174
+ async send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void> {
175
+ if (!this._started) {
176
+ throw new Error('Transport not started');
177
+ }
178
+ if (this._closed) {
179
+ throw new Error('Transport has been closed');
180
+ }
181
+
182
+ // Only handle outgoing requests and notifications (messages with a method)
183
+ if (!('method' in message)) {
184
+ return;
185
+ }
186
+
187
+ // Lazily ensure connection exists before processing any message
188
+ await this._ensureConnection();
189
+
190
+ // Intercept 'initialize' request - Smithery Connect handles initialization server-side
191
+ // Return the real serverInfo from the connection
192
+ if (message.method === 'initialize' && 'id' in message && message.id !== undefined) {
193
+ if (this.onmessage) {
194
+ const serverInfo = this._connection?.serverInfo ?? {
195
+ name: 'smithery-connect',
196
+ version: '1.0.0',
197
+ };
198
+
199
+ const initializeResponse: JSONRPCResponse = {
200
+ jsonrpc: '2.0',
201
+ id: message.id,
202
+ result: {
203
+ protocolVersion: LATEST_PROTOCOL_VERSION,
204
+ serverInfo: {
205
+ name: serverInfo.name,
206
+ version: serverInfo.version,
207
+ },
208
+ capabilities: this._capabilities,
209
+ } as Record<string, unknown>,
210
+ };
211
+ // Use setTimeout to make this async and match real transport behavior
212
+ setTimeout(() => this.onmessage!(initializeResponse), 0);
213
+ }
214
+ return;
215
+ }
216
+
217
+ // Intercept 'notifications/initialized' - no response needed, just acknowledge
218
+ if (message.method === 'notifications/initialized') {
219
+ return;
220
+ }
221
+
222
+ try {
223
+ // Build the RPC call params, only including id if it's defined
224
+ const rpcParams: Parameters<typeof this._client.beta.connect.rpc.call>[1] = {
225
+ namespace: this._namespace,
226
+ jsonrpc: '2.0',
227
+ method: message.method,
228
+ };
229
+
230
+ // Only add id if present (for requests, not notifications)
231
+ if ('id' in message && message.id !== undefined) {
232
+ rpcParams.id = message.id;
233
+ }
234
+
235
+ // Only add params if present
236
+ if ('params' in message && message.params !== undefined) {
237
+ rpcParams.params = message.params as Record<string, unknown>;
238
+ }
239
+
240
+ const response = await this._client.beta.connect.rpc.call(this._connectionId!, rpcParams);
241
+
242
+ // Route the response back via onmessage callback for requests (messages with an id)
243
+ if ('id' in message && message.id !== undefined && this.onmessage) {
244
+ const jsonRpcResponse: JSONRPCResponse = {
245
+ jsonrpc: '2.0',
246
+ id: response.id!,
247
+ result: response.result as Record<string, unknown>,
248
+ };
249
+ this.onmessage(jsonRpcResponse);
250
+ }
251
+ } catch (error) {
252
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
253
+
254
+ // For requests, send an error response via onmessage
255
+ if ('id' in message && message.id !== undefined && this.onmessage) {
256
+ const errorResponse: JSONRPCResponse = {
257
+ jsonrpc: '2.0',
258
+ id: message.id,
259
+ error: {
260
+ code: -32603, // Internal error
261
+ message: normalizedError.message,
262
+ },
263
+ };
264
+ this.onmessage(errorResponse);
265
+ }
266
+
267
+ // Also report via onerror callback
268
+ this.onerror?.(normalizedError);
269
+ }
270
+ }
271
+
272
+ async close(): Promise<void> {
273
+ this._closed = true;
274
+ this._started = false;
275
+ this.onclose?.();
276
+ }
277
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.23.0'; // x-release-please-version
1
+ export const VERSION = '0.24.0'; // x-release-please-version
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.23.0";
1
+ export declare const VERSION = "0.24.0";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.23.0";
1
+ export declare const VERSION = "0.24.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '0.23.0'; // x-release-please-version
4
+ exports.VERSION = '0.24.0'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.23.0'; // x-release-please-version
1
+ export const VERSION = '0.24.0'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map