@elnora-ai/mcp-server 0.1.0 → 0.2.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 (70) hide show
  1. package/README.md +2 -2
  2. package/dist/auth/clients-store.d.ts +13 -0
  3. package/dist/auth/clients-store.d.ts.map +1 -0
  4. package/dist/auth/clients-store.js +35 -0
  5. package/dist/auth/clients-store.js.map +1 -0
  6. package/dist/auth/provider.d.ts +55 -0
  7. package/dist/auth/provider.d.ts.map +1 -0
  8. package/dist/auth/provider.js +234 -0
  9. package/dist/auth/provider.js.map +1 -0
  10. package/dist/constants.d.ts +7 -2
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +18 -4
  13. package/dist/constants.js.map +1 -1
  14. package/dist/index.js +81 -13
  15. package/dist/index.js.map +1 -1
  16. package/dist/middleware/cors.d.ts +11 -0
  17. package/dist/middleware/cors.d.ts.map +1 -0
  18. package/dist/middleware/cors.js +42 -0
  19. package/dist/middleware/cors.js.map +1 -0
  20. package/dist/middleware/rate-limiter.d.ts +13 -0
  21. package/dist/middleware/rate-limiter.d.ts.map +1 -0
  22. package/dist/middleware/rate-limiter.js +59 -0
  23. package/dist/middleware/rate-limiter.js.map +1 -0
  24. package/dist/middleware/tool-logging.d.ts +11 -0
  25. package/dist/middleware/tool-logging.d.ts.map +1 -0
  26. package/dist/middleware/tool-logging.js +40 -0
  27. package/dist/middleware/tool-logging.js.map +1 -0
  28. package/dist/server.d.ts +6 -1
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +10 -6
  31. package/dist/server.js.map +1 -1
  32. package/dist/services/elnora-api-client.d.ts +0 -2
  33. package/dist/services/elnora-api-client.d.ts.map +1 -1
  34. package/dist/services/elnora-api-client.js +0 -4
  35. package/dist/services/elnora-api-client.js.map +1 -1
  36. package/dist/tools/files.d.ts +2 -1
  37. package/dist/tools/files.d.ts.map +1 -1
  38. package/dist/tools/files.js +8 -7
  39. package/dist/tools/files.js.map +1 -1
  40. package/dist/tools/messages.d.ts +2 -1
  41. package/dist/tools/messages.d.ts.map +1 -1
  42. package/dist/tools/messages.js +5 -4
  43. package/dist/tools/messages.js.map +1 -1
  44. package/dist/tools/protocols.d.ts +2 -1
  45. package/dist/tools/protocols.d.ts.map +1 -1
  46. package/dist/tools/protocols.js +4 -3
  47. package/dist/tools/protocols.js.map +1 -1
  48. package/dist/tools/scope-guard.d.ts +19 -0
  49. package/dist/tools/scope-guard.d.ts.map +1 -0
  50. package/dist/tools/scope-guard.js +33 -0
  51. package/dist/tools/scope-guard.js.map +1 -0
  52. package/dist/tools/tasks.d.ts +2 -1
  53. package/dist/tools/tasks.d.ts.map +1 -1
  54. package/dist/tools/tasks.js +8 -7
  55. package/dist/tools/tasks.js.map +1 -1
  56. package/dist/tools/with-guard.d.ts +19 -0
  57. package/dist/tools/with-guard.d.ts.map +1 -0
  58. package/dist/tools/with-guard.js +32 -0
  59. package/dist/tools/with-guard.js.map +1 -0
  60. package/dist/types.d.ts +32 -0
  61. package/dist/types.d.ts.map +1 -1
  62. package/package.json +5 -4
  63. package/dist/auth/middleware.d.ts +0 -12
  64. package/dist/auth/middleware.d.ts.map +0 -1
  65. package/dist/auth/middleware.js +0 -40
  66. package/dist/auth/middleware.js.map +0 -1
  67. package/dist/auth/protected-resource.d.ts +0 -4
  68. package/dist/auth/protected-resource.d.ts.map +0 -1
  69. package/dist/auth/protected-resource.js +0 -19
  70. package/dist/auth/protected-resource.js.map +0 -1
package/README.md CHANGED
@@ -15,7 +15,7 @@ Add the Elnora MCP server to your AI client. No installation required — just p
15
15
  ### Claude Code
16
16
 
