@forumone/throughline-core 0.4.0 → 0.5.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @forumone/throughline-core
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1a4a441: Let every server's tools be served by Payload's own MCP plugin
8
+
9
+ `createMcpToolCollector()` in core, and an `mcpTools` option on all six servers. The host hands the collector's array to `@payloadcms/plugin-mcp` at config time and each plugin fills it at `onInit` — which works because the plugin reads `mcp.tools` inside the handler it builds per request, so an array handed over empty is read populated.
10
+
11
+ That ordering is the whole problem this solves: every tool in the suite is built at `onInit` because every one closes over `payload`, and `mcpPlugin` takes its tools as a config option.
12
+
13
+ Omit `mcpTools` and nothing changes — each server keeps its own `/mcp` endpoint, which is what lets a host move one at a time rather than all six at once.
14
+
15
+ Duplicate tool names are refused, naming both servers. Six servers each owning a `publish` was fine while each had its own endpoint; one server is one namespace, and an MCP client offered two tools under one name gets whichever registered last.
16
+
17
+ **Also fixes a defect the integration test found.** `service.loadDocument` called `findByID` without `disableErrors`, so a missing document threw `NotFound` before the pipeline ran — which made the `exist` step's `not-found` branch unreachable from every caller, and turned "publish a document that does not exist" into a thrown error instead of the diagnostic the pipeline exists to return. The step's own tests passed it an empty document and so never noticed. `unpublish` now distinguishes a missing document from one that is merely already a draft.
18
+
3
19
  ## 0.4.0
4
20
 
