@prmichaelsen/mcp-auth 0.1.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/auth/base-provider.js +173 -0
  4. package/dist/auth/base-provider.js.map +7 -0
  5. package/dist/auth/index.js +11 -0
  6. package/dist/auth/index.js.map +7 -0
  7. package/dist/auth/providers/env-provider.js +71 -0
  8. package/dist/auth/providers/env-provider.js.map +7 -0
  9. package/dist/auth/providers/index.js +11 -0
  10. package/dist/auth/providers/index.js.map +7 -0
  11. package/dist/auth/providers/simple-resolver.js +185 -0
  12. package/dist/auth/providers/simple-resolver.js.map +7 -0
  13. package/dist/auth/types.js +1 -0
  14. package/dist/auth/types.js.map +7 -0
  15. package/dist/index.js +111 -0
  16. package/dist/index.js.map +7 -0
  17. package/dist/server/config.js +1 -0
  18. package/dist/server/config.js.map +7 -0
  19. package/dist/server/decorators.js +149 -0
  20. package/dist/server/decorators.js.map +7 -0
  21. package/dist/server/index.js +25 -0
  22. package/dist/server/index.js.map +7 -0
  23. package/dist/server/mcp-server.js +269 -0
  24. package/dist/server/mcp-server.js.map +7 -0
  25. package/dist/server/tool.js +66 -0
  26. package/dist/server/tool.js.map +7 -0
  27. package/dist/types.js +1 -0
  28. package/dist/types.js.map +7 -0
  29. package/dist/utils/errors.js +143 -0
  30. package/dist/utils/errors.js.map +7 -0
  31. package/dist/utils/index.js +81 -0
  32. package/dist/utils/index.js.map +7 -0
  33. package/dist/utils/logger.js +200 -0
  34. package/dist/utils/logger.js.map +7 -0
  35. package/dist/utils/validation.js +172 -0
  36. package/dist/utils/validation.js.map +7 -0
  37. package/dist/wrapper/config.js +1 -0
  38. package/dist/wrapper/config.js.map +7 -0
  39. package/dist/wrapper/index.js +10 -0
  40. package/dist/wrapper/index.js.map +7 -0
  41. package/dist/wrapper/server-wrapper.js +427 -0
  42. package/dist/wrapper/server-wrapper.js.map +7 -0
  43. package/package.json +93 -0
