Skip to content

Commit c715854

Browse files
committed
feat(create-objectstack): default scaffold ships the three generic connector executors (#3056)
Closes the last authoring gap in the ADR-0097 promise that integrations are expressible **and executable** as pure metadata. `npm create objectstack` now generates an `objectstack.config.ts` whose `plugins:` wires the `rest`, `openapi`, and `mcp` connector executors (zero-arg = contribute the provider factory only), so an author (human or AI) can add a declarative `connectors:` entry naming `provider: 'rest' | 'openapi' | 'mcp'` and have it materialize into a live, dispatchable connector at boot — no host-code edit. Why `requires: ['automation']` is added alongside the plugins: the connector plugins declare a hard `dependencies = ['com.objectstack.service-automation']`, and the automation service is what actually materializes declarative `connectors:` entries (ADR-0097). Without it, the kernel throws `Dependency 'com.objectstack.service-automation' not found` at boot — a broken scaffold. Verified end-to-end against the published registry: connectors-only crashes boot; connectors + `requires: ['automation']` boots healthy and a declarative `provider: 'rest'` instance materializes (a declarative connector whose factory is absent fails boot loudly). Automation ships transitively via `@objectstack/cli`, so no new runtime dependency is needed. Scope note: the showcase demo half (in-repo stdio MCP fixture, DevToolsMcpConnector, CI-pinned dogfood) already landed in #3062; this is the template-preset half that was blocked on the 15.1.0 publish (now 15.1.1 is `latest`, and the template's `^15.0.0` pins resolve to it). Changes: - templates/blank/objectstack.config.ts — `requires: ['automation']` + `plugins:` with the three zero-arg executors; brand connectors stay marketplace/opt-in; stdio-MCP opt-in (#3055) documented inline. - templates/blank/package.json — add `@objectstack/connector-{rest,openapi,mcp}` at `^15.0.0` (in lockstep via scripts/sync-template-versions.mjs). - templates/blank/README.md — "Connectors (default providers)" section. - docs/getting-started/your-first-project.mdx — config snippet + packages table match the new scaffold output. - docs/automation/flows.mdx — restore the "scaffolded apps ship the three executors" statement. - changeset (create-objectstack, minor). Refs #3056, #3062 (showcase half), #3055 / #3059 (stdio gate), ADR-0097. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjAgyTXaxSMVDWtGYxAXL7
1 parent 89467f5 commit c715854

6 files changed

Lines changed: 101 additions & 3 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
"create-objectstack": minor
3+
---
4+
5+
feat(create-objectstack): the blank scaffold ships the three generic connector executors by default
6+
7+
`npm create objectstack` now generates an `objectstack.config.ts` that wires the
8+
`rest`, `openapi`, and `mcp` connector executor plugins (ADR-0022/0023/0024 +
9+
ADR-0097) into `plugins:`, alongside `requires: ['automation']`. This closes the
10+
last authoring gap in the ADR-0097 promise that integrations are expressible
11+
**and executable** as pure metadata: an author (human or AI) can now add a
12+
declarative `connectors:` entry naming `provider: 'rest' | 'openapi' | 'mcp'`
13+
and have it materialize into a live, dispatchable connector at boot — with no
14+
host-code edit.
15+
16+
- `plugins:``new ConnectorRestPlugin()`, `new ConnectorOpenApiPlugin()`,
17+
`new ConnectorMcpPlugin()` (zero-arg = contribute the provider factory only).
18+
- `requires: ['automation']` — the automation service performs the
19+
materialization and owns the registry the executors register into. It is also
20+
a hard dependency of the connector plugins, so a scaffold that lists them in
21+
`plugins:` without it fails boot; automation ships transitively via
22+
`@objectstack/cli`.
23+
- deps — `@objectstack/connector-rest`, `@objectstack/connector-openapi`,
24+
`@objectstack/connector-mcp`.
25+
- Security (#3055): declarative `mcp` stdio transports stay denied by default —
26+
opt in per host with `new ConnectorMcpPlugin({ declarativeStdio: ['node'] })`.
27+
28+
Brand connectors (Slack, …) remain marketplace/opt-in.

content/docs/automation/flows.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Each node performs a specific action in the flow.
117117
| `map` | Sequential multi-instance — run a per-item subflow for each element, one at a time (each may pause); batch approval (ADR-0039) |
118118
| `connector_action` | Execute an external connector action |
119119

120-
`connector_action` dispatches against the runtime **connector registry**, which connector plugins populate. The three **generic executors**`rest`, `openapi`, and `mcp` — double as provider factories: with them in your app's `plugins:`, a declarative `connectors:` entry that names a `provider` is materialized into a live, dispatchable connector at boot with no plugin code (ADR-0097; the showcase example wires all three). Brand connectors (Slack, …) are installed separately. One security note: a declarative `mcp` instance using a **stdio** transport spawns a local process from metadata and is therefore denied by default — the host opts in with `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`; `http` transports need no opt-in.
120+
`connector_action` dispatches against the runtime **connector registry**, which connector plugins populate. The three **generic executors**`rest`, `openapi`, and `mcp` — double as provider factories: with them in your app's `plugins:`, a declarative `connectors:` entry that names a `provider` is materialized into a live, dispatchable connector at boot with no plugin code (ADR-0097). Scaffolded projects (`npm create objectstack`) ship all three executors by default — paired with the `automation` capability that performs the materialization — and the showcase wires them too. Brand connectors (Slack, …) are installed separately. One security note: a declarative `mcp` instance using a **stdio** transport spawns a local process from metadata and is therefore denied by default — the host opts in with `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`; `http` transports need no opt-in.
121121

122122
### Node Structure
123123

content/docs/getting-started/your-first-project.mdx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ filename-suffix magic — metadata exists in the app only if it is imported here
101101

102102
```typescript title="objectstack.config.ts"
103103
import { defineStack } from '@objectstack/spec';
104+
import { ConnectorRestPlugin } from '@objectstack/connector-rest';
105+
import { ConnectorOpenApiPlugin } from '@objectstack/connector-openapi';
106+
import { ConnectorMcpPlugin } from '@objectstack/connector-mcp';
104107
import * as objects from './src/objects/index.js';
105108

106109
export default defineStack({
@@ -111,12 +114,25 @@ export default defineStack({
111114
type: 'app',
112115
name: 'My App',
113116
},
117+
// `automation` runs flows and, per ADR-0097, materializes declarative
118+
// `connectors:` entries at boot. The three generic executors below register
119+
// their `rest` / `openapi` / `mcp` provider factories with it.
120+
requires: ['automation'],
121+
plugins: [
122+
new ConnectorRestPlugin(),
123+
new ConnectorOpenApiPlugin(),
124+
new ConnectorMcpPlugin(),
125+
],
114126
objects: Object.values(objects),
115127
});
116128
```
117129

118130
The REST API needs no configuration — it is on by default for every object
119-
with `apiEnabled`.
131+
with `apiEnabled`. The `plugins:` array ships the three **generic connector
132+
executors**, so you can integrate an external REST / OpenAPI / MCP service as
133+
pure metadata: add a `connectors:` entry naming a `provider` and the
134+
`automation` capability materializes it into a live connector at boot — see
135+
[Automation → Flows](/docs/automation/flows).
120136

121137
**`src/objects/note.object.ts`** is a complete data model — schema, validation,
122138
API surface, and searchability in one typed definition:
@@ -151,6 +167,7 @@ framework surface you install:
151167
| `@objectstack/runtime` | The kernel that interprets metadata at runtime. |
152168
| `@objectstack/driver-memory` | In-memory database driver for development. Swap for SQLite / Postgres / MongoDB in production — [no code changes](/docs/data-modeling/drivers). |
153169
| `@objectstack/plugin-hono-server` | The HTTP server that mounts the generated REST API. |
170+
| `@objectstack/connector-rest` · `-openapi` · `-mcp` | The three generic connector executors — register the `rest` / `openapi` / `mcp` provider factories so declarative `connectors:` entries materialize ([ADR-0097](/docs/automation/flows)). |
154171
| `@objectstack/cli` *(dev)* | The `os` / `objectstack` CLI: `dev`, `validate`, `build`, `start`. |
155172

156173
## 3. Run it

packages/create-objectstack/src/templates/blank/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,32 @@ curl -b cookies.txt "http://localhost:3000/api/v1/data/<your_object>"
2626
- `objectstack.config.ts` — environment manifest (objects, API, plugins)
2727
- `src/objects/` — object definitions (one file per object)
2828

29+
## Connectors (default providers)
30+
31+
`objectstack.config.ts` wires the three **generic connector executors**, so you
32+
can call an external system from a flow as pure metadata — no host code:
33+
34+
| Provider | Package | Use for |
35+
|:---|:---|:---|
36+
| `rest` | `@objectstack/connector-rest` | Any JSON/HTTP REST API |
37+
| `openapi` | `@objectstack/connector-openapi` | An API described by an OpenAPI document |
38+
| `mcp` | `@objectstack/connector-mcp` | A Model Context Protocol server |
39+
40+
Add a `connectors:` entry that names one of these `provider`s and the
41+
`automation` capability materializes it into a live, dispatchable connector at
42+
boot (ADR-0097); a flow's `connector_action` node then calls it. To add a brand
43+
connector (e.g. Slack), install its package and add `new ConnectorSlackPlugin()`
44+
to `plugins:`; to drop a provider, remove its plugin.
45+
46+
> **Security — declarative MCP over stdio.** An `mcp` connector whose transport
47+
> spawns a local process (`stdio`) is denied by default, because the command
48+
> comes from metadata. Opt in per host with
49+
> `new ConnectorMcpPlugin({ declarativeStdio: ['node'] })`; `http` transports
50+
> need no opt-in.
51+
52+
See [Automation → Flows](https://docs.objectstack.ai/docs/automation/flows) for
53+
the full connector and `connector_action` guide.
54+
2955
## Verify your changes
3056

3157
After editing any metadata, run:

packages/create-objectstack/src/templates/blank/objectstack.config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { defineStack } from '@objectstack/spec';
2+
import { ConnectorRestPlugin } from '@objectstack/connector-rest';
3+
import { ConnectorOpenApiPlugin } from '@objectstack/connector-openapi';
4+
import { ConnectorMcpPlugin } from '@objectstack/connector-mcp';
25
import * as objects from './src/objects/index.js';
36

47
export default defineStack({
@@ -15,5 +18,26 @@ export default defineStack({
1518
// scripts/sync-template-versions.mjs.
1619
engines: { protocol: '^15' },
1720
},
21+
22+
// `automation` backs flow execution and, per ADR-0097, materializes any
23+
// declarative `connectors:` entry into a live, dispatchable connector at boot.
24+
// The connector executors below register their provider factories with it —
25+
// without `automation` loaded they have nowhere to register and boot fails, so
26+
// keep this capability whenever `plugins:` lists a connector.
27+
requires: ['automation'],
28+
29+
// Generic connector executors (ADR-0022/0023/0024 + ADR-0097), default-present
30+
// so you can add a `connectors:` entry naming `provider: 'rest' | 'openapi' |
31+
// 'mcp'` and have it materialize with zero host code. Zero-arg = contribute the
32+
// provider factory only. Brand connectors (Slack, …) stay marketplace/opt-in.
33+
// Security (#3055): a declarative `mcp` stdio transport spawns a local process
34+
// from metadata and is denied by default — opt in per host with
35+
// `new ConnectorMcpPlugin({ declarativeStdio: ['<trusted-command>'] })`.
36+
plugins: [
37+
new ConnectorRestPlugin(),
38+
new ConnectorOpenApiPlugin(),
39+
new ConnectorMcpPlugin(),
40+
],
41+
1842
objects: Object.values(objects),
1943
});

packages/create-objectstack/src/templates/blank/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
"@objectstack/spec": "^15.0.0",
1515
"@objectstack/runtime": "^15.0.0",
1616
"@objectstack/driver-memory": "^15.0.0",
17-
"@objectstack/plugin-hono-server": "^15.0.0"
17+
"@objectstack/plugin-hono-server": "^15.0.0",
18+
"@objectstack/connector-rest": "^15.0.0",
19+
"@objectstack/connector-openapi": "^15.0.0",
20+
"@objectstack/connector-mcp": "^15.0.0"
1821
},
1922
"devDependencies": {
2023
"@objectstack/cli": "^15.0.0",

0 commit comments

Comments
 (0)