17
17
  ```bash
18
- claude mcp add elnora --transport streamable-http https://mcp.elnora.ai/mcp
18
+ claude mcp add elnora --transport http https://mcp.elnora.ai/mcp
19
19
  ```
20
20
 
21
21
  ### Cursor
@@ -40,7 +40,7 @@ Add to your `.vscode/mcp.json`:
40
40
  {
41
41
  "servers": {
42
42
  "elnora": {
43
- "type": "streamable-http",
43
+ "type": "http",
44
44
  "url": "https://mcp.elnora.ai/mcp"
45
45
  }
46
46
  }
@@ -0,0 +1,13 @@
1
+ import { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
2
+ import { OAuthClientInformationFull } from "@modelcontextprotocol/sdk/shared/auth.js";
3
+ /**
4
+ * In-memory OAuth client store supporting Dynamic Client Registration (RFC 7591).
5
+ *
6
+ * For single-instance deployments (ECS). Migrate to Redis/DynamoDB for multi-instance.
7
+ */
8
+ export declare class InMemoryClientsStore implements OAuthRegisteredClientsStore {
9
+ private clients;
10
+ getClient(clientId: string): OAuthClientInformationFull | undefined;
11
+ registerClient(client: Omit<OAuthClientInformationFull, "client_id" | "client_id_issued_at">): OAuthClientInformationFull;
12
+ }
13
+ //# sourceMappingURL=clients-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients-store.d.ts","sourceRoot":"","sources":["../../src/auth/clients-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AAGtF;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,2BAA2B;IACtE,OAAO,CAAC,OAAO,CAAiD;IAEhE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAYnE,cAAc,CACZ,MAAM,EAAE,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,qBAAqB,CAAC,GAC5E,0BAA0B;CAgB9B"}
@@ -0,0 +1,35 @@
1
+ import crypto from "node:crypto";
2
+ import { CLIENT_SECRET_TTL_SECONDS } from "../constants.js";
3
+ /**
4
+ * In-memory OAuth client store supporting Dynamic Client Registration (RFC 7591).
5
+ *
6
+ * For single-instance deployments (ECS). Migrate to Redis/DynamoDB for multi-instance.
7
+ */
8
+ export class InMemoryClientsStore {
9
+ clients = new Map();
10
+ getClient(clientId) {
11
+ const client = this.clients.get(clientId);
12
+ if (!client)
13
+ return undefined;
14
+ // Check secret expiration (per SDK docs: don't delete, just check)
15
+ if (client.client_secret_expires_at && client.client_secret_expires_at < Math.floor(Date.now() / 1000)) {
16
+ return undefined;
17
+ }
18
+ return client;
19
+ }
20
+ registerClient(client) {
21
+ const clientId = crypto.randomUUID();
22
+ const clientSecret = crypto.randomBytes(32).toString("base64url");
23
+ const now = Math.floor(Date.now() / 1000);
24
+ const registered = {
25
+ ...client,
26
+ client_id: clientId,
27
+ client_id_issued_at: now,
28
+ client_secret: clientSecret,
29
+ client_secret_expires_at: now + CLIENT_SECRET_TTL_SECONDS,
30
+ };
31
+ this.clients.set(clientId, registered);
32
+ return registered;
33
+ }
34
+ }
35
+ //# sourceMappingURL=clients-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients-store.js","sourceRoot":"","sources":["../../src/auth/clients-store.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAE5D;;;;GAIG;AACH,MAAM,OAAO,oBAAoB;IACvB,OAAO,GAAG,IAAI,GAAG,EAAsC,CAAC;IAEhE,SAAS,CAAC,QAAgB;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAE9B,mEAAmE;QACnE,IAAI,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,wBAAwB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACvG,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,cAAc,CACZ,MAA6E;QAE7E,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAE1C,MAAM,UAAU,GAA+B;YAC7C,GAAG,MAAM;YACT,SAAS,EAAE,QAAQ;YACnB,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,YAAY;YAC3B,wBAAwB,EAAE,GAAG,GAAG,yBAAyB;SAC1D,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACvC,OAAO,UAAU,CAAC;IACpB,CAAC;CACF"}
@@ -0,0 +1,55 @@
1
+ import { Response } from "express";
2
+ import { OAuthServerProvider, AuthorizationParams } from "@modelcontextprotocol/sdk/server/auth/provider.js";
3
+ import { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
4
+ import { OAuthClientInformationFull, OAuthTokens, OAuthTokenRevocationRequest } from "@modelcontextprotocol/sdk/shared/auth.js";
5
+ import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
6
+ import { ElnoraConfig } from "../types.js";
7
+ /**
8
+ * OAuth 2.1 provider that proxies to the Elnora platform auth system.
9
+ *
10
+ * Flow:
11
+ * 1. MCP client calls /authorize → provider redirects to Elnora platform login
12
+ * 2. User authenticates on platform → platform redirects back with platform auth code
13
+ * 3. MCP server exchanges platform code for platform token
14
+ * 4. MCP server issues its own access + refresh tokens, mapped to the platform token
15
+ * 5. On token validation, the provider checks its own token store and validates
16
+ * the underlying platform token hasn't been revoked
17
+ *
18
+ * CoSAI controls:
19
+ * - MCP-T1: PKCE S256 mandatory (handled by SDK)
20
+ * - MCP-T1: No token passthrough — MCP tokens are separate from platform tokens
21
+ * - MCP-T7: Short-lived access tokens (1h), refresh token rotation
22
+ * - MCP-T9: Audience binding via resource parameter
23
+ * - MCP-T12: Auth event logging
24
+ */
25
+ export declare class ElnoraOAuthProvider implements OAuthServerProvider {
26
+ private _clientsStore;
27
+ private authSessions;
28
+ private tokenRecords;
29
+ private refreshTokenIndex;
30
+ private config;
31
+ constructor(config: ElnoraConfig);
32
+ get clientsStore(): OAuthRegisteredClientsStore;
33
+ /**
34
+ * Redirect the user to the Elnora platform login page.
35
+ * After authentication, the platform redirects back to our callback,
36
+ * which completes the OAuth flow back to the MCP client.
37
+ */
38
+ authorize(client: OAuthClientInformationFull, params: AuthorizationParams, res: Response): Promise<void>;
39
+ challengeForAuthorizationCode(_client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
40
+ exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string, _redirectUri?: string, resource?: URL): Promise<OAuthTokens>;
41
+ exchangeRefreshToken(client: OAuthClientInformationFull, refreshToken: string, scopes?: string[], resource?: URL): Promise<OAuthTokens>;
42
+ verifyAccessToken(token: string): Promise<AuthInfo>;
43
+ revokeToken(client: OAuthClientInformationFull, request: OAuthTokenRevocationRequest): Promise<void>;
44
+ /**
45
+ * Handle the callback from the Elnora platform login.
46
+ * Called by the /oauth/callback route after the user authenticates.
47
+ */
48
+ handlePlatformCallback(mcpCode: string, platformCode: string): void;
49
+ /**
50
+ * Get redirect URL for MCP client after platform callback.
51
+ */
52
+ getClientRedirectUrl(mcpCode: string): string;
53
+ private issueTokens;
54
+ }
55
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/auth/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,mDAAmD,CAAC;AAC7G,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,2BAA2B,EAC5B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAqC,MAAM,aAAa,CAAC;AAQ9E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,mBAAoB,YAAW,mBAAmB;IAC7D,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,YAAY;IAKhC,IAAI,YAAY,IAAI,2BAA2B,CAE9C;IAED;;;;OAIG;IACG,SAAS,CAAC,MAAM,EAAE,0BAA0B,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BxG,6BAA6B,CACjC,OAAO,EAAE,0BAA0B,EACnC,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC;IAQZ,yBAAyB,CAC7B,MAAM,EAAE,0BAA0B,EAClC,iBAAiB,EAAE,MAAM,EACzB,aAAa,CAAC,EAAE,MAAM,EACtB,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,GAAG,GACb,OAAO,CAAC,WAAW,CAAC;IAoCjB,oBAAoB,CACxB,MAAM,EAAE,0BAA0B,EAClC,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EAAE,EACjB,QAAQ,CAAC,EAAE,GAAG,GACb,OAAO,CAAC,WAAW,CAAC;IA0BjB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAyCnD,WAAW,CACf,MAAM,EAAE,0BAA0B,EAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC;IAwBhB;;;OAGG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAmBnE;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAc7C,OAAO,CAAC,WAAW;CAwCpB"}
@@ -0,0 +1,234 @@
1
+ import crypto from "node:crypto";
2
+ import axios from "axios";
3
+ import { InMemoryClientsStore } from "./clients-store.js";
4
+ import { ACCESS_TOKEN_TTL_SECONDS, REFRESH_TOKEN_TTL_SECONDS, AUTH_CODE_TTL_SECONDS, REQUEST_TIMEOUT_MS, } from "../constants.js";
5
+ /**
6
+ * OAuth 2.1 provider that proxies to the Elnora platform auth system.
7
+ *
8
+ * Flow:
9
+ * 1. MCP client calls /authorize → provider redirects to Elnora platform login
10
+ * 2. User authenticates on platform → platform redirects back with platform auth code
11
+ * 3. MCP server exchanges platform code for platform token
12
+ * 4. MCP server issues its own access + refresh tokens, mapped to the platform token
13
+ * 5. On token validation, the provider checks its own token store and validates
14
+ * the underlying platform token hasn't been revoked
15
+ *
16
+ * CoSAI controls:
17
+ * - MCP-T1: PKCE S256 mandatory (handled by SDK)
18
+ * - MCP-T1: No token passthrough — MCP tokens are separate from platform tokens
19
+ * - MCP-T7: Short-lived access tokens (1h), refresh token rotation
20
+ * - MCP-T9: Audience binding via resource parameter
21
+ * - MCP-T12: Auth event logging
22
+ */
23
+ export class ElnoraOAuthProvider {
24
+ _clientsStore;
25
+ authSessions = new Map();
26
+ tokenRecords = new Map();
27
+ refreshTokenIndex = new Map(); // refreshToken -> accessToken
28
+ config;
29
+ constructor(config) {
30
+ this.config = config;
31
+ this._clientsStore = new InMemoryClientsStore();
32
+ }
33
+ get clientsStore() {
34
+ return this._clientsStore;
35
+ }
36
+ /**
37
+ * Redirect the user to the Elnora platform login page.
38
+ * After authentication, the platform redirects back to our callback,
39
+ * which completes the OAuth flow back to the MCP client.
40
+ */
41
+ async authorize(client, params, res) {
42
+ const authCode = crypto.randomBytes(32).toString("base64url");
43
+ // Store session for later exchange
44
+ this.authSessions.set(authCode, {
45
+ clientId: client.client_id,
46
+ codeChallenge: params.codeChallenge,
47
+ redirectUri: params.redirectUri,
48
+ scopes: params.scopes || [],
49
+ state: params.state,
50
+ resource: params.resource?.toString(),
51
+ createdAt: Date.now(),
52
+ });
53
+ // Schedule cleanup of expired sessions
54
+ setTimeout(() => this.authSessions.delete(authCode), AUTH_CODE_TTL_SECONDS * 1000);
55
+ // Redirect to Elnora platform login
56
+ const loginUrl = new URL(this.config.loginUrl);
57
+ loginUrl.searchParams.set("mcp_code", authCode);
58
+ loginUrl.searchParams.set("redirect_uri", `${this.config.publicUrl}/oauth/callback`);
59
+ loginUrl.searchParams.set("client_id", this.config.platformClientId);
60
+ console.error(`[auth] authorize: redirecting client ${client.client_id} to platform login`);
61
+ res.redirect(loginUrl.toString());
62
+ }
63
+ async challengeForAuthorizationCode(_client, authorizationCode) {
64
+ const session = this.authSessions.get(authorizationCode);
65
+ if (!session) {
66
+ throw new Error("Invalid or expired authorization code");
67
+ }
68
+ return session.codeChallenge;
69
+ }
70
+ async exchangeAuthorizationCode(client, authorizationCode, _codeVerifier, _redirectUri, resource) {
71
+ const session = this.authSessions.get(authorizationCode);
72
+ if (!session) {
73
+ throw new Error("Invalid or expired authorization code");
74
+ }
75
+ if (session.clientId !== client.client_id) {
76
+ throw new Error("Authorization code was not issued to this client");
77
+ }
78
+ // Delete the auth code — single use only
79
+ this.authSessions.delete(authorizationCode);
80
+ // Exchange with Elnora platform for a platform token
81
+ let platformToken;
82
+ try {
83
+ const response = await axios.post(this.config.tokenExchangeUrl, {
84
+ grant_type: "authorization_code",
85
+ code: session.platformCode || authorizationCode,
86
+ client_id: this.config.platformClientId,
87
+ client_secret: this.config.platformClientSecret,
88
+ }, { timeout: REQUEST_TIMEOUT_MS });
89
+ platformToken = response.data.access_token;
90
+ }
91
+ catch (error) {
92
+ console.error("[auth] platform token exchange failed:", error);
93
+ throw new Error("Failed to exchange authorization code with platform");
94
+ }
95
+ // Issue MCP tokens (separate from platform token — CoSAI MCP-T1)
96
+ return this.issueTokens(client.client_id, session.scopes, platformToken, resource?.toString());
97
+ }
98
+ async exchangeRefreshToken(client, refreshToken, scopes, resource) {
99
+ const accessTokenKey = this.refreshTokenIndex.get(refreshToken);
100
+ if (!accessTokenKey) {
101
+ throw new Error("Invalid refresh token");
102
+ }
103
+ const record = this.tokenRecords.get(accessTokenKey);
104
+ if (!record || record.clientId !== client.client_id) {
105
+ throw new Error("Invalid refresh token");
106
+ }
107
+ // Rotate: delete old tokens
108
+ this.tokenRecords.delete(accessTokenKey);
109
+ this.refreshTokenIndex.delete(refreshToken);
110
+ console.error(`[auth] refresh token rotation for client ${client.client_id}`);
111
+ // Issue new tokens with the same platform token
112
+ return this.issueTokens(client.client_id, scopes || record.scopes, record.platformToken, resource?.toString() || record.resource);
113
+ }
114
+ async verifyAccessToken(token) {
115
+ const record = this.tokenRecords.get(token);
116
+ if (!record) {
117
+ throw new Error("Invalid access token");
118
+ }
119
+ if (record.expiresAt < Math.floor(Date.now() / 1000)) {
120
+ this.tokenRecords.delete(token);
121
+ throw new Error("Access token expired");
122
+ }
123
+ // Validate platform token is still valid
124
+ try {
125
+ const validation = await axios.post(this.config.tokenValidationUrl, { token: record.platformToken }, { timeout: REQUEST_TIMEOUT_MS });
126
+ if (!validation.data.valid) {
127
+ this.tokenRecords.delete(token);
128
+ throw new Error("Underlying platform token revoked");
129
+ }
130
+ }
131
+ catch (error) {
132
+ if (axios.isAxiosError(error) && error.response?.status === 401) {
133
+ this.tokenRecords.delete(token);
134
+ throw new Error("Underlying platform token revoked");
135
+ }
136
+ // Network errors — don't invalidate, just log
137
+ console.error("[auth] platform token validation failed (non-fatal):", error);
138
+ }
139
+ return {
140
+ token,
141
+ clientId: record.clientId,
142
+ scopes: record.scopes,
143
+ expiresAt: record.expiresAt,
144
+ resource: record.resource ? new URL(record.resource) : undefined,
145
+ extra: { platformToken: record.platformToken },
146
+ };
147
+ }
148
+ async revokeToken(client, request) {
149
+ const token = request.token;
150
+ // Check if it's an access token
151
+ const record = this.tokenRecords.get(token);
152
+ if (record && record.clientId === client.client_id) {
153
+ this.refreshTokenIndex.delete(record.refreshToken);
154
+ this.tokenRecords.delete(token);
155
+ console.error(`[auth] revoked access token for client ${client.client_id}`);
156
+ return;
157
+ }
158
+ // Check if it's a refresh token
159
+ const accessTokenKey = this.refreshTokenIndex.get(token);
160
+ if (accessTokenKey) {
161
+ const rec = this.tokenRecords.get(accessTokenKey);
162
+ if (rec && rec.clientId === client.client_id) {
163
+ this.tokenRecords.delete(accessTokenKey);
164
+ this.refreshTokenIndex.delete(token);
165
+ console.error(`[auth] revoked refresh token for client ${client.client_id}`);
166
+ }
167
+ }
168
+ }
169
+ /**
170
+ * Handle the callback from the Elnora platform login.
171
+ * Called by the /oauth/callback route after the user authenticates.
172
+ */
173
+ handlePlatformCallback(mcpCode, platformCode) {
174
+ const session = this.authSessions.get(mcpCode);
175
+ if (!session) {
176
+ throw new Error("Invalid or expired MCP authorization code");
177
+ }
178
+ // Store the platform code for later exchange
179
+ session.platformCode = platformCode;
180
+ // Build the redirect back to the MCP client
181
+ const redirectUrl = new URL(session.redirectUri);
182
+ redirectUrl.searchParams.set("code", mcpCode);
183
+ if (session.state) {
184
+ redirectUrl.searchParams.set("state", session.state);
185
+ }
186
+ console.error(`[auth] platform callback: completing auth for client ${session.clientId}`);
187
+ }
188
+ /**
189
+ * Get redirect URL for MCP client after platform callback.
190
+ */
191
+ getClientRedirectUrl(mcpCode) {
192
+ const session = this.authSessions.get(mcpCode);
193
+ if (!session) {
194
+ throw new Error("Invalid or expired MCP authorization code");
195
+ }
196
+ const redirectUrl = new URL(session.redirectUri);
197
+ redirectUrl.searchParams.set("code", mcpCode);
198
+ if (session.state) {
199
+ redirectUrl.searchParams.set("state", session.state);
200
+ }
201
+ return redirectUrl.toString();
202
+ }
203
+ issueTokens(clientId, scopes, platformToken, resource) {
204
+ const accessToken = crypto.randomBytes(32).toString("base64url");
205
+ const refreshToken = crypto.randomBytes(32).toString("base64url");
206
+ const now = Math.floor(Date.now() / 1000);
207
+ const record = {
208
+ accessToken,
209
+ refreshToken,
210
+ platformToken,
211
+ clientId,
212
+ scopes,
213
+ resource,
214
+ expiresAt: now + ACCESS_TOKEN_TTL_SECONDS,
215
+ createdAt: now,
216
+ };
217
+ this.tokenRecords.set(accessToken, record);
218
+ this.refreshTokenIndex.set(refreshToken, accessToken);
219
+ // Schedule cleanup of expired tokens (cap at ~24 days to stay within 32-bit setTimeout limit)
220
+ const cleanupMs = Math.min(REFRESH_TOKEN_TTL_SECONDS * 1000, 2_000_000_000);
221
+ setTimeout(() => {
222
+ this.tokenRecords.delete(accessToken);
223
+ this.refreshTokenIndex.delete(refreshToken);
224
+ }, cleanupMs);
225
+ console.error(`[auth] issued tokens for client ${clientId} (expires ${new Date((now + ACCESS_TOKEN_TTL_SECONDS) * 1000).toISOString()})`);
226
+ return {
227
+ access_token: accessToken,
228
+ token_type: "Bearer",
229
+ expires_in: ACCESS_TOKEN_TTL_SECONDS,
230
+ refresh_token: refreshToken,
231
+ };
232
+ }
233
+ }
234
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/auth/provider.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,11 @@
1
- export declare const CHARACTER_LIMIT = 25000;
2
- export declare const DEFAULT_PAGE_SIZE = 20;
1
+ export declare const CHARACTER_LIMIT = 100000;
2
+ export declare const DEFAULT_PAGE_SIZE = 50;
3
3
  export declare const MAX_PAGE_SIZE = 100;
4
4
  export declare const REQUEST_TIMEOUT_MS = 30000;
5
5
  export declare const LONG_REQUEST_TIMEOUT_MS = 120000;
6
+ export declare const ACCESS_TOKEN_TTL_SECONDS = 3600;
7
+ export declare const REFRESH_TOKEN_TTL_SECONDS: number;
8
+ export declare const AUTH_CODE_TTL_SECONDS = 300;
9
+ export declare const CLIENT_SECRET_TTL_SECONDS: number;
10
+ export declare const SUPPORTED_SCOPES: readonly ["tasks:read", "tasks:write", "files:read", "files:write", "messages:read", "messages:write"];
6
11
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,QAAQ,CAAC;AACrC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,uBAAuB,SAAS,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,SAAU,CAAC;AACvC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,uBAAuB,SAAU,CAAC;AAG/C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AACxD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAGxD,eAAO,MAAM,gBAAgB,wGAOnB,CAAC"}
package/dist/constants.js CHANGED
@@ -1,6 +1,20 @@
1
- export const CHARACTER_LIMIT = 25000;
2
- export const DEFAULT_PAGE_SIZE = 20;
1
+ export const CHARACTER_LIMIT = 100_000;
2
+ export const DEFAULT_PAGE_SIZE = 50;
3
3
  export const MAX_PAGE_SIZE = 100;
4
- export const REQUEST_TIMEOUT_MS = 30000;
5
- export const LONG_REQUEST_TIMEOUT_MS = 120000;
4
+ export const REQUEST_TIMEOUT_MS = 30_000;
5
+ export const LONG_REQUEST_TIMEOUT_MS = 120_000;
6
+ // Auth constants
7
+ export const ACCESS_TOKEN_TTL_SECONDS = 3600; // 1 hour
8
+ export const REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 3600; // 30 days
9
+ export const AUTH_CODE_TTL_SECONDS = 300; // 5 minutes
10
+ export const CLIENT_SECRET_TTL_SECONDS = 90 * 24 * 3600; // 90 days
11
+ // MCP scopes
12
+ export const SUPPORTED_SCOPES = [
13
+ "tasks:read",
14
+ "tasks:write",
15
+ "files:read",
16
+ "files:write",
17
+ "messages:read",
18
+ "messages:write",
19
+ ];
6
20
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAE/C,iBAAiB;AACjB,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,CAAC,SAAS;AACvD,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AACnE,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC,CAAC,YAAY;AACtD,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,UAAU;AAEnE,aAAa;AACb,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,aAAa;IACb,eAAe;IACf,gBAAgB;CACR,CAAC"}
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
2
+ import { mcpAuthRouter, getOAuthProtectedResourceMetadataUrl } from "@modelcontextprotocol/sdk/server/auth/router.js";
3
+ import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
2
4
  import express from "express";
3
5
  import { ElnoraApiClient } from "./services/elnora-api-client.js";
4
- import { authMiddleware } from "./auth/middleware.js";
5
- import { protectedResourceMetadataHandler } from "./auth/protected-resource.js";
6
+ import { ElnoraOAuthProvider } from "./auth/provider.js";
6
7
  import { createElnoraServer } from "./server.js";
8
+ import { corsMiddleware } from "./middleware/cors.js";
9
+ import { mcpRateLimiter } from "./middleware/rate-limiter.js";
10
+ import { SUPPORTED_SCOPES } from "./constants.js";
7
11
  function requireEnv(name) {
8
12
  const value = process.env[name];
9
13
  if (!value) {
@@ -17,25 +21,81 @@ function loadConfig() {
17
21
  authUrl: requireEnv("ELNORA_AUTH_URL"),
18
22
  tokenValidationUrl: requireEnv("ELNORA_TOKEN_VALIDATION_URL"),
19
23
  port: parseInt(process.env.PORT || "3000", 10),
24
+ publicUrl: requireEnv("ELNORA_PUBLIC_URL"),
25
+ loginUrl: requireEnv("ELNORA_LOGIN_URL"),
26
+ tokenExchangeUrl: requireEnv("ELNORA_TOKEN_EXCHANGE_URL"),
27
+ platformClientId: requireEnv("ELNORA_PLATFORM_CLIENT_ID"),
28
+ platformClientSecret: requireEnv("ELNORA_PLATFORM_CLIENT_SECRET"),
20
29
  };
21
30
  }
22
31
  async function main() {
23
32
  const config = loadConfig();
24
33
  const app = express();
25
- app.use(express.json());
26
- // Health check
34
+ // --- Security middleware (CoSAI MCP-T7) ---
35
+ app.use(corsMiddleware(config));
36
+ app.use(express.json({ limit: "1mb" })); // Payload size limit (CoSAI MCP-T10)
37
+ // Health check (no auth)
27
38
  app.get("/health", (_req, res) => {
28
39
  res.json({ status: "ok", service: "elnora-mcp-server" });
29
40
  });
30
- // OAuth Protected Resource Metadata (per MCP spec, RFC 9728)
31
- app.get("/.well-known/oauth-protected-resource", protectedResourceMetadataHandler(config));
32
- // MCP endpoint with auth
33
- app.post("/mcp", authMiddleware(config), async (req, res) => {
41
+ // --- OAuth 2.1 Authorization Server ---
42
+ const provider = new ElnoraOAuthProvider(config);
43
+ const issuerUrl = new URL(config.publicUrl);
44
+ const mcpServerUrl = new URL(`${config.publicUrl}/mcp`);
45
+ // Install OAuth routes: /.well-known/oauth-authorization-server,
46
+ // /.well-known/oauth-protected-resource, /authorize, /token, /register, /revoke
47
+ app.use(mcpAuthRouter({
48
+ provider,
49
+ issuerUrl,
50
+ resourceServerUrl: mcpServerUrl,
51
+ scopesSupported: [...SUPPORTED_SCOPES],
52
+ resourceName: "Elnora MCP Server",
53
+ serviceDocumentationUrl: new URL("https://github.com/Elnora-AI/elnora-mcp-server"),
54
+ }));
55
+ // Platform OAuth callback — receives the auth code from Elnora platform login
56
+ // CSRF protection: validates mcp_code exists in our session store (CoSAI MCP-T7)
57
+ app.get("/oauth/callback", (req, res) => {
58
+ const mcpCode = req.query.mcp_code;
59
+ const platformCode = req.query.code;
60
+ const error = req.query.error;
61
+ if (error) {
62
+ console.error(`[auth] platform callback error: ${error}`);
63
+ res.status(400).json({ error: "platform_auth_failed", error_description: error });
64
+ return;
65
+ }
66
+ if (!mcpCode || !platformCode) {
67
+ res.status(400).json({ error: "invalid_request", error_description: "Missing mcp_code or code parameter" });
68
+ return;
69
+ }
70
+ try {
71
+ provider.handlePlatformCallback(mcpCode, platformCode);
72
+ const redirectUrl = provider.getClientRedirectUrl(mcpCode);
73
+ res.redirect(redirectUrl);
74
+ }
75
+ catch (err) {
76
+ console.error("[auth] platform callback failed:", err);
77
+ res.status(400).json({
78
+ error: "invalid_grant",
79
+ error_description: err instanceof Error ? err.message : "Callback processing failed",
80
+ });
81
+ }
82
+ });
83
+ // --- MCP Endpoint (protected by bearer auth + rate limiting) ---
84
+ const authMiddleware = requireBearerAuth({
85
+ verifier: provider,
86
+ requiredScopes: [],
87
+ resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(mcpServerUrl),
88
+ });
89
+ app.post("/mcp", mcpRateLimiter(), authMiddleware, async (req, res) => {
34
90
  try {
35
- // Create per-request MCP server and API client
36
- const client = new ElnoraApiClient(config, req.bearerToken);
37
- const getClient = () => client;
38
- const server = createElnoraServer(config, getClient);
91
+ // Extract auth context (set by provider.verifyAccessToken)
92
+ const platformToken = req.auth?.extra?.platformToken || "";
93
+ const clientId = req.auth?.clientId || "unknown";
94
+ const scopes = req.auth?.scopes || [];
95
+ // Create per-request MCP server and API client with auth context
96
+ const client = new ElnoraApiClient(config, platformToken);
97
+ const getContext = () => ({ client, clientId, scopes });
98
+ const server = createElnoraServer(config, getContext);
39
99
  // Stateless transport — new transport per request
40
100
  const transport = new StreamableHTTPServerTransport({
41
101
  sessionIdGenerator: undefined,
@@ -52,9 +112,17 @@ async function main() {
52
112
  }
53
113
  }
54
114
  });
115
+ // GET and DELETE on /mcp return 405 per MCP Streamable HTTP spec (stateless mode)
116
+ app.get("/mcp", (_req, res) => {
117
+ res.status(405).json({ error: "method_not_allowed", error_description: "Stateless server — use POST" });
118
+ });
119
+ app.delete("/mcp", (_req, res) => {
120
+ res.status(405).json({ error: "method_not_allowed", error_description: "Stateless server — sessions not supported" });
121
+ });
55
122
  app.listen(config.port, () => {
56
123
  console.error(`Elnora MCP server running on http://localhost:${config.port}/mcp`);
57
- console.error(`Protected Resource Metadata: http://localhost:${config.port}/.well-known/oauth-protected-resource`);
124
+ console.error(`OAuth AS Metadata: ${config.publicUrl}/.well-known/oauth-authorization-server`);
125
+ console.error(`Protected Resource Metadata: ${getOAuthProtectedResourceMetadataUrl(mcpServerUrl)}`);
58
126
  console.error(`Health check: http://localhost:${config.port}/health`);
59
127
  });
60
128
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { RequestHandler } from "express";
2
+ import { ElnoraConfig } from "../types.js";
3
+ /**
4
+ * CORS middleware restricting origins to the Elnora platform domain.
5
+ * CoSAI MCP-T7: Prevent cross-origin data leaks and CORS policy bypass.
6
+ *
7
+ * MCP clients communicate via direct HTTP (not browser), so CORS is primarily
8
+ * defense-in-depth against browser-based attacks targeting the MCP endpoint.
9
+ */
10
+ export declare function corsMiddleware(config: ElnoraConfig): RequestHandler;
11
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAsCnE"}