@@ -0,0 +1,185 @@
1
+ import { TokenResolutionError } from "../../utils/errors.js";
2
+ import { createLogger } from "../../utils/logger.js";
3
+ import { validateAccessToken } from "../../utils/validation.js";
4
+ class SimpleTokenResolver {
5
+ config;
6
+ logger;
7
+ tokenCache;
8
+ constructor(config = {}) {
9
+ this.config = {
10
+ tokenEnvVar: config.tokenEnvVar ?? "ACCESS_TOKEN",
11
+ resourceTokenEnvVars: config.resourceTokenEnvVars ?? {},
12
+ throwOnMissing: config.throwOnMissing ?? true,
13
+ validateToken: config.validateToken ?? true,
14
+ cacheTokens: config.cacheTokens ?? true,
15
+ cacheTtl: config.cacheTtl ?? 3e5,
16
+ // 5 minutes
17
+ autoRefresh: config.autoRefresh ?? false
18
+ };
19
+ this.logger = createLogger({ enabled: true, level: "info" });
20
+ this.tokenCache = /* @__PURE__ */ new Map();
21
+ }
22
+ /**
23
+ * Resolve access token for a user and resource type
24
+ */
25
+ async resolveToken(userId, resourceType) {
26
+ if (this.config.cacheTokens) {
27
+ const cacheKey = `${userId}:${resourceType}`;
28
+ const cached = this.tokenCache.get(cacheKey);
29
+ if (cached && cached.expiresAt > Date.now()) {
30
+ this.logger.debug("Token retrieved from cache", {
31
+ userId,
32
+ resourceType,
33
+ cacheKey
34
+ });
35
+ return cached.token;
36
+ }
37
+ }
38
+ const envVar = this.config.resourceTokenEnvVars[resourceType] || `${resourceType.toUpperCase()}_ACCESS_TOKEN`;
39
+ const token = process.env[envVar];
40
+ if (!token) {
41
+ const errorMessage = `Token not found in environment variable: ${envVar}`;
42
+ this.logger.warn("Token resolution failed", {
43
+ userId,
44
+ resourceType,
45
+ envVar
46
+ });
47
+ if (this.config.throwOnMissing) {
48
+ throw new TokenResolutionError(userId, resourceType, {
49
+ envVar,
50
+ reason: "Environment variable not set"
51
+ });
52
+ }
53
+ return null;
54
+ }
55
+ if (this.config.validateToken) {
56
+ try {
57
+ validateAccessToken(token);
58
+ } catch (error) {
59
+ this.logger.error("Token validation failed", error, {
60
+ userId,
61
+ resourceType,
62
+ envVar
63
+ });
64
+ if (this.config.throwOnMissing) {
65
+ throw new TokenResolutionError(userId, resourceType, {
66
+ envVar,
67
+ reason: "Invalid token format"
68
+ });
69
+ }
70
+ return null;
71
+ }
72
+ }
73
+ if (this.config.cacheTokens) {
74
+ const cacheKey = `${userId}:${resourceType}`;
75
+ this.tokenCache.set(cacheKey, {
76
+ token,
77
+ expiresAt: Date.now() + this.config.cacheTtl
78
+ });
79
+ this.logger.debug("Token cached", {
80
+ userId,
81
+ resourceType,
82
+ cacheKey,
83
+ ttl: this.config.cacheTtl
84
+ });
85
+ }
86
+ this.logger.info("Token resolved successfully", {
87
+ userId,
88
+ resourceType,
89
+ envVar,
90
+ tokenLength: token.length
91
+ });
92
+ return token;
93
+ }
94
+ /**
95
+ * Optional: Refresh token (not supported for env-based tokens)
96
+ */
97
+ async refreshToken(userId, resourceType) {
98
+ this.logger.warn("Token refresh not supported for environment-based tokens", {
99
+ userId,
100
+ resourceType
101
+ });
102
+ return this.resolveToken(userId, resourceType);
103
+ }
104
+ /**
105
+ * Optional: Validate token (checks if env var is set)
106
+ */
107
+ async validateToken(token, resourceType) {
108
+ if (!this.config.validateToken) {
109
+ return true;
110
+ }
111
+ try {
112
+ validateAccessToken(token);
113
+ return true;
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+ /**
119
+ * Optional: Initialize resolver
120
+ */
121
+ async initialize() {
122
+ this.logger.info("SimpleTokenResolver initialized", {
123
+ tokenEnvVar: this.config.tokenEnvVar,
124
+ resourceTokenEnvVars: Object.keys(this.config.resourceTokenEnvVars),
125
+ cacheEnabled: this.config.cacheTokens
126
+ });
127
+ const hasDefaultToken = !!process.env[this.config.tokenEnvVar];
128
+ const hasResourceTokens = Object.values(this.config.resourceTokenEnvVars).some((envVar) => !!process.env[envVar]);
129
+ if (!hasDefaultToken && !hasResourceTokens && this.config.throwOnMissing) {
130
+ this.logger.warn("No tokens found in environment variables", {
131
+ tokenEnvVar: this.config.tokenEnvVar,
132
+ resourceTokenEnvVars: this.config.resourceTokenEnvVars
133
+ });
134
+ }
135
+ }
136
+ /**
137
+ * Optional: Cleanup resources
138
+ */
139
+ async cleanup() {
140
+ this.tokenCache.clear();
141
+ this.logger.info("SimpleTokenResolver cleaned up");
142
+ }
143
+ /**
144
+ * Clear token cache
145
+ */
146
+ clearCache() {
147
+ this.tokenCache.clear();
148
+ this.logger.debug("Token cache cleared");
149
+ }
150
+ /**
151
+ * Get cache statistics
152
+ */
153
+ getCacheStats() {
154
+ return {
155
+ size: this.tokenCache.size,
156
+ keys: Array.from(this.tokenCache.keys())
157
+ };
158
+ }
159
+ /**
160
+ * Check if token is available for a resource type
161
+ */
162
+ hasToken(resourceType) {
163
+ const envVar = this.config.resourceTokenEnvVars[resourceType] || `${resourceType.toUpperCase()}_ACCESS_TOKEN`;
164
+ return !!process.env[envVar];
165
+ }
166
+ /**
167
+ * Get all available resource types
168
+ */
169
+ getAvailableResources() {
170
+ const resources = [];
171
+ if (process.env[this.config.tokenEnvVar]) {
172
+ resources.push("default");
173
+ }
174
+ for (const [resourceType, envVar] of Object.entries(this.config.resourceTokenEnvVars)) {
175
+ if (process.env[envVar]) {
176
+ resources.push(resourceType);
177
+ }
178
+ }
179
+ return resources;
180
+ }
181
+ }
182
+ export {
183
+ SimpleTokenResolver
184
+ };
185
+ //# sourceMappingURL=simple-resolver.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/auth/providers/simple-resolver.ts"],
4
+ "sourcesContent": ["/**\n * Simple token resolver for single-user scenarios\n * \n * Resolves tokens from environment variables. Useful for local development\n * and single-user deployments where all users share the same token.\n */\n\nimport type { ResourceTokenResolver, TokenResolverConfig } from '../types.js';\nimport { TokenResolutionError, MissingCredentialsError } from '../../utils/errors.js';\nimport { createLogger, type Logger } from '../../utils/logger.js';\nimport { validateAccessToken } from '../../utils/validation.js';\n\n/**\n * Configuration for SimpleTokenResolver\n */\nexport interface SimpleTokenResolverConfig extends TokenResolverConfig {\n /**\n * Environment variable name containing the access token\n * @default 'ACCESS_TOKEN'\n */\n tokenEnvVar?: string;\n \n /**\n * Optional: Map of resource types to environment variable names\n * Overrides tokenEnvVar for specific resource types\n * \n * @example\n * ```typescript\n * {\n * instagram: 'INSTAGRAM_ACCESS_TOKEN',\n * github: 'GITHUB_ACCESS_TOKEN'\n * }\n * ```\n */\n resourceTokenEnvVars?: Record<string, string>;\n \n /**\n * Whether to throw error if token is not found\n * @default true\n */\n throwOnMissing?: boolean;\n \n /**\n * Whether to validate token format\n * @default true\n */\n validateToken?: boolean;\n}\n\n/**\n * Simple token resolver that reads tokens from environment variables\n * \n * This resolver is designed for single-user scenarios where authentication\n * is handled externally or not required. It reads resource-specific tokens\n * from environment variables.\n * \n * @example\n * ```typescript\n * // Single token for all resources\n * const resolver = new SimpleTokenResolver({\n * tokenEnvVar: 'API_TOKEN'\n * });\n * \n * // Different tokens per resource\n * const resolver = new SimpleTokenResolver({\n * resourceTokenEnvVars: {\n * instagram: 'INSTAGRAM_ACCESS_TOKEN',\n * github: 'GITHUB_ACCESS_TOKEN'\n * }\n * });\n * ```\n */\nexport class SimpleTokenResolver implements ResourceTokenResolver {\n private config: Required<SimpleTokenResolverConfig>;\n private logger: Logger;\n private tokenCache: Map<string, { token: string; expiresAt: number }>;\n \n constructor(config: SimpleTokenResolverConfig = {}) {\n this.config = {\n tokenEnvVar: config.tokenEnvVar ?? 'ACCESS_TOKEN',\n resourceTokenEnvVars: config.resourceTokenEnvVars ?? {},\n throwOnMissing: config.throwOnMissing ?? true,\n validateToken: config.validateToken ?? true,\n cacheTokens: config.cacheTokens ?? true,\n cacheTtl: config.cacheTtl ?? 300000, // 5 minutes\n autoRefresh: config.autoRefresh ?? false\n };\n \n this.logger = createLogger({ enabled: true, level: 'info' });\n this.tokenCache = new Map();\n }\n \n /**\n * Resolve access token for a user and resource type\n */\n async resolveToken(userId: string, resourceType: string): Promise<string | null> {\n // Check cache if enabled\n if (this.config.cacheTokens) {\n const cacheKey = `${userId}:${resourceType}`;\n const cached = this.tokenCache.get(cacheKey);\n \n if (cached && cached.expiresAt > Date.now()) {\n this.logger.debug('Token retrieved from cache', {\n userId,\n resourceType,\n cacheKey\n });\n return cached.token;\n }\n }\n \n // Determine which environment variable to use\n const envVar = this.config.resourceTokenEnvVars[resourceType]\n || `${resourceType.toUpperCase()}_ACCESS_TOKEN`;\n \n // Read token from environment\n const token = process.env[envVar];\n \n if (!token) {\n const errorMessage = `Token not found in environment variable: ${envVar}`;\n \n this.logger.warn('Token resolution failed', {\n userId,\n resourceType,\n envVar\n });\n \n if (this.config.throwOnMissing) {\n throw new TokenResolutionError(userId, resourceType, {\n envVar,\n reason: 'Environment variable not set'\n });\n }\n \n return null;\n }\n \n // Validate token format if enabled\n if (this.config.validateToken) {\n try {\n validateAccessToken(token);\n } catch (error) {\n this.logger.error('Token validation failed', error as Error, {\n userId,\n resourceType,\n envVar\n });\n \n if (this.config.throwOnMissing) {\n throw new TokenResolutionError(userId, resourceType, {\n envVar,\n reason: 'Invalid token format'\n });\n }\n \n return null;\n }\n }\n \n // Cache token if enabled\n if (this.config.cacheTokens) {\n const cacheKey = `${userId}:${resourceType}`;\n this.tokenCache.set(cacheKey, {\n token,\n expiresAt: Date.now() + this.config.cacheTtl\n });\n \n this.logger.debug('Token cached', {\n userId,\n resourceType,\n cacheKey,\n ttl: this.config.cacheTtl\n });\n }\n \n this.logger.info('Token resolved successfully', {\n userId,\n resourceType,\n envVar,\n tokenLength: token.length\n });\n \n return token;\n }\n \n /**\n * Optional: Refresh token (not supported for env-based tokens)\n */\n async refreshToken(userId: string, resourceType: string): Promise<string | null> {\n this.logger.warn('Token refresh not supported for environment-based tokens', {\n userId,\n resourceType\n });\n \n // Re-read from environment in case it changed\n return this.resolveToken(userId, resourceType);\n }\n \n /**\n * Optional: Validate token (checks if env var is set)\n */\n async validateToken(token: string, resourceType: string): Promise<boolean> {\n if (!this.config.validateToken) {\n return true;\n }\n \n try {\n validateAccessToken(token);\n return true;\n } catch {\n return false;\n }\n }\n \n /**\n * Optional: Initialize resolver\n */\n async initialize(): Promise<void> {\n this.logger.info('SimpleTokenResolver initialized', {\n tokenEnvVar: this.config.tokenEnvVar,\n resourceTokenEnvVars: Object.keys(this.config.resourceTokenEnvVars),\n cacheEnabled: this.config.cacheTokens\n });\n \n // Validate that at least one token is available\n const hasDefaultToken = !!process.env[this.config.tokenEnvVar];\n const hasResourceTokens = Object.values(this.config.resourceTokenEnvVars)\n .some(envVar => !!process.env[envVar]);\n \n if (!hasDefaultToken && !hasResourceTokens && this.config.throwOnMissing) {\n this.logger.warn('No tokens found in environment variables', {\n tokenEnvVar: this.config.tokenEnvVar,\n resourceTokenEnvVars: this.config.resourceTokenEnvVars\n });\n }\n }\n \n /**\n * Optional: Cleanup resources\n */\n async cleanup(): Promise<void> {\n this.tokenCache.clear();\n this.logger.info('SimpleTokenResolver cleaned up');\n }\n \n /**\n * Clear token cache\n */\n clearCache(): void {\n this.tokenCache.clear();\n this.logger.debug('Token cache cleared');\n }\n \n /**\n * Get cache statistics\n */\n getCacheStats(): { size: number; keys: string[] } {\n return {\n size: this.tokenCache.size,\n keys: Array.from(this.tokenCache.keys())\n };\n }\n \n /**\n * Check if token is available for a resource type\n */\n hasToken(resourceType: string): boolean {\n const envVar = this.config.resourceTokenEnvVars[resourceType]\n || `${resourceType.toUpperCase()}_ACCESS_TOKEN`;\n \n return !!process.env[envVar];\n }\n \n /**\n * Get all available resource types\n */\n getAvailableResources(): string[] {\n const resources: string[] = [];\n \n // Check default token\n if (process.env[this.config.tokenEnvVar]) {\n resources.push('default');\n }\n \n // Check resource-specific tokens\n for (const [resourceType, envVar] of Object.entries(this.config.resourceTokenEnvVars)) {\n if (process.env[envVar]) {\n resources.push(resourceType);\n }\n }\n \n return resources;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
package/dist/index.js ADDED
@@ -0,0 +1,111 @@
1
+ import {
2
+ wrapServer,
3
+ AuthenticatedServerWrapper
4
+ } from "./wrapper/index.js";
5
+ import {
6
+ AuthenticatedMCPServer,
7
+ withAuth,
8
+ compose,
9
+ withLogging,
10
+ withRateLimit,
11
+ withTimeout,
12
+ withRetry,
13
+ AuthenticatedTool,
14
+ createAuthenticatedTool
15
+ } from "./server/index.js";
16
+ import { BaseAuthProvider } from "./auth/base-provider.js";
17
+ import {
18
+ EnvAuthProvider,
19
+ SimpleTokenResolver
20
+ } from "./auth/providers/index.js";
21
+ import {
22
+ MCPAuthError,
23
+ AuthenticationError,
24
+ TokenResolutionError,
25
+ InvalidTokenError,
26
+ MissingCredentialsError,
27
+ ConfigurationError,
28
+ RateLimitError,
29
+ ServerPoolError,
30
+ TransportError,
31
+ ValidationError,
32
+ isMCPAuthError,
33
+ isAuthenticationError,
34
+ isTokenResolutionError,
35
+ isRateLimitError,
36
+ formatErrorForClient,
37
+ Logger,
38
+ LogLevel,
39
+ defaultLogger,
40
+ createLogger,
41
+ sanitizeForLogging,
42
+ validateNonEmptyString,
43
+ validateUrl,
44
+ validatePositiveNumber,
45
+ validatePort,
46
+ validateEnum,
47
+ validateObject,
48
+ validateFunction,
49
+ validateRequiredFields,
50
+ validateTransportConfig,
51
+ validateRateLimitConfig,
52
+ validateLoggingConfig,
53
+ validatePoolingConfig,
54
+ sanitizeString,
55
+ validateUserId,
56
+ validateResourceType,
57
+ validateAccessToken
58
+ } from "./utils/index.js";
59
+ export {
60
+ AuthenticatedMCPServer,
61
+ AuthenticatedServerWrapper,
62
+ AuthenticatedTool,
63
+ AuthenticationError,
64
+ BaseAuthProvider,
65
+ ConfigurationError,
66
+ EnvAuthProvider,
67
+ InvalidTokenError,
68
+ LogLevel,
69
+ Logger,
70
+ MCPAuthError,
71
+ MissingCredentialsError,
72
+ RateLimitError,
73
+ ServerPoolError,
74
+ SimpleTokenResolver,
75
+ TokenResolutionError,
76
+ TransportError,
77
+ ValidationError,
78
+ compose,
79
+ createAuthenticatedTool,
80
+ createLogger,
81
+ defaultLogger,
82
+ formatErrorForClient,
83
+ isAuthenticationError,
84
+ isMCPAuthError,
85
+ isRateLimitError,
86
+ isTokenResolutionError,
87
+ sanitizeForLogging,
88
+ sanitizeString,
89
+ validateAccessToken,
90
+ validateEnum,
91
+ validateFunction,
92
+ validateLoggingConfig,
93
+ validateNonEmptyString,
94
+ validateObject,
95
+ validatePoolingConfig,
96
+ validatePort,
97
+ validatePositiveNumber,
98
+ validateRateLimitConfig,
99
+ validateRequiredFields,
100
+ validateResourceType,
101
+ validateTransportConfig,
102
+ validateUrl,
103
+ validateUserId,
104
+ withAuth,
105
+ withLogging,
106
+ withRateLimit,
107
+ withRetry,
108
+ withTimeout,
109
+ wrapServer
110
+ };
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["/**\n * @prmichaelsen/mcp-auth\n *\n * Authentication and multi-tenancy framework for MCP (Model Context Protocol) servers.\n *\n * Supports two complementary patterns:\n * 1. **Server Wrapping** - Wrap existing MCP servers without modification (MCP-level auth)\n * 2. **Tool-Level Auth** - Build new MCP servers with integrated auth\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// PATTERN 1: SERVER WRAPPING (MCP-Level Auth)\n// ============================================================================\n// Use this to wrap existing MCP servers without modifying them\n// Ideal for multi-tenant services that host multiple MCP servers\n\nexport {\n wrapServer,\n AuthenticatedServerWrapper,\n type ServerWrapperConfig,\n type MCPServerFactory,\n type NormalizedServerWrapperConfig\n} from './wrapper/index.js';\n\n// ============================================================================\n// PATTERN 2: TOOL-LEVEL AUTH\n// ============================================================================\n// Use this to build new MCP servers with integrated authentication\n// Provides fine-grained control over auth per tool\n\nexport {\n AuthenticatedMCPServer,\n type ServerConfig,\n type NormalizedServerConfig,\n withAuth,\n compose,\n withLogging,\n withRateLimit,\n withTimeout,\n withRetry,\n type Tool,\n AuthenticatedTool,\n createAuthenticatedTool,\n type AuthenticatedToolHandler\n} from './server/index.js';\n\n// ============================================================================\n// SHARED: CORE TYPES\n// ============================================================================\n\nexport type {\n TransportType,\n RequestContext,\n AuthResult,\n TransportConfig,\n RateLimitConfig,\n LoggingConfig,\n MiddlewareConfig,\n PoolingConfig,\n Result,\n AsyncFunction,\n ToolHandler,\n Middleware\n} from './types.js';\n\n// ============================================================================\n// SHARED: AUTHENTICATION\n// ============================================================================\n\nexport type {\n AuthProvider,\n ResourceTokenResolver,\n AuthenticatedContext,\n AuthProviderConfig,\n TokenResolverConfig\n} from './auth/types.js';\n\nexport { BaseAuthProvider } from './auth/base-provider.js';\n\n// Providers\nexport {\n EnvAuthProvider,\n type EnvAuthProviderConfig,\n SimpleTokenResolver,\n type SimpleTokenResolverConfig\n} from './auth/providers/index.js';\n\n// Advanced Providers (to be implemented in Phase 8)\n// export { JWTAuthProvider } from './auth/providers/jwt-provider.js';\n// export { OAuthProvider } from './auth/providers/oauth-provider.js';\n// export { APIKeyProvider } from './auth/providers/apikey-provider.js';\n// export { DatabaseTokenResolver } from './auth/providers/database-resolver.js';\n\n// ============================================================================\n// SHARED: UTILITIES\n// ============================================================================\n\nexport {\n // Errors\n MCPAuthError,\n AuthenticationError,\n TokenResolutionError,\n InvalidTokenError,\n MissingCredentialsError,\n ConfigurationError,\n RateLimitError,\n ServerPoolError,\n TransportError,\n ValidationError,\n isMCPAuthError,\n isAuthenticationError,\n isTokenResolutionError,\n isRateLimitError,\n formatErrorForClient,\n \n // Logger\n Logger,\n LogLevel,\n defaultLogger,\n createLogger,\n sanitizeForLogging,\n \n // Validation\n validateNonEmptyString,\n validateUrl,\n validatePositiveNumber,\n validatePort,\n validateEnum,\n validateObject,\n validateFunction,\n validateRequiredFields,\n validateTransportConfig,\n validateRateLimitConfig,\n validateLoggingConfig,\n validatePoolingConfig,\n sanitizeString,\n validateUserId,\n validateResourceType,\n validateAccessToken\n} from './utils/index.js';\n\n// Re-export types for convenience\nexport type { LogEntry } from './utils/logger.js';\n\n// ============================================================================\n// USAGE EXAMPLES\n// ============================================================================\n\n/**\n * @example Server Wrapping Pattern (MCP-Level Auth)\n * ```typescript\n * import { wrapServer, JWTAuthProvider, DatabaseTokenResolver } from '@prmichaelsen/mcp-auth';\n * import { createServer as createInstagramServer } from '@prmichaelsen/instagram-mcp';\n *\n * const wrapped = wrapServer({\n * serverFactory: (accessToken, userId) => createInstagramServer(accessToken, userId),\n * authProvider: new JWTAuthProvider({ jwtSecret: process.env.JWT_SECRET }),\n * tokenResolver: new DatabaseTokenResolver({ database: {...} }),\n * resourceType: 'instagram',\n * transport: { type: 'sse', port: 3000 }\n * });\n *\n * await wrapped.start();\n * ```\n *\n * @example Tool-Level Auth Pattern\n * ```typescript\n * import { AuthenticatedMCPServer, withAuth, EnvAuthProvider } from '@prmichaelsen/mcp-auth';\n *\n * const server = new AuthenticatedMCPServer({\n * name: 'my-server',\n * authProvider: new EnvAuthProvider(),\n * tokenResolver: new SimpleTokenResolver({ tokenEnvVar: 'API_TOKEN' }),\n * resourceType: 'myapi',\n * transport: { type: 'stdio' }\n * });\n *\n * server.registerTool('get_data', withAuth(async (args, accessToken, userId) => {\n * const client = new MyAPIClient(accessToken);\n * return client.getData(args);\n * }));\n *\n * await server.start();\n * ```\n */\n"],
5
+ "mappings": "AAkBA;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAQP;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,OAEK;AAiCP,SAAS,wBAAwB;AAGjC;AAAA,EACE;AAAA,EAEA;AAAA,OAEK;AAYP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,149 @@
1
+ import { AuthenticationError, TokenResolutionError } from "../utils/errors.js";
2
+ import { validateUserId, validateAccessToken } from "../utils/validation.js";
3
+ import { createLogger } from "../utils/logger.js";
4
+ const logger = createLogger({ enabled: true, level: "info" });
5
+ function withAuth(handler) {
6
+ return async (args, context, authProvider, tokenResolver, resourceType) => {
7
+ const authResult = await authProvider.authenticate(context);
8
+ if (!authResult.authenticated || !authResult.userId) {
9
+ throw new AuthenticationError(
10
+ authResult.error || "Authentication failed"
11
+ );
12
+ }
13
+ const userId = validateUserId(authResult.userId);
14
+ logger.debug("Request authenticated", { userId, resourceType });
15
+ const accessToken = await tokenResolver.resolveToken(userId, resourceType);
16
+ if (!accessToken) {
17
+ throw new TokenResolutionError(userId, resourceType);
18
+ }
19
+ validateAccessToken(accessToken);
20
+ logger.debug("Token resolved", { userId, resourceType });
21
+ return handler(args, accessToken, userId);
22
+ };
23
+ }
24
+ function compose(...middlewares) {
25
+ if (middlewares.length === 0) {
26
+ throw new Error("compose() requires at least one argument");
27
+ }
28
+ const handler = middlewares[middlewares.length - 1];
29
+ const mws = middlewares.slice(0, -1);
30
+ return mws.reduceRight(
31
+ (acc, middleware) => middleware(acc),
32
+ handler
33
+ );
34
+ }
35
+ function withLogging(options) {
36
+ const opts = {
37
+ logArgs: options?.logArgs ?? false,
38
+ logResult: options?.logResult ?? false
39
+ };
40
+ return (handler) => {
41
+ return async (args, accessToken, userId) => {
42
+ const startTime = Date.now();
43
+ logger.info("Tool execution started", {
44
+ userId,
45
+ ...opts.logArgs && { args }
46
+ });
47
+ try {
48
+ const result = await handler(args, accessToken, userId);
49
+ const duration = Date.now() - startTime;
50
+ logger.info("Tool execution completed", {
51
+ userId,
52
+ duration,
53
+ ...opts.logResult && { result }
54
+ });
55
+ return result;
56
+ } catch (error) {
57
+ const duration = Date.now() - startTime;
58
+ logger.error("Tool execution failed", error, {
59
+ userId,
60
+ duration
61
+ });
62
+ throw error;
63
+ }
64
+ };
65
+ };
66
+ }
67
+ function withRateLimit(config) {
68
+ const requests = /* @__PURE__ */ new Map();
69
+ return (handler) => {
70
+ return async (args, accessToken, userId) => {
71
+ const key = config.keyGenerator ? config.keyGenerator(userId) : userId;
72
+ const now = Date.now();
73
+ const timestamps = requests.get(key) || [];
74
+ const validTimestamps = timestamps.filter((t) => now - t < config.windowMs);
75
+ if (validTimestamps.length >= config.maxRequests) {
76
+ const oldestTimestamp = Math.min(...validTimestamps);
77
+ const retryAfter = Math.ceil((oldestTimestamp + config.windowMs - now) / 1e3);
78
+ logger.warn("Rate limit exceeded", {
79
+ userId,
80
+ key,
81
+ maxRequests: config.maxRequests,
82
+ windowMs: config.windowMs,
83
+ retryAfter
84
+ });
85
+ const error = new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`);
86
+ error.code = "RATE_LIMIT_EXCEEDED";
87
+ error.retryAfter = retryAfter;
88
+ throw error;
89
+ }
90
+ validTimestamps.push(now);
91
+ requests.set(key, validTimestamps);
92
+ return handler(args, accessToken, userId);
93
+ };
94
+ };
95
+ }
96
+ function withTimeout(timeoutMs) {
97
+ return (handler) => {
98
+ return async (args, accessToken, userId) => {
99
+ return Promise.race([
100
+ handler(args, accessToken, userId),
101
+ new Promise((_, reject) => {
102
+ setTimeout(() => {
103
+ reject(new Error(`Tool execution timeout after ${timeoutMs}ms`));
104
+ }, timeoutMs);
105
+ })
106
+ ]);
107
+ };
108
+ };
109
+ }
110
+ function withRetry(options) {
111
+ const opts = {
112
+ maxAttempts: options.maxAttempts,
113
+ delayMs: options.delayMs ?? 1e3,
114
+ shouldRetry: options.shouldRetry ?? (() => true)
115
+ };
116
+ return (handler) => {
117
+ return async (args, accessToken, userId) => {
118
+ let lastError;
119
+ for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
120
+ try {
121
+ return await handler(args, accessToken, userId);
122
+ } catch (error) {
123
+ lastError = error;
124
+ if (attempt < opts.maxAttempts && opts.shouldRetry(lastError)) {
125
+ logger.warn("Tool execution failed, retrying", {
126
+ userId,
127
+ attempt,
128
+ maxAttempts: opts.maxAttempts,
129
+ error: lastError.message
130
+ });
131
+ await new Promise((resolve) => setTimeout(resolve, opts.delayMs));
132
+ } else {
133
+ break;
134
+ }
135
+ }
136
+ }
137
+ throw lastError;
138
+ };
139
+ };
140
+ }
141
+ export {
142
+ compose,
143
+ withAuth,
144
+ withLogging,
145
+ withRateLimit,
146
+ withRetry,
147
+ withTimeout
148
+ };
149
+ //# sourceMappingURL=decorators.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/server/decorators.ts"],
4
+ "sourcesContent": ["/**\n * Decorators and middleware for tool-level authentication\n * \n * Provides function wrappers for adding authentication to tool handlers.\n */\n\nimport type { ToolHandler, Middleware, RequestContext } from '../types.js';\nimport type { AuthProvider, ResourceTokenResolver } from '../auth/types.js';\nimport { AuthenticationError, TokenResolutionError } from '../utils/errors.js';\nimport { validateUserId, validateAccessToken } from '../utils/validation.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger({ enabled: true, level: 'info' });\n\n/**\n * Authenticated tool handler type\n * Internal type used by the framework\n */\nexport type AuthenticatedToolHandler<TArgs = any, TResult = any> = (\n args: TArgs,\n context: RequestContext,\n authProvider: AuthProvider,\n tokenResolver: ResourceTokenResolver,\n resourceType: string\n) => Promise<TResult>;\n\n/**\n * Wrap a tool handler with authentication\n * \n * This is the primary decorator for adding authentication to function-based tools.\n * It automatically handles authentication and token resolution before calling your handler.\n * \n * @param handler - Tool handler function that receives (args, accessToken, userId)\n * @returns Authenticated tool handler\n * \n * @example\n * ```typescript\n * const getTool = withAuth(async (args, accessToken, userId) => {\n * const client = new APIClient(accessToken);\n * return client.getData(args);\n * });\n * \n * server.registerTool('get_data', getTool);\n * ```\n */\nexport function withAuth<TArgs = any, TResult = any>(\n handler: ToolHandler<TArgs, TResult>\n): AuthenticatedToolHandler<TArgs, TResult> {\n return async (\n args: TArgs,\n context: RequestContext,\n authProvider: AuthProvider,\n tokenResolver: ResourceTokenResolver,\n resourceType: string\n ): Promise<TResult> => {\n // 1. Authenticate request\n const authResult = await authProvider.authenticate(context);\n \n if (!authResult.authenticated || !authResult.userId) {\n throw new AuthenticationError(\n authResult.error || 'Authentication failed'\n );\n }\n \n const userId = validateUserId(authResult.userId);\n \n logger.debug('Request authenticated', { userId, resourceType });\n \n // 2. Resolve resource token\n const accessToken = await tokenResolver.resolveToken(userId, resourceType);\n \n if (!accessToken) {\n throw new TokenResolutionError(userId, resourceType);\n }\n \n validateAccessToken(accessToken);\n \n logger.debug('Token resolved', { userId, resourceType });\n \n // 3. Call handler with authenticated context\n return handler(args, accessToken, userId);\n };\n}\n\n/**\n * Compose multiple middleware functions\n * \n * Applies middleware in order from left to right.\n * Each middleware wraps the next one in the chain.\n * \n * @param middlewares - Middleware functions to compose\n * @returns Composed middleware function\n * \n * @example\n * ```typescript\n * const tool = compose(\n * withLogging(),\n * withRateLimit({ maxRequests: 10 }),\n * withAuth(),\n * handler\n * );\n * ```\n */\nexport function compose<TArgs = any, TResult = any>(\n ...middlewares: Array<Middleware<TArgs, TResult> | ToolHandler<TArgs, TResult>>\n): ToolHandler<TArgs, TResult> {\n if (middlewares.length === 0) {\n throw new Error('compose() requires at least one argument');\n }\n \n // Last item should be the handler\n const handler = middlewares[middlewares.length - 1] as ToolHandler<TArgs, TResult>;\n const mws = middlewares.slice(0, -1) as Middleware<TArgs, TResult>[];\n \n // Apply middleware from right to left\n return mws.reduceRight(\n (acc, middleware) => middleware(acc),\n handler\n );\n}\n\n/**\n * Create a logging middleware\n * \n * Logs tool execution with timing information.\n * \n * @param options - Logging options\n * @returns Logging middleware\n * \n * @example\n * ```typescript\n * const tool = compose(\n * withLogging({ logArgs: true }),\n * withAuth(),\n * handler\n * );\n * ```\n */\nexport function withLogging(options?: {\n logArgs?: boolean;\n logResult?: boolean;\n}): Middleware {\n const opts = {\n logArgs: options?.logArgs ?? false,\n logResult: options?.logResult ?? false\n };\n \n return (handler: ToolHandler) => {\n return async (args: any, accessToken: string, userId: string) => {\n const startTime = Date.now();\n \n logger.info('Tool execution started', {\n userId,\n ...(opts.logArgs && { args })\n });\n \n try {\n const result = await handler(args, accessToken, userId);\n const duration = Date.now() - startTime;\n \n logger.info('Tool execution completed', {\n userId,\n duration,\n ...(opts.logResult && { result })\n });\n \n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n \n logger.error('Tool execution failed', error as Error, {\n userId,\n duration\n });\n \n throw error;\n }\n };\n };\n}\n\n/**\n * Create a rate limiting middleware\n * \n * Limits the number of requests per user in a time window.\n * \n * @param config - Rate limit configuration\n * @returns Rate limiting middleware\n * \n * @example\n * ```typescript\n * const tool = compose(\n * withRateLimit({ maxRequests: 10, windowMs: 60000 }),\n * withAuth(),\n * handler\n * );\n * ```\n */\nexport function withRateLimit(config: {\n maxRequests: number;\n windowMs: number;\n keyGenerator?: (userId: string) => string;\n}): Middleware {\n // Simple in-memory rate limiter\n const requests = new Map<string, number[]>();\n \n return (handler: ToolHandler) => {\n return async (args: any, accessToken: string, userId: string) => {\n const key = config.keyGenerator ? config.keyGenerator(userId) : userId;\n const now = Date.now();\n \n // Get request timestamps for this key\n const timestamps = requests.get(key) || [];\n \n // Remove timestamps outside the window\n const validTimestamps = timestamps.filter(t => now - t < config.windowMs);\n \n // Check if limit exceeded\n if (validTimestamps.length >= config.maxRequests) {\n const oldestTimestamp = Math.min(...validTimestamps);\n const retryAfter = Math.ceil((oldestTimestamp + config.windowMs - now) / 1000);\n \n logger.warn('Rate limit exceeded', {\n userId,\n key,\n maxRequests: config.maxRequests,\n windowMs: config.windowMs,\n retryAfter\n });\n \n const error = new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`);\n (error as any).code = 'RATE_LIMIT_EXCEEDED';\n (error as any).retryAfter = retryAfter;\n throw error;\n }\n \n // Add current timestamp\n validTimestamps.push(now);\n requests.set(key, validTimestamps);\n \n // Execute handler\n return handler(args, accessToken, userId);\n };\n };\n}\n\n/**\n * Create a timeout middleware\n * \n * Adds timeout to tool execution.\n * \n * @param timeoutMs - Timeout in milliseconds\n * @returns Timeout middleware\n * \n * @example\n * ```typescript\n * const tool = compose(\n * withTimeout(5000), // 5 second timeout\n * withAuth(),\n * handler\n * );\n * ```\n */\nexport function withTimeout(timeoutMs: number): Middleware {\n return (handler: ToolHandler) => {\n return async (args: any, accessToken: string, userId: string) => {\n return Promise.race([\n handler(args, accessToken, userId),\n new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Tool execution timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n })\n ]);\n };\n };\n}\n\n/**\n * Create a retry middleware\n * \n * Retries tool execution on failure.\n * \n * @param options - Retry options\n * @returns Retry middleware\n * \n * @example\n * ```typescript\n * const tool = compose(\n * withRetry({ maxAttempts: 3, delayMs: 1000 }),\n * withAuth(),\n * handler\n * );\n * ```\n */\nexport function withRetry(options: {\n maxAttempts: number;\n delayMs?: number;\n shouldRetry?: (error: Error) => boolean;\n}): Middleware {\n const opts = {\n maxAttempts: options.maxAttempts,\n delayMs: options.delayMs ?? 1000,\n shouldRetry: options.shouldRetry ?? (() => true)\n };\n \n return (handler: ToolHandler) => {\n return async (args: any, accessToken: string, userId: string) => {\n let lastError: Error | undefined;\n \n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\n try {\n return await handler(args, accessToken, userId);\n } catch (error) {\n lastError = error as Error;\n \n if (attempt < opts.maxAttempts && opts.shouldRetry(lastError)) {\n logger.warn('Tool execution failed, retrying', {\n userId,\n attempt,\n maxAttempts: opts.maxAttempts,\n error: lastError.message\n });\n \n // Wait before retry\n await new Promise(resolve => setTimeout(resolve, opts.delayMs));\n } else {\n break;\n }\n }\n }\n \n throw lastError;\n };\n };\n}\n"],
5
+ "mappings": "AAQA,SAAS,qBAAqB,4BAA4B;AAC1D,SAAS,gBAAgB,2BAA2B;AACpD,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,EAAE,SAAS,MAAM,OAAO,OAAO,CAAC;AAiCrD,SAAS,SACd,SAC0C;AAC1C,SAAO,OACL,MACA,SACA,cACA,eACA,iBACqB;AAErB,UAAM,aAAa,MAAM,aAAa,aAAa,OAAO;AAE1D,QAAI,CAAC,WAAW,iBAAiB,CAAC,WAAW,QAAQ;AACnD,YAAM,IAAI;AAAA,QACR,WAAW,SAAS;AAAA,MACtB;AAAA,IACF;AAEA,UAAM,SAAS,eAAe,WAAW,MAAM;AAE/C,WAAO,MAAM,yBAAyB,EAAE,QAAQ,aAAa,CAAC;AAG9D,UAAM,cAAc,MAAM,cAAc,aAAa,QAAQ,YAAY;AAEzE,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,qBAAqB,QAAQ,YAAY;AAAA,IACrD;AAEA,wBAAoB,WAAW;AAE/B,WAAO,MAAM,kBAAkB,EAAE,QAAQ,aAAa,CAAC;AAGvD,WAAO,QAAQ,MAAM,aAAa,MAAM;AAAA,EAC1C;AACF;AAqBO,SAAS,WACX,aAC0B;AAC7B,MAAI,YAAY,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAGA,QAAM,UAAU,YAAY,YAAY,SAAS,CAAC;AAClD,QAAM,MAAM,YAAY,MAAM,GAAG,EAAE;AAGnC,SAAO,IAAI;AAAA,IACT,CAAC,KAAK,eAAe,WAAW,GAAG;AAAA,IACnC;AAAA,EACF;AACF;AAmBO,SAAS,YAAY,SAGb;AACb,QAAM,OAAO;AAAA,IACX,SAAS,SAAS,WAAW;AAAA,IAC7B,WAAW,SAAS,aAAa;AAAA,EACnC;AAEA,SAAO,CAAC,YAAyB;AAC/B,WAAO,OAAO,MAAW,aAAqB,WAAmB;AAC/D,YAAM,YAAY,KAAK,IAAI;AAE3B,aAAO,KAAK,0BAA0B;AAAA,QACpC;AAAA,QACA,GAAI,KAAK,WAAW,EAAE,KAAK;AAAA,MAC7B,CAAC;AAED,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,MAAM,aAAa,MAAM;AACtD,cAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,eAAO,KAAK,4BAA4B;AAAA,UACtC;AAAA,UACA;AAAA,UACA,GAAI,KAAK,aAAa,EAAE,OAAO;AAAA,QACjC,CAAC;AAED,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,eAAO,MAAM,yBAAyB,OAAgB;AAAA,UACpD;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAmBO,SAAS,cAAc,QAIf;AAEb,QAAM,WAAW,oBAAI,IAAsB;AAE3C,SAAO,CAAC,YAAyB;AAC/B,WAAO,OAAO,MAAW,aAAqB,WAAmB;AAC/D,YAAM,MAAM,OAAO,eAAe,OAAO,aAAa,MAAM,IAAI;AAChE,YAAM,MAAM,KAAK,IAAI;AAGrB,YAAM,aAAa,SAAS,IAAI,GAAG,KAAK,CAAC;AAGzC,YAAM,kBAAkB,WAAW,OAAO,OAAK,MAAM,IAAI,OAAO,QAAQ;AAGxE,UAAI,gBAAgB,UAAU,OAAO,aAAa;AAChD,cAAM,kBAAkB,KAAK,IAAI,GAAG,eAAe;AACnD,cAAM,aAAa,KAAK,MAAM,kBAAkB,OAAO,WAAW,OAAO,GAAI;AAE7E,eAAO,KAAK,uBAAuB;AAAA,UACjC;AAAA,UACA;AAAA,UACA,aAAa,OAAO;AAAA,UACpB,UAAU,OAAO;AAAA,UACjB;AAAA,QACF,CAAC;AAED,cAAM,QAAQ,IAAI,MAAM,oCAAoC,UAAU,WAAW;AACjF,QAAC,MAAc,OAAO;AACtB,QAAC,MAAc,aAAa;AAC5B,cAAM;AAAA,MACR;AAGA,sBAAgB,KAAK,GAAG;AACxB,eAAS,IAAI,KAAK,eAAe;AAGjC,aAAO,QAAQ,MAAM,aAAa,MAAM;AAAA,IAC1C;AAAA,EACF;AACF;AAmBO,SAAS,YAAY,WAA+B;AACzD,SAAO,CAAC,YAAyB;AAC/B,WAAO,OAAO,MAAW,aAAqB,WAAmB;AAC/D,aAAO,QAAQ,KAAK;AAAA,QAClB,QAAQ,MAAM,aAAa,MAAM;AAAA,QACjC,IAAI,QAAe,CAAC,GAAG,WAAW;AAChC,qBAAW,MAAM;AACf,mBAAO,IAAI,MAAM,gCAAgC,SAAS,IAAI,CAAC;AAAA,UACjE,GAAG,SAAS;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAmBO,SAAS,UAAU,SAIX;AACb,QAAM,OAAO;AAAA,IACX,aAAa,QAAQ;AAAA,IACrB,SAAS,QAAQ,WAAW;AAAA,IAC5B,aAAa,QAAQ,gBAAgB,MAAM;AAAA,EAC7C;AAEA,SAAO,CAAC,YAAyB;AAC/B,WAAO,OAAO,MAAW,aAAqB,WAAmB;AAC/D,UAAI;AAEJ,eAAS,UAAU,GAAG,WAAW,KAAK,aAAa,WAAW;AAC5D,YAAI;AACF,iBAAO,MAAM,QAAQ,MAAM,aAAa,MAAM;AAAA,QAChD,SAAS,OAAO;AACd,sBAAY;AAEZ,cAAI,UAAU,KAAK,eAAe,KAAK,YAAY,SAAS,GAAG;AAC7D,mBAAO,KAAK,mCAAmC;AAAA,cAC7C;AAAA,cACA;AAAA,cACA,aAAa,KAAK;AAAA,cAClB,OAAO,UAAU;AAAA,YACnB,CAAC;AAGD,kBAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,KAAK,OAAO,CAAC;AAAA,UAChE,OAAO;AACL;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ import { AuthenticatedMCPServer } from "./mcp-server.js";
2
+ import {
3
+ AuthenticatedTool,
4
+ createAuthenticatedTool
5
+ } from "./tool.js";
6
+ import {
7
+ withAuth,
8
+ compose,
9
+ withLogging,
10
+ withRateLimit,
11
+ withTimeout,
12
+ withRetry
13
+ } from "./decorators.js";
14
+ export {
15
+ AuthenticatedMCPServer,
16
+ AuthenticatedTool,
17
+ compose,
18
+ createAuthenticatedTool,
19
+ withAuth,
20
+ withLogging,
21
+ withRateLimit,
22
+ withRetry,
23
+ withTimeout
24
+ };
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/server/index.ts"],
4
+ "sourcesContent": ["/**\n * Tool-level authentication module exports\n * \n * Provides classes and decorators for building MCP servers with integrated authentication.\n */\n\n// Configuration\nexport type { ServerConfig, NormalizedServerConfig } from './config.js';\n\n// Server\nexport { AuthenticatedMCPServer } from './mcp-server.js';\n\n// Tools\nexport { \n type Tool,\n AuthenticatedTool,\n createAuthenticatedTool\n} from './tool.js';\n\n// Decorators and middleware\nexport {\n withAuth,\n compose,\n withLogging,\n withRateLimit,\n withTimeout,\n withRetry,\n type AuthenticatedToolHandler\n} from './decorators.js';\n"],
5
+ "mappings": "AAUA,SAAS,8BAA8B;AAGvC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;",
6
+ "names": []
7
+ }