@smithery/sdk 1.5.9 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,4 @@
1
1
  export * from "./shared/config.js";
2
2
  export * from "./shared/patch.js";
3
- export * from "./client/transport.js";
4
- export * from "./client/integrations/ai-sdk.js";
5
- export * from "./client/integrations/wrap-error.js";
6
3
  export { createStatefulServer, type StatefulServerOptions, } from "./server/stateful.js";
7
4
  export * from "./server/session.js";
package/dist/index.js CHANGED
@@ -4,10 +4,6 @@
4
4
  // Shared utilities
5
5
  export * from "./shared/config.js";
6
6
  export * from "./shared/patch.js";
7
- // Client-side helpers
8
- export * from "./client/transport.js";
9
- export * from "./client/integrations/ai-sdk.js";
10
- export * from "./client/integrations/wrap-error.js";
11
7
  // Server-side helpers (selective to avoid duplicate type names)
12
8
  export { createStatefulServer, } from "./server/stateful.js";
13
9
  export * from "./server/session.js";
@@ -1,3 +1,4 @@
1
1
  export * from "./stateful.js";
2
2
  export * from "./stateless.js";
3
3
  export * from "./session.js";
4
+ export * from "./oauth.js";
@@ -1,3 +1,4 @@
1
1
  export * from "./stateful.js";
2
2
  export * from "./stateless.js";
3
3
  export * from "./session.js";
4
+ export * from "./oauth.js";
@@ -0,0 +1,14 @@
1
+ import type express from "express";
2
+ import type { OAuthServerProvider } from "@modelcontextprotocol/sdk/server/auth/provider.js";
3
+ import type { Response } from "express";
4
+ /**
5
+ * OAuth server provider that supports a callback handler.
6
+ * The callback handler is invoked to catch the OAuth callback from the OAuth provider.
7
+ */
8
+ export interface CallbackOAuthServerProvider extends OAuthServerProvider {
9
+ /** Provider-specific callback handler used by the SDK */
10
+ handleOAuthCallback?: (code: string, state: string | undefined, res: Response) => Promise<URL>;
11
+ basePath?: string;
12
+ callbackPath: string;
13
+ }
14
+ export declare function mountOAuth(app: express.Application, provider: CallbackOAuthServerProvider): void;
@@ -0,0 +1,36 @@
1
+ import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
2
+ import { mcpAuthRouter } from "@modelcontextprotocol/sdk/server/auth/router.js";
3
+ export function mountOAuth(app, provider) {
4
+ // Mount OAuth authorization and token routes with dynamic issuer URL and provider
5
+ app.use(provider.basePath ?? "/", (req, res, next) => {
6
+ const host = req.get("host") ?? "localhost";
7
+ // Issuer URL must be https
8
+ const issuerUrl = new URL(`https://${host}`);
9
+ const router = mcpAuthRouter({ provider, issuerUrl });
10
+ return router(req, res, next);
11
+ });
12
+ const callbackHandler = provider.handleOAuthCallback;
13
+ if (callbackHandler) {
14
+ // Callback handler
15
+ app.get(provider.callbackPath, async (req, res) => {
16
+ const code = typeof req.query.code === "string" ? req.query.code : undefined;
17
+ const state = typeof req.query.state === "string" ? req.query.state : undefined;
18
+ if (!code) {
19
+ res.status(400).send("Invalid request parameters");
20
+ return;
21
+ }
22
+ try {
23
+ const redirectUrl = await callbackHandler.bind(provider)(code, state, res);
24
+ res.redirect(redirectUrl.toString());
25
+ }
26
+ catch (error) {
27
+ console.error(error);
28
+ res.status(500).send("Error during authentication callback");
29
+ }
30
+ });
31
+ }
32
+ // Bearer protection for all /mcp routes (POST/GET/DELETE)
33
+ app.use("/mcp", (req, res, next) => {
34
+ return requireBearerAuth({ verifier: provider })(req, res, next);
35
+ });
36
+ }
@@ -1,14 +1,17 @@
1
1
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
2
+ import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
2
3
  import express from "express";
3
4
  import type { z } from "zod";
4
5
  import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
5
6
  import { type SessionStore } from "./session.js";
7
+ import type { CallbackOAuthServerProvider } from "./oauth.js";
6
8
  /**
7
9
  * Arguments when we create a new instance of your server
8
10
  */
9
11
  export interface CreateServerArg<T = Record<string, unknown>> {
10
12
  sessionId: string;
11
13
  config: T;
14
+ auth?: AuthInfo;
12
15
  }
13
16
  export type CreateServerFn<T = Record<string, unknown>> = (arg: CreateServerArg<T>) => Server;
