@forumone/throughline 2.2.0 → 2.3.0-pr-315-e1a501e
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/CHANGELOG.md +16 -0
- package/dist/audit/types.d.ts +1 -1
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/audit/types.js +2 -0
- package/dist/audit/types.js.map +1 -1
- package/dist/editorial/palette/ReportsNav.d.ts +3 -1
- package/dist/editorial/palette/ReportsNav.d.ts.map +1 -1
- package/dist/editorial/palette/ReportsNav.js +3 -3
- package/dist/editorial/palette/ReportsNav.js.map +1 -1
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.d.ts.map +1 -1
- package/dist/exports/rsc.js +2 -0
- package/dist/exports/rsc.js.map +1 -1
- package/dist/mcp-oauth/admin/McpClientActions.d.ts +15 -0
- package/dist/mcp-oauth/admin/McpClientActions.d.ts.map +1 -0
- package/dist/mcp-oauth/admin/McpClientActions.js +79 -0
- package/dist/mcp-oauth/admin/McpClientActions.js.map +1 -0
- package/dist/mcp-oauth/admin/styles.d.ts +2 -0
- package/dist/mcp-oauth/admin/styles.d.ts.map +1 -0
- package/dist/mcp-oauth/admin/styles.js +27 -0
- package/dist/mcp-oauth/admin/styles.js.map +1 -0
- package/dist/mcp-oauth/admin/views.d.ts +4 -0
- package/dist/mcp-oauth/admin/views.d.ts.map +1 -0
- package/dist/mcp-oauth/admin/views.js +99 -0
- package/dist/mcp-oauth/admin/views.js.map +1 -0
- package/dist/mcp-oauth/auth.d.ts +12 -0
- package/dist/mcp-oauth/auth.d.ts.map +1 -0
- package/dist/mcp-oauth/auth.js +56 -0
- package/dist/mcp-oauth/auth.js.map +1 -0
- package/dist/mcp-oauth/cimd.d.ts +13 -0
- package/dist/mcp-oauth/cimd.d.ts.map +1 -0
- package/dist/mcp-oauth/cimd.js +93 -0
- package/dist/mcp-oauth/cimd.js.map +1 -0
- package/dist/mcp-oauth/clients.d.ts +42 -0
- package/dist/mcp-oauth/clients.d.ts.map +1 -0
- package/dist/mcp-oauth/clients.js +151 -0
- package/dist/mcp-oauth/clients.js.map +1 -0
- package/dist/mcp-oauth/collections.d.ts +10 -0
- package/dist/mcp-oauth/collections.d.ts.map +1 -0
- package/dist/mcp-oauth/collections.js +236 -0
- package/dist/mcp-oauth/collections.js.map +1 -0
- package/dist/mcp-oauth/crypto.d.ts +29 -0
- package/dist/mcp-oauth/crypto.d.ts.map +1 -0
- package/dist/mcp-oauth/crypto.js +91 -0
- package/dist/mcp-oauth/crypto.js.map +1 -0
- package/dist/mcp-oauth/endpoints.d.ts +11 -0
- package/dist/mcp-oauth/endpoints.d.ts.map +1 -0
- package/dist/mcp-oauth/endpoints.js +365 -0
- package/dist/mcp-oauth/endpoints.js.map +1 -0
- package/dist/mcp-oauth/index.d.ts +10 -0
- package/dist/mcp-oauth/index.d.ts.map +1 -0
- package/dist/mcp-oauth/index.js +6 -0
- package/dist/mcp-oauth/index.js.map +1 -0
- package/dist/mcp-oauth/metadata.d.ts +45 -0
- package/dist/mcp-oauth/metadata.d.ts.map +1 -0
- package/dist/mcp-oauth/metadata.js +84 -0
- package/dist/mcp-oauth/metadata.js.map +1 -0
- package/dist/mcp-oauth/plugin.d.ts +37 -0
- package/dist/mcp-oauth/plugin.d.ts.map +1 -0
- package/dist/mcp-oauth/plugin.js +90 -0
- package/dist/mcp-oauth/plugin.js.map +1 -0
- package/dist/mcp-oauth/runtime.d.ts +124 -0
- package/dist/mcp-oauth/runtime.d.ts.map +1 -0
- package/dist/mcp-oauth/runtime.js +111 -0
- package/dist/mcp-oauth/runtime.js.map +1 -0
- package/dist/mcp-oauth/store.d.ts +75 -0
- package/dist/mcp-oauth/store.d.ts.map +1 -0
- package/dist/mcp-oauth/store.js +408 -0
- package/dist/mcp-oauth/store.js.map +1 -0
- package/dist/migrate/exports.json +29 -0
- package/package.json +7 -3
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The two discovery documents, and the exact values clients check.
|
|
3
|
+
|
|
4
|
+
A client finds everything from the `401` on `/api/mcp`: its `WWW-Authenticate`
|
|
5
|
+
points at the protected-resource metadata (RFC 9728), which names this site as
|
|
6
|
+
the authorization server, whose own metadata (RFC 8414) lists the endpoints.
|
|
7
|
+
|
|
8
|
+
What each client is strict about, from their documentation:
|
|
9
|
+
|
|
10
|
+
- Claude uses only the **first** `authorization_servers` entry, and requires
|
|
11
|
+
`resource` to equal the URL the person typed, path included.
|
|
12
|
+
- Claude picks a client ID metadata document (CIMD) only when **both**
|
|
13
|
+
`client_id_metadata_document_supported` and `"none"` among the token
|
|
14
|
+
endpoint's auth methods are present; otherwise it registers (DCR).
|
|
15
|
+
- ChatGPT uses its stable callback only when the authorization response carries
|
|
16
|
+
`iss` (RFC 9207), and compares it to `issuer` byte for byte.
|
|
17
|
+
- Both append `offline_access` to the scopes when it is listed, which is what
|
|
18
|
+
gets them a refresh token.
|
|
19
|
+
*/
|
|
20
|
+
export const MCP_SCOPE = 'mcp';
|
|
21
|
+
export function authorizationServerMetadata(runtime) {
|
|
22
|
+
return {
|
|
23
|
+
issuer: runtime.issuer,
|
|
24
|
+
authorization_endpoint: runtime.endpoint('authorize'),
|
|
25
|
+
token_endpoint: runtime.endpoint('token'),
|
|
26
|
+
registration_endpoint: runtime.endpoint('register'),
|
|
27
|
+
revocation_endpoint: runtime.endpoint('revoke'),
|
|
28
|
+
response_types_supported: ['code'],
|
|
29
|
+
response_modes_supported: ['query'],
|
|
30
|
+
grant_types_supported: ['authorization_code', 'refresh_token'],
|
|
31
|
+
token_endpoint_auth_methods_supported: ['none'],
|
|
32
|
+
revocation_endpoint_auth_methods_supported: ['none'],
|
|
33
|
+
code_challenge_methods_supported: ['S256'],
|
|
34
|
+
scopes_supported: [MCP_SCOPE, 'offline_access'],
|
|
35
|
+
client_id_metadata_document_supported: true,
|
|
36
|
+
authorization_response_iss_parameter_supported: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function protectedResourceMetadata(runtime) {
|
|
40
|
+
return {
|
|
41
|
+
resource: runtime.resource,
|
|
42
|
+
authorization_servers: [runtime.issuer],
|
|
43
|
+
bearer_methods_supported: ['header'],
|
|
44
|
+
scopes_supported: [MCP_SCOPE],
|
|
45
|
+
resource_name: runtime.serverName,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Where the protected-resource metadata is served. */
|
|
49
|
+
export function protectedResourceMetadataUrl(runtime) {
|
|
50
|
+
return `${runtime.origin}/.well-known/oauth-protected-resource${new URL(runtime.resource).pathname}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Rewrites for `next.config`, so the well-known paths at the root reach the
|
|
54
|
+
* endpoints Payload serves under its API route. Payload only routes under
|
|
55
|
+
* `/api`; RFC 8414 and RFC 9728 put discovery at `/.well-known`.
|
|
56
|
+
*
|
|
57
|
+
* ```js
|
|
58
|
+
* async rewrites() {
|
|
59
|
+
* return mcpOAuthRewrites()
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function mcpOAuthRewrites({ apiRoute = '/api' } = {}) {
|
|
64
|
+
const api = apiRoute.replace(/\/+$/, '');
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
source: '/.well-known/oauth-protected-resource',
|
|
68
|
+
destination: `${api}/oauth/protected-resource`,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
source: '/.well-known/oauth-protected-resource/:path*',
|
|
72
|
+
destination: `${api}/oauth/protected-resource`,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
source: '/.well-known/oauth-authorization-server',
|
|
76
|
+
destination: `${api}/oauth/metadata`,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
source: '/.well-known/oauth-authorization-server/:path*',
|
|
80
|
+
destination: `${api}/oauth/metadata`,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/mcp-oauth/metadata.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;EAkBE;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAA;AAE9B,MAAM,UAAU,2BAA2B,CAAC,OAAwB;IAClE,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,sBAAsB,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;QACrD,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;QACzC,qBAAqB,EAAE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;QACnD,mBAAmB,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC/C,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,wBAAwB,EAAE,CAAC,OAAO,CAAC;QACnC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC9D,qCAAqC,EAAE,CAAC,MAAM,CAAC;QAC/C,0CAA0C,EAAE,CAAC,MAAM,CAAC;QACpD,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,gBAAgB,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC;QAC/C,qCAAqC,EAAE,IAAI;QAC3C,8CAA8C,EAAE,IAAI;KACrD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAwB;IAChE,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,qBAAqB,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;QACvC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;QACpC,gBAAgB,EAAE,CAAC,SAAS,CAAC;QAC7B,aAAa,EAAE,OAAO,CAAC,UAAU;KAClC,CAAA;AACH,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,4BAA4B,CAAC,OAAwB;IACnE,OAAO,GAAG,OAAO,CAAC,MAAM,wCAAwC,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAA;AACtG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAE,QAAQ,GAAG,MAAM,KAA4B,EAAE;IAChF,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACxC,OAAO;QACL;YACE,MAAM,EAAE,uCAAuC;YAC/C,WAAW,EAAE,GAAG,GAAG,2BAA2B;SAC/C;QACD;YACE,MAAM,EAAE,8CAA8C;YACtD,WAAW,EAAE,GAAG,GAAG,2BAA2B;SAC/C;QACD;YACE,MAAM,EAAE,yCAAyC;YACjD,WAAW,EAAE,GAAG,GAAG,iBAAiB;SACrC;QACD;YACE,MAAM,EAAE,gDAAgD;YACxD,WAAW,EAAE,GAAG,GAAG,iBAAiB;SACrC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Plugin } from 'payload';
|
|
2
|
+
import { type OverrideAuth } from './auth.js';
|
|
3
|
+
import { type EndpointOptions } from './endpoints.js';
|
|
4
|
+
import { type McpOAuthOptions, type McpOAuthRuntime } from './runtime.js';
|
|
5
|
+
export declare const CONNECT_MCP_VIEW_PATH = "@forumone/throughline/rsc#ConnectMcpView";
|
|
6
|
+
export declare const MCP_AUTHORIZE_VIEW_PATH = "@forumone/throughline/rsc#McpAuthorizeView";
|
|
7
|
+
export interface McpOAuth {
|
|
8
|
+
/** Registers the endpoints, the collections, the policy and the admin pages. */
|
|
9
|
+
plugin: Plugin;
|
|
10
|
+
/** For `mcpPlugin({ overrideAuth })`. */
|
|
11
|
+
overrideAuth: OverrideAuth;
|
|
12
|
+
runtime: McpOAuthRuntime;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* OAuth sign-in for `/api/mcp`: a person adds the server's URL to Claude or
|
|
16
|
+
* ChatGPT, signs in to the admin as themselves, and allows the connection. No
|
|
17
|
+
* key to copy.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* const oauth = mcpOAuth({ serverURL, serverName: 'Example', tools: mcpTools, prompts: mcpPrompts,
|
|
21
|
+
* isAdmin, eligible })
|
|
22
|
+
*
|
|
23
|
+
* plugins: [
|
|
24
|
+
* ...throughline plugins, // declare the tools first
|
|
25
|
+
* oauth.plugin,
|
|
26
|
+
* mcpPlugin({ mcp: { tools: mcpTools, prompts: mcpPrompts }, overrideAuth: oauth.overrideAuth }),
|
|
27
|
+
* ]
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* And in `next.config`, `rewrites: async () => mcpOAuthRewrites()`, so the
|
|
31
|
+
* discovery documents are found at `/.well-known`.
|
|
32
|
+
*
|
|
33
|
+
* API keys keep working beside it: a bearer token that is not one of these is
|
|
34
|
+
* handed to the plugin's own key lookup.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mcpOAuth(options: McpOAuthOptions, endpointOptions?: EndpointOptions): McpOAuth;
|
|
37
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/mcp-oauth/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,MAAM,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA;AAEjE,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAA;AAErB,eAAO,MAAM,qBAAqB,6CAA6C,CAAA;AAC/E,eAAO,MAAM,uBAAuB,+CAA+C,CAAA;AAEnF,MAAM,WAAW,QAAQ;IACvB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,YAAY,EAAE,YAAY,CAAA;IAC1B,OAAO,EAAE,eAAe,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,eAAe,EACxB,eAAe,GAAE,eAAoB,GACpC,QAAQ,CAiEV"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { REPORTS_NAV_PATH } from '../editorial/plugin.js';
|
|
2
|
+
import { createOverrideAuth } from './auth.js';
|
|
3
|
+
import { accessGlobal, clientsCollection, grantsCollection } from './collections.js';
|
|
4
|
+
import { oauthEndpoints } from './endpoints.js';
|
|
5
|
+
import { createRuntime, MCP_OAUTH_CUSTOM_KEY, } from './runtime.js';
|
|
6
|
+
export const CONNECT_MCP_VIEW_PATH = '@forumone/throughline/rsc#ConnectMcpView';
|
|
7
|
+
export const MCP_AUTHORIZE_VIEW_PATH = '@forumone/throughline/rsc#McpAuthorizeView';
|
|
8
|
+
/**
|
|
9
|
+
* OAuth sign-in for `/api/mcp`: a person adds the server's URL to Claude or
|
|
10
|
+
* ChatGPT, signs in to the admin as themselves, and allows the connection. No
|
|
11
|
+
* key to copy.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const oauth = mcpOAuth({ serverURL, serverName: 'Example', tools: mcpTools, prompts: mcpPrompts,
|
|
15
|
+
* isAdmin, eligible })
|
|
16
|
+
*
|
|
17
|
+
* plugins: [
|
|
18
|
+
* ...throughline plugins, // declare the tools first
|
|
19
|
+
* oauth.plugin,
|
|
20
|
+
* mcpPlugin({ mcp: { tools: mcpTools, prompts: mcpPrompts }, overrideAuth: oauth.overrideAuth }),
|
|
21
|
+
* ]
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* And in `next.config`, `rewrites: async () => mcpOAuthRewrites()`, so the
|
|
25
|
+
* discovery documents are found at `/.well-known`.
|
|
26
|
+
*
|
|
27
|
+
* API keys keep working beside it: a bearer token that is not one of these is
|
|
28
|
+
* handed to the plugin's own key lookup.
|
|
29
|
+
*/
|
|
30
|
+
export function mcpOAuth(options, endpointOptions = {}) {
|
|
31
|
+
const runtime = createRuntime(options);
|
|
32
|
+
const plugin = (incoming) => {
|
|
33
|
+
/*
|
|
34
|
+
The tool names are read now, not when `mcpOAuth` was called: the modules
|
|
35
|
+
declare theirs while the config is built, so this plugin has to come after
|
|
36
|
+
them, and an empty list here means it did not.
|
|
37
|
+
*/
|
|
38
|
+
if (runtime.tools.length === 0) {
|
|
39
|
+
throw new Error('mcpOAuth(): no MCP tools had been declared when its plugin ran. Register it after the plugins that declare tools (throughline()), and hand it the same array mcpPlugin serves.');
|
|
40
|
+
}
|
|
41
|
+
const served = new Set(runtime.tools.map((tool) => tool.name));
|
|
42
|
+
runtime.defaults.editorTools = runtime.defaults.editorTools.filter((name) => served.has(name));
|
|
43
|
+
const group = options.adminGroup ?? 'Admin';
|
|
44
|
+
const views = incoming.admin?.components?.views ?? {};
|
|
45
|
+
return {
|
|
46
|
+
...incoming,
|
|
47
|
+
collections: [
|
|
48
|
+
...(incoming.collections ?? []),
|
|
49
|
+
clientsCollection(runtime, group),
|
|
50
|
+
grantsCollection(runtime, group),
|
|
51
|
+
],
|
|
52
|
+
globals: [...(incoming.globals ?? []), accessGlobal(runtime, group)],
|
|
53
|
+
endpoints: [...(incoming.endpoints ?? []), ...oauthEndpoints(runtime, endpointOptions)],
|
|
54
|
+
admin: {
|
|
55
|
+
...incoming.admin,
|
|
56
|
+
components: {
|
|
57
|
+
...incoming.admin?.components,
|
|
58
|
+
views: {
|
|
59
|
+
...views,
|
|
60
|
+
connectMcp: {
|
|
61
|
+
Component: CONNECT_MCP_VIEW_PATH,
|
|
62
|
+
path: runtime.connectPath,
|
|
63
|
+
exact: true,
|
|
64
|
+
meta: { title: 'Connect MCP' },
|
|
65
|
+
},
|
|
66
|
+
mcpAuthorize: {
|
|
67
|
+
Component: MCP_AUTHORIZE_VIEW_PATH,
|
|
68
|
+
path: `${runtime.connectPath}/authorize`,
|
|
69
|
+
exact: true,
|
|
70
|
+
meta: { title: `Connect an app to ${runtime.serverName}` },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
afterNavLinks: [
|
|
74
|
+
...(incoming.admin?.components?.afterNavLinks ?? []),
|
|
75
|
+
{
|
|
76
|
+
path: REPORTS_NAV_PATH,
|
|
77
|
+
clientProps: {
|
|
78
|
+
label: 'MCP',
|
|
79
|
+
reports: [{ path: runtime.connectPath, label: 'Connect MCP' }],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
custom: { ...incoming.custom, [MCP_OAUTH_CUSTOM_KEY]: runtime },
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
return { plugin, overrideAuth: createOverrideAuth(runtime), runtime };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/mcp-oauth/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
import { type McpClientKind } from './clients.js';
|
|
3
|
+
export declare const MCP_OAUTH_CLIENTS_SLUG = "mcp-oauth-clients";
|
|
4
|
+
export declare const MCP_OAUTH_GRANTS_SLUG = "mcp-oauth-grants";
|
|
5
|
+
export declare const MCP_ACCESS_SLUG = "mcp-access";
|
|
6
|
+
/** The strategy name a person signed in through an OAuth token carries. */
|
|
7
|
+
export declare const MCP_OAUTH_STRATEGY = "mcp-oauth";
|
|
8
|
+
type UserDoc = Record<string, unknown>;
|
|
9
|
+
export interface McpOAuthOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The site's public origin, e.g. `https://www.example.com`. The issuer, the
|
|
12
|
+
* MCP resource and every endpoint are built from it, and a client compares
|
|
13
|
+
* them byte for byte, so it must be the host people actually use: not an
|
|
14
|
+
* alias that redirects, and not a deployment URL.
|
|
15
|
+
*/
|
|
16
|
+
serverURL: string;
|
|
17
|
+
/** The site's name, as the consent screen and the Connect MCP page say it. */
|
|
18
|
+
serverName: string;
|
|
19
|
+
/** The tools `plugin-mcp` serves: the same array the host hands `mcpPlugin`. */
|
|
20
|
+
tools: readonly {
|
|
21
|
+
name: string;
|
|
22
|
+
}[];
|
|
23
|
+
/** The prompts it serves. Everybody who may connect is offered all of them. */
|
|
24
|
+
prompts?: readonly {
|
|
25
|
+
name: string;
|
|
26
|
+
}[];
|
|
27
|
+
/** An administrator: chooses the policy, sees every connection, revokes any. */
|
|
28
|
+
isAdmin: (user: UserDoc) => boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Who may connect at all: `true`, or the reason they may not. Asked at
|
|
31
|
+
* consent, at every token refresh and on every MCP request, so somebody who
|
|
32
|
+
* loses the role loses the connection with it.
|
|
33
|
+
*/
|
|
34
|
+
eligible: (user: UserDoc) => true | string;
|
|
35
|
+
/**
|
|
36
|
+
* The tools a non-administrator is offered until an administrator changes
|
|
37
|
+
* it. Defaults to the authoring tools.
|
|
38
|
+
*/
|
|
39
|
+
editorTools?: readonly string[];
|
|
40
|
+
/** Which apps may connect until an administrator changes it. Each defaults on. */
|
|
41
|
+
clients?: Partial<Record<McpClientKind, boolean>>;
|
|
42
|
+
/**
|
|
43
|
+
* How people add the server to Claude. `organization` when a Team or
|
|
44
|
+
* Enterprise Owner has added it for everybody, so members only click
|
|
45
|
+
* Connect; `personal` (the default) when each person adds it themselves, and
|
|
46
|
+
* the page links to Claude's add-connector form with the URL filled in.
|
|
47
|
+
*/
|
|
48
|
+
claudeConnector?: 'organization' | 'personal';
|
|
49
|
+
/**
|
|
50
|
+
* The name Claude Code gives the server in the command the Connect MCP page
|
|
51
|
+
* shows. Defaults to `serverName`, lowercased and hyphenated.
|
|
52
|
+
*/
|
|
53
|
+
claudeCodeName?: string;
|
|
54
|
+
/** Default `/api`. */
|
|
55
|
+
apiRoute?: string;
|
|
56
|
+
/** Where `plugin-mcp` serves, under `apiRoute`. Default `/mcp`. */
|
|
57
|
+
mcpPath?: string;
|
|
58
|
+
/** Default `users`. */
|
|
59
|
+
users?: string;
|
|
60
|
+
/** The admin sidebar group for the two collections. Default `Admin`. */
|
|
61
|
+
adminGroup?: string;
|
|
62
|
+
/** The Connect MCP page, under the admin route. Default `/connect-mcp`. */
|
|
63
|
+
connectPath?: string;
|
|
64
|
+
/** Seconds. Default an hour. */
|
|
65
|
+
accessTokenTtl?: number;
|
|
66
|
+
/** Seconds since last use. Default thirty days. */
|
|
67
|
+
refreshTokenTtl?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Also ask `eligible` of the person behind an API key, on every request.
|
|
70
|
+
* Default true: an API key's holder is otherwise checked only when the key is
|
|
71
|
+
* made.
|
|
72
|
+
*/
|
|
73
|
+
recheckApiKeyHolders?: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface McpOAuthRuntime {
|
|
76
|
+
serverName: string;
|
|
77
|
+
claudeConnector: 'organization' | 'personal';
|
|
78
|
+
claudeCodeName: string;
|
|
79
|
+
origin: string;
|
|
80
|
+
issuer: string;
|
|
81
|
+
resource: string;
|
|
82
|
+
apiRoute: string;
|
|
83
|
+
users: string;
|
|
84
|
+
connectPath: string;
|
|
85
|
+
accessTokenTtl: number;
|
|
86
|
+
refreshTokenTtl: number;
|
|
87
|
+
recheckApiKeyHolders: boolean;
|
|
88
|
+
isAdmin: (user: UserDoc) => boolean;
|
|
89
|
+
eligible: (user: UserDoc) => true | string;
|
|
90
|
+
defaults: {
|
|
91
|
+
clients: Record<McpClientKind, boolean>;
|
|
92
|
+
editorTools: readonly string[];
|
|
93
|
+
};
|
|
94
|
+
tools: readonly {
|
|
95
|
+
name: string;
|
|
96
|
+
}[];
|
|
97
|
+
prompts: readonly {
|
|
98
|
+
name: string;
|
|
99
|
+
}[];
|
|
100
|
+
endpoint: (name: string) => string;
|
|
101
|
+
}
|
|
102
|
+
export declare const MCP_OAUTH_CUSTOM_KEY = "throughline:mcp-oauth";
|
|
103
|
+
export declare function createRuntime(options: McpOAuthOptions): McpOAuthRuntime;
|
|
104
|
+
/** The runtime `mcpOAuth` stored on the config, for the views. */
|
|
105
|
+
export declare function mcpOAuthRuntime(config: {
|
|
106
|
+
custom?: Record<string, unknown>;
|
|
107
|
+
}): McpOAuthRuntime;
|
|
108
|
+
export declare function keys(payload: Pick<Payload, 'secret'>): {
|
|
109
|
+
token: Buffer<ArrayBufferLike>;
|
|
110
|
+
request: Buffer<ArrayBufferLike>;
|
|
111
|
+
};
|
|
112
|
+
export interface McpAccessPolicy {
|
|
113
|
+
clients: Record<McpClientKind, boolean>;
|
|
114
|
+
editorTools: string[];
|
|
115
|
+
adminAllTools: boolean;
|
|
116
|
+
adminTools: string[];
|
|
117
|
+
}
|
|
118
|
+
export declare function readPolicy(payload: Payload, runtime: McpOAuthRuntime): Promise<McpAccessPolicy>;
|
|
119
|
+
/** The tools a person is offered under a policy, by served name. */
|
|
120
|
+
export declare function toolsFor(user: UserDoc, policy: McpAccessPolicy, runtime: Pick<McpOAuthRuntime, 'isAdmin' | 'tools'>): string[];
|
|
121
|
+
/** `plugin-mcp`'s key for a tool or prompt name. Its own `toCamelCase`. */
|
|
122
|
+
export declare function toCamelCase(value: string): string;
|
|
123
|
+
export {};
|
|
124
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/mcp-oauth/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { AUTHORING_TOOL_DESCRIPTORS } from '../authoring/descriptors.js';
|
|
2
|
+
import { MCP_CLIENT_KINDS } from './clients.js';
|
|
3
|
+
import { deriveKey } from './crypto.js';
|
|
4
|
+
export const MCP_OAUTH_CLIENTS_SLUG = 'mcp-oauth-clients';
|
|
5
|
+
export const MCP_OAUTH_GRANTS_SLUG = 'mcp-oauth-grants';
|
|
6
|
+
export const MCP_ACCESS_SLUG = 'mcp-access';
|
|
7
|
+
/** The strategy name a person signed in through an OAuth token carries. */
|
|
8
|
+
export const MCP_OAUTH_STRATEGY = 'mcp-oauth';
|
|
9
|
+
export const MCP_OAUTH_CUSTOM_KEY = 'throughline:mcp-oauth';
|
|
10
|
+
function slug(name) {
|
|
11
|
+
return (name
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
14
|
+
.replace(/^-+|-+$/g, '') || 'site');
|
|
15
|
+
}
|
|
16
|
+
export function createRuntime(options) {
|
|
17
|
+
let origin;
|
|
18
|
+
try {
|
|
19
|
+
origin = new URL(options.serverURL).origin;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new Error(`mcpOAuth(): serverURL "${options.serverURL}" is not a URL.`);
|
|
23
|
+
}
|
|
24
|
+
const apiRoute = (options.apiRoute ?? '/api').replace(/\/+$/, '');
|
|
25
|
+
const mcpPath = options.mcpPath ?? '/mcp';
|
|
26
|
+
const served = new Set(options.tools.map((tool) => tool.name));
|
|
27
|
+
const authoring = AUTHORING_TOOL_DESCRIPTORS.map((tool) => tool.name);
|
|
28
|
+
return {
|
|
29
|
+
serverName: options.serverName,
|
|
30
|
+
claudeConnector: options.claudeConnector ?? 'personal',
|
|
31
|
+
claudeCodeName: options.claudeCodeName ?? slug(options.serverName),
|
|
32
|
+
origin,
|
|
33
|
+
issuer: origin,
|
|
34
|
+
resource: `${origin}${apiRoute}${mcpPath}`,
|
|
35
|
+
apiRoute,
|
|
36
|
+
users: options.users ?? 'users',
|
|
37
|
+
connectPath: options.connectPath ?? '/connect-mcp',
|
|
38
|
+
accessTokenTtl: options.accessTokenTtl ?? 60 * 60,
|
|
39
|
+
refreshTokenTtl: options.refreshTokenTtl ?? 30 * 24 * 60 * 60,
|
|
40
|
+
recheckApiKeyHolders: options.recheckApiKeyHolders ?? true,
|
|
41
|
+
isAdmin: options.isAdmin,
|
|
42
|
+
eligible: options.eligible,
|
|
43
|
+
defaults: {
|
|
44
|
+
clients: Object.fromEntries(MCP_CLIENT_KINDS.map((kind) => [kind, options.clients?.[kind] ?? true])),
|
|
45
|
+
editorTools: options.editorTools ?? authoring.filter((name) => served.size === 0 || served.has(name)),
|
|
46
|
+
},
|
|
47
|
+
tools: options.tools,
|
|
48
|
+
prompts: options.prompts ?? [],
|
|
49
|
+
endpoint: (name) => `${origin}${apiRoute}/oauth/${name}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The runtime `mcpOAuth` stored on the config, for the views. */
|
|
53
|
+
export function mcpOAuthRuntime(config) {
|
|
54
|
+
const runtime = config.custom?.[MCP_OAUTH_CUSTOM_KEY];
|
|
55
|
+
if (!runtime)
|
|
56
|
+
throw new Error('mcpOAuth() is not registered in this Payload config.');
|
|
57
|
+
return runtime;
|
|
58
|
+
}
|
|
59
|
+
export function keys(payload) {
|
|
60
|
+
return {
|
|
61
|
+
token: deriveKey(payload.secret, 'token'),
|
|
62
|
+
request: deriveKey(payload.secret, 'request'),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export async function readPolicy(payload, runtime) {
|
|
66
|
+
let doc;
|
|
67
|
+
try {
|
|
68
|
+
doc = (await payload.findGlobal({
|
|
69
|
+
slug: MCP_ACCESS_SLUG,
|
|
70
|
+
depth: 0,
|
|
71
|
+
overrideAccess: true,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
doc = {};
|
|
76
|
+
}
|
|
77
|
+
const clients = (doc['clients'] ?? {});
|
|
78
|
+
const editors = (doc['editors'] ?? {});
|
|
79
|
+
const admins = (doc['admins'] ?? {});
|
|
80
|
+
const names = (value, fallback) => Array.isArray(value)
|
|
81
|
+
? value.filter((each) => typeof each === 'string')
|
|
82
|
+
: [...fallback];
|
|
83
|
+
return {
|
|
84
|
+
clients: Object.fromEntries(MCP_CLIENT_KINDS.map((kind) => [
|
|
85
|
+
kind,
|
|
86
|
+
typeof clients[kind] === 'boolean'
|
|
87
|
+
? clients[kind]
|
|
88
|
+
: runtime.defaults.clients[kind],
|
|
89
|
+
])),
|
|
90
|
+
editorTools: names(editors['tools'], runtime.defaults.editorTools),
|
|
91
|
+
adminAllTools: typeof admins['allTools'] === 'boolean' ? admins['allTools'] : true,
|
|
92
|
+
adminTools: names(admins['tools'], []),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** The tools a person is offered under a policy, by served name. */
|
|
96
|
+
export function toolsFor(user, policy, runtime) {
|
|
97
|
+
const served = runtime.tools.map((tool) => tool.name);
|
|
98
|
+
if (runtime.isAdmin(user)) {
|
|
99
|
+
if (policy.adminAllTools)
|
|
100
|
+
return served;
|
|
101
|
+
return served.filter((name) => policy.adminTools.includes(name));
|
|
102
|
+
}
|
|
103
|
+
return served.filter((name) => policy.editorTools.includes(name));
|
|
104
|
+
}
|
|
105
|
+
/** `plugin-mcp`'s key for a tool or prompt name. Its own `toCamelCase`. */
|
|
106
|
+
export function toCamelCase(value) {
|
|
107
|
+
return value
|
|
108
|
+
.replace(/[-_\s]+(.)?/g, (_, chr) => (chr ? chr.toUpperCase() : ''))
|
|
109
|
+
.replace(/^(.)/, (_, chr) => chr.toLowerCase());
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/mcp-oauth/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Payload } from 'payload';
|
|
2
|
+
import { type FetchLike } from './cimd.js';
|
|
3
|
+
import { type McpClientKind } from './clients.js';
|
|
4
|
+
import { type McpAccessPolicy, type McpOAuthRuntime } from './runtime.js';
|
|
5
|
+
type Doc = Record<string, unknown>;
|
|
6
|
+
export interface ClientRecord {
|
|
7
|
+
id: number | string;
|
|
8
|
+
clientId: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
kind: McpClientKind;
|
|
11
|
+
method: 'dcr' | 'cimd';
|
|
12
|
+
redirectUris: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A registration request's client, registered — or the one already registered
|
|
16
|
+
* with the same name and redirects. Registering is unauthenticated by design
|
|
17
|
+
* (RFC 7591), so identical requests share a row rather than each adding one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerClient(payload: Payload, policy: McpAccessPolicy, request: {
|
|
20
|
+
redirectUris: unknown[];
|
|
21
|
+
name?: string;
|
|
22
|
+
}): Promise<ClientRecord | {
|
|
23
|
+
error: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* The client a `client_id` names: a registered one, or a metadata document,
|
|
27
|
+
* fetched (and cached for a day) and held to the same allowlist.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveClient(payload: Payload, policy: McpAccessPolicy, clientId: unknown, fetchImpl?: FetchLike): Promise<ClientRecord | {
|
|
30
|
+
error: string;
|
|
31
|
+
}>;
|
|
32
|
+
export interface PendingRequest {
|
|
33
|
+
clientId: string;
|
|
34
|
+
redirectUri: string;
|
|
35
|
+
codeChallenge: string;
|
|
36
|
+
state?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Consent: a pending grant and the code that completes it. */
|
|
39
|
+
export declare function createPendingGrant(payload: Payload, user: Doc, client: ClientRecord, request: PendingRequest): Promise<string>;
|
|
40
|
+
export interface IssuedTokens {
|
|
41
|
+
access_token: string;
|
|
42
|
+
token_type: 'Bearer';
|
|
43
|
+
expires_in: number;
|
|
44
|
+
refresh_token: string;
|
|
45
|
+
scope: string;
|
|
46
|
+
}
|
|
47
|
+
export type TokenError = {
|
|
48
|
+
error: 'invalid_grant' | 'invalid_request' | 'invalid_target';
|
|
49
|
+
error_description: string;
|
|
50
|
+
};
|
|
51
|
+
/** Ends a grant: its tokens stop working at once. */
|
|
52
|
+
export declare function revokeGrant(payload: Payload, grant: Doc, reason: string): Promise<void>;
|
|
53
|
+
/** `grant_type=authorization_code`. */
|
|
54
|
+
export declare function exchangeCode(payload: Payload, runtime: McpOAuthRuntime, policy: McpAccessPolicy, params: {
|
|
55
|
+
code?: string;
|
|
56
|
+
clientId?: string;
|
|
57
|
+
redirectUri?: string;
|
|
58
|
+
codeVerifier?: string;
|
|
59
|
+
}): Promise<IssuedTokens | TokenError>;
|
|
60
|
+
/** `grant_type=refresh_token`. */
|
|
61
|
+
export declare function refresh(payload: Payload, runtime: McpOAuthRuntime, policy: McpAccessPolicy, params: {
|
|
62
|
+
refreshToken?: string;
|
|
63
|
+
clientId?: string;
|
|
64
|
+
}): Promise<IssuedTokens | TokenError>;
|
|
65
|
+
/** RFC 7009. Unknown tokens are not an error. */
|
|
66
|
+
export declare function revokeToken(payload: Payload, token: unknown): Promise<void>;
|
|
67
|
+
/** An access token's grant and person, if it is live and still allowed. */
|
|
68
|
+
export declare function authenticateAccessToken(payload: Payload, runtime: McpOAuthRuntime, policy: McpAccessPolicy, token: string): Promise<{
|
|
69
|
+
user: Doc;
|
|
70
|
+
grant: Doc;
|
|
71
|
+
} | {
|
|
72
|
+
reason: string;
|
|
73
|
+
}>;
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/mcp-oauth/store.ts"],"names":[],"mappings":"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"}
|