strapi-oauth-mcp-manager 0.1.2 → 0.1.4

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.
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  const node_crypto = require("node:crypto");
3
3
  const PLUGIN_ID = "strapi-oauth-mcp-manager";
4
- const PLUGIN_UID$3 = `plugin::${PLUGIN_ID}`;
4
+ const PLUGIN_UID$2 = `plugin::${PLUGIN_ID}`;
5
+ const MCP_ENDPOINT_PATTERN = /^\/api\/[^/]+\/mcp(\/.*)?$/;
5
6
  function extractBearerToken(authHeader) {
6
7
  if (!authHeader?.startsWith("Bearer ")) {
7
8
  return null;
@@ -21,7 +22,7 @@ function buildWwwAuthenticateHeader(ctx, strapi) {
21
22
  }
22
23
  async function validateOAuthToken(token, strapi) {
23
24
  try {
24
- const tokenRecord = await strapi.documents(`${PLUGIN_UID$3}.mcp-oauth-token`).findFirst({
25
+ const tokenRecord = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).findFirst({
25
26
  filters: { accessToken: token, revoked: false }
26
27
  });
27
28
  if (!tokenRecord) {
@@ -30,7 +31,7 @@ async function validateOAuthToken(token, strapi) {
30
31
  if (new Date(tokenRecord.expiresAt) < /* @__PURE__ */ new Date()) {
31
32
  return { valid: false, error: "Token expired" };
32
33
  }
33
- const client = await strapi.documents(`${PLUGIN_UID$3}.mcp-oauth-client`).findFirst({
34
+ const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
34
35
  filters: { clientId: tokenRecord.clientId }
35
36
  });
36
37
  if (!client) {
@@ -45,32 +46,15 @@ async function validateOAuthToken(token, strapi) {
45
46
  return { valid: false, error: "Token validation failed" };
46
47
  }
47
48
  }
49
+ function isMcpEndpoint(path) {
50
+ return MCP_ENDPOINT_PATTERN.test(path);
51
+ }
48
52
  const mcpOauthMiddleware = (config2, { strapi }) => {
49
- let endpointCache = [];
50
- let lastCacheUpdate = 0;
51
- const CACHE_TTL = 6e4;
52
- async function refreshEndpointCache() {
53
- const now = Date.now();
54
- if (now - lastCacheUpdate > CACHE_TTL) {
55
- try {
56
- const endpoints = await strapi.documents(`${PLUGIN_UID$3}.mcp-endpoint`).findMany({
57
- filters: { active: true }
58
- });
59
- endpointCache = endpoints.map((e) => e.path);
60
- lastCacheUpdate = now;
61
- } catch (error) {
62
- strapi.log.error(`[${PLUGIN_ID}] Error refreshing endpoint cache`, { error });
63
- }
64
- }
65
- }
66
- function isProtectedPath(path) {
67
- return endpointCache.some((endpoint) => path.includes(endpoint));
68
- }
69
53
  return async (ctx, next) => {
70
- await refreshEndpointCache();
71
- if (!isProtectedPath(ctx.path)) {
54
+ if (!isMcpEndpoint(ctx.path)) {
72
55
  return next();
73
56
  }
57
+ strapi.log.debug(`[${PLUGIN_ID}] Protecting MCP endpoint: ${ctx.path}`);
74
58
  const authHeader = ctx.request.headers.authorization;
75
59
  const token = extractBearerToken(authHeader);
76
60
  if (!token) {
@@ -109,18 +93,18 @@ const config = {
109
93
  validator() {
110
94
  }
111
95
  };
112
- const kind$3 = "collectionType";
113
- const collectionName$3 = "mcp_oauth_clients";
114
- const info$3 = {
96
+ const kind$2 = "collectionType";
97
+ const collectionName$2 = "mcp_oauth_clients";
98
+ const info$2 = {
115
99
  singularName: "mcp-oauth-client",
116
100
  pluralName: "mcp-oauth-clients",
117
101
  displayName: "MCP OAuth Client",
118
102
  description: "OAuth 2.0 clients for MCP authentication"
119
103
  };
120
- const options$3 = {
104
+ const options$2 = {
121
105
  draftAndPublish: false
122
106
  };
123
- const pluginOptions$3 = {
107
+ const pluginOptions$2 = {
124
108
  "content-manager": {
125
109
  visible: true
126
110
  },
@@ -128,7 +112,7 @@ const pluginOptions$3 = {
128
112
  visible: true
129
113
  }
130
114
  };
131
- const attributes$3 = {
115
+ const attributes$2 = {
132
116
  name: {
133
117
  type: "string",
134
118
  required: true
@@ -161,25 +145,25 @@ const attributes$3 = {
161
145
  }
162
146
  };
163
147
  const mcpOauthClient = {
164
- kind: kind$3,
165
- collectionName: collectionName$3,
166
- info: info$3,
167
- options: options$3,
168
- pluginOptions: pluginOptions$3,
169
- attributes: attributes$3
148
+ kind: kind$2,
149
+ collectionName: collectionName$2,
150
+ info: info$2,
151
+ options: options$2,
152
+ pluginOptions: pluginOptions$2,
153
+ attributes: attributes$2
170
154
  };
171
- const kind$2 = "collectionType";
172
- const collectionName$2 = "mcp_oauth_codes";
173
- const info$2 = {
155
+ const kind$1 = "collectionType";
156
+ const collectionName$1 = "mcp_oauth_codes";
157
+ const info$1 = {
174
158
  singularName: "mcp-oauth-code",
175
159
  pluralName: "mcp-oauth-codes",
176
160
  displayName: "MCP OAuth Code",
177
161
  description: "OAuth 2.0 authorization codes"
178
162
  };
179
- const options$2 = {
163
+ const options$1 = {
180
164
  draftAndPublish: false
181
165
  };
182
- const pluginOptions$2 = {
166
+ const pluginOptions$1 = {
183
167
  "content-manager": {
184
168
  visible: false
185
169
  },
@@ -187,7 +171,7 @@ const pluginOptions$2 = {
187
171
  visible: false
188
172
  }
189
173
  };
190
- const attributes$2 = {
174
+ const attributes$1 = {
191
175
  code: {
192
176
  type: "string",
193
177
  required: true,
@@ -217,25 +201,25 @@ const attributes$2 = {
217
201
  }
218
202
  };
219
203
  const mcpOauthCode = {
220
- kind: kind$2,
221
- collectionName: collectionName$2,
222
- info: info$2,
223
- options: options$2,
224
- pluginOptions: pluginOptions$2,
225
- attributes: attributes$2
204
+ kind: kind$1,
205
+ collectionName: collectionName$1,
206
+ info: info$1,
207
+ options: options$1,
208
+ pluginOptions: pluginOptions$1,
209
+ attributes: attributes$1
226
210
  };
227
- const kind$1 = "collectionType";
228
- const collectionName$1 = "mcp_oauth_tokens";
229
- const info$1 = {
211
+ const kind = "collectionType";
212
+ const collectionName = "mcp_oauth_tokens";
213
+ const info = {
230
214
  singularName: "mcp-oauth-token",
231
215
  pluralName: "mcp-oauth-tokens",
232
216
  displayName: "MCP OAuth Token",
233
217
  description: "OAuth 2.0 access and refresh tokens"
234
218
  };
235
- const options$1 = {
219
+ const options = {
236
220
  draftAndPublish: false
237
221
  };
238
- const pluginOptions$1 = {
222
+ const pluginOptions = {
239
223
  "content-manager": {
240
224
  visible: false
241
225
  },
@@ -243,7 +227,7 @@ const pluginOptions$1 = {
243
227
  visible: false
244
228
  }
245
229
  };
246
- const attributes$1 = {
230
+ const attributes = {
247
231
  accessToken: {
248
232
  type: "string",
249
233
  required: true,
@@ -274,55 +258,6 @@ const attributes$1 = {
274
258
  }
275
259
  };
276
260
  const mcpOauthToken = {
277
- kind: kind$1,
278
- collectionName: collectionName$1,
279
- info: info$1,
280
- options: options$1,
281
- pluginOptions: pluginOptions$1,
282
- attributes: attributes$1
283
- };
284
- const kind = "collectionType";
285
- const collectionName = "mcp_endpoints";
286
- const info = {
287
- singularName: "mcp-endpoint",
288
- pluralName: "mcp-endpoints",
289
- displayName: "MCP Endpoint",
290
- description: "Registered MCP endpoints protected by OAuth"
291
- };
292
- const options = {
293
- draftAndPublish: false
294
- };
295
- const pluginOptions = {
296
- "content-manager": {
297
- visible: true
298
- },
299
- "content-type-builder": {
300
- visible: true
301
- }
302
- };
303
- const attributes = {
304
- name: {
305
- type: "string",
306
- required: true
307
- },
308
- pluginId: {
309
- type: "string",
310
- required: true
311
- },
312
- path: {
313
- type: "string",
314
- required: true,
315
- unique: true
316
- },
317
- description: {
318
- type: "text"
319
- },
320
- active: {
321
- type: "boolean",
322
- "default": true
323
- }
324
- };
325
- const mcpEndpoint = {
326
261
  kind,
327
262
  collectionName,
328
263
  info,
@@ -333,10 +268,9 @@ const mcpEndpoint = {
333
268
  const contentTypes = {
334
269
  "mcp-oauth-client": { schema: mcpOauthClient },
335
270
  "mcp-oauth-code": { schema: mcpOauthCode },
336
- "mcp-oauth-token": { schema: mcpOauthToken },
337
- "mcp-endpoint": { schema: mcpEndpoint }
271
+ "mcp-oauth-token": { schema: mcpOauthToken }
338
272
  };
339
- const PLUGIN_UID$2 = `plugin::${PLUGIN_ID}`;
273
+ const PLUGIN_UID$1 = `plugin::${PLUGIN_ID}`;
340
274
  function getBaseUrl(ctx, strapi) {
341
275
  const forwardedProto = ctx.request.headers["x-forwarded-proto"] || ctx.protocol;
342
276
  const forwardedHost = ctx.request.headers["x-forwarded-host"] || ctx.request.headers["host"];
@@ -373,17 +307,15 @@ const oauthController = ({ strapi }) => ({
373
307
  /**
374
308
  * OAuth 2.0 Protected Resource Metadata (RFC 9728)
375
309
  * GET /.well-known/oauth-protected-resource
310
+ *
311
+ * Convention-based protection: all /api/{plugin}/mcp endpoints are protected.
376
312
  */
377
313
  async protectedResource(ctx) {
378
314
  const baseUrl = getBaseUrl(ctx, strapi);
379
315
  const pluginPath = `/api/${PLUGIN_ID}`;
380
316
  const authServer = `${baseUrl}${pluginPath}`;
381
- const endpoints = await strapi.documents(`${PLUGIN_UID$2}.mcp-endpoint`).findMany({
382
- filters: { active: true }
383
- });
384
- const resources = endpoints.map((e) => `${baseUrl}${e.path}`);
385
317
  ctx.body = {
386
- resource: resources.length === 1 ? resources[0] : resources,
318
+ resource: `${baseUrl}/api`,
387
319
  authorization_servers: [authServer],
388
320
  bearer_methods_supported: ["header"]
389
321
  };
@@ -409,7 +341,7 @@ const oauthController = ({ strapi }) => ({
409
341
  ctx.body = { error: "unsupported_response_type", error_description: "Only code response type is supported" };
410
342
  return;
411
343
  }
412
- const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
344
+ const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
413
345
  filters: { clientId: client_id, active: true }
414
346
  });
415
347
  if (!client) {
@@ -438,7 +370,7 @@ const oauthController = ({ strapi }) => ({
438
370
  }
439
371
  const code = node_crypto.randomBytes(32).toString("hex");
440
372
  const expiresAt = new Date(Date.now() + 10 * 60 * 1e3);
441
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).create({
373
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).create({
442
374
  data: {
443
375
  code,
444
376
  clientId: client_id,
@@ -476,7 +408,7 @@ const oauthController = ({ strapi }) => ({
476
408
  ctx.body = { error: "invalid_client", error_description: "Client authentication required" };
477
409
  return;
478
410
  }
479
- const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
411
+ const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
480
412
  filters: { clientId: authClientId, active: true }
481
413
  });
482
414
  if (!client || authClientSecret && client.clientSecret !== authClientSecret) {
@@ -500,7 +432,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
500
432
  ctx.body = { error: "invalid_request", error_description: "code is required" };
501
433
  return;
502
434
  }
503
- const authCode = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).findFirst({
435
+ const authCode = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).findFirst({
504
436
  filters: { code, clientId: client.clientId, used: false }
505
437
  });
506
438
  if (!authCode) {
@@ -518,7 +450,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
518
450
  ctx.body = { error: "invalid_grant", error_description: "redirect_uri mismatch" };
519
451
  return;
520
452
  }
521
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).update({
453
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).update({
522
454
  documentId: authCode.documentId,
523
455
  data: { used: true }
524
456
  });
@@ -526,7 +458,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
526
458
  const refreshToken = node_crypto.randomBytes(32).toString("hex");
527
459
  const expiresIn = 3600;
528
460
  const refreshExpiresIn = 30 * 24 * 3600;
529
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).create({
461
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).create({
530
462
  data: {
531
463
  accessToken,
532
464
  refreshToken,
@@ -549,7 +481,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
549
481
  ctx.body = { error: "invalid_request", error_description: "refresh_token is required" };
550
482
  return;
551
483
  }
552
- const token = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).findFirst({
484
+ const token = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findFirst({
553
485
  filters: { refreshToken, clientId: client.clientId, revoked: false }
554
486
  });
555
487
  if (!token) {
@@ -562,7 +494,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
562
494
  ctx.body = { error: "invalid_grant", error_description: "Refresh token expired" };
563
495
  return;
564
496
  }
565
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).update({
497
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).update({
566
498
  documentId: token.documentId,
567
499
  data: { revoked: true }
568
500
  });
@@ -570,7 +502,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
570
502
  const newRefreshToken = node_crypto.randomBytes(32).toString("hex");
571
503
  const expiresIn = 3600;
572
504
  const refreshExpiresIn = 30 * 24 * 3600;
573
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).create({
505
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).create({
574
506
  data: {
575
507
  accessToken: newAccessToken,
576
508
  refreshToken: newRefreshToken,
@@ -647,14 +579,14 @@ const routes = {
647
579
  routes: [...admin]
648
580
  }
649
581
  };
650
- const PLUGIN_UID$1 = `plugin::${PLUGIN_ID}`;
582
+ const PLUGIN_UID = `plugin::${PLUGIN_ID}`;
651
583
  const oauthService = ({ strapi }) => ({
652
584
  /**
653
585
  * Validate an OAuth access token
654
586
  */
655
587
  async validateToken(accessToken) {
656
588
  try {
657
- const tokenRecord = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findFirst({
589
+ const tokenRecord = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findFirst({
658
590
  filters: { accessToken, revoked: false }
659
591
  });
660
592
  if (!tokenRecord) {
@@ -663,7 +595,7 @@ const oauthService = ({ strapi }) => ({
663
595
  if (new Date(tokenRecord.expiresAt) < /* @__PURE__ */ new Date()) {
664
596
  return { valid: false, error: "Token expired" };
665
597
  }
666
- const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
598
+ const client = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-client`).findFirst({
667
599
  filters: { clientId: tokenRecord.clientId }
668
600
  });
669
601
  if (!client) {
@@ -683,11 +615,11 @@ const oauthService = ({ strapi }) => ({
683
615
  * Revoke all tokens for a client
684
616
  */
685
617
  async revokeClientTokens(clientId) {
686
- const tokens = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findMany({
618
+ const tokens = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findMany({
687
619
  filters: { clientId, revoked: false }
688
620
  });
689
621
  for (const token of tokens) {
690
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).update({
622
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).update({
691
623
  documentId: token.documentId,
692
624
  data: { revoked: true }
693
625
  });
@@ -699,19 +631,19 @@ const oauthService = ({ strapi }) => ({
699
631
  */
700
632
  async cleanupExpired() {
701
633
  const now = (/* @__PURE__ */ new Date()).toISOString();
702
- const expiredCodes = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).findMany({
634
+ const expiredCodes = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-code`).findMany({
703
635
  filters: { expiresAt: { $lt: now } }
704
636
  });
705
637
  for (const code of expiredCodes) {
706
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).delete({
638
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-code`).delete({
707
639
  documentId: code.documentId
708
640
  });
709
641
  }
710
- const expiredTokens = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findMany({
642
+ const expiredTokens = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findMany({
711
643
  filters: { refreshExpiresAt: { $lt: now } }
712
644
  });
713
645
  for (const token of expiredTokens) {
714
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).delete({
646
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).delete({
715
647
  documentId: token.documentId
716
648
  });
717
649
  }
@@ -721,80 +653,8 @@ const oauthService = ({ strapi }) => ({
721
653
  };
722
654
  }
723
655
  });
724
- const PLUGIN_UID = `plugin::${PLUGIN_ID}`;
725
- const endpointService = ({ strapi }) => ({
726
- /**
727
- * Register an MCP endpoint for OAuth protection
728
- */
729
- async register(endpoint) {
730
- const existing = await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findFirst({
731
- filters: { path: endpoint.path }
732
- });
733
- if (existing) {
734
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).update({
735
- documentId: existing.documentId,
736
- data: {
737
- name: endpoint.name,
738
- pluginId: endpoint.pluginId,
739
- description: endpoint.description,
740
- active: true
741
- }
742
- });
743
- }
744
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).create({
745
- data: {
746
- name: endpoint.name,
747
- pluginId: endpoint.pluginId,
748
- path: endpoint.path,
749
- description: endpoint.description,
750
- active: true
751
- }
752
- });
753
- },
754
- /**
755
- * Unregister an MCP endpoint
756
- */
757
- async unregister(path) {
758
- const endpoint = await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findFirst({
759
- filters: { path }
760
- });
761
- if (!endpoint) {
762
- return false;
763
- }
764
- await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).update({
765
- documentId: endpoint.documentId,
766
- data: { active: false }
767
- });
768
- return true;
769
- },
770
- /**
771
- * Get all registered endpoints
772
- */
773
- async getAll(activeOnly = true) {
774
- const filters = activeOnly ? { active: true } : {};
775
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findMany({ filters });
776
- },
777
- /**
778
- * Get endpoints for a specific plugin
779
- */
780
- async getByPlugin(pluginId, activeOnly = true) {
781
- const filters = { pluginId };
782
- if (activeOnly) {
783
- filters.active = true;
784
- }
785
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findMany({ filters });
786
- },
787
- /**
788
- * Check if a path is a protected endpoint
789
- */
790
- async isProtected(path) {
791
- const endpoints = await this.getAll(true);
792
- return endpoints.some((e) => path.includes(e.path));
793
- }
794
- });
795
656
  const services = {
796
- oauth: oauthService,
797
- endpoint: endpointService
657
+ oauth: oauthService
798
658
  };
799
659
  const index = {
800
660
  register,
@@ -1,6 +1,7 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  const PLUGIN_ID = "strapi-oauth-mcp-manager";
3
- const PLUGIN_UID$3 = `plugin::${PLUGIN_ID}`;
3
+ const PLUGIN_UID$2 = `plugin::${PLUGIN_ID}`;
4
+ const MCP_ENDPOINT_PATTERN = /^\/api\/[^/]+\/mcp(\/.*)?$/;
4
5
  function extractBearerToken(authHeader) {
5
6
  if (!authHeader?.startsWith("Bearer ")) {
6
7
  return null;
@@ -20,7 +21,7 @@ function buildWwwAuthenticateHeader(ctx, strapi) {
20
21
  }
21
22
  async function validateOAuthToken(token, strapi) {
22
23
  try {
23
- const tokenRecord = await strapi.documents(`${PLUGIN_UID$3}.mcp-oauth-token`).findFirst({
24
+ const tokenRecord = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).findFirst({
24
25
  filters: { accessToken: token, revoked: false }
25
26
  });
26
27
  if (!tokenRecord) {
@@ -29,7 +30,7 @@ async function validateOAuthToken(token, strapi) {
29
30
  if (new Date(tokenRecord.expiresAt) < /* @__PURE__ */ new Date()) {
30
31
  return { valid: false, error: "Token expired" };
31
32
  }
32
- const client = await strapi.documents(`${PLUGIN_UID$3}.mcp-oauth-client`).findFirst({
33
+ const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
33
34
  filters: { clientId: tokenRecord.clientId }
34
35
  });
35
36
  if (!client) {
@@ -44,32 +45,15 @@ async function validateOAuthToken(token, strapi) {
44
45
  return { valid: false, error: "Token validation failed" };
45
46
  }
46
47
  }
48
+ function isMcpEndpoint(path) {
49
+ return MCP_ENDPOINT_PATTERN.test(path);
50
+ }
47
51
  const mcpOauthMiddleware = (config2, { strapi }) => {
48
- let endpointCache = [];
49
- let lastCacheUpdate = 0;
50
- const CACHE_TTL = 6e4;
51
- async function refreshEndpointCache() {
52
- const now = Date.now();
53
- if (now - lastCacheUpdate > CACHE_TTL) {
54
- try {
55
- const endpoints = await strapi.documents(`${PLUGIN_UID$3}.mcp-endpoint`).findMany({
56
- filters: { active: true }
57
- });
58
- endpointCache = endpoints.map((e) => e.path);
59
- lastCacheUpdate = now;
60
- } catch (error) {
61
- strapi.log.error(`[${PLUGIN_ID}] Error refreshing endpoint cache`, { error });
62
- }
63
- }
64
- }
65
- function isProtectedPath(path) {
66
- return endpointCache.some((endpoint) => path.includes(endpoint));
67
- }
68
52
  return async (ctx, next) => {
69
- await refreshEndpointCache();
70
- if (!isProtectedPath(ctx.path)) {
53
+ if (!isMcpEndpoint(ctx.path)) {
71
54
  return next();
72
55
  }
56
+ strapi.log.debug(`[${PLUGIN_ID}] Protecting MCP endpoint: ${ctx.path}`);
73
57
  const authHeader = ctx.request.headers.authorization;
74
58
  const token = extractBearerToken(authHeader);
75
59
  if (!token) {
@@ -108,18 +92,18 @@ const config = {
108
92
  validator() {
109
93
  }
110
94
  };
111
- const kind$3 = "collectionType";
112
- const collectionName$3 = "mcp_oauth_clients";
113
- const info$3 = {
95
+ const kind$2 = "collectionType";
96
+ const collectionName$2 = "mcp_oauth_clients";
97
+ const info$2 = {
114
98
  singularName: "mcp-oauth-client",
115
99
  pluralName: "mcp-oauth-clients",
116
100
  displayName: "MCP OAuth Client",
117
101
  description: "OAuth 2.0 clients for MCP authentication"
118
102
  };
119
- const options$3 = {
103
+ const options$2 = {
120
104
  draftAndPublish: false
121
105
  };
122
- const pluginOptions$3 = {
106
+ const pluginOptions$2 = {
123
107
  "content-manager": {
124
108
  visible: true
125
109
  },
@@ -127,7 +111,7 @@ const pluginOptions$3 = {
127
111
  visible: true
128
112
  }
129
113
  };
130
- const attributes$3 = {
114
+ const attributes$2 = {
131
115
  name: {
132
116
  type: "string",
133
117
  required: true
@@ -160,25 +144,25 @@ const attributes$3 = {
160
144
  }
161
145
  };
162
146
  const mcpOauthClient = {
163
- kind: kind$3,
164
- collectionName: collectionName$3,
165
- info: info$3,
166
- options: options$3,
167
- pluginOptions: pluginOptions$3,
168
- attributes: attributes$3
147
+ kind: kind$2,
148
+ collectionName: collectionName$2,
149
+ info: info$2,
150
+ options: options$2,
151
+ pluginOptions: pluginOptions$2,
152
+ attributes: attributes$2
169
153
  };
170
- const kind$2 = "collectionType";
171
- const collectionName$2 = "mcp_oauth_codes";
172
- const info$2 = {
154
+ const kind$1 = "collectionType";
155
+ const collectionName$1 = "mcp_oauth_codes";
156
+ const info$1 = {
173
157
  singularName: "mcp-oauth-code",
174
158
  pluralName: "mcp-oauth-codes",
175
159
  displayName: "MCP OAuth Code",
176
160
  description: "OAuth 2.0 authorization codes"
177
161
  };
178
- const options$2 = {
162
+ const options$1 = {
179
163
  draftAndPublish: false
180
164
  };
181
- const pluginOptions$2 = {
165
+ const pluginOptions$1 = {
182
166
  "content-manager": {
183
167
  visible: false
184
168
  },
@@ -186,7 +170,7 @@ const pluginOptions$2 = {
186
170
  visible: false
187
171
  }
188
172
  };
189
- const attributes$2 = {
173
+ const attributes$1 = {
190
174
  code: {
191
175
  type: "string",
192
176
  required: true,
@@ -216,25 +200,25 @@ const attributes$2 = {
216
200
  }
217
201
  };
218
202
  const mcpOauthCode = {
219
- kind: kind$2,
220
- collectionName: collectionName$2,
221
- info: info$2,
222
- options: options$2,
223
- pluginOptions: pluginOptions$2,
224
- attributes: attributes$2
203
+ kind: kind$1,
204
+ collectionName: collectionName$1,
205
+ info: info$1,
206
+ options: options$1,
207
+ pluginOptions: pluginOptions$1,
208
+ attributes: attributes$1
225
209
  };
226
- const kind$1 = "collectionType";
227
- const collectionName$1 = "mcp_oauth_tokens";
228
- const info$1 = {
210
+ const kind = "collectionType";
211
+ const collectionName = "mcp_oauth_tokens";
212
+ const info = {
229
213
  singularName: "mcp-oauth-token",
230
214
  pluralName: "mcp-oauth-tokens",
231
215
  displayName: "MCP OAuth Token",
232
216
  description: "OAuth 2.0 access and refresh tokens"
233
217
  };
234
- const options$1 = {
218
+ const options = {
235
219
  draftAndPublish: false
236
220
  };
237
- const pluginOptions$1 = {
221
+ const pluginOptions = {
238
222
  "content-manager": {
239
223
  visible: false
240
224
  },
@@ -242,7 +226,7 @@ const pluginOptions$1 = {
242
226
  visible: false
243
227
  }
244
228
  };
245
- const attributes$1 = {
229
+ const attributes = {
246
230
  accessToken: {
247
231
  type: "string",
248
232
  required: true,
@@ -273,55 +257,6 @@ const attributes$1 = {
273
257
  }
274
258
  };
275
259
  const mcpOauthToken = {
276
- kind: kind$1,
277
- collectionName: collectionName$1,
278
- info: info$1,
279
- options: options$1,
280
- pluginOptions: pluginOptions$1,
281
- attributes: attributes$1
282
- };
283
- const kind = "collectionType";
284
- const collectionName = "mcp_endpoints";
285
- const info = {
286
- singularName: "mcp-endpoint",
287
- pluralName: "mcp-endpoints",
288
- displayName: "MCP Endpoint",
289
- description: "Registered MCP endpoints protected by OAuth"
290
- };
291
- const options = {
292
- draftAndPublish: false
293
- };
294
- const pluginOptions = {
295
- "content-manager": {
296
- visible: true
297
- },
298
- "content-type-builder": {
299
- visible: true
300
- }
301
- };
302
- const attributes = {
303
- name: {
304
- type: "string",
305
- required: true
306
- },
307
- pluginId: {
308
- type: "string",
309
- required: true
310
- },
311
- path: {
312
- type: "string",
313
- required: true,
314
- unique: true
315
- },
316
- description: {
317
- type: "text"
318
- },
319
- active: {
320
- type: "boolean",
321
- "default": true
322
- }
323
- };
324
- const mcpEndpoint = {
325
260
  kind,
326
261
  collectionName,
327
262
  info,
@@ -332,10 +267,9 @@ const mcpEndpoint = {
332
267
  const contentTypes = {
333
268
  "mcp-oauth-client": { schema: mcpOauthClient },
334
269
  "mcp-oauth-code": { schema: mcpOauthCode },
335
- "mcp-oauth-token": { schema: mcpOauthToken },
336
- "mcp-endpoint": { schema: mcpEndpoint }
270
+ "mcp-oauth-token": { schema: mcpOauthToken }
337
271
  };
338
- const PLUGIN_UID$2 = `plugin::${PLUGIN_ID}`;
272
+ const PLUGIN_UID$1 = `plugin::${PLUGIN_ID}`;
339
273
  function getBaseUrl(ctx, strapi) {
340
274
  const forwardedProto = ctx.request.headers["x-forwarded-proto"] || ctx.protocol;
341
275
  const forwardedHost = ctx.request.headers["x-forwarded-host"] || ctx.request.headers["host"];
@@ -372,17 +306,15 @@ const oauthController = ({ strapi }) => ({
372
306
  /**
373
307
  * OAuth 2.0 Protected Resource Metadata (RFC 9728)
374
308
  * GET /.well-known/oauth-protected-resource
309
+ *
310
+ * Convention-based protection: all /api/{plugin}/mcp endpoints are protected.
375
311
  */
376
312
  async protectedResource(ctx) {
377
313
  const baseUrl = getBaseUrl(ctx, strapi);
378
314
  const pluginPath = `/api/${PLUGIN_ID}`;
379
315
  const authServer = `${baseUrl}${pluginPath}`;
380
- const endpoints = await strapi.documents(`${PLUGIN_UID$2}.mcp-endpoint`).findMany({
381
- filters: { active: true }
382
- });
383
- const resources = endpoints.map((e) => `${baseUrl}${e.path}`);
384
316
  ctx.body = {
385
- resource: resources.length === 1 ? resources[0] : resources,
317
+ resource: `${baseUrl}/api`,
386
318
  authorization_servers: [authServer],
387
319
  bearer_methods_supported: ["header"]
388
320
  };
@@ -408,7 +340,7 @@ const oauthController = ({ strapi }) => ({
408
340
  ctx.body = { error: "unsupported_response_type", error_description: "Only code response type is supported" };
409
341
  return;
410
342
  }
411
- const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
343
+ const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
412
344
  filters: { clientId: client_id, active: true }
413
345
  });
414
346
  if (!client) {
@@ -437,7 +369,7 @@ const oauthController = ({ strapi }) => ({
437
369
  }
438
370
  const code = randomBytes(32).toString("hex");
439
371
  const expiresAt = new Date(Date.now() + 10 * 60 * 1e3);
440
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).create({
372
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).create({
441
373
  data: {
442
374
  code,
443
375
  clientId: client_id,
@@ -475,7 +407,7 @@ const oauthController = ({ strapi }) => ({
475
407
  ctx.body = { error: "invalid_client", error_description: "Client authentication required" };
476
408
  return;
477
409
  }
478
- const client = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-client`).findFirst({
410
+ const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
479
411
  filters: { clientId: authClientId, active: true }
480
412
  });
481
413
  if (!client || authClientSecret && client.clientSecret !== authClientSecret) {
@@ -499,7 +431,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
499
431
  ctx.body = { error: "invalid_request", error_description: "code is required" };
500
432
  return;
501
433
  }
502
- const authCode = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).findFirst({
434
+ const authCode = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).findFirst({
503
435
  filters: { code, clientId: client.clientId, used: false }
504
436
  });
505
437
  if (!authCode) {
@@ -517,7 +449,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
517
449
  ctx.body = { error: "invalid_grant", error_description: "redirect_uri mismatch" };
518
450
  return;
519
451
  }
520
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-code`).update({
452
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).update({
521
453
  documentId: authCode.documentId,
522
454
  data: { used: true }
523
455
  });
@@ -525,7 +457,7 @@ async function handleAuthorizationCodeGrant(ctx, strapi, client, code, redirect_
525
457
  const refreshToken = randomBytes(32).toString("hex");
526
458
  const expiresIn = 3600;
527
459
  const refreshExpiresIn = 30 * 24 * 3600;
528
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).create({
460
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).create({
529
461
  data: {
530
462
  accessToken,
531
463
  refreshToken,
@@ -548,7 +480,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
548
480
  ctx.body = { error: "invalid_request", error_description: "refresh_token is required" };
549
481
  return;
550
482
  }
551
- const token = await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).findFirst({
483
+ const token = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findFirst({
552
484
  filters: { refreshToken, clientId: client.clientId, revoked: false }
553
485
  });
554
486
  if (!token) {
@@ -561,7 +493,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
561
493
  ctx.body = { error: "invalid_grant", error_description: "Refresh token expired" };
562
494
  return;
563
495
  }
564
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).update({
496
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).update({
565
497
  documentId: token.documentId,
566
498
  data: { revoked: true }
567
499
  });
@@ -569,7 +501,7 @@ async function handleRefreshTokenGrant(ctx, strapi, client, refreshToken) {
569
501
  const newRefreshToken = randomBytes(32).toString("hex");
570
502
  const expiresIn = 3600;
571
503
  const refreshExpiresIn = 30 * 24 * 3600;
572
- await strapi.documents(`${PLUGIN_UID$2}.mcp-oauth-token`).create({
504
+ await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).create({
573
505
  data: {
574
506
  accessToken: newAccessToken,
575
507
  refreshToken: newRefreshToken,
@@ -646,14 +578,14 @@ const routes = {
646
578
  routes: [...admin]
647
579
  }
648
580
  };
649
- const PLUGIN_UID$1 = `plugin::${PLUGIN_ID}`;
581
+ const PLUGIN_UID = `plugin::${PLUGIN_ID}`;
650
582
  const oauthService = ({ strapi }) => ({
651
583
  /**
652
584
  * Validate an OAuth access token
653
585
  */
654
586
  async validateToken(accessToken) {
655
587
  try {
656
- const tokenRecord = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findFirst({
588
+ const tokenRecord = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findFirst({
657
589
  filters: { accessToken, revoked: false }
658
590
  });
659
591
  if (!tokenRecord) {
@@ -662,7 +594,7 @@ const oauthService = ({ strapi }) => ({
662
594
  if (new Date(tokenRecord.expiresAt) < /* @__PURE__ */ new Date()) {
663
595
  return { valid: false, error: "Token expired" };
664
596
  }
665
- const client = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-client`).findFirst({
597
+ const client = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-client`).findFirst({
666
598
  filters: { clientId: tokenRecord.clientId }
667
599
  });
668
600
  if (!client) {
@@ -682,11 +614,11 @@ const oauthService = ({ strapi }) => ({
682
614
  * Revoke all tokens for a client
683
615
  */
684
616
  async revokeClientTokens(clientId) {
685
- const tokens = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findMany({
617
+ const tokens = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findMany({
686
618
  filters: { clientId, revoked: false }
687
619
  });
688
620
  for (const token of tokens) {
689
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).update({
621
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).update({
690
622
  documentId: token.documentId,
691
623
  data: { revoked: true }
692
624
  });
@@ -698,19 +630,19 @@ const oauthService = ({ strapi }) => ({
698
630
  */
699
631
  async cleanupExpired() {
700
632
  const now = (/* @__PURE__ */ new Date()).toISOString();
701
- const expiredCodes = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).findMany({
633
+ const expiredCodes = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-code`).findMany({
702
634
  filters: { expiresAt: { $lt: now } }
703
635
  });
704
636
  for (const code of expiredCodes) {
705
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-code`).delete({
637
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-code`).delete({
706
638
  documentId: code.documentId
707
639
  });
708
640
  }
709
- const expiredTokens = await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).findMany({
641
+ const expiredTokens = await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).findMany({
710
642
  filters: { refreshExpiresAt: { $lt: now } }
711
643
  });
712
644
  for (const token of expiredTokens) {
713
- await strapi.documents(`${PLUGIN_UID$1}.mcp-oauth-token`).delete({
645
+ await strapi.documents(`${PLUGIN_UID}.mcp-oauth-token`).delete({
714
646
  documentId: token.documentId
715
647
  });
716
648
  }
@@ -720,80 +652,8 @@ const oauthService = ({ strapi }) => ({
720
652
  };
721
653
  }
722
654
  });
723
- const PLUGIN_UID = `plugin::${PLUGIN_ID}`;
724
- const endpointService = ({ strapi }) => ({
725
- /**
726
- * Register an MCP endpoint for OAuth protection
727
- */
728
- async register(endpoint) {
729
- const existing = await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findFirst({
730
- filters: { path: endpoint.path }
731
- });
732
- if (existing) {
733
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).update({
734
- documentId: existing.documentId,
735
- data: {
736
- name: endpoint.name,
737
- pluginId: endpoint.pluginId,
738
- description: endpoint.description,
739
- active: true
740
- }
741
- });
742
- }
743
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).create({
744
- data: {
745
- name: endpoint.name,
746
- pluginId: endpoint.pluginId,
747
- path: endpoint.path,
748
- description: endpoint.description,
749
- active: true
750
- }
751
- });
752
- },
753
- /**
754
- * Unregister an MCP endpoint
755
- */
756
- async unregister(path) {
757
- const endpoint = await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findFirst({
758
- filters: { path }
759
- });
760
- if (!endpoint) {
761
- return false;
762
- }
763
- await strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).update({
764
- documentId: endpoint.documentId,
765
- data: { active: false }
766
- });
767
- return true;
768
- },
769
- /**
770
- * Get all registered endpoints
771
- */
772
- async getAll(activeOnly = true) {
773
- const filters = activeOnly ? { active: true } : {};
774
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findMany({ filters });
775
- },
776
- /**
777
- * Get endpoints for a specific plugin
778
- */
779
- async getByPlugin(pluginId, activeOnly = true) {
780
- const filters = { pluginId };
781
- if (activeOnly) {
782
- filters.active = true;
783
- }
784
- return strapi.documents(`${PLUGIN_UID}.mcp-endpoint`).findMany({ filters });
785
- },
786
- /**
787
- * Check if a path is a protected endpoint
788
- */
789
- async isProtected(path) {
790
- const endpoints = await this.getAll(true);
791
- return endpoints.some((e) => path.includes(e.path));
792
- }
793
- });
794
655
  const services = {
795
- oauth: oauthService,
796
- endpoint: endpointService
656
+ oauth: oauthService
797
657
  };
798
658
  const index = {
799
659
  register,
@@ -159,50 +159,5 @@ declare const _default: {
159
159
  };
160
160
  };
161
161
  };
162
- 'mcp-endpoint': {
163
- schema: {
164
- kind: string;
165
- collectionName: string;
166
- info: {
167
- singularName: string;
168
- pluralName: string;
169
- displayName: string;
170
- description: string;
171
- };
172
- options: {
173
- draftAndPublish: boolean;
174
- };
175
- pluginOptions: {
176
- "content-manager": {
177
- visible: boolean;
178
- };
179
- "content-type-builder": {
180
- visible: boolean;
181
- };
182
- };
183
- attributes: {
184
- name: {
185
- type: string;
186
- required: boolean;
187
- };
188
- pluginId: {
189
- type: string;
190
- required: boolean;
191
- };
192
- path: {
193
- type: string;
194
- required: boolean;
195
- unique: boolean;
196
- };
197
- description: {
198
- type: string;
199
- };
200
- active: {
201
- type: string;
202
- default: boolean;
203
- };
204
- };
205
- };
206
- };
207
162
  };
208
163
  export default _default;
@@ -15,6 +15,8 @@ declare const oauthController: ({ strapi }: {
15
15
  /**
16
16
  * OAuth 2.0 Protected Resource Metadata (RFC 9728)
17
17
  * GET /.well-known/oauth-protected-resource
18
+ *
19
+ * Convention-based protection: all /api/{plugin}/mcp endpoints are protected.
18
20
  */
19
21
  protectedResource(ctx: any): Promise<void>;
20
22
  /**
@@ -51,15 +51,6 @@ declare const _default: {
51
51
  codes: number;
52
52
  }>;
53
53
  };
54
- endpoint: ({ strapi }: {
55
- strapi: import("@strapi/types/dist/core").Strapi;
56
- }) => {
57
- register(endpoint: import("./services/endpoint").EndpointRegistration): Promise<any>;
58
- unregister(path: string): Promise<boolean>;
59
- getAll(activeOnly?: boolean): Promise<any[]>;
60
- getByPlugin(pluginId: string, activeOnly?: boolean): Promise<any[]>;
61
- isProtected(path: string): Promise<boolean>;
62
- };
63
54
  };
64
55
  contentTypes: {
65
56
  'mcp-oauth-client': {
@@ -222,51 +213,6 @@ declare const _default: {
222
213
  };
223
214
  };
224
215
  };
225
- 'mcp-endpoint': {
226
- schema: {
227
- kind: string;
228
- collectionName: string;
229
- info: {
230
- singularName: string;
231
- pluralName: string;
232
- displayName: string;
233
- description: string;
234
- };
235
- options: {
236
- draftAndPublish: boolean;
237
- };
238
- pluginOptions: {
239
- "content-manager": {
240
- visible: boolean;
241
- };
242
- "content-type-builder": {
243
- visible: boolean;
244
- };
245
- };
246
- attributes: {
247
- name: {
248
- type: string;
249
- required: boolean;
250
- };
251
- pluginId: {
252
- type: string;
253
- required: boolean;
254
- };
255
- path: {
256
- type: string;
257
- required: boolean;
258
- unique: boolean;
259
- };
260
- description: {
261
- type: string;
262
- };
263
- active: {
264
- type: string;
265
- default: boolean;
266
- };
267
- };
268
- };
269
- };
270
216
  };
271
217
  policies: {};
272
218
  middlewares: {
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * MCP OAuth Authentication Middleware
3
3
  *
4
- * This middleware provides OAuth 2.0 authentication for all registered MCP endpoints.
4
+ * This middleware provides OAuth 2.0 authentication for all MCP endpoints.
5
+ * Uses convention-based protection: any route matching /api/{plugin}/mcp is protected.
6
+ *
5
7
  * It supports dual authentication:
6
8
  * - OAuth 2.0 tokens (for ChatGPT and other OAuth clients)
7
9
  * - Direct Strapi API tokens (for Claude Desktop and scripts)
@@ -9,14 +9,5 @@ declare const _default: {
9
9
  codes: number;
10
10
  }>;
11
11
  };
12
- endpoint: ({ strapi }: {
13
- strapi: import("@strapi/types/dist/core").Strapi;
14
- }) => {
15
- register(endpoint: import("./endpoint").EndpointRegistration): Promise<any>;
16
- unregister(path: string): Promise<boolean>;
17
- getAll(activeOnly?: boolean): Promise<any[]>;
18
- getByPlugin(pluginId: string, activeOnly?: boolean): Promise<any[]>;
19
- isProtected(path: string): Promise<boolean>;
20
- };
21
12
  };
22
13
  export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-oauth-mcp-manager",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Centralized OAuth 2.0 authentication manager for Strapi MCP plugins. Supports ChatGPT, Claude, and custom OAuth clients.",
5
5
  "keywords": [
6
6
  "strapi",
@@ -1,37 +0,0 @@
1
- /**
2
- * Endpoint Registration Service
3
- *
4
- * Allows MCP plugins to register their endpoints for OAuth protection.
5
- */
6
- import type { Core } from '@strapi/strapi';
7
- export interface EndpointRegistration {
8
- name: string;
9
- pluginId: string;
10
- path: string;
11
- description?: string;
12
- }
13
- declare const endpointService: ({ strapi }: {
14
- strapi: Core.Strapi;
15
- }) => {
16
- /**
17
- * Register an MCP endpoint for OAuth protection
18
- */
19
- register(endpoint: EndpointRegistration): Promise<any>;
20
- /**
21
- * Unregister an MCP endpoint
22
- */
23
- unregister(path: string): Promise<boolean>;
24
- /**
25
- * Get all registered endpoints
26
- */
27
- getAll(activeOnly?: boolean): Promise<any[]>;
28
- /**
29
- * Get endpoints for a specific plugin
30
- */
31
- getByPlugin(pluginId: string, activeOnly?: boolean): Promise<any[]>;
32
- /**
33
- * Check if a path is a protected endpoint
34
- */
35
- isProtected(path: string): Promise<boolean>;
36
- };
37
- export default endpointService;