@smithery/sdk 1.6.1 → 1.6.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.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/server/auth/identity.d.ts +18 -0
- package/dist/server/auth/identity.js +55 -0
- package/dist/server/auth/oauth.d.ts +13 -0
- package/dist/server/auth/oauth.js +141 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/stateful.d.ts +0 -5
- package/dist/server/stateful.js +0 -6
- package/dist/server/stateless.d.ts +2 -5
- package/dist/server/stateless.js +0 -6
- package/package.json +3 -1
- package/dist/server/oauth.d.ts +0 -14
- package/dist/server/oauth.js +0 -36
package/dist/index.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ export * from "./shared/config.js";
|
|
|
2
2
|
export * from "./shared/patch.js";
|
|
3
3
|
export { createStatefulServer, type StatefulServerOptions, } from "./server/stateful.js";
|
|
4
4
|
export * from "./server/session.js";
|
|
5
|
+
export * from "./server/auth/identity.js";
|
|
6
|
+
export * from "./server/auth/oauth.js";
|
package/dist/index.js
CHANGED
|
@@ -7,3 +7,5 @@ export * from "./shared/patch.js";
|
|
|
7
7
|
// Server-side helpers (selective to avoid duplicate type names)
|
|
8
8
|
export { createStatefulServer, } from "./server/stateful.js";
|
|
9
9
|
export * from "./server/session.js";
|
|
10
|
+
export * from "./server/auth/identity.js";
|
|
11
|
+
export * from "./server/auth/oauth.js";
|
|
@@ -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 = `${req.protocol}://${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,13 @@
|
|
|
1
|
+
import type { OAuthServerProvider, OAuthTokenVerifier } from "@modelcontextprotocol/sdk/server/auth/provider.js";
|
|
2
|
+
import type { Application, Response } from "express";
|
|
3
|
+
import { type IdentityHandler } from "./identity.js";
|
|
4
|
+
export interface CallbackOAuthServerProvider extends OAuthServerProvider {
|
|
5
|
+
basePath?: string;
|
|
6
|
+
callbackPath?: string;
|
|
7
|
+
handleOAuthCallback?: (code: string, state: string | undefined, res: Response) => Promise<URL>;
|
|
8
|
+
}
|
|
9
|
+
export interface OAuthMountOptions {
|
|
10
|
+
provider?: CallbackOAuthServerProvider | OAuthTokenVerifier;
|
|
11
|
+
identity?: IdentityHandler;
|
|
12
|
+
}
|
|
13
|
+
export declare function mountOAuth(app: Application, opts: OAuthMountOptions): void;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
|
|
2
|
+
import { mcpAuthMetadataRouter, createOAuthMetadata, } from "@modelcontextprotocol/sdk/server/auth/router.js";
|
|
3
|
+
import { authorizationHandler } from "@modelcontextprotocol/sdk/server/auth/handlers/authorize.js";
|
|
4
|
+
import { tokenHandler } from "@modelcontextprotocol/sdk/server/auth/handlers/token.js";
|
|
5
|
+
import { clientRegistrationHandler } from "@modelcontextprotocol/sdk/server/auth/handlers/register.js";
|
|
6
|
+
import { revocationHandler } from "@modelcontextprotocol/sdk/server/auth/handlers/revoke.js";
|
|
7
|
+
import { metadataHandler } from "@modelcontextprotocol/sdk/server/auth/handlers/metadata.js";
|
|
8
|
+
import { mountIdentity } from "./identity.js";
|
|
9
|
+
function isOAuthProvider(provider) {
|
|
10
|
+
return !!provider && "authorize" in provider;
|
|
11
|
+
}
|
|
12
|
+
export function mountOAuth(app, opts) {
|
|
13
|
+
// Determine base path once based on OAuth provider or identity
|
|
14
|
+
const provider = opts.provider;
|
|
15
|
+
const hasOAuth = isOAuthProvider(provider);
|
|
16
|
+
const rawBasePath = hasOAuth
|
|
17
|
+
? (provider.basePath ?? "/")
|
|
18
|
+
: (opts.identity?.basePath ?? "/");
|
|
19
|
+
const basePath = rawBasePath.endsWith("/") ? rawBasePath : `${rawBasePath}/`;
|
|
20
|
+
// Precompute endpoint pathnames from metadata
|
|
21
|
+
let authorizationPath;
|
|
22
|
+
let tokenPath;
|
|
23
|
+
let registrationPath;
|
|
24
|
+
let revocationPath;
|
|
25
|
+
if (isOAuthProvider(provider)) {
|
|
26
|
+
const placeholderIssuer = new URL("https://localhost");
|
|
27
|
+
const placeholderBaseUrl = new URL(basePath, placeholderIssuer);
|
|
28
|
+
const localMetadata = createOAuthMetadata({
|
|
29
|
+
provider,
|
|
30
|
+
issuerUrl: placeholderIssuer,
|
|
31
|
+
baseUrl: placeholderBaseUrl,
|
|
32
|
+
});
|
|
33
|
+
authorizationPath = new URL(localMetadata.authorization_endpoint).pathname;
|
|
34
|
+
tokenPath = new URL(localMetadata.token_endpoint).pathname;
|
|
35
|
+
if (localMetadata.registration_endpoint) {
|
|
36
|
+
registrationPath = new URL(localMetadata.registration_endpoint).pathname;
|
|
37
|
+
}
|
|
38
|
+
if (localMetadata.revocation_endpoint) {
|
|
39
|
+
revocationPath = new URL(localMetadata.revocation_endpoint).pathname;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Metadata endpoints
|
|
43
|
+
if (isOAuthProvider(provider)) {
|
|
44
|
+
// Mount a per-request adapter so issuer/baseUrl reflect Host/Proto
|
|
45
|
+
app.use((req, res, next) => {
|
|
46
|
+
if (!req.path.startsWith("/.well-known/"))
|
|
47
|
+
return next();
|
|
48
|
+
const host = req.get("host") ?? "localhost";
|
|
49
|
+
if (req.protocol !== "https") {
|
|
50
|
+
console.warn("Detected http but using https for issuer URL in OAuth metadata since it will fail otherwise.");
|
|
51
|
+
}
|
|
52
|
+
const issuerUrl = new URL(`https://${host}`);
|
|
53
|
+
const baseUrl = new URL(basePath, issuerUrl);
|
|
54
|
+
const oauthMetadata = createOAuthMetadata({
|
|
55
|
+
provider,
|
|
56
|
+
issuerUrl,
|
|
57
|
+
baseUrl,
|
|
58
|
+
});
|
|
59
|
+
if (opts.identity) {
|
|
60
|
+
oauthMetadata.grant_types_supported = Array.from(new Set([
|
|
61
|
+
...(oauthMetadata.grant_types_supported ?? []),
|
|
62
|
+
"urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
63
|
+
]));
|
|
64
|
+
}
|
|
65
|
+
const resourceServerUrl = new URL("/mcp", issuerUrl);
|
|
66
|
+
const metadataRouter = mcpAuthMetadataRouter({
|
|
67
|
+
oauthMetadata,
|
|
68
|
+
resourceServerUrl,
|
|
69
|
+
});
|
|
70
|
+
return metadataRouter(req, res, next);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
else if (opts.identity) {
|
|
74
|
+
// Identity-only: explicitly mount protected resource metadata endpoint
|
|
75
|
+
app.use("/.well-known/oauth-protected-resource", (req, res, next) => {
|
|
76
|
+
const host = req.get("host") ?? "localhost";
|
|
77
|
+
const issuerUrl = new URL(`${req.protocol}://${host}`);
|
|
78
|
+
const protectedResourceMetadata = {
|
|
79
|
+
resource: new URL("/mcp", issuerUrl).href,
|
|
80
|
+
};
|
|
81
|
+
return metadataHandler(protectedResourceMetadata)(req, res, next);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// Mount identity (JWT bearer grant) first so OAuth token can fall through
|
|
85
|
+
if (opts.identity) {
|
|
86
|
+
const identityOptions = {
|
|
87
|
+
...opts.identity,
|
|
88
|
+
basePath,
|
|
89
|
+
tokenPath: tokenPath ?? `${basePath}token`,
|
|
90
|
+
};
|
|
91
|
+
mountIdentity(app, identityOptions);
|
|
92
|
+
}
|
|
93
|
+
// Mount OAuth endpoints functionally if an OAuth provider is present
|
|
94
|
+
if (isOAuthProvider(provider)) {
|
|
95
|
+
// Authorization endpoint
|
|
96
|
+
const authPath = authorizationPath ?? `${basePath}authorize`;
|
|
97
|
+
app.use(authPath, authorizationHandler({ provider }));
|
|
98
|
+
// Token endpoint (OAuth); identity's token handler will handle JWT grant and call next() otherwise
|
|
99
|
+
const tokPath = tokenPath ?? `${basePath}token`;
|
|
100
|
+
app.use(tokPath, tokenHandler({ provider }));
|
|
101
|
+
// Dynamic client registration if supported
|
|
102
|
+
if (provider.clientsStore?.registerClient) {
|
|
103
|
+
const regPath = registrationPath ?? `${basePath}register`;
|
|
104
|
+
app.use(regPath, clientRegistrationHandler({ clientsStore: provider.clientsStore }));
|
|
105
|
+
}
|
|
106
|
+
// Token revocation if supported
|
|
107
|
+
if (provider.revokeToken) {
|
|
108
|
+
const revPath = revocationPath ?? `${basePath}revoke`;
|
|
109
|
+
app.use(revPath, revocationHandler({ provider }));
|
|
110
|
+
}
|
|
111
|
+
// Optional OAuth callback
|
|
112
|
+
const callbackHandler = provider.handleOAuthCallback?.bind(provider);
|
|
113
|
+
if (callbackHandler) {
|
|
114
|
+
const callbackPath = provider.callbackPath ?? "/callback";
|
|
115
|
+
app.get(callbackPath, async (req, res) => {
|
|
116
|
+
const code = typeof req.query.code === "string" ? req.query.code : undefined;
|
|
117
|
+
const state = typeof req.query.state === "string" ? req.query.state : undefined;
|
|
118
|
+
if (!code) {
|
|
119
|
+
res.status(400).send("Invalid request parameters");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const redirectUrl = await callbackHandler(code, state, res);
|
|
124
|
+
res.redirect(redirectUrl.toString());
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error(error);
|
|
128
|
+
res.status(500).send("Error during authentication callback");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Protect MCP resource with bearer auth if a verifier/provider is present
|
|
134
|
+
if (provider) {
|
|
135
|
+
app.use("/mcp", (req, res, next) => {
|
|
136
|
+
return requireBearerAuth({
|
|
137
|
+
verifier: provider,
|
|
138
|
+
})(req, res, next);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
package/dist/server/index.d.ts
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -4,7 +4,6 @@ import express from "express";
|
|
|
4
4
|
import type { z } from "zod";
|
|
5
5
|
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { type SessionStore } from "./session.js";
|
|
7
|
-
import type { CallbackOAuthServerProvider } from "./oauth.js";
|
|
8
7
|
/**
|
|
9
8
|
* Arguments when we create a new instance of your server
|
|
10
9
|
*/
|
|
@@ -30,10 +29,6 @@ export interface StatefulServerOptions<T = Record<string, unknown>> {
|
|
|
30
29
|
* Express app instance to use (optional)
|
|
31
30
|
*/
|
|
32
31
|
app?: express.Application;
|
|
33
|
-
/**
|
|
34
|
-
* OAuth provider instance. If provided, OAuth routes and bearer protection are auto-wired.
|
|
35
|
-
*/
|
|
36
|
-
oauthProvider?: CallbackOAuthServerProvider;
|
|
37
32
|
}
|
|
38
33
|
/**
|
|
39
34
|
* Creates a stateful server for handling MCP requests.
|
package/dist/server/stateful.js
CHANGED
|
@@ -5,7 +5,6 @@ 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";
|
|
9
8
|
/**
|
|
10
9
|
* Creates a stateful server for handling MCP requests.
|
|
11
10
|
* For every new session, we invoke createMcpServer to create a new instance of the server.
|
|
@@ -15,11 +14,6 @@ import { mountOAuth } from "./oauth.js";
|
|
|
15
14
|
*/
|
|
16
15
|
export function createStatefulServer(createMcpServer, options) {
|
|
17
16
|
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
|
-
}
|
|
23
17
|
app.use("/mcp", express.json());
|
|
24
18
|
const sessionStore = options?.sessionStore ?? createLRUStore();
|
|
25
19
|
// Handle POST requests for client-to-server communication
|
|
@@ -2,7 +2,7 @@ import express from "express";
|
|
|
2
2
|
import type { z } from "zod";
|
|
3
3
|
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
4
|
import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { OAuthMountOptions } from "./auth/oauth.js";
|
|
6
6
|
/**
|
|
7
7
|
* Arguments when we create a stateless server instance
|
|
8
8
|
*/
|
|
@@ -23,10 +23,7 @@ export interface StatelessServerOptions<T = Record<string, unknown>> {
|
|
|
23
23
|
* Express app instance to use (optional)
|
|
24
24
|
*/
|
|
25
25
|
app?: express.Application;
|
|
26
|
-
|
|
27
|
-
* OAuth provider instance. If provided, OAuth routes and bearer protection are auto-wired.
|
|
28
|
-
*/
|
|
29
|
-
oauthProvider?: CallbackOAuthServerProvider;
|
|
26
|
+
oauth?: OAuthMountOptions;
|
|
30
27
|
}
|
|
31
28
|
/**
|
|
32
29
|
* Creates a stateless server for handling MCP requests.
|
package/dist/server/stateless.js
CHANGED
|
@@ -2,7 +2,6 @@ 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";
|
|
6
5
|
/**
|
|
7
6
|
* Creates a stateless server for handling MCP requests.
|
|
8
7
|
* Each request creates a new server instance - no session state is maintained.
|
|
@@ -14,11 +13,6 @@ import { mountOAuth } from "./oauth.js";
|
|
|
14
13
|
*/
|
|
15
14
|
export function createStatelessServer(createMcpServer, options) {
|
|
16
15
|
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
|
-
}
|
|
22
16
|
app.use("/mcp", express.json());
|
|
23
17
|
// Handle POST requests for client-to-server communication
|
|
24
18
|
app.post("/mcp", async (req, res) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smithery/sdk",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "SDK to develop with Smithery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
"watch": "tsc --watch",
|
|
19
19
|
"check": "npx @biomejs/biome check --write --unsafe"
|
|
20
20
|
},
|
|
21
|
+
"packageManager": "npm@11.4.1",
|
|
21
22
|
"license": "MIT",
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@modelcontextprotocol/sdk": "^1.18.0",
|
|
24
25
|
"express": "^5.1.0",
|
|
26
|
+
"jose": "^6.1.0",
|
|
25
27
|
"json-schema": "^0.4.0",
|
|
26
28
|
"lodash": "^4.17.21",
|
|
27
29
|
"okay-error": "^1.0.3",
|
package/dist/server/oauth.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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;
|
package/dist/server/oauth.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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
|
-
}
|