@1mcp/agent 0.11.0 → 0.13.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.
- package/README.md +45 -50
- package/build/auth/clientSessionManager.d.ts +94 -0
- package/build/auth/clientSessionManager.d.ts.map +1 -0
- package/build/auth/clientSessionManager.js +220 -0
- package/build/auth/clientSessionManager.js.map +1 -0
- package/build/auth/sdkOAuthClientProvider.d.ts +93 -0
- package/build/auth/sdkOAuthClientProvider.d.ts.map +1 -0
- package/build/auth/sdkOAuthClientProvider.js +199 -0
- package/build/auth/sdkOAuthClientProvider.js.map +1 -0
- package/build/auth/sdkOAuthServerProvider.d.ts +63 -0
- package/build/auth/sdkOAuthServerProvider.d.ts.map +1 -0
- package/build/auth/sdkOAuthServerProvider.js +428 -0
- package/build/auth/sdkOAuthServerProvider.js.map +1 -0
- package/build/{server/auth/sessionManager.d.ts → auth/serverSessionManager.d.ts} +26 -37
- package/build/auth/serverSessionManager.d.ts.map +1 -0
- package/build/{server/auth/sessionManager.js → auth/serverSessionManager.js} +104 -19
- package/build/auth/serverSessionManager.js.map +1 -0
- package/build/auth/sessionTypes.d.ts +24 -0
- package/build/auth/sessionTypes.d.ts.map +1 -0
- package/build/auth/sessionTypes.js +3 -0
- package/build/auth/sessionTypes.js.map +1 -0
- package/build/capabilities/capabilityManager.d.ts +2 -2
- package/build/capabilities/capabilityManager.d.ts.map +1 -1
- package/build/capabilities/capabilityManager.js +40 -7
- package/build/capabilities/capabilityManager.js.map +1 -1
- package/build/config/{configManager.d.ts → mcpConfigManager.d.ts} +18 -7
- package/build/config/mcpConfigManager.d.ts.map +1 -0
- package/build/config/{configManager.js → mcpConfigManager.js} +50 -10
- package/build/config/mcpConfigManager.js.map +1 -0
- package/build/constants.d.ts +36 -14
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +40 -17
- package/build/constants.js.map +1 -1
- package/build/{client.d.ts → core/client/clientFactory.d.ts} +1 -1
- package/build/core/client/clientFactory.d.ts.map +1 -0
- package/build/{client.js → core/client/clientFactory.js} +2 -2
- package/build/core/client/clientFactory.js.map +1 -0
- package/build/{clients → core/client}/clientManager.d.ts +14 -6
- package/build/core/client/clientManager.d.ts.map +1 -0
- package/build/core/client/clientManager.js +209 -0
- package/build/core/client/clientManager.js.map +1 -0
- package/build/{server/config/serverConfig.d.ts → core/server/agentConfig.d.ts} +50 -15
- package/build/core/server/agentConfig.d.ts.map +1 -0
- package/build/core/server/agentConfig.js +166 -0
- package/build/core/server/agentConfig.js.map +1 -0
- package/build/core/server/serverManager.d.ts +39 -0
- package/build/core/server/serverManager.d.ts.map +1 -0
- package/build/core/server/serverManager.js +169 -0
- package/build/core/server/serverManager.js.map +1 -0
- package/build/core/types/client.d.ts +51 -0
- package/build/core/types/client.d.ts.map +1 -0
- package/build/core/types/client.js +15 -0
- package/build/core/types/client.js.map +1 -0
- package/build/core/types/index.d.ts +4 -0
- package/build/core/types/index.d.ts.map +1 -0
- package/build/core/types/index.js +5 -0
- package/build/core/types/index.js.map +1 -0
- package/build/core/types/server.d.ts +14 -0
- package/build/core/types/server.d.ts.map +1 -0
- package/build/core/types/server.js +2 -0
- package/build/core/types/server.js.map +1 -0
- package/build/{types.d.ts → core/types/transport.d.ts} +59 -49
- package/build/core/types/transport.d.ts.map +1 -0
- package/build/{types.js → core/types/transport.js} +11 -13
- package/build/core/types/transport.js.map +1 -0
- package/build/handlers/notificationHandlers.d.ts +3 -3
- package/build/handlers/notificationHandlers.d.ts.map +1 -1
- package/build/handlers/notificationHandlers.js +13 -9
- package/build/handlers/notificationHandlers.js.map +1 -1
- package/build/handlers/requestHandlers.d.ts +2 -2
- package/build/handlers/requestHandlers.d.ts.map +1 -1
- package/build/handlers/requestHandlers.js +25 -3
- package/build/handlers/requestHandlers.js.map +1 -1
- package/build/index.js +48 -8
- package/build/index.js.map +1 -1
- package/build/logger/logger.js +1 -1
- package/build/logger/logger.js.map +1 -1
- package/build/{middleware/loggingMiddleware.d.ts → logger/mcpLoggingEnhancer.d.ts} +1 -1
- package/build/logger/mcpLoggingEnhancer.d.ts.map +1 -0
- package/build/{middleware/loggingMiddleware.js → logger/mcpLoggingEnhancer.js} +2 -2
- package/build/logger/mcpLoggingEnhancer.js.map +1 -0
- package/build/server.d.ts +1 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +9 -6
- package/build/server.js.map +1 -1
- package/build/services/configReloadService.d.ts +15 -5
- package/build/services/configReloadService.d.ts.map +1 -1
- package/build/services/configReloadService.js +31 -14
- package/build/services/configReloadService.js.map +1 -1
- package/build/transport/http/middlewares/errorHandler.d.ts.map +1 -0
- package/build/{server → transport/http/middlewares}/errorHandler.js +1 -1
- package/build/transport/http/middlewares/errorHandler.js.map +1 -0
- package/build/transport/http/middlewares/scopeAuthMiddleware.d.ts +42 -0
- package/build/transport/http/middlewares/scopeAuthMiddleware.d.ts.map +1 -0
- package/build/transport/http/middlewares/scopeAuthMiddleware.js +136 -0
- package/build/transport/http/middlewares/scopeAuthMiddleware.js.map +1 -0
- package/build/transport/http/middlewares/securityMiddleware.d.ts +30 -0
- package/build/transport/http/middlewares/securityMiddleware.d.ts.map +1 -0
- package/build/transport/http/middlewares/securityMiddleware.js +201 -0
- package/build/transport/http/middlewares/securityMiddleware.js.map +1 -0
- package/build/transport/http/middlewares/tagsExtractor.d.ts.map +1 -0
- package/build/transport/http/middlewares/tagsExtractor.js.map +1 -0
- package/build/transport/http/routes/oauthRoutes.d.ts +4 -0
- package/build/transport/http/routes/oauthRoutes.d.ts.map +1 -0
- package/build/transport/http/routes/oauthRoutes.js +474 -0
- package/build/transport/http/routes/oauthRoutes.js.map +1 -0
- package/build/transport/http/routes/sseRoutes.d.ts +4 -0
- package/build/transport/http/routes/sseRoutes.d.ts.map +1 -0
- package/build/{server → transport/http}/routes/sseRoutes.js +12 -10
- package/build/transport/http/routes/sseRoutes.js.map +1 -0
- package/build/transport/http/routes/streamableHttpRoutes.d.ts +4 -0
- package/build/transport/http/routes/streamableHttpRoutes.d.ts.map +1 -0
- package/build/{server → transport/http}/routes/streamableHttpRoutes.js +46 -13
- package/build/transport/http/routes/streamableHttpRoutes.js.map +1 -0
- package/build/{server/expressServer.d.ts → transport/http/server.d.ts} +5 -4
- package/build/transport/http/server.d.ts.map +1 -0
- package/build/{server/expressServer.js → transport/http/server.js} +60 -23
- package/build/transport/http/server.js.map +1 -0
- package/build/transport/transportFactory.d.ts +9 -0
- package/build/transport/transportFactory.d.ts.map +1 -0
- package/build/transport/transportFactory.js +148 -0
- package/build/transport/transportFactory.js.map +1 -0
- package/build/utils/clientFiltering.d.ts +4 -4
- package/build/utils/clientFiltering.d.ts.map +1 -1
- package/build/utils/clientFiltering.js +14 -14
- package/build/utils/clientFiltering.js.map +1 -1
- package/build/utils/errorHandling.d.ts +0 -11
- package/build/utils/errorHandling.d.ts.map +1 -1
- package/build/utils/errorHandling.js +1 -18
- package/build/utils/errorHandling.js.map +1 -1
- package/build/utils/errorTypes.js +4 -4
- package/build/utils/errorTypes.js.map +1 -1
- package/build/utils/pagination.d.ts +2 -2
- package/build/utils/pagination.d.ts.map +1 -1
- package/build/utils/pagination.js +87 -8
- package/build/utils/pagination.js.map +1 -1
- package/build/utils/parsing.d.ts +13 -0
- package/build/utils/parsing.d.ts.map +1 -0
- package/build/utils/parsing.js +32 -0
- package/build/utils/parsing.js.map +1 -0
- package/build/utils/sanitization.d.ts +60 -0
- package/build/utils/sanitization.d.ts.map +1 -0
- package/build/utils/sanitization.js +149 -0
- package/build/utils/sanitization.js.map +1 -0
- package/build/utils/scopeValidation.d.ts +102 -0
- package/build/utils/scopeValidation.d.ts.map +1 -0
- package/build/utils/scopeValidation.js +244 -0
- package/build/utils/scopeValidation.js.map +1 -0
- package/package.json +23 -9
- package/build/client.d.ts.map +0 -1
- package/build/client.js.map +0 -1
- package/build/clients/clientManager.d.ts.map +0 -1
- package/build/clients/clientManager.js +0 -147
- package/build/clients/clientManager.js.map +0 -1
- package/build/config/configManager.d.ts.map +0 -1
- package/build/config/configManager.js.map +0 -1
- package/build/config/transportConfig.d.ts +0 -7
- package/build/config/transportConfig.d.ts.map +0 -1
- package/build/config/transportConfig.js +0 -90
- package/build/config/transportConfig.js.map +0 -1
- package/build/middleware/loggingMiddleware.d.ts.map +0 -1
- package/build/middleware/loggingMiddleware.js.map +0 -1
- package/build/server/auth/authManager.d.ts +0 -109
- package/build/server/auth/authManager.d.ts.map +0 -1
- package/build/server/auth/authManager.js +0 -173
- package/build/server/auth/authManager.js.map +0 -1
- package/build/server/auth/authMiddleware.d.ts +0 -16
- package/build/server/auth/authMiddleware.d.ts.map +0 -1
- package/build/server/auth/authMiddleware.js +0 -45
- package/build/server/auth/authMiddleware.js.map +0 -1
- package/build/server/auth/sessionManager.d.ts.map +0 -1
- package/build/server/auth/sessionManager.js.map +0 -1
- package/build/server/config/serverConfig.d.ts.map +0 -1
- package/build/server/config/serverConfig.js +0 -117
- package/build/server/config/serverConfig.js.map +0 -1
- package/build/server/errorHandler.d.ts.map +0 -1
- package/build/server/errorHandler.js.map +0 -1
- package/build/server/expressServer.d.ts.map +0 -1
- package/build/server/expressServer.js.map +0 -1
- package/build/server/routes/oauthRoutes.d.ts +0 -14
- package/build/server/routes/oauthRoutes.d.ts.map +0 -1
- package/build/server/routes/oauthRoutes.js +0 -132
- package/build/server/routes/oauthRoutes.js.map +0 -1
- package/build/server/routes/sseRoutes.d.ts +0 -4
- package/build/server/routes/sseRoutes.d.ts.map +0 -1
- package/build/server/routes/sseRoutes.js.map +0 -1
- package/build/server/routes/streamableHttpRoutes.d.ts +0 -4
- package/build/server/routes/streamableHttpRoutes.d.ts.map +0 -1
- package/build/server/routes/streamableHttpRoutes.js.map +0 -1
- package/build/server/tagsExtractor.d.ts.map +0 -1
- package/build/server/tagsExtractor.js.map +0 -1
- package/build/serverManager.d.ts +0 -27
- package/build/serverManager.d.ts.map +0 -1
- package/build/serverManager.js +0 -87
- package/build/serverManager.js.map +0 -1
- package/build/types.d.ts.map +0 -1
- package/build/types.js.map +0 -1
- /package/build/{server → transport/http/middlewares}/errorHandler.d.ts +0 -0
- /package/build/{server → transport/http/middlewares}/tagsExtractor.d.ts +0 -0
- /package/build/{server → transport/http/middlewares}/tagsExtractor.js +0 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import logger from '../logger/logger.js';
|
|
3
|
+
import { ServerSessionManager } from './serverSessionManager.js';
|
|
4
|
+
import { AgentConfigManager } from '../core/server/agentConfig.js';
|
|
5
|
+
import { AUTH_CONFIG } from '../constants.js';
|
|
6
|
+
import { validateScopesAgainstAvailableTags, tagsToScopes, scopesToTags, auditScopeOperation, } from '../utils/scopeValidation.js';
|
|
7
|
+
import { McpConfigManager } from '../config/mcpConfigManager.js';
|
|
8
|
+
/**
|
|
9
|
+
* File-based OAuth clients store implementation using AUTH_CONFIG settings
|
|
10
|
+
*/
|
|
11
|
+
class FileBasedClientsStore {
|
|
12
|
+
sessionManager;
|
|
13
|
+
constructor(sessionManager) {
|
|
14
|
+
this.sessionManager = sessionManager;
|
|
15
|
+
}
|
|
16
|
+
getClient(clientId) {
|
|
17
|
+
const clientKey = this.getClientKey(clientId);
|
|
18
|
+
const clientSession = this.sessionManager.getSession(clientKey);
|
|
19
|
+
if (!clientSession?.data) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(clientSession.data);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
logger.error(`Failed to parse client data for ${clientId}:`, error);
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
registerClient(client) {
|
|
31
|
+
const clientKey = this.getClientKey(client.client_id);
|
|
32
|
+
// Store client for 30 days (same as original implementation)
|
|
33
|
+
const ttlMs = AUTH_CONFIG.CLIENT.OAUTH.TTL_MS;
|
|
34
|
+
try {
|
|
35
|
+
this.sessionManager.createSessionWithData(clientKey, JSON.stringify(client), ttlMs);
|
|
36
|
+
logger.info(`Registered OAuth client: ${client.client_id}`);
|
|
37
|
+
return client;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
logger.error(`Failed to register client ${client.client_id}:`, error);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
getClientKey(clientId) {
|
|
45
|
+
// Create a deterministic UUID-like key from the client ID for consistent retrieval
|
|
46
|
+
// We need to ensure this passes the session ID validation which expects sess- + UUID format
|
|
47
|
+
const hashInput = `${AUTH_CONFIG.CLIENT.PREFIXES.CLIENT}${clientId}`;
|
|
48
|
+
// Generate a deterministic UUID-like string using a simple hash
|
|
49
|
+
const hash = this.hashToUuid(hashInput);
|
|
50
|
+
return `sess-${hash}`;
|
|
51
|
+
}
|
|
52
|
+
hashToUuid(input) {
|
|
53
|
+
// Simple hash to UUID conversion (not cryptographically secure, but deterministic)
|
|
54
|
+
// Validate input is actually a string to prevent DoS attacks
|
|
55
|
+
if (typeof input !== 'string') {
|
|
56
|
+
throw new Error('Input must be a string');
|
|
57
|
+
}
|
|
58
|
+
// Limit input length to prevent DoS attacks
|
|
59
|
+
const maxLength = 1000;
|
|
60
|
+
// Use Math.min to ensure we never exceed maxLength, even if length property is malicious
|
|
61
|
+
const actualLength = Math.min(input.length, maxLength);
|
|
62
|
+
const safeInput = input.substring(0, actualLength);
|
|
63
|
+
let hash = 0;
|
|
64
|
+
// Use actualLength instead of safeInput.length to avoid potential issues
|
|
65
|
+
for (let i = 0; i < actualLength; i++) {
|
|
66
|
+
const char = safeInput.charCodeAt(i);
|
|
67
|
+
hash = (hash << 5) - hash + char;
|
|
68
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
69
|
+
}
|
|
70
|
+
// Convert hash to a UUID-like format
|
|
71
|
+
const hashStr = Math.abs(hash).toString(16).padStart(8, '0');
|
|
72
|
+
const uuid = `${hashStr.slice(0, 8)}-${hashStr.slice(0, 4)}-4${hashStr.slice(1, 4)}-8${hashStr.slice(4, 7)}-${hashStr.repeat(3).slice(0, 12)}`;
|
|
73
|
+
return uuid;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Implementation of SDK's OAuthServerProvider interface using existing SessionManager.
|
|
78
|
+
*
|
|
79
|
+
* This provider implements OAuth 2.1 server functionality using the MCP SDK's interfaces
|
|
80
|
+
* while maintaining compatibility with the existing session storage system.
|
|
81
|
+
*/
|
|
82
|
+
export class SDKOAuthServerProvider {
|
|
83
|
+
sessionManager;
|
|
84
|
+
configManager;
|
|
85
|
+
_clientsStore;
|
|
86
|
+
constructor(sessionStoragePath) {
|
|
87
|
+
this.sessionManager = new ServerSessionManager(sessionStoragePath);
|
|
88
|
+
this.configManager = AgentConfigManager.getInstance();
|
|
89
|
+
this._clientsStore = new FileBasedClientsStore(this.sessionManager);
|
|
90
|
+
}
|
|
91
|
+
get clientsStore() {
|
|
92
|
+
return this._clientsStore;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Handles the authorization request with scope validation and user consent
|
|
96
|
+
*/
|
|
97
|
+
async authorize(client, params, res) {
|
|
98
|
+
logger.debug('Authorizing client', { clientId: client.client_id, params });
|
|
99
|
+
try {
|
|
100
|
+
// Get requested scopes (default to all available tags if none specified)
|
|
101
|
+
const requestedScopes = params.scopes || [];
|
|
102
|
+
const configManager = McpConfigManager.getInstance();
|
|
103
|
+
const availableTags = configManager.getAvailableTags();
|
|
104
|
+
// If no scopes requested, default to all available tags
|
|
105
|
+
const finalScopes = requestedScopes.length > 0 ? requestedScopes : tagsToScopes(availableTags);
|
|
106
|
+
// Validate requested scopes against available tags
|
|
107
|
+
const validation = validateScopesAgainstAvailableTags(finalScopes, availableTags);
|
|
108
|
+
if (!validation.isValid) {
|
|
109
|
+
auditScopeOperation('scope_validation_failed', {
|
|
110
|
+
clientId: client.client_id,
|
|
111
|
+
requestedScopes: finalScopes,
|
|
112
|
+
success: false,
|
|
113
|
+
error: validation.errors.join(', '),
|
|
114
|
+
});
|
|
115
|
+
logger.warn(`Invalid scopes requested by client ${client.client_id}`, {
|
|
116
|
+
requestedScopes: finalScopes,
|
|
117
|
+
errors: validation.errors,
|
|
118
|
+
});
|
|
119
|
+
res.status(400).json({
|
|
120
|
+
error: 'invalid_scope',
|
|
121
|
+
error_description: `Invalid scopes: ${validation.errors.join(', ')}`,
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Check if this is a direct authorization (auto-approve) or requires user consent
|
|
126
|
+
const requiresUserConsent = this.requiresUserConsent(client, finalScopes);
|
|
127
|
+
if (requiresUserConsent) {
|
|
128
|
+
// Show consent page
|
|
129
|
+
await this.renderConsentPage(client, params, finalScopes, availableTags, res);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Auto-approve with validated scopes
|
|
133
|
+
await this.approveAuthorization(client, params, validation.validScopes, res);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
logger.error('Authorization error:', error);
|
|
138
|
+
res.status(500).json({ error: 'server_error', error_description: 'Internal server error' });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Determines if user consent is required for the authorization
|
|
143
|
+
*/
|
|
144
|
+
requiresUserConsent(client, scopes) {
|
|
145
|
+
logger.debug('Requires user consent', { clientId: client.client_id, scopes });
|
|
146
|
+
// For now, always require user consent for security
|
|
147
|
+
// In the future, this could be configurable based on client trust level
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Renders the consent page for scope selection
|
|
152
|
+
*/
|
|
153
|
+
async renderConsentPage(client, params, requestedScopes, availableTags, res) {
|
|
154
|
+
const scopeTags = scopesToTags(requestedScopes);
|
|
155
|
+
const consentPageHtml = this.generateConsentPageHtml(client, params, scopeTags, availableTags);
|
|
156
|
+
// Remove any CSP that might interfere with form submission
|
|
157
|
+
res.removeHeader('Content-Security-Policy');
|
|
158
|
+
res.set('Content-Type', 'text/html');
|
|
159
|
+
res.send(consentPageHtml);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Approves the authorization and redirects back to client
|
|
163
|
+
*/
|
|
164
|
+
async approveAuthorization(client, params, grantedScopes, res) {
|
|
165
|
+
logger.debug('Approving authorization', { clientId: client.client_id, params, grantedScopes });
|
|
166
|
+
// Create authorization code with granted scopes
|
|
167
|
+
const metadata = {
|
|
168
|
+
scopes: grantedScopes,
|
|
169
|
+
resource: params.resource?.toString() || '',
|
|
170
|
+
codeChallenge: params.codeChallenge,
|
|
171
|
+
redirectUri: params.redirectUri,
|
|
172
|
+
};
|
|
173
|
+
const ttlMs = this.configManager.getOAuthCodeTtlMs();
|
|
174
|
+
const code = this.sessionManager.createAuthCode(client.client_id, params.redirectUri, JSON.stringify(metadata), ttlMs);
|
|
175
|
+
// Build redirect URL
|
|
176
|
+
const redirectUrl = new URL(params.redirectUri);
|
|
177
|
+
redirectUrl.searchParams.set('code', code);
|
|
178
|
+
if (params.state) {
|
|
179
|
+
redirectUrl.searchParams.set('state', params.state);
|
|
180
|
+
}
|
|
181
|
+
auditScopeOperation('authorization_granted', {
|
|
182
|
+
clientId: client.client_id,
|
|
183
|
+
requestedScopes: params.scopes || [],
|
|
184
|
+
grantedScopes,
|
|
185
|
+
success: true,
|
|
186
|
+
});
|
|
187
|
+
logger.info(`OAuth authorization granted for client ${client.client_id}`, {
|
|
188
|
+
clientId: client.client_id,
|
|
189
|
+
redirectUri: params.redirectUri,
|
|
190
|
+
grantedScopes,
|
|
191
|
+
});
|
|
192
|
+
res.redirect(redirectUrl.toString());
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Generates the HTML for the consent page
|
|
196
|
+
*/
|
|
197
|
+
generateConsentPageHtml(client, params, requestedTags, availableTags) {
|
|
198
|
+
const clientName = client.client_name || client.client_id;
|
|
199
|
+
return `
|
|
200
|
+
<!DOCTYPE html>
|
|
201
|
+
<html>
|
|
202
|
+
<head>
|
|
203
|
+
<title>Authorize ${clientName}</title>
|
|
204
|
+
<meta charset="utf-8">
|
|
205
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
206
|
+
<style>
|
|
207
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
|
|
208
|
+
.container { max-width: 500px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
|
209
|
+
h1 { color: #333; margin-bottom: 20px; }
|
|
210
|
+
.app-info { background: #f8f9fa; padding: 15px; border-radius: 6px; margin-bottom: 20px; }
|
|
211
|
+
.scopes-section { margin-bottom: 25px; }
|
|
212
|
+
.scope-item { display: flex; align-items: center; margin-bottom: 10px; }
|
|
213
|
+
.scope-item input { margin-right: 10px; }
|
|
214
|
+
.scope-item label { flex: 1; }
|
|
215
|
+
.tag-description { font-size: 0.9em; color: #666; margin-left: 25px; }
|
|
216
|
+
.buttons { display: flex; gap: 10px; justify-content: flex-end; }
|
|
217
|
+
.btn { padding: 10px 20px; border-radius: 4px; font-size: 14px; cursor: pointer; }
|
|
218
|
+
.btn-primary { background: #007bff; color: white; border: none; }
|
|
219
|
+
.btn-secondary { background: #6c757d; color: white; border: none; }
|
|
220
|
+
.btn:hover { opacity: 0.9; }
|
|
221
|
+
.security-notice { background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; border-radius: 4px; margin-bottom: 20px; }
|
|
222
|
+
</style>
|
|
223
|
+
</head>
|
|
224
|
+
<body>
|
|
225
|
+
<div class="container">
|
|
226
|
+
<h1>Authorize Application</h1>
|
|
227
|
+
|
|
228
|
+
<div class="app-info">
|
|
229
|
+
<strong>${clientName}</strong> is requesting access to your MCP servers.
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<div class="security-notice">
|
|
233
|
+
<strong>Security Notice:</strong> Only grant access to server groups that this application needs.
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<form method="POST" action="/oauth/consent">
|
|
237
|
+
<input type="hidden" name="client_id" value="${client.client_id}">
|
|
238
|
+
<input type="hidden" name="redirect_uri" value="${params.redirectUri}">
|
|
239
|
+
<input type="hidden" name="code_challenge" value="${params.codeChallenge || ''}">
|
|
240
|
+
<input type="hidden" name="code_challenge_method" value="S256">
|
|
241
|
+
<input type="hidden" name="state" value="${params.state || ''}">
|
|
242
|
+
<input type="hidden" name="resource" value="${params.resource?.toString() || ''}">
|
|
243
|
+
|
|
244
|
+
<div class="scopes-section">
|
|
245
|
+
<h3>Server Access Permissions</h3>
|
|
246
|
+
<p>Select which server groups this application can access:</p>
|
|
247
|
+
|
|
248
|
+
${availableTags
|
|
249
|
+
.map((tag) => `
|
|
250
|
+
<div class="scope-item">
|
|
251
|
+
<input type="checkbox"
|
|
252
|
+
id="scope_${tag}"
|
|
253
|
+
name="scopes"
|
|
254
|
+
value="tag:${tag}"
|
|
255
|
+
${requestedTags.includes(tag) ? 'checked' : ''}>
|
|
256
|
+
<label for="scope_${tag}">
|
|
257
|
+
<strong>${tag}</strong> servers
|
|
258
|
+
</label>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="tag-description">
|
|
261
|
+
Access servers tagged with "${tag}"
|
|
262
|
+
</div>
|
|
263
|
+
`)
|
|
264
|
+
.join('')}
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div class="buttons">
|
|
268
|
+
<button type="submit" name="action" value="deny" class="btn btn-secondary">Deny</button>
|
|
269
|
+
<button type="submit" name="action" value="approve" class="btn btn-primary">Approve</button>
|
|
270
|
+
</div>
|
|
271
|
+
</form>
|
|
272
|
+
</div>
|
|
273
|
+
</body>
|
|
274
|
+
</html>
|
|
275
|
+
`;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Retrieves the PKCE challenge for an authorization code
|
|
279
|
+
*/
|
|
280
|
+
async challengeForAuthorizationCode(client, authorizationCode) {
|
|
281
|
+
logger.debug('Challenge for authorization code', { clientId: client.client_id, authorizationCode });
|
|
282
|
+
const codeData = this.sessionManager.getAuthCode(authorizationCode);
|
|
283
|
+
if (!codeData || codeData.clientId !== client.client_id) {
|
|
284
|
+
throw new Error('Invalid authorization code');
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const metadata = JSON.parse(codeData.resource);
|
|
288
|
+
return metadata.codeChallenge || '';
|
|
289
|
+
}
|
|
290
|
+
catch (_e) {
|
|
291
|
+
return '';
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Exchanges authorization code for access token
|
|
296
|
+
*/
|
|
297
|
+
async exchangeAuthorizationCode(client, authorizationCode,
|
|
298
|
+
// Note: code verifier is checked in SDK's token.ts by default
|
|
299
|
+
// it's unused here for that reason.
|
|
300
|
+
_codeVerifier, redirectUri, resource) {
|
|
301
|
+
logger.debug('Exchanging authorization code', {
|
|
302
|
+
clientId: client.client_id,
|
|
303
|
+
authorizationCode,
|
|
304
|
+
redirectUri,
|
|
305
|
+
resource,
|
|
306
|
+
});
|
|
307
|
+
const codeData = this.sessionManager.getAuthCode(authorizationCode);
|
|
308
|
+
if (!codeData) {
|
|
309
|
+
throw new Error('Invalid or expired authorization code');
|
|
310
|
+
}
|
|
311
|
+
// Validate client ID
|
|
312
|
+
if (codeData.clientId !== client.client_id) {
|
|
313
|
+
throw new Error('Client ID mismatch');
|
|
314
|
+
}
|
|
315
|
+
// Validate redirect URI if provided
|
|
316
|
+
if (redirectUri && codeData.redirectUri !== redirectUri) {
|
|
317
|
+
throw new Error('Redirect URI mismatch');
|
|
318
|
+
}
|
|
319
|
+
// Parse metadata to check PKCE and other parameters
|
|
320
|
+
let metadata = {};
|
|
321
|
+
try {
|
|
322
|
+
metadata = JSON.parse(codeData.resource);
|
|
323
|
+
}
|
|
324
|
+
catch (_e) {
|
|
325
|
+
// Legacy format, treat as plain resource string
|
|
326
|
+
metadata = { resource: codeData.resource };
|
|
327
|
+
}
|
|
328
|
+
// Validate resource if provided
|
|
329
|
+
if (resource && metadata.resource && metadata.resource !== resource.toString()) {
|
|
330
|
+
throw new Error('Resource mismatch');
|
|
331
|
+
}
|
|
332
|
+
// Delete the authorization code (one-time use)
|
|
333
|
+
this.sessionManager.deleteAuthCode(authorizationCode);
|
|
334
|
+
// Create access token
|
|
335
|
+
const tokenId = randomUUID();
|
|
336
|
+
const accessToken = AUTH_CONFIG.SERVER.PREFIXES.ACCESS_TOKEN + tokenId;
|
|
337
|
+
const ttlMs = this.configManager.getOAuthTokenTtlMs();
|
|
338
|
+
// Store session for token validation
|
|
339
|
+
this.sessionManager.createSessionWithId(tokenId, client.client_id, metadata.resource || '', ttlMs);
|
|
340
|
+
const tokens = {
|
|
341
|
+
access_token: accessToken,
|
|
342
|
+
token_type: 'Bearer',
|
|
343
|
+
expires_in: Math.floor(ttlMs / 1000),
|
|
344
|
+
scope: metadata.scopes ? metadata.scopes.join(' ') : '',
|
|
345
|
+
};
|
|
346
|
+
logger.info(`Exchanged authorization code for access token`, {
|
|
347
|
+
clientId: client.client_id,
|
|
348
|
+
tokenId: tokenId.substring(0, 8) + '...',
|
|
349
|
+
expiresIn: tokens.expires_in,
|
|
350
|
+
});
|
|
351
|
+
return tokens;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Exchanges refresh token for new access token (not implemented)
|
|
355
|
+
*/
|
|
356
|
+
async exchangeRefreshToken(_client, _refreshToken, _scopes, _resource) {
|
|
357
|
+
throw new Error('Refresh tokens not supported');
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Verifies access token and returns auth info with granted scopes
|
|
361
|
+
*/
|
|
362
|
+
async verifyAccessToken(token) {
|
|
363
|
+
logger.debug('Verifying access token', { token });
|
|
364
|
+
if (!this.configManager.isAuthEnabled()) {
|
|
365
|
+
// Auth disabled, return minimal auth info with all available tags as scopes
|
|
366
|
+
const configManager = McpConfigManager.getInstance();
|
|
367
|
+
const availableTags = configManager.getAvailableTags();
|
|
368
|
+
return {
|
|
369
|
+
token,
|
|
370
|
+
clientId: 'anonymous',
|
|
371
|
+
scopes: tagsToScopes(availableTags),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// Strip prefix if present
|
|
375
|
+
const tokenId = token.startsWith(AUTH_CONFIG.SERVER.PREFIXES.ACCESS_TOKEN)
|
|
376
|
+
? token.slice(AUTH_CONFIG.SERVER.PREFIXES.ACCESS_TOKEN.length)
|
|
377
|
+
: token;
|
|
378
|
+
// Get session data
|
|
379
|
+
const sessionId = AUTH_CONFIG.SERVER.PREFIXES.SESSION_ID + tokenId;
|
|
380
|
+
const sessionData = this.sessionManager.getSession(sessionId);
|
|
381
|
+
if (!sessionData) {
|
|
382
|
+
throw new Error('Invalid or expired access token');
|
|
383
|
+
}
|
|
384
|
+
// Extract scopes from session resource (stored during authorization)
|
|
385
|
+
let scopes = [];
|
|
386
|
+
if (sessionData.resource) {
|
|
387
|
+
try {
|
|
388
|
+
const metadata = JSON.parse(sessionData.resource);
|
|
389
|
+
scopes = metadata.scopes || [];
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
logger.warn(`Failed to parse session metadata for token ${tokenId}:`, error);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
token,
|
|
397
|
+
clientId: sessionData.clientId,
|
|
398
|
+
scopes,
|
|
399
|
+
expiresAt: sessionData.expires,
|
|
400
|
+
resource: sessionData.resource ? new URL(sessionData.resource) : undefined,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Revokes a token
|
|
405
|
+
*/
|
|
406
|
+
async revokeToken(client, request) {
|
|
407
|
+
logger.debug('Revoking token', { clientId: client.client_id, request });
|
|
408
|
+
const token = request.token;
|
|
409
|
+
// Strip prefix if present
|
|
410
|
+
const tokenId = token.startsWith(AUTH_CONFIG.SERVER.PREFIXES.ACCESS_TOKEN)
|
|
411
|
+
? token.slice(AUTH_CONFIG.SERVER.PREFIXES.ACCESS_TOKEN.length)
|
|
412
|
+
: token;
|
|
413
|
+
const sessionId = AUTH_CONFIG.SERVER.PREFIXES.SESSION_ID + tokenId;
|
|
414
|
+
const success = this.sessionManager.deleteSession(sessionId);
|
|
415
|
+
if (success) {
|
|
416
|
+
logger.info(`Revoked access token for client ${client.client_id}`, {
|
|
417
|
+
tokenId: tokenId.substring(0, 8) + '...',
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Graceful shutdown
|
|
423
|
+
*/
|
|
424
|
+
shutdown() {
|
|
425
|
+
this.sessionManager.shutdown();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=sdkOAuthServerProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdkOAuthServerProvider.js","sourceRoot":"","sources":["../../src/auth/sdkOAuthServerProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,37 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Represents session data stored for access tokens.
|
|
3
|
-
*
|
|
4
|
-
* Contains all necessary information to validate and manage user sessions
|
|
5
|
-
* including client identification, resource access, and expiration details.
|
|
6
|
-
*/
|
|
7
|
-
export interface SessionData {
|
|
8
|
-
/** The client ID that owns this session */
|
|
9
|
-
clientId: string;
|
|
10
|
-
/** The resource this session has access to */
|
|
11
|
-
resource: string;
|
|
12
|
-
/** Unix timestamp when this session expires */
|
|
13
|
-
expires: number;
|
|
14
|
-
/** Unix timestamp when this session was created */
|
|
15
|
-
createdAt: number;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Represents authorization code data for OAuth 2.1 flow.
|
|
19
|
-
*
|
|
20
|
-
* Contains information about authorization codes used in the OAuth
|
|
21
|
-
* authorization code grant flow, including client and redirect details.
|
|
22
|
-
*/
|
|
23
|
-
export interface AuthCodeData {
|
|
24
|
-
/** The client ID that requested this authorization code */
|
|
25
|
-
clientId: string;
|
|
26
|
-
/** The redirect URI where the code should be used */
|
|
27
|
-
redirectUri: string;
|
|
28
|
-
/** The resource this code grants access to */
|
|
29
|
-
resource: string;
|
|
30
|
-
/** Unix timestamp when this code expires */
|
|
31
|
-
expires: number;
|
|
32
|
-
/** Unix timestamp when this code was created */
|
|
33
|
-
createdAt: number;
|
|
34
|
-
}
|
|
1
|
+
import { SessionData, AuthCodeData } from './sessionTypes.js';
|
|
35
2
|
/**
|
|
36
3
|
* SessionManager handles file-based session storage with automatic cleanup.
|
|
37
4
|
*
|
|
@@ -52,7 +19,7 @@ export interface AuthCodeData {
|
|
|
52
19
|
* const session = sessionManager.getSession(sessionId);
|
|
53
20
|
* ```
|
|
54
21
|
*/
|
|
55
|
-
export declare class
|
|
22
|
+
export declare class ServerSessionManager {
|
|
56
23
|
private sessionStoragePath;
|
|
57
24
|
private cleanupInterval;
|
|
58
25
|
/**
|
|
@@ -64,6 +31,12 @@ export declare class SessionManager {
|
|
|
64
31
|
* @param sessionStoragePath - Optional custom path for session storage
|
|
65
32
|
*/
|
|
66
33
|
constructor(sessionStoragePath?: string);
|
|
34
|
+
/**
|
|
35
|
+
* Gets the session storage path.
|
|
36
|
+
*
|
|
37
|
+
* @returns The absolute path to the session storage directory
|
|
38
|
+
*/
|
|
39
|
+
getSessionStoragePath(): string;
|
|
67
40
|
/**
|
|
68
41
|
* Ensures the session storage directory exists.
|
|
69
42
|
*
|
|
@@ -88,7 +61,8 @@ export declare class SessionManager {
|
|
|
88
61
|
*/
|
|
89
62
|
private getAuthCodeFilePath;
|
|
90
63
|
/**
|
|
91
|
-
* Utility to validate session IDs and auth codes for
|
|
64
|
+
* Utility to validate session IDs and auth codes for proper format and security.
|
|
65
|
+
* Ensures proper format with prefix and UUID structure for security.
|
|
92
66
|
* @param id - The session ID or auth code to validate
|
|
93
67
|
* @returns true if valid, false otherwise
|
|
94
68
|
*/
|
|
@@ -173,6 +147,10 @@ export declare class SessionManager {
|
|
|
173
147
|
* by removing them to prevent future errors.
|
|
174
148
|
*/
|
|
175
149
|
private cleanupExpiredSessions;
|
|
150
|
+
/**
|
|
151
|
+
* Cleans up expired server sessions and authorization codes.
|
|
152
|
+
*/
|
|
153
|
+
private cleanupExpiredServerSessions;
|
|
176
154
|
/**
|
|
177
155
|
* Performs graceful shutdown of the SessionManager.
|
|
178
156
|
*
|
|
@@ -192,5 +170,16 @@ export declare class SessionManager {
|
|
|
192
170
|
* @throws Error if session creation fails
|
|
193
171
|
*/
|
|
194
172
|
createSessionWithId(tokenId: string, clientId: string, resource: string, ttlMs: number): string;
|
|
173
|
+
/**
|
|
174
|
+
* Creates a new session with custom data.
|
|
175
|
+
* Used for OAuth client data storage where arbitrary data needs to be stored.
|
|
176
|
+
*
|
|
177
|
+
* @param sessionId - The session ID to use
|
|
178
|
+
* @param data - The custom data to store
|
|
179
|
+
* @param ttlMs - Time-to-live in milliseconds
|
|
180
|
+
* @returns The session ID
|
|
181
|
+
* @throws Error if session creation fails
|
|
182
|
+
*/
|
|
183
|
+
createSessionWithData(sessionId: string, data: string, ttlMs: number): string;
|
|
195
184
|
}
|
|
196
|
-
//# sourceMappingURL=
|
|
185
|
+
//# sourceMappingURL=serverSessionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverSessionManager.d.ts","sourceRoot":"","sources":["../../src/auth/serverSessionManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,eAAe,CAA+C;IAEtE;;;;;;;OAOG;gBACS,kBAAkB,CAAC,EAAE,MAAM;IAOvC;;;;OAIG;IACI,qBAAqB,IAAI,MAAM;IAItC;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAoCjB;;;;;;;;;;;OAWG;IACI,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAoB/E;;;;;;;;OAQG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IA0BxD;;;;;;;OAOG;IACI,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAmBhD;;;;;;;;;;;;OAYG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAqBrG;;;;;;;;OAQG;IACI,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IA0BrD;;;;;;;OAOG;IACI,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAmB5C;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAqCpC;;;;;OAKG;IACI,QAAQ,IAAI,IAAI;IAOvB;;;;;;;;;;OAUG;IACI,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAoBtG;;;;;;;;;OASG;IACI,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;CAmBrF"}
|