@smithery/sdk 1.7.2 → 1.7.3

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.
@@ -0,0 +1,11 @@
1
+ export * from "./shared/config.js";
2
+ export * from "./shared/patch.js";
3
+ export { createStatefulServer, type StatefulServerOptions, } from "./server/stateful.js";
4
+ export * from "./server/session.js";
5
+ export * from "./server/auth/identity.js";
6
+ export * from "./server/auth/oauth.js";
7
+ export { createWidgetServer } from "./server/widget.js";
8
+ export type { WidgetServerOptions } from "./server/widget.js";
9
+ export { widget } from "./openai/index.js";
10
+ export type { WidgetToolOptions, WidgetResponseOptions, WidgetResourceOptions, } from "./openai/index.js";
11
+ export type { Theme, DisplayMode, OpenAiGlobals, CallToolResponse, } from "./react/types.js";
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Smithery SDK – Main exports
2
+ // Use subpath imports for tree-shaking: @smithery/sdk/server, /helpers, /react
3
+ // === Shared Utilities ===
4
+ export * from "./shared/config.js";
5
+ export * from "./shared/patch.js";
6
+ // === Server Primitives ===
7
+ // Stateful/stateless server patterns, session management, auth
8
+ export { createStatefulServer, } from "./server/stateful.js";
9
+ export * from "./server/session.js";
10
+ export * from "./server/auth/identity.js";
11
+ export * from "./server/auth/oauth.js";
12
+ // === Widget SDK - Server ===
13
+ // createWidgetServer() - MCP server wrapper for widgets
14
+ export { createWidgetServer } from "./server/widget.js";
15
+ // === Widget SDK - OpenAI ===
16
+ // widget.response() - Standard success response
17
+ // widget.error() - Standard error response
18
+ // widget.resource() - Auto-generate widget HTML
19
+ export { widget } from "./openai/index.js";
@@ -0,0 +1,2 @@
1
+ export { widget } from "./widget.js";
2
+ export type { WidgetResponseOptions, WidgetResourceOptions, WidgetToolOptions, } from "./widget.js";
@@ -0,0 +1 @@
1
+ export { widget } from "./widget.js";
@@ -0,0 +1,67 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface WidgetResponseOptions<TState = Record<string, unknown>> {
3
+ structuredData: TState;
4
+ message: string;
5
+ meta?: Record<string, unknown>;
6
+ }
7
+ export interface WidgetResourceOptions {
8
+ name: string;
9
+ description?: string;
10
+ prefersBorder?: boolean;
11
+ csp?: {
12
+ connect_domains?: string[];
13
+ resource_domains?: string[];
14
+ };
15
+ bundlePath?: string;
16
+ bundleURL?: string;
17
+ cssURLs?: string | string[];
18
+ }
19
+ export interface WidgetToolOptions {
20
+ template: string;
21
+ invoking?: string;
22
+ invoked?: string;
23
+ widgetAccessible?: boolean;
24
+ }
25
+ export interface WidgetErrorOptions {
26
+ message: string;
27
+ details?: unknown;
28
+ meta?: Record<string, unknown>;
29
+ }
30
+ export declare function response<TState = Record<string, unknown>>(options: WidgetResponseOptions<TState>): {
31
+ structuredContent: Record<string, unknown>;
32
+ content: {
33
+ type: "text";
34
+ text: string;
35
+ }[];
36
+ _meta: Record<string, unknown>;
37
+ };
38
+ export declare function error(options: string | WidgetErrorOptions): {
39
+ _meta?: Record<string, unknown> | undefined;
40
+ content: {
41
+ type: "text";
42
+ text: string;
43
+ }[];
44
+ isError: boolean;
45
+ };
46
+ export declare function resource<TState = Record<string, unknown>>(options: WidgetResourceOptions): {
47
+ name: string;
48
+ uri: string;
49
+ handler: () => Promise<{
50
+ contents: Array<{
51
+ uri: string;
52
+ text: string;
53
+ mimeType: "text/html+skybridge";
54
+ _meta?: Record<string, unknown>;
55
+ }>;
56
+ }>;
57
+ toolConfig: (options?: Omit<WidgetToolOptions, "template">) => Record<string, unknown>;
58
+ response: (options: WidgetResponseOptions<TState>) => ReturnType<typeof response<TState>>;
59
+ register: (server: Pick<McpServer, "registerResource">) => void;
60
+ };
61
+ export declare function toolConfig(options: WidgetToolOptions): Record<string, unknown>;
62
+ export declare const widget: {
63
+ response: typeof response;
64
+ error: typeof error;
65
+ resource: typeof resource;
66
+ toolConfig: typeof toolConfig;
67
+ };
@@ -0,0 +1,126 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ export function response(options) {
4
+ const { structuredData, message, meta = {} } = options;
5
+ return {
6
+ structuredContent: structuredData,
7
+ content: [
8
+ {
9
+ type: "text",
10
+ text: message,
11
+ },
12
+ ],
13
+ _meta: meta,
14
+ };
15
+ }
16
+ export function error(options) {
17
+ const isString = typeof options === "string";
18
+ const message = isString ? options : options.message;
19
+ const details = isString ? undefined : options.details;
20
+ const meta = isString ? undefined : options.meta;
21
+ const finalMeta = {
22
+ ...(meta || {}),
23
+ };
24
+ if (details) {
25
+ finalMeta.errorDetails = details;
26
+ }
27
+ return {
28
+ content: [
29
+ {
30
+ type: "text",
31
+ text: message,
32
+ },
33
+ ],
34
+ isError: true,
35
+ ...(Object.keys(finalMeta).length > 0 && { _meta: finalMeta }),
36
+ };
37
+ }
38
+ export function resource(options) {
39
+ const { name, description, prefersBorder, csp, bundlePath = `.smithery/${name}.js`, bundleURL, } = options;
40
+ const uri = `ui://widget/${name}.html`;
41
+ const handler = async () => {
42
+ let scriptTag;
43
+ if (bundleURL) {
44
+ scriptTag = `<script type="module" src="${bundleURL}"></script>`;
45
+ }
46
+ else {
47
+ const js = await readFile(resolve(process.cwd(), bundlePath), "utf-8");
48
+ scriptTag = `<script type="module">${js}</script>`;
49
+ }
50
+ const cssUrls = Array.isArray(options.cssURLs)
51
+ ? options.cssURLs
52
+ : options.cssURLs
53
+ ? [options.cssURLs]
54
+ : [];
55
+ const cssLinks = cssUrls
56
+ .map(url => `<link rel="stylesheet" href="${url}">`)
57
+ .join("\n");
58
+ const html = `
59
+ <div id="${name}-root"></div>
60
+ ${cssLinks}
61
+ ${scriptTag}
62
+ `.trim();
63
+ const _meta = {};
64
+ if (description)
65
+ _meta["openai/widgetDescription"] = description;
66
+ if (prefersBorder !== undefined)
67
+ _meta["openai/widgetPrefersBorder"] = prefersBorder;
68
+ if (csp)
69
+ _meta["openai/widgetCSP"] = csp;
70
+ return {
71
+ contents: [
72
+ {
73
+ uri,
74
+ text: html,
75
+ mimeType: "text/html+skybridge",
76
+ ...(Object.keys(_meta).length > 0 && { _meta }),
77
+ },
78
+ ],
79
+ };
80
+ };
81
+ const toolConfig = (options) => {
82
+ return {
83
+ "openai/outputTemplate": uri,
84
+ "openai/widgetAccessible": options?.widgetAccessible ?? true,
85
+ ...(options?.invoking && {
86
+ "openai/toolInvocation/invoking": options.invoking,
87
+ }),
88
+ ...(options?.invoked && {
89
+ "openai/toolInvocation/invoked": options.invoked,
90
+ }),
91
+ };
92
+ };
93
+ const typedResponse = (options) => {
94
+ return response(options);
95
+ };
96
+ const register = (server) => {
97
+ server.registerResource(name, uri, {}, handler);
98
+ };
99
+ return {
100
+ name,
101
+ uri,
102
+ handler,
103
+ toolConfig,
104
+ response: typedResponse,
105
+ register,
106
+ };
107
+ }
108
+ export function toolConfig(options) {
109
+ const meta = {
110
+ "openai/outputTemplate": `ui://widget/${options.template}.html`,
111
+ "openai/widgetAccessible": options.widgetAccessible ?? true,
112
+ };
113
+ if (options.invoking) {
114
+ meta["openai/toolInvocation/invoking"] = options.invoking;
115
+ }
116
+ if (options.invoked) {
117
+ meta["openai/toolInvocation/invoked"] = options.invoked;
118
+ }
119
+ return meta;
120
+ }
121
+ export const widget = {
122
+ response,
123
+ error,
124
+ resource,
125
+ toolConfig,
126
+ };
@@ -0,0 +1,18 @@
1
+ import { Component, type ReactNode } from "react";
2
+ interface ErrorBoundaryProps {
3
+ children: ReactNode;
4
+ fallback?: (error: Error) => ReactNode;
5
+ }
6
+ interface ErrorBoundaryState {
7
+ hasError: boolean;
8
+ error: Error | null;
9
+ }
10
+ export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
11
+ constructor(props: ErrorBoundaryProps);
12
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
13
+ componentDidCatch(error: Error, errorInfo: {
14
+ componentStack?: string;
15
+ }): void;
16
+ render(): ReactNode;
17
+ }
18
+ export {};
@@ -0,0 +1,28 @@
1
+ import { Component, createElement } from "react";
2
+ export class ErrorBoundary extends Component {
3
+ constructor(props) {
4
+ super(props);
5
+ this.state = { hasError: false, error: null };
6
+ }
7
+ static getDerivedStateFromError(error) {
8
+ return { hasError: true, error };
9
+ }
10
+ componentDidCatch(error, errorInfo) {
11
+ console.error("Widget error:", error, errorInfo);
12
+ }
13
+ render() {
14
+ if (this.state.hasError && this.state.error) {
15
+ if (this.props.fallback) {
16
+ return this.props.fallback(this.state.error);
17
+ }
18
+ return createElement("div", {
19
+ style: {
20
+ padding: "16px",
21
+ color: "#d32f2f",
22
+ fontFamily: "system-ui, sans-serif",
23
+ },
24
+ }, createElement("h3", { style: { margin: "0 0 8px 0", fontSize: "14px" } }, "Widget Error"), createElement("p", { style: { margin: "0", fontSize: "12px", opacity: 0.8 } }, this.state.error.message || "An error occurred"));
25
+ }
26
+ return this.props.children;
27
+ }
28
+ }
@@ -0,0 +1,32 @@
1
+ import { type SetStateAction } from "react";
2
+ import type { OpenAiGlobals } from "./types.js";
3
+ export declare function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K] | undefined;
4
+ export declare function useTheme(): import("./types.js").Theme;
5
+ export declare function useDisplayMode(): import("./types.js").DisplayMode;
6
+ export declare function useUserAgent(): import("./types.js").UserAgent | undefined;
7
+ export declare function useMaxHeight(): number | undefined;
8
+ export declare function useSafeArea(): import("./types.js").SafeArea | undefined;
9
+ export declare function useLocale(): string;
10
+ export declare function useToolInput<T = Record<string, unknown>>(): T | undefined;
11
+ export declare function useToolOutput<T = unknown>(): {
12
+ content: {
13
+ type: string;
14
+ text: string;
15
+ }[];
16
+ structuredContent: T | undefined;
17
+ };
18
+ export declare function useToolResponseMetadata<T = Record<string, unknown>>(): T | undefined;
19
+ export declare function useCallTool<TArgs = Record<string, unknown>, TResult = unknown>(toolName: string): {
20
+ call: (args: TArgs) => Promise<void>;
21
+ isPending: boolean;
22
+ error: Error | null;
23
+ data: TResult | null;
24
+ };
25
+ export declare function useSendFollowUp(): {
26
+ send: (prompt: string) => Promise<void>;
27
+ isPending: boolean;
28
+ error: Error | null;
29
+ };
30
+ export declare function useRequestDisplayMode(): (mode: "inline" | "pip" | "fullscreen") => Promise<void>;
31
+ export declare function useWidgetState<T extends Record<string, unknown>>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
32
+ export declare function useWidgetState<T extends Record<string, unknown>>(defaultState?: T | (() => T | null) | null): readonly [T | null, (state: SetStateAction<T | null>) => void];
@@ -0,0 +1,135 @@
1
+ import { useSyncExternalStore, useCallback, useState, useEffect, } from "react";
2
+ const SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
3
+ function getOpenAiGlobal(key) {
4
+ if (!window.openai)
5
+ return undefined;
6
+ return window.openai[key];
7
+ }
8
+ function subscribeToOpenAi(callback) {
9
+ const handler = () => callback();
10
+ window.addEventListener(SET_GLOBALS_EVENT_TYPE, handler);
11
+ return () => window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handler);
12
+ }
13
+ export function useOpenAiGlobal(key) {
14
+ return useSyncExternalStore(subscribeToOpenAi, () => getOpenAiGlobal(key), () => undefined);
15
+ }
16
+ export function useTheme() {
17
+ return useOpenAiGlobal("theme") ?? "dark";
18
+ }
19
+ export function useDisplayMode() {
20
+ return useOpenAiGlobal("displayMode") ?? "inline";
21
+ }
22
+ export function useUserAgent() {
23
+ return useOpenAiGlobal("userAgent");
24
+ }
25
+ export function useMaxHeight() {
26
+ return useOpenAiGlobal("maxHeight");
27
+ }
28
+ export function useSafeArea() {
29
+ return useOpenAiGlobal("safeArea");
30
+ }
31
+ export function useLocale() {
32
+ return useOpenAiGlobal("locale") ?? "en";
33
+ }
34
+ export function useToolInput() {
35
+ return useOpenAiGlobal("toolInput");
36
+ }
37
+ export function useToolOutput() {
38
+ const output = useOpenAiGlobal("toolOutput");
39
+ return {
40
+ content: output?.content ?? [],
41
+ structuredContent: output?.structuredContent,
42
+ };
43
+ }
44
+ export function useToolResponseMetadata() {
45
+ return useOpenAiGlobal("toolResponseMetadata");
46
+ }
47
+ export function useCallTool(toolName) {
48
+ const [isPending, setIsPending] = useState(false);
49
+ const [error, setError] = useState(null);
50
+ const [data, setData] = useState(null);
51
+ const callTool = useOpenAiGlobal("callTool");
52
+ const call = useCallback(async (args) => {
53
+ if (!callTool) {
54
+ setError(new Error("callTool not available"));
55
+ return;
56
+ }
57
+ setIsPending(true);
58
+ setError(null);
59
+ try {
60
+ const result = await callTool(toolName, args);
61
+ if (result.isError) {
62
+ throw new Error(result.content?.[0]?.text ?? "Unknown error");
63
+ }
64
+ setData((result._meta?.gameState ??
65
+ result.structuredContent ??
66
+ null));
67
+ }
68
+ catch (err) {
69
+ setError(err instanceof Error ? err : new Error(String(err)));
70
+ }
71
+ finally {
72
+ setIsPending(false);
73
+ }
74
+ }, [callTool, toolName]);
75
+ return { call, isPending, error, data };
76
+ }
77
+ export function useSendFollowUp() {
78
+ const [isPending, setIsPending] = useState(false);
79
+ const [error, setError] = useState(null);
80
+ const sendFollowUpMessage = useOpenAiGlobal("sendFollowUpMessage");
81
+ const send = useCallback(async (prompt) => {
82
+ if (!sendFollowUpMessage) {
83
+ setError(new Error("sendFollowUpMessage not available"));
84
+ return;
85
+ }
86
+ setIsPending(true);
87
+ setError(null);
88
+ try {
89
+ await sendFollowUpMessage({ prompt });
90
+ }
91
+ catch (err) {
92
+ setError(err instanceof Error ? err : new Error(String(err)));
93
+ }
94
+ finally {
95
+ setIsPending(false);
96
+ }
97
+ }, [sendFollowUpMessage]);
98
+ return { send, isPending, error };
99
+ }
100
+ export function useRequestDisplayMode() {
101
+ const requestDisplayMode = useOpenAiGlobal("requestDisplayMode");
102
+ const request = useCallback(async (mode) => {
103
+ if (!requestDisplayMode) {
104
+ return;
105
+ }
106
+ await requestDisplayMode({ mode });
107
+ }, [requestDisplayMode]);
108
+ return request;
109
+ }
110
+ export function useWidgetState(defaultState) {
111
+ const widgetStateFromWindow = useOpenAiGlobal("widgetState");
112
+ const [widgetState, _setWidgetState] = useState(() => {
113
+ if (widgetStateFromWindow != null) {
114
+ return widgetStateFromWindow;
115
+ }
116
+ return typeof defaultState === "function"
117
+ ? defaultState()
118
+ : (defaultState ?? null);
119
+ });
120
+ useEffect(() => {
121
+ if (widgetStateFromWindow != null) {
122
+ _setWidgetState(widgetStateFromWindow);
123
+ }
124
+ }, [widgetStateFromWindow]);
125
+ const setWidgetState = useCallback((state) => {
126
+ _setWidgetState((prevState) => {
127
+ const newState = typeof state === "function" ? state(prevState) : state;
128
+ if (newState != null && window.openai?.setWidgetState) {
129
+ window.openai.setWidgetState(newState);
130
+ }
131
+ return newState;
132
+ });
133
+ }, []);
134
+ return [widgetState, setWidgetState];
135
+ }
@@ -0,0 +1,3 @@
1
+ export { useOpenAiGlobal, useTheme, useDisplayMode, useUserAgent, useMaxHeight, useSafeArea, useLocale, useToolInput, useToolOutput, useToolResponseMetadata, useWidgetState, useCallTool, useSendFollowUp, useRequestDisplayMode, } from "./hooks.js";
2
+ export type { Theme, DisplayMode, DeviceType, UserAgent, SafeAreaInsets, SafeArea, CallToolResponse, OpenAiGlobals, } from "./types.js";
3
+ export { ErrorBoundary } from "./ErrorBoundary.js";
@@ -0,0 +1,2 @@
1
+ export { useOpenAiGlobal, useTheme, useDisplayMode, useUserAgent, useMaxHeight, useSafeArea, useLocale, useToolInput, useToolOutput, useToolResponseMetadata, useWidgetState, useCallTool, useSendFollowUp, useRequestDisplayMode, } from "./hooks.js";
2
+ export { ErrorBoundary } from "./ErrorBoundary.js";
@@ -0,0 +1,66 @@
1
+ export type Theme = "light" | "dark";
2
+ export type DisplayMode = "inline" | "pip" | "fullscreen";
3
+ export interface DeviceType {
4
+ type: "mobile" | "tablet" | "desktop" | "unknown";
5
+ }
6
+ export interface UserAgent {
7
+ device: DeviceType;
8
+ capabilities: {
9
+ hover: boolean;
10
+ touch: boolean;
11
+ };
12
+ }
13
+ export interface SafeAreaInsets {
14
+ top: number;
15
+ bottom: number;
16
+ left: number;
17
+ right: number;
18
+ }
19
+ export interface SafeArea {
20
+ insets: SafeAreaInsets;
21
+ }
22
+ export interface CallToolResponse {
23
+ content?: Array<{
24
+ type: string;
25
+ text: string;
26
+ }>;
27
+ structuredContent?: unknown;
28
+ _meta?: Record<string, unknown>;
29
+ isError?: boolean;
30
+ }
31
+ export interface OpenAiGlobals {
32
+ theme: Theme;
33
+ displayMode: DisplayMode;
34
+ userAgent: UserAgent;
35
+ locale: string;
36
+ maxHeight: number;
37
+ safeArea: SafeArea;
38
+ toolInput: Record<string, unknown>;
39
+ toolOutput: {
40
+ content?: Array<{
41
+ type: string;
42
+ text: string;
43
+ }>;
44
+ structuredContent?: unknown;
45
+ } | null;
46
+ toolResponseMetadata: Record<string, unknown> | null;
47
+ widgetState: Record<string, unknown> | null;
48
+ callTool: (name: string, args: Record<string, unknown>) => Promise<CallToolResponse>;
49
+ sendFollowUpMessage: (args: {
50
+ prompt: string;
51
+ }) => Promise<void>;
52
+ openExternal: (payload: {
53
+ href: string;
54
+ }) => void;
55
+ requestDisplayMode: (args: {
56
+ mode: DisplayMode;
57
+ }) => Promise<{
58
+ mode: DisplayMode;
59
+ }>;
60
+ setWidgetState: (state: Record<string, unknown>) => Promise<void>;
61
+ }
62
+ declare global {
63
+ interface Window {
64
+ openai?: OpenAiGlobals;
65
+ }
66
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { Application, Request, Router } from "express";
2
+ import { type JWTPayload } from "jose";
3
+ import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
4
+ export type IdentityJwtClaims = JWTPayload & Record<string, unknown>;
5
+ export interface IdentityHandler {
6
+ /** Base path to mount metadata and token endpoints. Default: "/" */
7
+ basePath?: string;
8
+ /** Expected JWT issuer. Default: "https://server.smithery.ai" */
9
+ issuer?: string;
10
+ /** JWKS URL for issuer. Default: "https://server.smithery.ai/.well-known/jwks.json" */
11
+ jwksUrl?: string;
12
+ /** Optional explicit token path. Overrides basePath+"token". */
13
+ tokenPath?: string;
14
+ /** Handle a JWT grant provided by an external identity provider (i.e., Smithery) and mint access tokens */
15
+ handleJwtGrant: (claims: IdentityJwtClaims, req: Request) => Promise<OAuthTokens | null>;
16
+ }
17
+ export declare function createIdentityTokenRouter(options: IdentityHandler): Router;
18
+ export declare function mountIdentity(app: Application, options: IdentityHandler): void;
@@ -0,0 +1,55 @@
1
+ import express from "express";
2
+ import { createRemoteJWKSet, jwtVerify } from "jose";
3
+ function normalizeBasePath(basePath) {
4
+ const value = basePath ?? "/";
5
+ return value.endsWith("/") ? value : `${value}/`;
6
+ }
7
+ export function createIdentityTokenRouter(options) {
8
+ const basePath = normalizeBasePath(options.basePath);
9
+ const issuer = options.issuer ?? "https://server.smithery.ai";
10
+ const jwksUrl = new URL(options.jwksUrl ?? "https://server.smithery.ai/.well-known/jwks.json");
11
+ const tokenPath = typeof options.tokenPath === "string" && options.tokenPath.length > 0
12
+ ? options.tokenPath
13
+ : `${basePath}token`;
14
+ // Create JWKS resolver once; jose caches keys internally
15
+ const JWKS = createRemoteJWKSet(jwksUrl);
16
+ const tokenRouter = express.Router();
17
+ // urlencoded parser required for OAuth token requests
18
+ tokenRouter.use(express.urlencoded({ extended: false }));
19
+ tokenRouter.post(tokenPath, async (req, res, next) => {
20
+ try {
21
+ const grantType = typeof req.body?.grant_type === "string"
22
+ ? req.body.grant_type
23
+ : undefined;
24
+ if (grantType !== "urn:ietf:params:oauth:grant-type:jwt-bearer")
25
+ return next();
26
+ const assertion = typeof req.body?.assertion === "string" ? req.body.assertion : undefined;
27
+ if (!assertion) {
28
+ res.status(400).json({
29
+ error: "invalid_request",
30
+ error_description: "Missing assertion",
31
+ });
32
+ return;
33
+ }
34
+ const host = req.get("host") ?? "localhost";
35
+ const audience = `https://${host}${tokenPath}`;
36
+ const { payload } = await jwtVerify(assertion, JWKS, {
37
+ issuer,
38
+ audience,
39
+ algorithms: ["RS256"],
40
+ });
41
+ const result = await options.handleJwtGrant(payload, req);
42
+ if (!result)
43
+ return next();
44
+ res.json(result);
45
+ }
46
+ catch (error) {
47
+ console.error(error);
48
+ res.status(400).json({ error: "invalid_grant" });
49
+ }
50
+ });
51
+ return tokenRouter;
52
+ }
53
+ export function mountIdentity(app, options) {
54
+ app.use(createIdentityTokenRouter(options));
55
+ }
@@ -0,0 +1,21 @@
1
+ import type { OAuthServerProvider, OAuthTokenVerifier } from "@modelcontextprotocol/sdk/server/auth/provider.js";
2
+ import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
3
+ import type { Application, Response } from "express";
4
+ import { type IdentityHandler } from "./identity.js";
5
+ export interface TokenVerifier extends OAuthTokenVerifier {
6
+ verifyAccessToken: (token: string) => Promise<AuthInfo>;
7
+ requiredScopes?: string[];
8
+ resourceMetadataUrl?: string;
9
+ }
10
+ type ProviderVerifier = OAuthServerProvider & TokenVerifier;
11
+ export interface OAuthProvider extends ProviderVerifier {
12
+ basePath?: string;
13
+ callbackPath?: string;
14
+ handleOAuthCallback?: (code: string, state: string | undefined, res: Response) => Promise<URL>;
15
+ }
16
+ export interface OAuthMountOptions {
17
+ provider?: OAuthProvider | TokenVerifier;
18
+ identity?: IdentityHandler;
19
+ }
20
+ export declare function mountOAuth(app: Application, opts: OAuthMountOptions): void;
21
+ export {};