@leanmcp/core 0.3.12 → 0.3.13

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.js CHANGED
@@ -41,6 +41,9 @@ function Tool(options = {}) {
41
41
  if (options.inputClass) {
42
42
  Reflect.defineMetadata("tool:inputClass", options.inputClass, descriptor.value);
43
43
  }
44
+ if (options.securitySchemes) {
45
+ Reflect.defineMetadata("tool:securitySchemes", options.securitySchemes, descriptor.value);
46
+ }
44
47
  };
45
48
  }
46
49
  function Prompt(options = {}) {
@@ -551,7 +554,8 @@ async function createHTTPServer(serverInput, options) {
551
554
  logging: serverOptions.logging,
552
555
  sessionTimeout: serverOptions.sessionTimeout,
553
556
  stateless: serverOptions.stateless,
554
- dashboard: serverOptions.dashboard
557
+ dashboard: serverOptions.dashboard,
558
+ auth: serverOptions.auth
555
559
  };
556
560
  }
557
561
  const [express, { StreamableHTTPServerTransport }, cors] = await Promise.all([
@@ -713,6 +717,73 @@ async function createHTTPServer(serverInput, options) {
713
717
  uptime: process.uptime()
714
718
  });
715
719
  });
720
+ app.get("/.well-known/oauth-protected-resource", (req, res) => {
721
+ const host = req.headers.host || "localhost";
722
+ const protocol = req.headers["x-forwarded-proto"] || "http";
723
+ const resource = httpOptions.auth?.resource || `${protocol}://${host}`;
724
+ const authServers = httpOptions.auth?.authorizationServers || [
725
+ resource
726
+ ];
727
+ res.json({
728
+ resource,
729
+ authorization_servers: authServers,
730
+ scopes_supported: httpOptions.auth?.scopesSupported || [],
731
+ resource_documentation: httpOptions.auth?.documentationUrl
732
+ });
733
+ });
734
+ if (httpOptions.auth?.enableOAuthServer && httpOptions.auth?.oauthServerOptions) {
735
+ const authOpts = httpOptions.auth.oauthServerOptions;
736
+ app.get("/.well-known/oauth-authorization-server", (req, res) => {
737
+ const host = req.headers.host || "localhost";
738
+ const protocol = req.headers["x-forwarded-proto"] || "http";
739
+ const issuer = httpOptions.auth?.resource || `${protocol}://${host}`;
740
+ res.json({
741
+ issuer,
742
+ authorization_endpoint: `${issuer}/oauth/authorize`,
743
+ token_endpoint: `${issuer}/oauth/token`,
744
+ registration_endpoint: `${issuer}/oauth/register`,
745
+ scopes_supported: httpOptions.auth?.scopesSupported || [],
746
+ response_types_supported: [
747
+ "code"
748
+ ],
749
+ grant_types_supported: [
750
+ "authorization_code",
751
+ "refresh_token"
752
+ ],
753
+ code_challenge_methods_supported: [
754
+ "S256"
755
+ ],
756
+ token_endpoint_auth_methods_supported: [
757
+ "client_secret_post",
758
+ "client_secret_basic",
759
+ "none"
760
+ ]
761
+ });
762
+ });
763
+ (async () => {
764
+ try {
765
+ const authServerModule = await import(
766
+ /* webpackIgnore: true */
767
+ "@leanmcp/auth/server"
768
+ );
769
+ const { OAuthAuthorizationServer } = authServerModule;
770
+ const authServer = new OAuthAuthorizationServer({
771
+ issuer: httpOptions.auth?.resource || `http://localhost:${basePort}`,
772
+ sessionSecret: authOpts.sessionSecret,
773
+ jwtSigningSecret: authOpts.jwtSigningSecret,
774
+ jwtEncryptionSecret: authOpts.jwtEncryptionSecret,
775
+ tokenTTL: authOpts.tokenTTL,
776
+ upstreamProvider: authOpts.upstreamProvider,
777
+ scopesSupported: httpOptions.auth?.scopesSupported,
778
+ enableDCR: true
779
+ });
780
+ app.use(authServer.getRouter());
781
+ logger.info("OAuth authorization server mounted");
782
+ } catch (e) {
783
+ logger.warn("OAuth server requested but @leanmcp/auth/server not available");
784
+ }
785
+ })();
786
+ }
716
787
  const handleMCPRequestStateful = /* @__PURE__ */ __name(async (req, res) => {
717
788
  const sessionId = req.headers["mcp-session-id"];
718
789
  let transport;
@@ -728,6 +799,17 @@ async function createHTTPServer(serverInput, options) {
728
799
  logMessage += ` (session: ${sessionId.substring(0, 8)}...)`;
729
800
  }
730
801
  logger.info(logMessage);
802
+ logger.info(logMessage);
803
+ if (req.headers.authorization) {
804
+ if (!req.body.params) req.body.params = {};
805
+ if (!req.body.params._meta) req.body.params._meta = {};
806
+ const authHeader = req.headers.authorization;
807
+ if (authHeader.startsWith("Bearer ")) {
808
+ req.body.params._meta.authToken = authHeader.substring(7);
809
+ } else {
810
+ req.body.params._meta.authToken = authHeader;
811
+ }
812
+ }
731
813
  try {
732
814
  if (sessionId && transports[sessionId]) {
733
815
  transport = transports[sessionId];
@@ -784,7 +866,18 @@ async function createHTTPServer(serverInput, options) {
784
866
  if (params?.name) logMessage += ` [${params.name}]`;
785
867
  else if (params?.uri) logMessage += ` [${params.uri}]`;
786
868
  logger.info(logMessage);
869
+ logger.info(logMessage);
787
870
  try {
871
+ if (req.headers.authorization) {
872
+ if (!req.body.params) req.body.params = {};
873
+ if (!req.body.params._meta) req.body.params._meta = {};
874
+ const authHeader = req.headers.authorization;
875
+ if (authHeader.startsWith("Bearer ")) {
876
+ req.body.params._meta.authToken = authHeader.substring(7);
877
+ } else {
878
+ req.body.params._meta.authToken = authHeader;
879
+ }
880
+ }
788
881
  const freshServer = await statelessServerFactory();
789
882
  if (freshServer && typeof freshServer.waitForInit === "function") {
790
883
  await freshServer.waitForInit();
@@ -941,6 +1034,56 @@ var init_http_server = __esm({
941
1034
  }
942
1035
  });
943
1036
 
1037
+ // src/auth-helpers.ts
1038
+ function createAuthError(message, options) {
1039
+ const error = options.error || "invalid_token";
1040
+ const errorDescription = options.errorDescription || message;
1041
+ const wwwAuth = `Bearer resource_metadata="${options.resourceMetadataUrl}", error="${error}", error_description="${errorDescription}"`;
1042
+ return {
1043
+ content: [
1044
+ {
1045
+ type: "text",
1046
+ text: message
1047
+ }
1048
+ ],
1049
+ _meta: {
1050
+ "mcp/www_authenticate": [
1051
+ wwwAuth
1052
+ ]
1053
+ },
1054
+ isError: true
1055
+ };
1056
+ }
1057
+ function isAuthError(result) {
1058
+ if (!result || typeof result !== "object") return false;
1059
+ const r = result;
1060
+ return r.isError === true && r._meta !== void 0 && typeof r._meta === "object" && r._meta !== null && "mcp/www_authenticate" in r._meta;
1061
+ }
1062
+ function extractBearerToken(authHeader) {
1063
+ if (!authHeader) return null;
1064
+ if (!authHeader.startsWith("Bearer ")) return null;
1065
+ return authHeader.slice(7);
1066
+ }
1067
+ function createProtectedResourceMetadata(options) {
1068
+ return {
1069
+ resource: options.resource,
1070
+ authorization_servers: options.authorizationServers || [
1071
+ options.resource
1072
+ ],
1073
+ scopes_supported: options.scopesSupported,
1074
+ resource_documentation: options.documentationUrl
1075
+ };
1076
+ }
1077
+ var init_auth_helpers = __esm({
1078
+ "src/auth-helpers.ts"() {
1079
+ "use strict";
1080
+ __name(createAuthError, "createAuthError");
1081
+ __name(isAuthError, "isAuthError");
1082
+ __name(extractBearerToken, "extractBearerToken");
1083
+ __name(createProtectedResourceMetadata, "createProtectedResourceMetadata");
1084
+ }
1085
+ });
1086
+
944
1087
  // src/index.ts
945
1088
  var index_exports = {};
946
1089
  __export(index_exports, {
@@ -960,10 +1103,14 @@ __export(index_exports, {
960
1103
  UserEnvs: () => UserEnvs,
961
1104
  classToJsonSchema: () => classToJsonSchema,
962
1105
  classToJsonSchemaWithConstraints: () => classToJsonSchemaWithConstraints,
1106
+ createAuthError: () => createAuthError,
963
1107
  createHTTPServer: () => createHTTPServer,
1108
+ createProtectedResourceMetadata: () => createProtectedResourceMetadata,
964
1109
  defaultLogger: () => defaultLogger,
1110
+ extractBearerToken: () => extractBearerToken,
965
1111
  getDecoratedMethods: () => getDecoratedMethods,
966
1112
  getMethodMetadata: () => getMethodMetadata,
1113
+ isAuthError: () => isAuthError,
967
1114
  startMCPServer: () => startMCPServer,
968
1115
  validateNonEmpty: () => validateNonEmpty,
969
1116
  validatePath: () => validatePath,
@@ -993,6 +1140,7 @@ var init_index = __esm({
993
1140
  init_http_server();
994
1141
  init_logger();
995
1142
  init_validation();
1143
+ init_auth_helpers();
996
1144
  init_decorators();
997
1145
  init_schema_generator();
998
1146
  init_logger();
@@ -2010,10 +2158,14 @@ init_index();
2010
2158
  UserEnvs,
2011
2159
  classToJsonSchema,
2012
2160
  classToJsonSchemaWithConstraints,
2161
+ createAuthError,
2013
2162
  createHTTPServer,
2163
+ createProtectedResourceMetadata,
2014
2164
  defaultLogger,
2165
+ extractBearerToken,
2015
2166
  getDecoratedMethods,
2016
2167
  getMethodMetadata,
2168
+ isAuthError,
2017
2169
  startMCPServer,
2018
2170
  validateNonEmpty,
2019
2171
  validatePath,
package/dist/index.mjs CHANGED
@@ -22,6 +22,9 @@ function Tool(options = {}) {
22
22
  if (options.inputClass) {
23
23
  Reflect.defineMetadata("tool:inputClass", options.inputClass, descriptor.value);
24
24
  }
25
+ if (options.securitySchemes) {
26
+ Reflect.defineMetadata("tool:securitySchemes", options.securitySchemes, descriptor.value);
27
+ }
25
28
  };
26
29
  }
27
30
  __name(Tool, "Tool");
@@ -513,7 +516,8 @@ async function createHTTPServer(serverInput, options) {
513
516
  logging: serverOptions.logging,
514
517
  sessionTimeout: serverOptions.sessionTimeout,
515
518
  stateless: serverOptions.stateless,
516
- dashboard: serverOptions.dashboard
519
+ dashboard: serverOptions.dashboard,
520
+ auth: serverOptions.auth
517
521
  };
518
522
  }
519
523
  const [express, { StreamableHTTPServerTransport }, cors] = await Promise.all([
@@ -675,6 +679,73 @@ async function createHTTPServer(serverInput, options) {
675
679
  uptime: process.uptime()
676
680
  });
677
681
  });
682
+ app.get("/.well-known/oauth-protected-resource", (req, res) => {
683
+ const host = req.headers.host || "localhost";
684
+ const protocol = req.headers["x-forwarded-proto"] || "http";
685
+ const resource = httpOptions.auth?.resource || `${protocol}://${host}`;
686
+ const authServers = httpOptions.auth?.authorizationServers || [
687
+ resource
688
+ ];
689
+ res.json({
690
+ resource,
691
+ authorization_servers: authServers,
692
+ scopes_supported: httpOptions.auth?.scopesSupported || [],
693
+ resource_documentation: httpOptions.auth?.documentationUrl
694
+ });
695
+ });
696
+ if (httpOptions.auth?.enableOAuthServer && httpOptions.auth?.oauthServerOptions) {
697
+ const authOpts = httpOptions.auth.oauthServerOptions;
698
+ app.get("/.well-known/oauth-authorization-server", (req, res) => {
699
+ const host = req.headers.host || "localhost";
700
+ const protocol = req.headers["x-forwarded-proto"] || "http";
701
+ const issuer = httpOptions.auth?.resource || `${protocol}://${host}`;
702
+ res.json({
703
+ issuer,
704
+ authorization_endpoint: `${issuer}/oauth/authorize`,
705
+ token_endpoint: `${issuer}/oauth/token`,
706
+ registration_endpoint: `${issuer}/oauth/register`,
707
+ scopes_supported: httpOptions.auth?.scopesSupported || [],
708
+ response_types_supported: [
709
+ "code"
710
+ ],
711
+ grant_types_supported: [
712
+ "authorization_code",
713
+ "refresh_token"
714
+ ],
715
+ code_challenge_methods_supported: [
716
+ "S256"
717
+ ],
718
+ token_endpoint_auth_methods_supported: [
719
+ "client_secret_post",
720
+ "client_secret_basic",
721
+ "none"
722
+ ]
723
+ });
724
+ });
725
+ (async () => {
726
+ try {
727
+ const authServerModule = await import(
728
+ /* webpackIgnore: true */
729
+ "@leanmcp/auth/server"
730
+ );
731
+ const { OAuthAuthorizationServer } = authServerModule;
732
+ const authServer = new OAuthAuthorizationServer({
733
+ issuer: httpOptions.auth?.resource || `http://localhost:${basePort}`,
734
+ sessionSecret: authOpts.sessionSecret,
735
+ jwtSigningSecret: authOpts.jwtSigningSecret,
736
+ jwtEncryptionSecret: authOpts.jwtEncryptionSecret,
737
+ tokenTTL: authOpts.tokenTTL,
738
+ upstreamProvider: authOpts.upstreamProvider,
739
+ scopesSupported: httpOptions.auth?.scopesSupported,
740
+ enableDCR: true
741
+ });
742
+ app.use(authServer.getRouter());
743
+ logger.info("OAuth authorization server mounted");
744
+ } catch (e) {
745
+ logger.warn("OAuth server requested but @leanmcp/auth/server not available");
746
+ }
747
+ })();
748
+ }
678
749
  const handleMCPRequestStateful = /* @__PURE__ */ __name(async (req, res) => {
679
750
  const sessionId = req.headers["mcp-session-id"];
680
751
  let transport;
@@ -690,6 +761,17 @@ async function createHTTPServer(serverInput, options) {
690
761
  logMessage += ` (session: ${sessionId.substring(0, 8)}...)`;
691
762
  }
692
763
  logger.info(logMessage);
764
+ logger.info(logMessage);
765
+ if (req.headers.authorization) {
766
+ if (!req.body.params) req.body.params = {};
767
+ if (!req.body.params._meta) req.body.params._meta = {};
768
+ const authHeader = req.headers.authorization;
769
+ if (authHeader.startsWith("Bearer ")) {
770
+ req.body.params._meta.authToken = authHeader.substring(7);
771
+ } else {
772
+ req.body.params._meta.authToken = authHeader;
773
+ }
774
+ }
693
775
  try {
694
776
  if (sessionId && transports[sessionId]) {
695
777
  transport = transports[sessionId];
@@ -746,7 +828,18 @@ async function createHTTPServer(serverInput, options) {
746
828
  if (params?.name) logMessage += ` [${params.name}]`;
747
829
  else if (params?.uri) logMessage += ` [${params.uri}]`;
748
830
  logger.info(logMessage);
831
+ logger.info(logMessage);
749
832
  try {
833
+ if (req.headers.authorization) {
834
+ if (!req.body.params) req.body.params = {};
835
+ if (!req.body.params._meta) req.body.params._meta = {};
836
+ const authHeader = req.headers.authorization;
837
+ if (authHeader.startsWith("Bearer ")) {
838
+ req.body.params._meta.authToken = authHeader.substring(7);
839
+ } else {
840
+ req.body.params._meta.authToken = authHeader;
841
+ }
842
+ }
750
843
  const freshServer = await statelessServerFactory();
751
844
  if (freshServer && typeof freshServer.waitForInit === "function") {
752
845
  await freshServer.waitForInit();
@@ -892,6 +985,51 @@ async function createHTTPServer(serverInput, options) {
892
985
  }
893
986
  __name(createHTTPServer, "createHTTPServer");
894
987
 
988
+ // src/auth-helpers.ts
989
+ function createAuthError(message, options) {
990
+ const error = options.error || "invalid_token";
991
+ const errorDescription = options.errorDescription || message;
992
+ const wwwAuth = `Bearer resource_metadata="${options.resourceMetadataUrl}", error="${error}", error_description="${errorDescription}"`;
993
+ return {
994
+ content: [
995
+ {
996
+ type: "text",
997
+ text: message
998
+ }
999
+ ],
1000
+ _meta: {
1001
+ "mcp/www_authenticate": [
1002
+ wwwAuth
1003
+ ]
1004
+ },
1005
+ isError: true
1006
+ };
1007
+ }
1008
+ __name(createAuthError, "createAuthError");
1009
+ function isAuthError(result) {
1010
+ if (!result || typeof result !== "object") return false;
1011
+ const r = result;
1012
+ return r.isError === true && r._meta !== void 0 && typeof r._meta === "object" && r._meta !== null && "mcp/www_authenticate" in r._meta;
1013
+ }
1014
+ __name(isAuthError, "isAuthError");
1015
+ function extractBearerToken(authHeader) {
1016
+ if (!authHeader) return null;
1017
+ if (!authHeader.startsWith("Bearer ")) return null;
1018
+ return authHeader.slice(7);
1019
+ }
1020
+ __name(extractBearerToken, "extractBearerToken");
1021
+ function createProtectedResourceMetadata(options) {
1022
+ return {
1023
+ resource: options.resource,
1024
+ authorization_servers: options.authorizationServers || [
1025
+ options.resource
1026
+ ],
1027
+ scopes_supported: options.scopesSupported,
1028
+ resource_documentation: options.documentationUrl
1029
+ };
1030
+ }
1031
+ __name(createProtectedResourceMetadata, "createProtectedResourceMetadata");
1032
+
895
1033
  // src/index.ts
896
1034
  var ajv = new Ajv();
897
1035
  var MCPServer = class {
@@ -1908,10 +2046,14 @@ export {
1908
2046
  UserEnvs,
1909
2047
  classToJsonSchema,
1910
2048
  classToJsonSchemaWithConstraints,
2049
+ createAuthError,
1911
2050
  createHTTPServer,
2051
+ createProtectedResourceMetadata,
1912
2052
  defaultLogger,
2053
+ extractBearerToken,
1913
2054
  getDecoratedMethods,
1914
2055
  getMethodMetadata,
2056
+ isAuthError,
1915
2057
  startMCPServer,
1916
2058
  validateNonEmpty,
1917
2059
  validatePath,