5
21
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ export { DEFAULT_API_KEYS_SLUG, createApiKeysCollection, createBearerTokenAuthen
4
4
  export type { ApiKeysCollectionOptions, BearerTokenAuthenticatorOptions } from './auth/index.js';
5
5
  export { createInngestClient } from './events/index.js';
6
6
  export type { CoreEvents, FrameworkEvents, InngestClientOptions } from './events/index.js';
7
- export { McpMetaSchema, auditContext, createMcpHandler, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
8
- export type { AuditContextFields, McpHandlerOptions, McpMeta, PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './mcp/index.js';
7
+ export { McpMetaSchema, auditContext, createMcpHandler, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
8
+ export type { AddToolsOptions, AuditContextFields, CreateMcpToolCollectorOptions, McpHandlerOptions, McpMeta, McpToolCollector, PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './mcp/index.js';
9
9
  export { defaultLogger, createNamedLogger } from './logger/index.js';
10
10
  export { documentContentHash } from './utils/index.js';
11
11
  export type { DocumentContentHashOptions } from './utils/index.js';
@@ -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,EACL,qBAAqB,EACrB,uBAAuB,EACvB,8BAA8B,EAC9B,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,wBAAwB,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAA;AAEhG,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,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,OAAO,EACP,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAIlE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,MAAM,EACN,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,uCAAuC,CAAA"}
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,EACL,qBAAqB,EACrB,uBAAuB,EACvB,8BAA8B,EAC9B,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,wBAAwB,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAA;AAEhG,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,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,6BAA6B,EAC7B,iBAAiB,EACjB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAIlE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,MAAM,EACN,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,uCAAuC,CAAA"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS, DEFAULT_AUDIT_SLUG, auditPlugin, createAuditCollection, createAuditWriter, getAuditWriter, } from './audit/index.js';
4
4
  export { DEFAULT_API_KEYS_SLUG, createApiKeysCollection, createBearerTokenAuthenticator, generateApiKey, sha256Hex, } from './auth/index.js';
5
5
  export { createInngestClient } from './events/index.js';
6
- export { McpMetaSchema, auditContext, createMcpHandler, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
6
+ export { McpMetaSchema, auditContext, createMcpHandler, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
7
7
  export { defaultLogger, createNamedLogger } from './logger/index.js';
8
8
  export { documentContentHash } from './utils/index.js';
9
9
  //# 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,EACL,qBAAqB,EACrB,uBAAuB,EACvB,8BAA8B,EAC9B,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAUvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA"}
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,EACL,qBAAqB,EACrB,uBAAuB,EACvB,8BAA8B,EAC9B,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAavB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,34 @@
1
+ import type { McpToolDefinition } from '@forumone/throughline-plugin-contract';
2
+ import { type PayloadMcpTool, type ToPayloadMcpToolOptions } from './payload-mcp.js';
3
+ export interface McpToolCollector {
4
+ /**
5
+ * The array to hand `mcpPlugin`. Empty until the plugins initialise, and the
6
+ * same array afterwards — do not copy or spread it at config time, or the
7
+ * tools will be added to something nobody reads.
8
+ */
9
+ readonly tools: PayloadMcpTool[];
10
+ /** Called by a plugin at `onInit`, once it can build its tools. */
11
+ add(tools: McpToolDefinition[], options?: AddToolsOptions): void;
12
+ /** Which servers have contributed, in the order they initialised. */
13
+ readonly servers: string[];
14
+ }
15
+ export interface AddToolsOptions extends ToPayloadMcpToolOptions {
16
+ /**
17
+ * Which server these came from — `'publishing'`, `'approvals'`. Used to name
18
+ * both sides of a duplicate-name collision, which is the only thing that
19
+ * makes that error actionable.
20
+ */
21
+ serverName?: string;
22
+ }
23
+ export type CreateMcpToolCollectorOptions = ToPayloadMcpToolOptions;
24
+ /**
25
+ * Somewhere for the plugins to put their tools, that the host can pass to
26
+ * Payload's MCP plugin before they exist.
27
+ *
28
+ * Duplicate names are refused rather than silently shadowed. Six servers that
29
+ * each named their own `publish` were fine while each had its own endpoint; one
30
+ * server means one namespace, and an MCP client offered two tools with one name
31
+ * gets whichever registered last.
32
+ */
33
+ export declare function createMcpToolCollector(options?: CreateMcpToolCollectorOptions): McpToolCollector;
34
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +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;AA6BvG,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAAA;IAChC,mEAAmE;IACnE,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IAChE,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,eAAgB,SAAQ,uBAAuB;IAC9D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,6BAA6B,GAAG,uBAAuB,CAAA;AAEnE;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,6BAAkC,GAC1C,gBAAgB,CA2BlB"}
@@ -0,0 +1,34 @@
1
+ import { toPayloadMcpTools } from './payload-mcp.js';
2
+ /**
3
+ * Somewhere for the plugins to put their tools, that the host can pass to
4
+ * Payload's MCP plugin before they exist.
5
+ *
6
+ * Duplicate names are refused rather than silently shadowed. Six servers that
7
+ * each named their own `publish` were fine while each had its own endpoint; one
8
+ * server means one namespace, and an MCP client offered two tools with one name
9
+ * gets whichever registered last.
10
+ */
11
+ export function createMcpToolCollector(options = {}) {
12
+ const tools = [];
13
+ const servers = [];
14
+ const byName = new Map();
15
+ return {
16
+ tools,
17
+ servers,
18
+ add(incoming, addOptions = {}) {
19
+ const { serverName = 'an unnamed server', ...toolOptions } = addOptions;
20
+ for (const tool of incoming) {
21
+ const existing = byName.get(tool.name);
22
+ if (existing !== undefined) {
23
+ throw new Error(`Two MCP tools are called "${tool.name}" — one from ${existing}, one from ` +
24
+ `${serverName}. Under a single MCP server a tool name is a namespace, and a client ` +
25
+ `offered both gets whichever registered last. Rename one.`);
26
+ }
27
+ byName.set(tool.name, serverName);
28
+ }
29
+ tools.push(...toPayloadMcpTools(incoming, { ...options, ...toolOptions }));
30
+ servers.push(serverName);
31
+ },
32
+ };
33
+ }
34
+ //# sourceMappingURL=collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/mcp/collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAqD,MAAM,kBAAkB,CAAA;AAqDvG;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAyC,EAAE;IAE3C,MAAM,KAAK,GAAqB,EAAE,CAAA;IAClC,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IAExC,OAAO;QACL,KAAK;QACL,OAAO;QACP,GAAG,CAAC,QAAQ,EAAE,UAAU,GAAG,EAAE;YAC3B,MAAM,EAAE,UAAU,GAAG,mBAAmB,EAAE,GAAG,WAAW,EAAE,GAAG,UAAU,CAAA;YAEvE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,MAAM,IAAI,KAAK,CACb,6BAA6B,IAAI,CAAC,IAAI,gBAAgB,QAAQ,aAAa;wBACzE,GAAG,UAAU,uEAAuE;wBACpF,0DAA0D,CAC7D,CAAA;gBACH,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;YACnC,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,WAAW,EAAE,CAAC,CAAC,CAAA;YAC1E,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC1B,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -6,4 +6,6 @@ export { auditContext } from './audit-context.js';
6
6
  export type { AuditContextFields } from './audit-context.js';
7
7
  export { toPayloadMcpTool, toPayloadMcpTools } from './payload-mcp.js';
8
8
  export type { PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './payload-mcp.js';
9
+ export { createMcpToolCollector } from './collector.js';
10
+ export type { AddToolsOptions, CreateMcpToolCollectorOptions, McpToolCollector, } from './collector.js';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErD,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErD,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,gBAAgB,GACjB,MAAM,gBAAgB,CAAA"}
package/dist/mcp/index.js CHANGED
@@ -2,4 +2,5 @@ export { createMcpHandler } from './handler.js';
2
2
  export { McpMetaSchema, withMeta } from './meta.js';
3
3
  export { auditContext } from './audit-context.js';
4
4
  export { toPayloadMcpTool, toPayloadMcpTools } from './payload-mcp.js';
5
+ export { createMcpToolCollector } from './collector.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAG/C,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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAG/C,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forumone/throughline-core",
3
- "version": "0.4.0",
3
+ "version": "0.5.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",