@frogbotai/plugin-mcp 0.29.0 → 0.31.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 +2 -2
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +57 -31
- package/dist/access.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -17
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @frogbotai/plugin-mcp
|
|
2
2
|
|
|
3
|
-
Expose selected FrogBot collections and globals to external MCP clients
|
|
3
|
+
Expose selected FrogBot collections and globals to external MCP clients.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { apiKeysPlugin } from '@frogbotai/plugin-api-keys';
|
|
@@ -25,4 +25,4 @@ export default buildConfig({
|
|
|
25
25
|
|
|
26
26
|
Connect MCP clients to `/api/mcp` with a Bearer token minted by `@frogbotai/plugin-api-keys`. Revoked, malformed, and unknown keys are rejected. The plugin requires `apiKeysPlugin()` earlier in the plugin array.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
The plugin also adds a dormant `payload-mcp-api-keys` collection for schema stability, but its keys cannot authenticate this endpoint. Experimental config, collection-definition, job, and auth-mutation tools are unavailable. SSE is not supported.
|
package/dist/access.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAsB,MAAM,SAAS,CAAC;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,KAAK,uBAAuB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,aAAa,EAAE,eAAe,CAAC;IAC/B,GAAG,EAAE,cAAc,CAAC;CACrB,CAAC;AAOF,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,eAAe,GAAG,IAAI,CAiB5E;AA0BD,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,QAAQ,EACR,aAAa,EACb,GAAG,GACJ,EAAE,uBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAsCtD"}
|
package/dist/access.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import { executeAuthStrategy } from 'frogbot/internal';
|
|
1
|
+
import { attachRegisteredFrogBot, executeAuthStrategy } from 'frogbot/internal';
|
|
2
2
|
import { UnauthorizedError } from 'payload';
|
|
3
|
-
const toCamelCase = (value) =>
|
|
4
|
-
.replace(/[-_\s]+(.)?/g, (_, character) => character?.toUpperCase() ?? '')
|
|
5
|
-
.replace(/^(.)/, (_, character) => character.toLowerCase());
|
|
3
|
+
const toCamelCase = (value)=>value.replace(/[-_\s]+(.)?/g, (_, character)=>character?.toUpperCase() ?? '').replace(/^(.)/, (_, character)=>character.toLowerCase());
|
|
6
4
|
export function validateMcpCapabilities(pluginOptions) {
|
|
7
|
-
const reserved = new Set([
|
|
5
|
+
const reserved = new Set([
|
|
6
|
+
'auth',
|
|
7
|
+
'config',
|
|
8
|
+
'jobs'
|
|
9
|
+
]);
|
|
8
10
|
for (const [type, entities] of [
|
|
9
|
-
[
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
[
|
|
12
|
+
'Collection',
|
|
13
|
+
pluginOptions.collections
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
'Global',
|
|
17
|
+
pluginOptions.globals
|
|
18
|
+
]
|
|
19
|
+
]){
|
|
20
|
+
for (const slug of Object.keys(entities ?? {})){
|
|
13
21
|
const capability = toCamelCase(slug);
|
|
14
22
|
if (reserved.has(capability)) {
|
|
15
23
|
throw new Error(`[plugin-mcp] ${type} slug '${slug}' maps to reserved MCP capability '${capability}'.`);
|
|
@@ -18,24 +26,33 @@ export function validateMcpCapabilities(pluginOptions) {
|
|
|
18
26
|
}
|
|
19
27
|
}
|
|
20
28
|
function collectionGrants(options) {
|
|
21
|
-
return Object.fromEntries(Object.entries(options ?? {}).map(([slug, config])
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
return Object.fromEntries(Object.entries(options ?? {}).map(([slug, config])=>[
|
|
30
|
+
toCamelCase(slug),
|
|
31
|
+
config?.enabled === true ? {
|
|
32
|
+
create: true,
|
|
33
|
+
delete: true,
|
|
34
|
+
find: true,
|
|
35
|
+
update: true
|
|
36
|
+
} : config?.enabled
|
|
37
|
+
]));
|
|
27
38
|
}
|
|
28
39
|
function globalGrants(options) {
|
|
29
|
-
return Object.fromEntries(Object.entries(options ?? {}).map(([slug, config])
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
return Object.fromEntries(Object.entries(options ?? {}).map(([slug, config])=>[
|
|
41
|
+
toCamelCase(slug),
|
|
42
|
+
config?.enabled === true ? {
|
|
43
|
+
find: true,
|
|
44
|
+
update: true
|
|
45
|
+
} : config?.enabled
|
|
46
|
+
]));
|
|
33
47
|
}
|
|
34
48
|
function namedGrants(items) {
|
|
35
|
-
return Object.fromEntries((items ?? []).map(({ name })
|
|
49
|
+
return Object.fromEntries((items ?? []).map(({ name })=>[
|
|
50
|
+
toCamelCase(name),
|
|
51
|
+
true
|
|
52
|
+
]));
|
|
36
53
|
}
|
|
37
|
-
export async function resolveMcpAccess({ collection, strategy, pluginOptions, req
|
|
38
|
-
const frogbotReq = req;
|
|
54
|
+
export async function resolveMcpAccess({ collection, strategy, pluginOptions, req }) {
|
|
55
|
+
const frogbotReq = attachRegisteredFrogBot(req);
|
|
39
56
|
const frogbot = frogbotReq.frogbot;
|
|
40
57
|
let result;
|
|
41
58
|
try {
|
|
@@ -45,16 +62,17 @@ export async function resolveMcpAccess({ collection, strategy, pluginOptions, re
|
|
|
45
62
|
frogbot,
|
|
46
63
|
headers: req.headers,
|
|
47
64
|
req: frogbotReq,
|
|
48
|
-
strategyName: strategy.name
|
|
65
|
+
strategyName: strategy.name
|
|
49
66
|
});
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
67
|
+
} catch {
|
|
52
68
|
throw new UnauthorizedError();
|
|
53
69
|
}
|
|
54
|
-
if (!result.user)
|
|
55
|
-
throw new UnauthorizedError();
|
|
70
|
+
if (!result.user) throw new UnauthorizedError();
|
|
56
71
|
return {
|
|
57
|
-
user: {
|
|
72
|
+
user: {
|
|
73
|
+
...result.user,
|
|
74
|
+
collection: result.user.collection ?? collection
|
|
75
|
+
},
|
|
58
76
|
...collectionGrants(pluginOptions.collections),
|
|
59
77
|
...globalGrants(pluginOptions.globals),
|
|
60
78
|
'payload-mcp-tool': namedGrants(pluginOptions.mcp?.tools),
|
|
@@ -66,10 +84,18 @@ export async function resolveMcpAccess({ collection, strategy, pluginOptions, re
|
|
|
66
84
|
login: false,
|
|
67
85
|
resetPassword: false,
|
|
68
86
|
unlock: false,
|
|
69
|
-
verify: false
|
|
87
|
+
verify: false
|
|
70
88
|
},
|
|
71
|
-
config: {
|
|
72
|
-
|
|
89
|
+
config: {
|
|
90
|
+
find: false,
|
|
91
|
+
update: false
|
|
92
|
+
},
|
|
93
|
+
jobs: {
|
|
94
|
+
create: false,
|
|
95
|
+
run: false,
|
|
96
|
+
update: false
|
|
97
|
+
}
|
|
73
98
|
};
|
|
74
99
|
}
|
|
100
|
+
|
|
75
101
|
//# sourceMappingURL=access.js.map
|
package/dist/access.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/access.ts"],"names":["attachRegisteredFrogBot","executeAuthStrategy","UnauthorizedError","toCamelCase","value","replace","_","character","toUpperCase","toLowerCase","validateMcpCapabilities","pluginOptions","reserved","Set","type","entities","collections","globals","slug","Object","keys","capability","has","Error","collectionGrants","options","fromEntries","entries","map","config","enabled","create","delete","find","update","globalGrants","namedGrants","items","name","resolveMcpAccess","collection","strategy","req","frogbotReq","frogbot","result","headers","strategyName","user","mcp","tools","prompts","resources","auth","forgotPassword","login","resetPassword","unlock","verify","jobs","run"],"mappings":"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","file":"access.js"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,eAAe,EAAE,cAAc,GAAG,cAAc,CAAC,CAAC;AAEtF,wBAAgB,SAAS,CAAC,aAAa,GAAE,gBAAqB,GAAG,MAAM,CAsCtE"}
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import { isApiKeyStrategy } from '@frogbotai/plugin-api-keys';
|
|
2
2
|
import { mcpPlugin as payloadMcpPlugin } from '@payloadcms/plugin-mcp';
|
|
3
|
+
import { wrapPayloadPlugin } from 'frogbot/internal';
|
|
3
4
|
import { resolveMcpAccess, validateMcpCapabilities } from './access.js';
|
|
4
5
|
export function mcpPlugin(pluginOptions = {}) {
|
|
5
6
|
validateMcpCapabilities(pluginOptions);
|
|
6
|
-
return async (config)
|
|
7
|
-
const apiKeyStrategy = config.collections
|
|
8
|
-
.flatMap((collection) => {
|
|
7
|
+
return async (config)=>{
|
|
8
|
+
const apiKeyStrategy = config.collections.flatMap((collection)=>{
|
|
9
9
|
const auth = typeof collection.auth === 'object' ? collection.auth : undefined;
|
|
10
|
-
return (auth?.strategies ?? []).map((strategy)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})
|
|
15
|
-
.find(({ strategy }) => isApiKeyStrategy(strategy));
|
|
10
|
+
return (auth?.strategies ?? []).map((strategy)=>({
|
|
11
|
+
collection: collection.slug,
|
|
12
|
+
strategy
|
|
13
|
+
}));
|
|
14
|
+
}).find(({ strategy })=>isApiKeyStrategy(strategy));
|
|
16
15
|
if (!apiKeyStrategy) {
|
|
17
16
|
throw new Error('[plugin-mcp] apiKeysPlugin must be configured before mcpPlugin.');
|
|
18
17
|
}
|
|
19
18
|
const { experimental: _experimental, overrideAuth: _overrideAuth, ...options } = pluginOptions;
|
|
20
|
-
return (
|
|
19
|
+
return wrapPayloadPlugin(payloadMcpPlugin({
|
|
21
20
|
...options,
|
|
22
|
-
overrideAuth: (req)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})(config)
|
|
21
|
+
overrideAuth: (req)=>resolveMcpAccess({
|
|
22
|
+
collection: apiKeyStrategy.collection,
|
|
23
|
+
strategy: apiKeyStrategy.strategy,
|
|
24
|
+
pluginOptions: options,
|
|
25
|
+
req
|
|
26
|
+
})
|
|
27
|
+
}))(config);
|
|
29
28
|
};
|
|
30
29
|
}
|
|
30
|
+
|
|
31
31
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["isApiKeyStrategy","mcpPlugin","payloadMcpPlugin","wrapPayloadPlugin","resolveMcpAccess","validateMcpCapabilities","pluginOptions","config","apiKeyStrategy","collections","flatMap","collection","auth","undefined","strategies","map","strategy","slug","find","Error","experimental","_experimental","overrideAuth","_overrideAuth","options","req"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,6BAA6B;AAE9D,SAASC,aAAaC,gBAAgB,QAAQ,yBAAyB;AAEvE,SAASC,iBAAiB,QAAQ,mBAAmB;AAErD,SAASC,gBAAgB,EAAEC,uBAAuB,QAAQ,cAAc;AAIxE,OAAO,SAASJ,UAAUK,gBAAkC,CAAC,CAAC;IAC5DD,wBAAwBC;IAExB,OAAO,OAAOC;QACZ,MAAMC,iBAAiBD,OAAOE,WAAW,CACtCC,OAAO,CAAC,CAACC;YACR,MAAMC,OAAO,OAAOD,WAAWC,IAAI,KAAK,WAAWD,WAAWC,IAAI,GAAGC;YAErE,OAAO,AAACD,CAAAA,MAAME,cAAc,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC,WAAc,CAAA;oBACjDL,YAAYA,WAAWM,IAAI;oBAC3BD;gBACF,CAAA;QACF,GACCE,IAAI,CAAC,CAAC,EAAEF,QAAQ,EAAE,GAAKhB,iBAAiBgB;QAE3C,IAAI,CAACR,gBAAgB;YACnB,MAAM,IAAIW,MAAM;QAClB;QAEA,MAAM,EACJC,cAAcC,aAAa,EAC3BC,cAAcC,aAAa,EAC3B,GAAGC,SACJ,GAAGlB;QAEJ,OAAOH,kBACLD,iBAAiB;YACf,GAAGsB,OAAO;YACVF,cAAc,CAACG,MACbrB,iBAAiB;oBACfO,YAAYH,eAAeG,UAAU;oBACrCK,UAAUR,eAAeQ,QAAQ;oBACjCV,eAAekB;oBACfC;gBACF;QACJ,IACAlB;IACJ;AACF","file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frogbotai/plugin-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Payload MCP integration for FrogBot.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Colby Gilbert",
|
|
@@ -31,21 +31,21 @@
|
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"payload": "3.90.1",
|
|
34
|
-
"@frogbotai/plugin-api-keys": "0.
|
|
35
|
-
"frogbot": "0.
|
|
34
|
+
"@frogbotai/plugin-api-keys": "0.31.0",
|
|
35
|
+
"frogbot": "0.31.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"payload": "3.90.1",
|
|
39
39
|
"typescript": "5.6.2",
|
|
40
|
-
"@frogbotai/plugin-
|
|
41
|
-
"@frogbotai/plugin-
|
|
42
|
-
"frogbot": "0.
|
|
40
|
+
"@frogbotai/plugin-api-keys": "0.31.0",
|
|
41
|
+
"@frogbotai/plugin-roles": "0.31.0",
|
|
42
|
+
"frogbot": "0.31.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
|
-
"build": "
|
|
48
|
+
"build": "node ../../../scripts/build-package.mjs",
|
|
49
49
|
"clean": "rm -rf dist",
|
|
50
50
|
"typecheck": "tsc --noEmit"
|
|
51
51
|
}
|