@forumone/throughline-core 0.6.0 → 0.8.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/CHANGELOG.md +94 -0
- package/README.md +8 -3
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/collector.d.ts +23 -6
- package/dist/mcp/collector.d.ts.map +1 -1
- package/dist/mcp/collector.js +51 -8
- package/dist/mcp/collector.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -3
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/payload-mcp.d.ts.map +1 -1
- package/dist/mcp/payload-mcp.js.map +1 -1
- package/dist/utils/content-hash.js +1 -1
- package/dist/utils/content-hash.js.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/sha256.d.ts +10 -0
- package/dist/utils/sha256.d.ts.map +1 -0
- package/dist/utils/sha256.js +16 -0
- package/dist/utils/sha256.js.map +1 -0
- package/dist/utils/zod-issues.d.ts +19 -0
- package/dist/utils/zod-issues.d.ts.map +1 -0
- package/dist/utils/zod-issues.js +22 -0
- package/dist/utils/zod-issues.js.map +1 -0
- package/package.json +2 -2
- package/dist/auth/api-keys.d.ts +0 -21
- package/dist/auth/api-keys.d.ts.map +0 -1
- package/dist/auth/api-keys.js +0 -115
- package/dist/auth/api-keys.js.map +0 -1
- package/dist/auth/authenticator.d.ts +0 -19
- package/dist/auth/authenticator.d.ts.map +0 -1
- package/dist/auth/authenticator.js +0 -74
- package/dist/auth/authenticator.js.map +0 -1
- package/dist/auth/index.d.ts +0 -5
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -3
- package/dist/auth/index.js.map +0 -1
- package/dist/mcp/handler.d.ts +0 -20
- package/dist/mcp/handler.d.ts.map +0 -1
- package/dist/mcp/handler.js +0 -132
- package/dist/mcp/handler.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @forumone/throughline-core
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a9262da: Per-tool gating works, because tool names no longer wait for `onInit`
|
|
8
|
+
|
|
9
|
+
`@payloadcms/plugin-mcp` generates one per-key checkbox per tool while the host's
|
|
10
|
+
config is being built, and then gates every call on the checkbox matching the
|
|
11
|
+
tool's name. Every Throughline tool was built at `onInit` — each closes over
|
|
12
|
+
`payload`, the publishing service or the manifest loader — so the array it maps
|
|
13
|
+
over was empty, no checkboxes were generated, and its `?? false` denied all 27
|
|
14
|
+
tools to every key. A valid key got a 200 and an empty `tools/list`, with nothing
|
|
15
|
+
wrong on either side.
|
|
16
|
+
|
|
17
|
+
The plugin needs only `name` and `description` then, and neither needs a Payload.
|
|
18
|
+
So a server now **declares** its tools as the config is built and **binds** their
|
|
19
|
+
handlers at `onInit`:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
options.mcpTools?.declare(PUBLISHING_TOOL_DESCRIPTORS, { serverName: 'publishing' })
|
|
23
|
+
// …later, at onInit:
|
|
24
|
+
options.mcpTools?.add(tools, { serverName: 'publishing' })
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Each package gained a `tools/descriptors.ts` holding every tool's name and
|
|
28
|
+
description; the factories spread from it, so the checkbox and the MCP client
|
|
29
|
+
cannot describe a tool differently. A `descriptors.test.ts` in each package
|
|
30
|
+
asserts the two sets match, without needing a database.
|
|
31
|
+
|
|
32
|
+
`createMcpToolCollector` gains `declare()` and an `unbound` list. Both mismatches
|
|
33
|
+
are refused rather than absorbed: a tool built but never declared throws at
|
|
34
|
+
`onInit` (it would otherwise be denied to every key, silently), and a tool
|
|
35
|
+
declared but never bound stays advertised with a handler that explains itself.
|
|
36
|
+
|
|
37
|
+
**Order in the host's plugin array is now load-bearing.** Every tool-bearing
|
|
38
|
+
server must come before `mcpPlugin`, or it declares into an array that has
|
|
39
|
+
already been read. It was only a convention before; it is a requirement now, and
|
|
40
|
+
the failure mode — a server's tools missing from every key — is the one this
|
|
41
|
+
change exists to remove.
|
|
42
|
+
|
|
43
|
+
`requiredScope` stays declared and read by nothing. Enforcement is the checkbox;
|
|
44
|
+
these record which tools are consequential, and are the mapping a scope-aware
|
|
45
|
+
default would be built from.
|
|
46
|
+
|
|
47
|
+
The playground registers `mcpPlugin` for the first time, so the suite's only
|
|
48
|
+
end-to-end host now exercises the tools rather than just their composition.
|
|
49
|
+
|
|
50
|
+
## 0.7.0
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- 3140ea0: One MCP transport, not seven
|
|
55
|
+
|
|
56
|
+
Every plugin served its own `POST /<prefix>/mcp` on a 146-line JSON-RPC subset of
|
|
57
|
+
the protocol that spoke `tools/list` and `tools/call` and nothing else. Payload
|
|
58
|
+
ships an MCP server built on the official SDK — streamable HTTP, sessions, per-key
|
|
59
|
+
capability checkboxes — and the tools were never the transport. They now reach a
|
|
60
|
+
client through the host's `@payloadcms/plugin-mcp`, on one `/api/mcp`, via the
|
|
61
|
+
collector `createMcpToolCollector` already provided.
|
|
62
|
+
|
|
63
|
+
**Breaking.** Removed from `@forumone/throughline-core`: `createMcpHandler`,
|
|
64
|
+
`McpHandlerOptions`, `createApiKeysCollection`, `ApiKeysCollectionOptions`,
|
|
65
|
+
`DEFAULT_API_KEYS_SLUG`, `createBearerTokenAuthenticator`,
|
|
66
|
+
`BearerTokenAuthenticatorOptions`, `generateApiKey`. Removed from
|
|
67
|
+
`@forumone/throughline-plugin-contract`: `McpAuthenticator`, `McpAuthResult`.
|
|
68
|
+
`sha256Hex` stays exported, from `./utils` rather than `./auth`.
|
|
69
|
+
|
|
70
|
+
`routePrefix` is gone from `auditQueryPlugin`, `componentsPlugin` and
|
|
71
|
+
`integrationsPlugin` — omitted from their options types, so passing one is a
|
|
72
|
+
compile error rather than config that reads as if it does something. `/mcp` was
|
|
73
|
+
the only endpoint any of the three served. `publishingPlugin`, `approvalsPlugin`
|
|
74
|
+
and `formsPlugin` keep theirs; they still serve admin controls, the approval
|
|
75
|
+
action link and the public form post.
|
|
76
|
+
|
|
77
|
+
**A host that passes no `mcpTools` collector now has no MCP surface.** There is no
|
|
78
|
+
per-server endpoint left as a fallback. This is a config change of one line per
|
|
79
|
+
plugin, and `createMcpToolCollector`'s own docs carry the shape.
|
|
80
|
+
|
|
81
|
+
**What this costs, stated plainly.** `requiredScope` is now read by nothing —
|
|
82
|
+
`plugin-mcp` gates on checkboxes generated at config time, which this suite cannot
|
|
83
|
+
fill because every tool is built at `onInit`. So a key that authenticates reaches
|
|
84
|
+
every collected tool, exactly as an all-or-nothing per-server key did. The
|
|
85
|
+
declarations are kept because they are the mapping those checkboxes need; #78
|
|
86
|
+
tracks restoring enforcement, and the type's own doc comment says so.
|
|
87
|
+
|
|
88
|
+
Also drops the key collection from the playground, which leaves that app with no
|
|
89
|
+
MCP surface at all until `mcpPlugin` can be wired there — #79, blocked on moving
|
|
90
|
+
it off `payload@^3.83.0`.
|
|
91
|
+
|
|
92
|
+
### Patch Changes
|
|
93
|
+
|
|
94
|
+
- Updated dependencies [3140ea0]
|
|
95
|
+
- @forumone/throughline-plugin-contract@0.4.0
|
|
96
|
+
|
|
3
97
|
## 0.6.0
|
|
4
98
|
|
|
5
99
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -7,11 +7,16 @@ The shared plumbing every Throughline server package depends on. Drop it into a
|
|
|
7
7
|
| Subsystem | Subpath | Role |
|
|
8
8
|
|---|---|---|
|
|
9
9
|
| Audit | `./audit` | `auditPlugin`, `createAuditCollection`, `createAuditWriter`, `getAuditWriter`, `AUDIT_ACTIONS`, `AUDIT_MCP_SERVERS` |
|
|
10
|
-
| Auth | `./auth` | `createApiKeysCollection`, `createBearerTokenAuthenticator`, `generateApiKey`, `sha256Hex` |
|
|
11
10
|
| Events | `./events` | `createInngestClient`, `CoreEvents`, `FrameworkEvents` (module-augmentation seam) |
|
|
12
|
-
| MCP | `./mcp` | `
|
|
11
|
+
| MCP | `./mcp` | `createMcpToolCollector`, `toPayloadMcpTools`, `McpMetaSchema`, `withMeta`, `auditContext` |
|
|
13
12
|
| Logger | (main) | `defaultLogger`, `createNamedLogger` |
|
|
14
|
-
| Utils | (main) | `documentContentHash` |
|
|
13
|
+
| Utils | (main) | `documentContentHash`, `sha256Hex`, `formatZodIssues` |
|
|
14
|
+
|
|
15
|
+
There is no `./auth` any more. It held an MCP key collection, a bearer-token
|
|
16
|
+
authenticator and `createMcpHandler` — a JSON-RPC subset each plugin mounted at its
|
|
17
|
+
own `/mcp`. `@payloadcms/plugin-mcp` owns the transport, the keys and authentication
|
|
18
|
+
now; `createMcpToolCollector` is how this suite's tools get to it. `sha256Hex`
|
|
19
|
+
survived, under `./utils`.
|
|
15
20
|
|
|
16
21
|
The main entry re-exports everything; the subpath exports keep bundles smaller for consumers who only need one slice.
|
|
17
22
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS, DEFAULT_AUDIT_SLUG, auditPlugin, createAuditCollection, createAuditWriter, getAuditWriter, } from './audit/index.js';
|
|
2
2
|
export type { AuditAction, AuditActor, AuditCollectionOptions, AuditEventInput, AuditMcpServer, AuditPluginOptions, AuditWriter, AuditWriterOptions, } from './audit/index.js';
|
|
3
|
-
export { DEFAULT_API_KEYS_SLUG, createApiKeysCollection, createBearerTokenAuthenticator, generateApiKey, sha256Hex, } from './auth/index.js';
|
|
4
|
-
export type { ApiKeysCollectionOptions, BearerTokenAuthenticatorOptions } from './auth/index.js';
|
|
5
3
|
export { createInngestClient } from './events/index.js';
|
|
6
4
|
export type { CoreEvents, FrameworkEvents, InngestClientOptions } from './events/index.js';
|
|
7
|
-
export { McpMetaSchema, auditContext, deniedEnvelope,
|
|
8
|
-
export type { AddToolsOptions, AuditContextFields, CreateMcpToolCollectorOptions,
|
|
5
|
+
export { McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
6
|
+
export type { AddToolsOptions, AuditContextFields, CreateMcpToolCollectorOptions, DeclareToolsOptions, McpMeta, McpToolCollector, McpToolDescriptor, PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './mcp/index.js';
|
|
9
7
|
export { defaultLogger, createNamedLogger } from './logger/index.js';
|
|
10
|
-
export { documentContentHash, unwrapRelationshipId } from './utils/index.js';
|
|
8
|
+
export { documentContentHash, formatZodIssues, sha256Hex, unwrapRelationshipId, } from './utils/index.js';
|
|
11
9
|
export type { DocumentContentHashOptions } from './utils/index.js';
|
|
12
|
-
export type { AuthenticatedUser, BaseCorePluginOptions, CorePlugin, Logger,
|
|
10
|
+
export type { AuthenticatedUser, BaseCorePluginOptions, CorePlugin, Logger, McpToolContext, McpToolDefinition, PluginRegistry, PluginRegistryEntry, } from '@forumone/throughline-plugin-contract';
|
|
13
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,6BAA6B,EAC7B,mBAAmB,EACnB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAIlE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,uCAAuC,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// Subsystems are re-exported as they are added during C4. The aggregated
|
|
2
2
|
// surface here mirrors the package's `./<subpath>` exports.
|
|
3
3
|
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS, DEFAULT_AUDIT_SLUG, auditPlugin, createAuditCollection, createAuditWriter, getAuditWriter, } from './audit/index.js';
|
|
4
|
-
export { DEFAULT_API_KEYS_SLUG, createApiKeysCollection, createBearerTokenAuthenticator, generateApiKey, sha256Hex, } from './auth/index.js';
|
|
5
4
|
export { createInngestClient } from './events/index.js';
|
|
6
|
-
export { McpMetaSchema, auditContext, deniedEnvelope,
|
|
5
|
+
export { McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
7
6
|
export { defaultLogger, createNamedLogger } from './logger/index.js';
|
|
8
|
-
export { documentContentHash, unwrapRelationshipId } from './utils/index.js';
|
|
7
|
+
export { documentContentHash, formatZodIssues, sha256Hex, unwrapRelationshipId, } from './utils/index.js';
|
|
9
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4DAA4D;AAE5D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AAYzB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4DAA4D;AAE5D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AAYzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAcvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
|
package/dist/mcp/collector.d.ts
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
import type { McpToolDefinition } from '@forumone/throughline-plugin-contract';
|
|
2
2
|
import { type PayloadMcpTool, type ToPayloadMcpToolOptions } from './payload-mcp.js';
|
|
3
|
+
/** What `plugin-mcp` needs about a tool while the config is being built. */
|
|
4
|
+
export interface McpToolDescriptor {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}
|
|
3
8
|
export interface McpToolCollector {
|
|
4
9
|
/**
|
|
5
|
-
* The array to hand `mcpPlugin`.
|
|
6
|
-
*
|
|
7
|
-
* tools will be added to something nobody reads.
|
|
10
|
+
* The array to hand `mcpPlugin`. Filled by `declare` at config time and
|
|
11
|
+
* completed by `add` at `onInit` — and the same array throughout, so do not
|
|
12
|
+
* copy or spread it, or the tools will be added to something nobody reads.
|
|
8
13
|
*/
|
|
9
14
|
readonly tools: PayloadMcpTool[];
|
|
10
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Called by a plugin as the config is built, with its tools' names and
|
|
17
|
+
* descriptions. This is what `plugin-mcp` turns into per-key checkboxes.
|
|
18
|
+
*/
|
|
19
|
+
declare(descriptors: readonly McpToolDescriptor[], options?: DeclareToolsOptions): void;
|
|
20
|
+
/** Called by a plugin at `onInit`, once it can build its handlers. */
|
|
11
21
|
add(tools: McpToolDefinition[], options?: AddToolsOptions): void;
|
|
12
|
-
/** Which servers have
|
|
22
|
+
/** Which servers have declared, in the order they did. */
|
|
13
23
|
readonly servers: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Tools declared and never bound. Empty after every server's `onInit` has
|
|
26
|
+
* run; anything left is a server that declared a tool it does not build.
|
|
27
|
+
*/
|
|
28
|
+
readonly unbound: string[];
|
|
14
29
|
}
|
|
15
|
-
export interface
|
|
30
|
+
export interface DeclareToolsOptions {
|
|
16
31
|
/**
|
|
17
32
|
* Which server these came from — `'publishing'`, `'approvals'`. Used to name
|
|
18
33
|
* both sides of a duplicate-name collision, which is the only thing that
|
|
@@ -20,6 +35,8 @@ export interface AddToolsOptions extends ToPayloadMcpToolOptions {
|
|
|
20
35
|
*/
|
|
21
36
|
serverName?: string;
|
|
22
37
|
}
|
|
38
|
+
export interface AddToolsOptions extends ToPayloadMcpToolOptions, DeclareToolsOptions {
|
|
39
|
+
}
|
|
23
40
|
export type CreateMcpToolCollectorOptions = ToPayloadMcpToolOptions;
|
|
24
41
|
/**
|
|
25
42
|
* Somewhere for the plugins to put their tools, that the host can pass to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/mcp/collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/mcp/collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AA4CvG,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAAA;IAChC;;;OAGG;IACH,OAAO,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACvF,sEAAsE;IACtE,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IAChE,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,uBAAuB,EAAE,mBAAmB;CAAG;AAExF,MAAM,MAAM,6BAA6B,GAAG,uBAAuB,CAAA;AAEnE;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,6BAAkC,GAC1C,gBAAgB,CA+ElB"}
|
package/dist/mcp/collector.js
CHANGED
|
@@ -11,24 +11,67 @@ import { toPayloadMcpTools } from './payload-mcp.js';
|
|
|
11
11
|
export function createMcpToolCollector(options = {}) {
|
|
12
12
|
const tools = [];
|
|
13
13
|
const servers = [];
|
|
14
|
-
const
|
|
14
|
+
const declaredBy = new Map();
|
|
15
|
+
const slots = new Map();
|
|
16
|
+
const bound = new Set();
|
|
15
17
|
return {
|
|
16
18
|
tools,
|
|
17
19
|
servers,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
get unbound() {
|
|
21
|
+
return [...declaredBy.keys()].filter(name => !bound.has(name));
|
|
22
|
+
},
|
|
23
|
+
declare(descriptors, declareOptions = {}) {
|
|
24
|
+
const { serverName = 'an unnamed server' } = declareOptions;
|
|
25
|
+
for (const descriptor of descriptors) {
|
|
26
|
+
const existing = declaredBy.get(descriptor.name);
|
|
22
27
|
if (existing !== undefined) {
|
|
23
|
-
throw new Error(`Two MCP tools are called "${
|
|
28
|
+
throw new Error(`Two MCP tools are called "${descriptor.name}" — one from ${existing}, one from ` +
|
|
24
29
|
`${serverName}. Under a single MCP server a tool name is a namespace, and a client ` +
|
|
25
30
|
`offered both gets whichever registered last. Rename one.`);
|
|
26
31
|
}
|
|
27
|
-
|
|
32
|
+
declaredBy.set(descriptor.name, serverName);
|
|
33
|
+
/*
|
|
34
|
+
A slot, not a tool. `name` and `description` are everything the plugin
|
|
35
|
+
reads now; `parameters` and `handler` arrive at `onInit`, on this same
|
|
36
|
+
object, because the array identity is what the host handed over.
|
|
37
|
+
*/
|
|
38
|
+
const slot = {
|
|
39
|
+
name: descriptor.name,
|
|
40
|
+
description: descriptor.description,
|
|
41
|
+
parameters: {},
|
|
42
|
+
handler: () => {
|
|
43
|
+
throw new Error(`MCP tool "${descriptor.name}" was declared by ${serverName} and never bound. ` +
|
|
44
|
+
`A server declares its tools as the config is built and binds their handlers at ` +
|
|
45
|
+
`onInit; this one did not reach the second step, so the tool is advertised and ` +
|
|
46
|
+
`cannot run.`);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
slots.set(descriptor.name, slot);
|
|
50
|
+
tools.push(slot);
|
|
28
51
|
}
|
|
29
|
-
tools.push(...toPayloadMcpTools(incoming, { ...options, ...toolOptions }));
|
|
30
52
|
servers.push(serverName);
|
|
31
53
|
},
|
|
54
|
+
add(incoming, addOptions = {}) {
|
|
55
|
+
const { serverName = 'an unnamed server', ...toolOptions } = addOptions;
|
|
56
|
+
for (const tool of toPayloadMcpTools(incoming, { ...options, ...toolOptions })) {
|
|
57
|
+
const slot = slots.get(tool.name);
|
|
58
|
+
if (!slot) {
|
|
59
|
+
throw new Error(`${serverName} built an MCP tool called "${tool.name}" that it never declared. ` +
|
|
60
|
+
`Add it to that package's tool descriptors: a tool the collector does not know ` +
|
|
61
|
+
`about while the config is built gets no per-key checkbox, and \`plugin-mcp\` ` +
|
|
62
|
+
`then denies it to every key with no error anywhere.`);
|
|
63
|
+
}
|
|
64
|
+
/*
|
|
65
|
+
Mutated rather than replaced. `mcpPlugin` was handed this array at config
|
|
66
|
+
time and reads it per request; swapping the element would leave the
|
|
67
|
+
checkbox pointing at an object nobody serves.
|
|
68
|
+
*/
|
|
69
|
+
slot.description = tool.description;
|
|
70
|
+
slot.parameters = tool.parameters;
|
|
71
|
+
slot.handler = tool.handler;
|
|
72
|
+
bound.add(tool.name);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
32
75
|
};
|
|
33
76
|
}
|
|
34
77
|
//# sourceMappingURL=collector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/mcp/collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAqD,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/mcp/collector.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { createMcpHandler } from './handler.js';
|
|
2
|
-
export type { McpHandlerOptions } from './handler.js';
|
|
3
1
|
export { McpMetaSchema, withMeta } from './meta.js';
|
|
4
2
|
export type { McpMeta } from './meta.js';
|
|
5
3
|
export { auditContext } from './audit-context.js';
|
|
@@ -7,6 +5,6 @@ export type { AuditContextFields } from './audit-context.js';
|
|
|
7
5
|
export { toPayloadMcpTool, toPayloadMcpTools } from './payload-mcp.js';
|
|
8
6
|
export type { PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './payload-mcp.js';
|
|
9
7
|
export { createMcpToolCollector } from './collector.js';
|
|
10
|
-
export type { AddToolsOptions, CreateMcpToolCollectorOptions, McpToolCollector, } from './collector.js';
|
|
8
|
+
export type { AddToolsOptions, CreateMcpToolCollectorOptions, DeclareToolsOptions, McpToolCollector, McpToolDescriptor, } from './collector.js';
|
|
11
9
|
export { deniedEnvelope } from './envelope.js';
|
|
12
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACnD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACtE,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EACV,eAAe,EACf,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/mcp/index.js
CHANGED
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAOtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AASvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-mcp.d.ts","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAkB,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"payload-mcp.d.ts","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAkB,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAwBtG,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,CAAC,WAAW,CAAA;IACzB,OAAO,EAAE,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,OAAO,KACX,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAA;CACjE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IAClG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE,uBAA4B,GACpC,cAAc,CAYhB;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EAAE,EAC1B,OAAO,GAAE,uBAA4B,GACpC,cAAc,EAAE,CAElB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-mcp.js","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"payload-mcp.js","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AA8DlD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAuB,EACvB,UAAmC,EAAE;IAErC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3B,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,KAAK;QACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;YAClE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;QAC/E,CAAC;KACF,CAAA;AACH,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,iBAAiB,CAC/B,KAA0B,EAC1B,UAAmC,EAAE;IAErC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,OAAO,CAAC,IAAuB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAA;IAC/B,IAAI,MAAM,YAAY,CAAC,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,KAAsB,CAAA;IACvE,MAAM,IAAI,KAAK,CACb,SAAS,IAAI,CAAC,IAAI,2EAA2E;QAC3F,0FAA0F,CAC7F,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAsB,EAAE,OAAgC;IAC3E,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI;QACnB,CAAC,CAAC;YACE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;YAC7B,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnD,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC,CAAC,EAAE;YACxE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,MAAmB,CAAC,CAAC,CAAC,EAAE;SAC5E;QACH,CAAC,CAAC,IAAI,CAAA;IAER,OAAO;QACL,IAAI;QACJ;;;;;UAKE;QACF,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,aAAa;KAC/D,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-hash.js","sourceRoot":"","sources":["../../src/utils/content-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"content-hash.js","sourceRoot":"","sources":["../../src/utils/content-hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;AAWlG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAiC,EACjC,UAAsC,EAAE;IAExC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,CAAA;IACzC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC9D,OAAO,SAAS,CAAC,eAAe,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;AACxE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,SAAS,CAAC,KAAc,EAAE,QAAqB,EAAE,QAAQ,GAAG,KAAK;IACxE,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAA;IACjF,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE7D,MAAM,MAAM,GAA4B,EAAE,CAAA;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QAC5E,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC/B,IAAI,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAE,SAAQ;QACtC,uEAAuE;QACvE,wEAAwE;QACxE,0BAA0B;QAC1B,IAAI,KAAK,KAAK,SAAS;YAAE,SAAQ;QACjC,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IACpD,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACjF,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC3B,CAAA;QACD,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IAC/F,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAA;AACxC,CAAC"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { documentContentHash } from './content-hash.js';
|
|
2
2
|
export type { DocumentContentHashOptions } from './content-hash.js';
|
|
3
|
+
export { sha256Hex } from './sha256.js';
|
|
3
4
|
export { unwrapRelationshipId } from './relationships.js';
|
|
5
|
+
export { formatZodIssues } from './zod-issues.js';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
|
package/dist/utils/index.js
CHANGED
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashes a string with SHA-256 using the Web Crypto API; returns lowercase hex.
|
|
3
|
+
*
|
|
4
|
+
* Lived in `auth/api-keys.ts` while this package minted and stored its own MCP
|
|
5
|
+
* keys. Those are gone — `@payloadcms/plugin-mcp` owns key storage now — and
|
|
6
|
+
* `documentContentHash` is the remaining caller, so the function moved to sit
|
|
7
|
+
* beside it rather than being deleted with the collection it was written for.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sha256Hex(input: string): Promise<string>;
|
|
10
|
+
//# sourceMappingURL=sha256.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256.d.ts","sourceRoot":"","sources":["../../src/utils/sha256.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hashes a string with SHA-256 using the Web Crypto API; returns lowercase hex.
|
|
3
|
+
*
|
|
4
|
+
* Lived in `auth/api-keys.ts` while this package minted and stored its own MCP
|
|
5
|
+
* keys. Those are gone — `@payloadcms/plugin-mcp` owns key storage now — and
|
|
6
|
+
* `documentContentHash` is the remaining caller, so the function moved to sit
|
|
7
|
+
* beside it rather than being deleted with the collection it was written for.
|
|
8
|
+
*/
|
|
9
|
+
export async function sha256Hex(input) {
|
|
10
|
+
const data = new TextEncoder().encode(input);
|
|
11
|
+
const buffer = await crypto.subtle.digest('SHA-256', data);
|
|
12
|
+
return Array.from(new Uint8Array(buffer))
|
|
13
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
14
|
+
.join('');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=sha256.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256.js","sourceRoot":"","sources":["../../src/utils/sha256.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod's issues as an indented list, one per line.
|
|
4
|
+
*
|
|
5
|
+
* `componentsPlugin`'s options and a publishable collection's config formatted
|
|
6
|
+
* them identically, because the shape is what makes a config error readable:
|
|
7
|
+
* the path to the field, then what is wrong with it. Both plugins already
|
|
8
|
+
* depend on this package, so sharing costs nothing.
|
|
9
|
+
*
|
|
10
|
+
* `(root)` for an issue with no path — what a schema-level refinement produces,
|
|
11
|
+
* and what an empty `join('.')` would otherwise render as nothing at all.
|
|
12
|
+
*
|
|
13
|
+
* A third copy lives in `design-contract`'s loader and stays there. That
|
|
14
|
+
* package depends on `zod` and nothing else, which is what lets the scaffolder
|
|
15
|
+
* and a standalone design system consume it; trading that for four lines would
|
|
16
|
+
* pull the whole plugin surface behind it.
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatZodIssues(error: z.ZodError): string;
|
|
19
|
+
//# sourceMappingURL=zod-issues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-issues.d.ts","sourceRoot":"","sources":["../../src/utils/zod-issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAIzD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod's issues as an indented list, one per line.
|
|
3
|
+
*
|
|
4
|
+
* `componentsPlugin`'s options and a publishable collection's config formatted
|
|
5
|
+
* them identically, because the shape is what makes a config error readable:
|
|
6
|
+
* the path to the field, then what is wrong with it. Both plugins already
|
|
7
|
+
* depend on this package, so sharing costs nothing.
|
|
8
|
+
*
|
|
9
|
+
* `(root)` for an issue with no path — what a schema-level refinement produces,
|
|
10
|
+
* and what an empty `join('.')` would otherwise render as nothing at all.
|
|
11
|
+
*
|
|
12
|
+
* A third copy lives in `design-contract`'s loader and stays there. That
|
|
13
|
+
* package depends on `zod` and nothing else, which is what lets the scaffolder
|
|
14
|
+
* and a standalone design system consume it; trading that for four lines would
|
|
15
|
+
* pull the whole plugin surface behind it.
|
|
16
|
+
*/
|
|
17
|
+
export function formatZodIssues(error) {
|
|
18
|
+
return error.issues
|
|
19
|
+
.map((issue) => ` - ${issue.path.join('.') || '(root)'}: ${issue.message}`)
|
|
20
|
+
.join('\n');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=zod-issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-issues.js","sourceRoot":"","sources":["../../src/utils/zod-issues.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,OAAO,KAAK,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAC3E,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forumone/throughline-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Core plumbing for Throughline: audit log, MCP authentication and handler, event taxonomy + Inngest client factory, logger, shared utilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"zod": "^3.23.0",
|
|
60
60
|
"zod-to-json-schema": "^3.25.2",
|
|
61
|
-
"@forumone/throughline-plugin-contract": "0.
|
|
61
|
+
"@forumone/throughline-plugin-contract": "0.4.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/node": "^20.17.0",
|
package/dist/auth/api-keys.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { CollectionConfig } from 'payload';
|
|
2
|
-
export interface ApiKeysCollectionOptions {
|
|
3
|
-
/** Override the collection slug. Default: `'mcp-api-keys'`. */
|
|
4
|
-
slug?: string;
|
|
5
|
-
/** Slug of the users collection the key links to. Default: `'users'`. */
|
|
6
|
-
usersSlug?: string;
|
|
7
|
-
/** Allowed scope strings shown in the admin UI. */
|
|
8
|
-
availableScopes?: string[];
|
|
9
|
-
}
|
|
10
|
-
export declare const DEFAULT_API_KEYS_SLUG = "mcp-api-keys";
|
|
11
|
-
/**
|
|
12
|
-
* Builds the API-keys collection config. Stores keys as SHA-256 hashes;
|
|
13
|
-
* raw keys are surfaced one-time via the `keyDisplay` field on create
|
|
14
|
-
* so the admin UI can show them to the operator.
|
|
15
|
-
*/
|
|
16
|
-
export declare function createApiKeysCollection(options?: ApiKeysCollectionOptions): CollectionConfig;
|
|
17
|
-
/** Generates a random API key prefixed with `tl_`. */
|
|
18
|
-
export declare function generateApiKey(): string;
|
|
19
|
-
/** Hashes a string with SHA-256 using the Web Crypto API; returns lowercase hex. */
|
|
20
|
-
export declare function sha256Hex(input: string): Promise<string>;
|
|
21
|
-
//# sourceMappingURL=api-keys.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../../src/auth/api-keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAEvD,MAAM,WAAW,wBAAwB;IACvC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,eAAO,MAAM,qBAAqB,iBAAiB,CAAA;AAwBnD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,wBAA6B,GACrC,gBAAgB,CAyElB;AAED,sDAAsD;AACtD,wBAAgB,cAAc,IAAI,MAAM,CAOvC;AAED,oFAAoF;AACpF,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9D"}
|
package/dist/auth/api-keys.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_API_KEYS_SLUG = 'mcp-api-keys';
|
|
2
|
-
const DEFAULT_SCOPES = [
|
|
3
|
-
'content.read',
|
|
4
|
-
'content.write',
|
|
5
|
-
'design.read',
|
|
6
|
-
'publishing.execute',
|
|
7
|
-
'approvals.request',
|
|
8
|
-
'approvals.decide',
|
|
9
|
-
'forms.manage',
|
|
10
|
-
'integrations.trigger',
|
|
11
|
-
'audit.read',
|
|
12
|
-
];
|
|
13
|
-
/**
|
|
14
|
-
* Returns true when the requesting user has the `admin` role. Used as the
|
|
15
|
-
* default access check for the keys collection — keys grant capability,
|
|
16
|
-
* so creating/reading them must be tightly scoped.
|
|
17
|
-
*/
|
|
18
|
-
const adminOnly = ({ req }) => {
|
|
19
|
-
const roles = req.user?.['roles'] ?? [];
|
|
20
|
-
return roles.includes('admin');
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Builds the API-keys collection config. Stores keys as SHA-256 hashes;
|
|
24
|
-
* raw keys are surfaced one-time via the `keyDisplay` field on create
|
|
25
|
-
* so the admin UI can show them to the operator.
|
|
26
|
-
*/
|
|
27
|
-
export function createApiKeysCollection(options = {}) {
|
|
28
|
-
const slug = options.slug ?? DEFAULT_API_KEYS_SLUG;
|
|
29
|
-
const usersSlug = options.usersSlug ?? 'users';
|
|
30
|
-
const availableScopes = options.availableScopes ?? [...DEFAULT_SCOPES];
|
|
31
|
-
return {
|
|
32
|
-
slug,
|
|
33
|
-
admin: {
|
|
34
|
-
useAsTitle: 'name',
|
|
35
|
-
defaultColumns: ['name', 'linkedUser', 'enabled', 'lastUsedAt'],
|
|
36
|
-
description: 'API keys for MCP clients. Each key inherits the linked user\'s access control; keys are stored as SHA-256 hashes.',
|
|
37
|
-
},
|
|
38
|
-
access: {
|
|
39
|
-
read: adminOnly,
|
|
40
|
-
create: adminOnly,
|
|
41
|
-
update: adminOnly,
|
|
42
|
-
delete: adminOnly,
|
|
43
|
-
},
|
|
44
|
-
fields: [
|
|
45
|
-
{ name: 'name', type: 'text', required: true },
|
|
46
|
-
{
|
|
47
|
-
name: 'linkedUser',
|
|
48
|
-
type: 'relationship',
|
|
49
|
-
relationTo: usersSlug,
|
|
50
|
-
required: true,
|
|
51
|
-
admin: { description: 'The user whose access control this key inherits.' },
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: 'scopes',
|
|
55
|
-
type: 'select',
|
|
56
|
-
hasMany: true,
|
|
57
|
-
required: true,
|
|
58
|
-
options: availableScopes.map((value) => ({ label: value, value })),
|
|
59
|
-
},
|
|
60
|
-
{ name: 'enabled', type: 'checkbox', defaultValue: true, required: true },
|
|
61
|
-
{
|
|
62
|
-
name: 'keyHash',
|
|
63
|
-
type: 'text',
|
|
64
|
-
required: true,
|
|
65
|
-
admin: {
|
|
66
|
-
readOnly: true,
|
|
67
|
-
description: 'SHA-256 hash of the key. The raw key is never stored.',
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
name: 'keyDisplay',
|
|
72
|
-
type: 'text',
|
|
73
|
-
admin: {
|
|
74
|
-
readOnly: true,
|
|
75
|
-
description: 'First and last 4 characters of the key for identification.',
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
{ name: 'expiresAt', type: 'date' },
|
|
79
|
-
{ name: 'lastUsedAt', type: 'date', admin: { readOnly: true } },
|
|
80
|
-
],
|
|
81
|
-
hooks: {
|
|
82
|
-
beforeChange: [
|
|
83
|
-
async ({ data, operation }) => {
|
|
84
|
-
if (operation !== 'create')
|
|
85
|
-
return data;
|
|
86
|
-
if (data['keyHash'])
|
|
87
|
-
return data;
|
|
88
|
-
const rawKey = generateApiKey();
|
|
89
|
-
data['keyHash'] = await sha256Hex(rawKey);
|
|
90
|
-
data['keyDisplay'] = `${rawKey.slice(0, 8)}...${rawKey.slice(-4)}`;
|
|
91
|
-
data.__rawKey = rawKey;
|
|
92
|
-
return data;
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Generates a random API key prefixed with `tl_`. */
|
|
99
|
-
export function generateApiKey() {
|
|
100
|
-
const bytes = new Uint8Array(32);
|
|
101
|
-
crypto.getRandomValues(bytes);
|
|
102
|
-
const hex = Array.from(bytes)
|
|
103
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
104
|
-
.join('');
|
|
105
|
-
return `tl_${hex}`;
|
|
106
|
-
}
|
|
107
|
-
/** Hashes a string with SHA-256 using the Web Crypto API; returns lowercase hex. */
|
|
108
|
-
export async function sha256Hex(input) {
|
|
109
|
-
const data = new TextEncoder().encode(input);
|
|
110
|
-
const buffer = await crypto.subtle.digest('SHA-256', data);
|
|
111
|
-
return Array.from(new Uint8Array(buffer))
|
|
112
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
113
|
-
.join('');
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=api-keys.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/auth/api-keys.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAA;AAEnD,MAAM,cAAc,GAAG;IACrB,cAAc;IACd,eAAe;IACf,aAAa;IACb,oBAAoB;IACpB,mBAAmB;IACnB,kBAAkB;IAClB,cAAc;IACd,sBAAsB;IACtB,YAAY;CACJ,CAAA;AAEV;;;;GAIG;AACH,MAAM,SAAS,GAAW,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;IACpC,MAAM,KAAK,GAAI,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAA0B,IAAI,EAAE,CAAA;IACjE,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;AAChC,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAoC,EAAE;IAEtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,qBAAqB,CAAA;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAA;IAC9C,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,GAAG,cAAc,CAAC,CAAA;IAEtE,OAAO;QACL,IAAI;QACJ,KAAK,EAAE;YACL,UAAU,EAAE,MAAM;YAClB,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC;YAC/D,WAAW,EACT,mHAAmH;SACtH;QACD,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;SAClB;QACD,MAAM,EAAE;YACN,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC9C;gBACE,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,SAAS;gBACrB,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,EAAE,WAAW,EAAE,kDAAkD,EAAE;aAC3E;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;aACnE;YACD,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;YACzE;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE;oBACL,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,uDAAuD;iBACrE;aACF;YACD;gBACE,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE;oBACL,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,4DAA4D;iBAC1E;aACF;YACD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;YACnC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;SAChE;QACD,KAAK,EAAE;YACL,YAAY,EAAE;gBACZ,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;oBAC5B,IAAI,SAAS,KAAK,QAAQ;wBAAE,OAAO,IAAI,CAAA;oBACvC,IAAI,IAAI,CAAC,SAAS,CAAC;wBAAE,OAAO,IAAI,CAAA;oBAEhC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;oBAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;oBACzC,IAAI,CAAC,YAAY,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAGjE;oBAAC,IAAgC,CAAC,QAAQ,GAAG,MAAM,CAAA;oBACpD,OAAO,IAAI,CAAA;gBACb,CAAC;aACF;SACF;KACF,CAAA;AACH,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAA;IACX,OAAO,MAAM,GAAG,EAAE,CAAA;AACpB,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAa;IAC3C,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAA;AACb,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Payload } from 'payload';
|
|
2
|
-
import type { McpAuthenticator } from '@forumone/throughline-plugin-contract';
|
|
3
|
-
export interface BearerTokenAuthenticatorOptions {
|
|
4
|
-
payload: Payload;
|
|
5
|
-
/** Slug for the API-keys collection. Default: `'mcp-api-keys'`. */
|
|
6
|
-
collectionSlug?: string;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Authenticates incoming MCP requests by looking up the bearer token's hash
|
|
10
|
-
* against the API-keys collection. Returns the linked user plus key metadata
|
|
11
|
-
* on success, `null` on any failure (no token, unknown token, disabled key,
|
|
12
|
-
* key without linked user, expired key).
|
|
13
|
-
*
|
|
14
|
-
* The key's `scopes` come back with it. They are what the handler holds a
|
|
15
|
-
* scoped tool against; until they did, the field was a label on a key that
|
|
16
|
-
* could do everything its linked user could.
|
|
17
|
-
*/
|
|
18
|
-
export declare function createBearerTokenAuthenticator(options: BearerTokenAuthenticatorOptions): McpAuthenticator;
|
|
19
|
-
//# sourceMappingURL=authenticator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authenticator.d.ts","sourceRoot":"","sources":["../../src/auth/authenticator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,uCAAuC,CAAA;AAG9C,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAA;IAChB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,gBAAgB,CAyClB"}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_API_KEYS_SLUG, sha256Hex } from './api-keys.js';
|
|
2
|
-
/**
|
|
3
|
-
* Authenticates incoming MCP requests by looking up the bearer token's hash
|
|
4
|
-
* against the API-keys collection. Returns the linked user plus key metadata
|
|
5
|
-
* on success, `null` on any failure (no token, unknown token, disabled key,
|
|
6
|
-
* key without linked user, expired key).
|
|
7
|
-
*
|
|
8
|
-
* The key's `scopes` come back with it. They are what the handler holds a
|
|
9
|
-
* scoped tool against; until they did, the field was a label on a key that
|
|
10
|
-
* could do everything its linked user could.
|
|
11
|
-
*/
|
|
12
|
-
export function createBearerTokenAuthenticator(options) {
|
|
13
|
-
const { payload, collectionSlug = DEFAULT_API_KEYS_SLUG } = options;
|
|
14
|
-
return {
|
|
15
|
-
async authenticate(request) {
|
|
16
|
-
const token = extractBearerToken(request);
|
|
17
|
-
if (!token)
|
|
18
|
-
return null;
|
|
19
|
-
const hash = await sha256Hex(token);
|
|
20
|
-
const result = await payload.find({
|
|
21
|
-
collection: collectionSlug,
|
|
22
|
-
where: {
|
|
23
|
-
and: [{ keyHash: { equals: hash } }, { enabled: { equals: true } }],
|
|
24
|
-
},
|
|
25
|
-
limit: 1,
|
|
26
|
-
depth: 1,
|
|
27
|
-
});
|
|
28
|
-
const apiKey = result.docs[0];
|
|
29
|
-
if (!apiKey)
|
|
30
|
-
return null;
|
|
31
|
-
const expiresAt = apiKey['expiresAt'];
|
|
32
|
-
if (typeof expiresAt === 'string' && Date.parse(expiresAt) <= Date.now()) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
const linkedUser = apiKey['linkedUser'];
|
|
36
|
-
if (!linkedUser || typeof linkedUser !== 'object')
|
|
37
|
-
return null;
|
|
38
|
-
const user = toAuthenticatedUser(linkedUser);
|
|
39
|
-
if (!user)
|
|
40
|
-
return null;
|
|
41
|
-
return {
|
|
42
|
-
user,
|
|
43
|
-
apiKeyName: String(apiKey['name'] ?? ''),
|
|
44
|
-
apiKeyId: String(apiKey['id']),
|
|
45
|
-
scopes: toScopes(apiKey['scopes']),
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function extractBearerToken(request) {
|
|
51
|
-
const header = request.headers.get('authorization');
|
|
52
|
-
if (!header)
|
|
53
|
-
return null;
|
|
54
|
-
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
55
|
-
return match?.[1]?.trim() || null;
|
|
56
|
-
}
|
|
57
|
-
function toAuthenticatedUser(raw) {
|
|
58
|
-
if (raw['id'] === undefined || raw['email'] === undefined)
|
|
59
|
-
return null;
|
|
60
|
-
return {
|
|
61
|
-
id: String(raw['id']),
|
|
62
|
-
email: String(raw['email']),
|
|
63
|
-
name: String(raw['name'] ?? raw['email']),
|
|
64
|
-
roles: raw['roles'] ?? [],
|
|
65
|
-
groups: raw['groups'] ?? [],
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
/** The stored `scopes` as a string list, whatever shape the row came back in. */
|
|
69
|
-
function toScopes(raw) {
|
|
70
|
-
if (!Array.isArray(raw))
|
|
71
|
-
return [];
|
|
72
|
-
return raw.filter((scope) => typeof scope === 'string');
|
|
73
|
-
}
|
|
74
|
-
//# sourceMappingURL=authenticator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"authenticator.js","sourceRoot":"","sources":["../../src/auth/authenticator.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { createBearerTokenAuthenticator } from './authenticator.js';
|
|
2
|
-
export type { BearerTokenAuthenticatorOptions } from './authenticator.js';
|
|
3
|
-
export { createApiKeysCollection, generateApiKey, sha256Hex, DEFAULT_API_KEYS_SLUG, } from './api-keys.js';
|
|
4
|
-
export type { ApiKeysCollectionOptions } from './api-keys.js';
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAA;AACnE,YAAY,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAA;AAEzE,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,qBAAqB,GACtB,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/auth/index.js
DELETED
package/dist/auth/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAA;AAGnE,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,qBAAqB,GACtB,MAAM,eAAe,CAAA"}
|
package/dist/mcp/handler.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Payload } from 'payload';
|
|
2
|
-
import type { Logger, McpAuthenticator, McpToolDefinition } from '@forumone/throughline-plugin-contract';
|
|
3
|
-
export interface McpHandlerOptions {
|
|
4
|
-
payload: Payload;
|
|
5
|
-
/** Server identifier surfaced in logs (e.g. `'publishing'`). */
|
|
6
|
-
serverName: string;
|
|
7
|
-
/** Tools the server exposes via `tools/list` and `tools/call`. */
|
|
8
|
-
tools: McpToolDefinition[];
|
|
9
|
-
/** Optional override; defaults to a bearer-token authenticator. */
|
|
10
|
-
authenticator?: McpAuthenticator;
|
|
11
|
-
/** Optional logger; defaults to the framework's console logger. */
|
|
12
|
-
logger?: Logger;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Returns an HTTP handler that implements the Model Context Protocol's
|
|
16
|
-
* JSON-RPC subset over a single POST endpoint. Handles authentication,
|
|
17
|
-
* tool listing, tool dispatch, and error formatting.
|
|
18
|
-
*/
|
|
19
|
-
export declare function createMcpHandler(options: McpHandlerOptions): (request: Request) => Promise<Response>;
|
|
20
|
-
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/mcp/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGtC,OAAO,KAAK,EACV,MAAM,EACN,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,uCAAuC,CAAA;AAI9C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,KAAK,EAAE,iBAAiB,EAAE,CAAA;IAC1B,mEAAmE;IACnE,aAAa,CAAC,EAAE,gBAAgB,CAAA;IAChC,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAsGpG"}
|
package/dist/mcp/handler.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
-
import { createBearerTokenAuthenticator } from '../auth/index.js';
|
|
4
|
-
import { createNamedLogger, defaultLogger } from '../logger/index.js';
|
|
5
|
-
/**
|
|
6
|
-
* Returns an HTTP handler that implements the Model Context Protocol's
|
|
7
|
-
* JSON-RPC subset over a single POST endpoint. Handles authentication,
|
|
8
|
-
* tool listing, tool dispatch, and error formatting.
|
|
9
|
-
*/
|
|
10
|
-
export function createMcpHandler(options) {
|
|
11
|
-
const authenticator = options.authenticator ?? createBearerTokenAuthenticator({ payload: options.payload });
|
|
12
|
-
const toolsByName = new Map(options.tools.map((t) => [t.name, t]));
|
|
13
|
-
const logger = options.logger ?? defaultLogger;
|
|
14
|
-
const tag = `[${options.serverName}]`;
|
|
15
|
-
// `createNamedLogger` is forty lines away in this same package and does
|
|
16
|
-
// exactly this. The handler used to rebuild it inline.
|
|
17
|
-
const toolLogger = createNamedLogger(options.serverName, logger);
|
|
18
|
-
return async function handleMcp(request) {
|
|
19
|
-
const auth = await authenticator.authenticate(request);
|
|
20
|
-
if (!auth)
|
|
21
|
-
return jsonResponse({ error: 'Unauthorized' }, 401);
|
|
22
|
-
let body;
|
|
23
|
-
try {
|
|
24
|
-
body = await request.json();
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return jsonRpcError(null, JSON_RPC_PARSE_ERROR, 'Parse error');
|
|
28
|
-
}
|
|
29
|
-
const parsed = JsonRpcRequestSchema.safeParse(body);
|
|
30
|
-
if (!parsed.success)
|
|
31
|
-
return jsonRpcError(null, JSON_RPC_INVALID_REQUEST, 'Invalid request');
|
|
32
|
-
const rpc = parsed.data;
|
|
33
|
-
const id = rpc.id ?? null;
|
|
34
|
-
try {
|
|
35
|
-
if (rpc.method === 'tools/list') {
|
|
36
|
-
/*
|
|
37
|
-
Only what this key may actually call.
|
|
38
|
-
|
|
39
|
-
An agent shown a tool it will be refused for will try it, be refused,
|
|
40
|
-
and try something else — and the transcript reads like the tool is
|
|
41
|
-
broken rather than like the key is narrow. Hiding it is the difference
|
|
42
|
-
between "you cannot publish" and "publishing is unavailable", and only
|
|
43
|
-
one of those is true.
|
|
44
|
-
*/
|
|
45
|
-
return jsonRpcResult(id, {
|
|
46
|
-
tools: options.tools.filter(permits(auth.scopes)).map((tool) => ({
|
|
47
|
-
name: tool.name,
|
|
48
|
-
description: tool.description,
|
|
49
|
-
inputSchema: zodToJsonSchema(tool.inputSchema, { target: 'jsonSchema7' }),
|
|
50
|
-
})),
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (rpc.method === 'tools/call') {
|
|
54
|
-
const params = ToolCallParamsSchema.safeParse(rpc.params);
|
|
55
|
-
if (!params.success) {
|
|
56
|
-
return jsonRpcError(id, JSON_RPC_INVALID_PARAMS, 'Invalid params');
|
|
57
|
-
}
|
|
58
|
-
const tool = toolsByName.get(params.data.name);
|
|
59
|
-
if (!tool) {
|
|
60
|
-
return jsonRpcError(id, JSON_RPC_METHOD_NOT_FOUND, `Unknown tool: ${params.data.name}`);
|
|
61
|
-
}
|
|
62
|
-
// Named rather than merely refused: a caller that cannot see why it was
|
|
63
|
-
// turned away has no way to ask for the right key.
|
|
64
|
-
if (!permits(auth.scopes)(tool)) {
|
|
65
|
-
logger.warn(`${tag} refused ${tool.name}: key "${auth.apiKeyName}" lacks scope ${String(tool.requiredScope)}`);
|
|
66
|
-
return jsonRpcError(id, JSON_RPC_INVALID_REQUEST, `This API key does not carry the "${String(tool.requiredScope)}" scope, which ${tool.name} requires.`);
|
|
67
|
-
}
|
|
68
|
-
const inputResult = tool.inputSchema.safeParse(params.data.arguments ?? {});
|
|
69
|
-
if (!inputResult.success) {
|
|
70
|
-
return jsonRpcError(id, JSON_RPC_INVALID_PARAMS, `Invalid arguments: ${inputResult.error.message}`);
|
|
71
|
-
}
|
|
72
|
-
const result = await tool.handler(inputResult.data, {
|
|
73
|
-
user: auth.user,
|
|
74
|
-
apiKeyName: auth.apiKeyName,
|
|
75
|
-
logger: toolLogger,
|
|
76
|
-
});
|
|
77
|
-
return jsonRpcResult(id, {
|
|
78
|
-
content: [
|
|
79
|
-
{
|
|
80
|
-
type: 'text',
|
|
81
|
-
text: typeof result === 'string' ? result : JSON.stringify(result),
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
return jsonRpcError(id, JSON_RPC_METHOD_NOT_FOUND, `Method not found: ${rpc.method}`);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
logger.error(`${tag} MCP handler error`, { error: String(error), method: rpc.method });
|
|
90
|
-
return jsonRpcError(id, JSON_RPC_INTERNAL_ERROR, 'Internal error');
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
const JSON_RPC_PARSE_ERROR = -32700;
|
|
95
|
-
const JSON_RPC_INVALID_REQUEST = -32600;
|
|
96
|
-
const JSON_RPC_METHOD_NOT_FOUND = -32601;
|
|
97
|
-
const JSON_RPC_INVALID_PARAMS = -32602;
|
|
98
|
-
const JSON_RPC_INTERNAL_ERROR = -32603;
|
|
99
|
-
const JsonRpcRequestSchema = z.object({
|
|
100
|
-
jsonrpc: z.literal('2.0'),
|
|
101
|
-
id: z.union([z.string(), z.number(), z.null()]).optional(),
|
|
102
|
-
method: z.string(),
|
|
103
|
-
params: z.unknown().optional(),
|
|
104
|
-
});
|
|
105
|
-
const ToolCallParamsSchema = z.object({
|
|
106
|
-
name: z.string(),
|
|
107
|
-
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
108
|
-
});
|
|
109
|
-
function jsonResponse(body, status = 200) {
|
|
110
|
-
return new Response(JSON.stringify(body), {
|
|
111
|
-
status,
|
|
112
|
-
headers: { 'content-type': 'application/json' },
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
function jsonRpcResult(id, result) {
|
|
116
|
-
return jsonResponse({ jsonrpc: '2.0', id, result });
|
|
117
|
-
}
|
|
118
|
-
function jsonRpcError(id, code, message) {
|
|
119
|
-
return jsonResponse({ jsonrpc: '2.0', id, error: { code, message } });
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Whether a key holding `scopes` may call a given tool.
|
|
123
|
-
*
|
|
124
|
-
* A tool declaring no `requiredScope` is callable by any authenticated key —
|
|
125
|
-
* the right default for a read. A tool that declares one needs it named on the
|
|
126
|
-
* key, and a key carrying no scopes at all passes nothing.
|
|
127
|
-
*/
|
|
128
|
-
function permits(scopes) {
|
|
129
|
-
const held = new Set(scopes ?? []);
|
|
130
|
-
return (tool) => tool.requiredScope === undefined || held.has(tool.requiredScope);
|
|
131
|
-
}
|
|
132
|
-
//# sourceMappingURL=handler.js.map
|
package/dist/mcp/handler.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/mcp/handler.ts"],"names":[],"mappings":"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"}
|