14
17
  /**
@@ -27,6 +30,10 @@ export interface StatefulServerOptions<T = Record<string, unknown>> {
27
30
  * Express app instance to use (optional)
28
31
  */
29
32
  app?: express.Application;
33
+ /**
34
+ * OAuth provider instance. If provided, OAuth routes and bearer protection are auto-wired.
35
+ */
36
+ oauthProvider?: CallbackOAuthServerProvider;
30
37
  }
31
38
  /**
32
39
  * Creates a stateful server for handling MCP requests.
@@ -5,6 +5,7 @@ import { randomUUID } from "node:crypto";
5
5
  import { parseAndValidateConfig } from "../shared/config.js";
6
6
  import { zodToJsonSchema } from "zod-to-json-schema";
7
7
  import { createLRUStore } from "./session.js";
8
+ import { mountOAuth } from "./oauth.js";
8
9
  /**
9
10
  * Creates a stateful server for handling MCP requests.
10
11
  * For every new session, we invoke createMcpServer to create a new instance of the server.
@@ -14,6 +15,11 @@ import { createLRUStore } from "./session.js";
14
15
  */
15
16
  export function createStatefulServer(createMcpServer, options) {
16
17
  const app = options?.app ?? express();
18
+ // Auto-wire OAuth routes and bearer protection if configured
19
+ const oauthProvider = options?.oauthProvider;
20
+ if (oauthProvider) {
21
+ mountOAuth(app, oauthProvider);
22
+ }
17
23
  app.use("/mcp", express.json());
18
24
  const sessionStore = options?.sessionStore ?? createLRUStore();
19
25
  // Handle POST requests for client-to-server communication
@@ -54,6 +60,7 @@ export function createStatefulServer(createMcpServer, options) {
54
60
  const server = createMcpServer({
55
61
  sessionId: newSessionId,
56
62
  config: config,
63
+ auth: req.auth,
57
64
  });
58
65
  // Connect to the MCP server
59
66
  await server.connect(transport);
@@ -1,11 +1,14 @@
1
1
  import express from "express";
2
2
  import type { z } from "zod";
3
3
  import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
5
+ import type { CallbackOAuthServerProvider } from "./oauth.js";
4
6
  /**
5
7
  * Arguments when we create a stateless server instance
6
8
  */
7
9
  export interface CreateStatelessServerArg<T = Record<string, unknown>> {
8
10
  config: T;
11
+ auth?: AuthInfo;
9
12
  }
10
13
  export type CreateStatelessServerFn<T = Record<string, unknown>> = (arg: CreateStatelessServerArg<T>) => Server;
11
14
  /**
@@ -20,6 +23,10 @@ export interface StatelessServerOptions<T = Record<string, unknown>> {
20
23
  * Express app instance to use (optional)
21
24
  */
22
25
  app?: express.Application;
26
+ /**
27
+ * OAuth provider instance. If provided, OAuth routes and bearer protection are auto-wired.
28
+ */
29
+ oauthProvider?: CallbackOAuthServerProvider;
23
30
  }
24
31
  /**
25
32
  * Creates a stateless server for handling MCP requests.
@@ -2,6 +2,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
2
2
  import express from "express";
3
3
  import { parseAndValidateConfig } from "../shared/config.js";
4
4
  import { zodToJsonSchema } from "zod-to-json-schema";
5
+ import { mountOAuth } from "./oauth.js";
5
6
  /**
6
7
  * Creates a stateless server for handling MCP requests.
7
8
  * Each request creates a new server instance - no session state is maintained.
@@ -13,6 +14,11 @@ import { zodToJsonSchema } from "zod-to-json-schema";
13
14
  */
14
15
  export function createStatelessServer(createMcpServer, options) {
15
16
  const app = options?.app ?? express();
17
+ // Auto-wire OAuth routes and bearer protection if configured
18
+ const oauthProvider = options?.oauthProvider;
19
+ if (oauthProvider) {
20
+ mountOAuth(app, oauthProvider);
21
+ }
16
22
  app.use("/mcp", express.json());
17
23
  // Handle POST requests for client-to-server communication
18
24
  app.post("/mcp", async (req, res) => {
@@ -31,6 +37,7 @@ export function createStatelessServer(createMcpServer, options) {
31
37
  // Create a fresh server instance for each request
32
38
  const server = createMcpServer({
33
39
  config,
40
+ auth: req.auth,
34
41
  });
35
42
  // Create a new transport for this request (no session management)
36
43
  const transport = new StreamableHTTPServerTransport({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smithery/sdk",
3
- "version": "1.5.9",
3
+ "version": "1.6.1",
4
4
  "description": "SDK to develop with Smithery",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,14 +20,11 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "@anthropic-ai/sdk": "^0.32.1",
24
- "@modelcontextprotocol/sdk": "^1.15.0",
25
- "ai": "^4.3.15",
23
+ "@modelcontextprotocol/sdk": "^1.18.0",
26
24
  "express": "^5.1.0",
27
25
  "json-schema": "^0.4.0",
28
26
  "lodash": "^4.17.21",
29
27
  "okay-error": "^1.0.3",
30
- "openai": "^4.0.0",
31
28
  "uuid": "^11.0.3",
32
29
  "zod": "^3.23.8",
33
30
  "zod-to-json-schema": "^3.24.1"
@@ -1,15 +0,0 @@
1
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
- import { type Tool } from "ai";
3
- type ToolClient = Pick<Client, "listTools" | "callTool" | "setNotificationHandler">;
4
- /**
5
- * Watches the MCP client for tool changes and updates the tools object accordingly.
6
- * @param client The MCP client to watch
7
- * @returns A record of tool names to their implementations
8
- */
9
- export declare function watchTools(client: ToolClient): Promise<Record<string, Tool>>;
10
- /**
11
- * Returns a set of wrapped AI SDK tools from the MCP server.
12
- * @returns A record of tool names to their implementations
13
- */
14
- export declare function listTools(client: ToolClient): Promise<Record<string, Tool>>;
15
- export {};
@@ -1,39 +0,0 @@
1
- import { ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
2
- import { jsonSchema, tool, } from "ai";
3
- /**
4
- * Watches the MCP client for tool changes and updates the tools object accordingly.
5
- * @param client The MCP client to watch
6
- * @returns A record of tool names to their implementations
7
- */
8
- export async function watchTools(client) {
9
- const tools = {};
10
- client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
11
- Object.assign(tools, await listTools(client));
12
- });
13
- Object.assign(tools, await listTools(client));
14
- return tools;
15
- }
16
- /**
17
- * Returns a set of wrapped AI SDK tools from the MCP server.
18
- * @returns A record of tool names to their implementations
19
- */
20
- export async function listTools(client) {
21
- const tools = {};
22
- const listToolsResult = await client.listTools();
23
- for (const { name, description, inputSchema } of listToolsResult.tools) {
24
- const parameters = jsonSchema(inputSchema);
25
- tools[name] = tool({
26
- description,
27
- parameters,
28
- execute: async (args, options) => {
29
- options?.abortSignal?.throwIfAborted();
30
- const result = await client.callTool({
31
- name,
32
- arguments: args,
33
- });
34
- return result;
35
- },
36
- });
37
- }
38
- return tools;
39
- }
@@ -1,12 +0,0 @@
1
- import type { Message, MessageParam, Tool } from "@anthropic-ai/sdk/resources/index.js";
2
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
- import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
- /**
5
- * Adapt an MCP client so it works seamlessly with Anthropic messages
6
- */
7
- export declare class AnthropicChatAdapter {
8
- private client;
9
- constructor(client: Pick<Client, "callTool" | "listTools">);
10
- listTools(): Promise<Tool[]>;
11
- callTool(response: Message, options?: RequestOptions): Promise<MessageParam[]>;
12
- }
@@ -1,48 +0,0 @@
1
- import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
2
- /**
3
- * Adapt an MCP client so it works seamlessly with Anthropic messages
4
- */
5
- export class AnthropicChatAdapter {
6
- constructor(client) {
7
- this.client = client;
8
- }
9
- async listTools() {
10
- const toolResult = await this.client.listTools();
11
- return toolResult.tools.map(tool => ({
12
- name: tool.name,
13
- description: tool.description,
14
- input_schema: tool.inputSchema,
15
- }));
16
- }
17
- // TODO: Support streaming
18
- async callTool(response, options) {
19
- const content = response.content;
20
- if (!content || content.length === 0) {
21
- return [];
22
- }
23
- // Find tool calls in the message content
24
- const toolCalls = content.filter(part => part.type === "tool_use");
25
- if (toolCalls.length === 0) {
26
- return [];
27
- }
28
- // Run parallel tool call
29
- const results = await Promise.all(toolCalls.map(async (toolCall) => {
30
- return await this.client.callTool({
31
- name: toolCall.name,
32
- arguments: toolCall.input,
33
- }, CallToolResultSchema, options);
34
- }));
35
- return [
36
- {
37
- role: "user",
38
- content: results.map((result, index) => ({
39
- tool_use_id: toolCalls[index].id,
40
- type: "tool_result",
41
- // TODO: Find a way to remove the any
42
- content: result.content.filter((part) => part.type === "text"),
43
- is_error: Boolean(result.isError),
44
- })),
45
- },
46
- ];
47
- }
48
- }
@@ -1,19 +0,0 @@
1
- import type { OpenAI } from "openai";
2
- import type { ChatCompletionTool, ChatCompletionToolMessageParam } from "openai/resources/index.js";
3
- import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
4
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
5
- interface OpenAIAdapterOptions {
6
- strict?: boolean;
7
- truncateDescriptionLength?: number;
8
- }
9
- /**
10
- * Adapt an MCP client so it works seamlessly with OpenAI chat completions
11
- */
12
- export declare class OpenAIChatAdapter {
13
- private client;
14
- private options;
15
- constructor(client: Pick<Client, "callTool" | "listTools">, options?: OpenAIAdapterOptions);
16
- listTools(): Promise<ChatCompletionTool[]>;
17
- callTool(response: OpenAI.Chat.Completions.ChatCompletion, options?: RequestOptions): Promise<ChatCompletionToolMessageParam[]>;
18
- }
19
- export {};
@@ -1,48 +0,0 @@
1
- import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
2
- /**
3
- * Adapt an MCP client so it works seamlessly with OpenAI chat completions
4
- */
5
- export class OpenAIChatAdapter {
6
- constructor(client, options = {
7
- // Restriction enforced by OpenAI
8
- truncateDescriptionLength: 1024,
9
- }) {
10
- this.client = client;
11
- this.options = options;
12
- }
13
- async listTools() {
14
- const toolResult = await this.client.listTools();
15
- return toolResult.tools.map(tool => ({
16
- type: "function",
17
- function: {
18
- name: tool.name,
19
- description: tool.description?.slice(0, this.options?.truncateDescriptionLength),
20
- parameters: tool.inputSchema,
21
- strict: this.options?.strict ?? false,
22
- },
23
- }));
24
- }
25
- // TODO: Support streaming
26
- async callTool(response, options) {
27
- if (response.choices.length !== 1) {
28
- // TODO: Support `n`
29
- throw new Error("Multiple choices not supported");
30
- }
31
- const choice = response.choices[0];
32
- if (!choice?.message?.tool_calls) {
33
- return [];
34
- }
35
- const toolCalls = choice.message.tool_calls;
36
- const results = await Promise.all(toolCalls.map(async (toolCall) => {
37
- return await this.client.callTool({
38
- name: toolCall.function.name,
39
- arguments: JSON.parse(toolCall.function.arguments),
40
- }, CallToolResultSchema, options);
41
- }));
42
- return results.map((result, index) => ({
43
- role: "tool",
44
- content: result.content,
45
- tool_call_id: toolCalls[index].id,
46
- }));
47
- }
48
- }
@@ -1,5 +0,0 @@
1
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
- /**
3
- * Wraps each tool call so any errors get sent back to the LLM instead of throwing
4
- */
5
- export declare function wrapError<C extends Pick<Client, "callTool">>(client: C): C;
@@ -1,24 +0,0 @@
1
- import { CallToolResultSchema, } from "@modelcontextprotocol/sdk/types.js";
2
- import { patch } from "../../shared/patch.js";
3
- /**
4
- * Wraps each tool call so any errors get sent back to the LLM instead of throwing
5
- */
6
- export function wrapError(client) {
7
- patch(client, "callTool", callTool => async (params, resultSchema = CallToolResultSchema, options) => {
8
- try {
9
- return await callTool(params, resultSchema, options);
10
- }
11
- catch (err) {
12
- return {
13
- content: [
14
- {
15
- type: "text",
16
- text: JSON.stringify(err, Object.getOwnPropertyNames(err)),
17
- },
18
- ],
19
- isError: true,
20
- };
21
- }
22
- });
23
- return client;
24
- }
@@ -1,9 +0,0 @@
1
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
2
- import { type SmitheryUrlOptions } from "../shared/config.js";
3
- /**
4
- * Creates a transport to connect to the Smithery server
5
- * @param baseUrl The URL of the Smithery server (without trailing slash or protocol)
6
- * @param options Optional configuration object
7
- * @returns Transport
8
- */
9
- export declare function createTransport(baseUrl: string, options?: SmitheryUrlOptions): StreamableHTTPClientTransport;
@@ -1,11 +0,0 @@
1
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
2
- import { createSmitheryUrl } from "../shared/config.js";
3
- /**
4
- * Creates a transport to connect to the Smithery server
5
- * @param baseUrl The URL of the Smithery server (without trailing slash or protocol)
6
- * @param options Optional configuration object
7
- * @returns Transport
8
- */
9
- export function createTransport(baseUrl, options) {
10
- return new StreamableHTTPClientTransport(createSmitheryUrl(baseUrl, options));
11
- }