@datanimbus/dnio-mcp 1.0.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.
Files changed (59) hide show
  1. package/Dockerfile +20 -0
  2. package/docs/README.md +35 -0
  3. package/docs/architecture.md +171 -0
  4. package/docs/authentication.md +74 -0
  5. package/docs/tools/apps.md +59 -0
  6. package/docs/tools/connectors.md +76 -0
  7. package/docs/tools/data-pipes.md +286 -0
  8. package/docs/tools/data-services.md +105 -0
  9. package/docs/tools/deployment-groups.md +152 -0
  10. package/docs/tools/plugins.md +94 -0
  11. package/docs/tools/records.md +97 -0
  12. package/docs/workflows.md +195 -0
  13. package/env.example +16 -0
  14. package/package.json +43 -0
  15. package/readme.md +144 -0
  16. package/src/clients/api-keys.js +10 -0
  17. package/src/clients/apps.js +13 -0
  18. package/src/clients/base-client.js +78 -0
  19. package/src/clients/bots.js +10 -0
  20. package/src/clients/connectors.js +30 -0
  21. package/src/clients/data-formats.js +40 -0
  22. package/src/clients/data-pipes.js +33 -0
  23. package/src/clients/deployment-groups.js +59 -0
  24. package/src/clients/formulas.js +10 -0
  25. package/src/clients/functions.js +10 -0
  26. package/src/clients/plugins.js +39 -0
  27. package/src/clients/records.js +51 -0
  28. package/src/clients/services.js +63 -0
  29. package/src/clients/user-groups.js +10 -0
  30. package/src/clients/users.js +10 -0
  31. package/src/examples/ai-sdk-client.js +165 -0
  32. package/src/examples/claude_desktop_config.json +34 -0
  33. package/src/examples/express-integration.js +181 -0
  34. package/src/index.js +283 -0
  35. package/src/schemas/schema-converter.js +179 -0
  36. package/src/services/auth-manager.js +277 -0
  37. package/src/services/dnio-client.js +40 -0
  38. package/src/services/service-registry.js +150 -0
  39. package/src/services/session-manager.js +161 -0
  40. package/src/stdio-bridge.js +185 -0
  41. package/src/tools/_helpers.js +32 -0
  42. package/src/tools/api-keys.js +5 -0
  43. package/src/tools/apps.js +185 -0
  44. package/src/tools/bots.js +5 -0
  45. package/src/tools/connectors.js +165 -0
  46. package/src/tools/data-formats.js +806 -0
  47. package/src/tools/data-pipes.js +1305 -0
  48. package/src/tools/data-service-registry.js +500 -0
  49. package/src/tools/deployment-groups.js +511 -0
  50. package/src/tools/formulas.js +5 -0
  51. package/src/tools/functions.js +5 -0
  52. package/src/tools/mcp-tools-registry.js +38 -0
  53. package/src/tools/plugins.js +250 -0
  54. package/src/tools/records.js +217 -0
  55. package/src/tools/services.js +476 -0
  56. package/src/tools/user-groups.js +5 -0
  57. package/src/tools/users.js +5 -0
  58. package/src/utils/constants.js +135 -0
  59. package/src/utils/logger.js +63 -0
package/Dockerfile ADDED
@@ -0,0 +1,20 @@
1
+ FROM node:22-alpine
2
+
3
+ RUN apk update && apk upgrade && apk add --no-cache dumb-init
4
+
5
+ WORKDIR /app
6
+
7
+ COPY package.json package-lock.json ./
8
+
9
+ RUN npm ci --omit=dev
10
+
11
+ COPY src/ src/
12
+
13
+ ENV NODE_ENV=production
14
+ ENV TRANSPORT=http
15
+ ENV MCP_PORT=3100
16
+ ENV LOG_LEVEL=info
17
+
18
+ EXPOSE 3100
19
+
20
+ CMD ["dumb-init", "node", "src/index.js"]
package/docs/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # DNIO MCP Server — Documentation
2
+
3
+ This directory documents the DNIO MCP server in depth. The top-level [`readme.md`](../readme.md) is the entry point for users; these docs are for anyone extending the server, debugging tool behaviour, or needing the full surface reference.
4
+
5
+ ## Index
6
+
7
+ ### Overview
8
+ - [`architecture.md`](architecture.md) — codebase organization, master-client + per-domain pattern, file layout.
9
+ - [`authentication.md`](authentication.md) — admin + MCP-user dual-token model, refresh lifecycle, app provisioning.
10
+
11
+ ### Tool reference (one file per domain)
12
+ - [`tools/apps.md`](tools/apps.md) — app & service discovery (5 tools)
13
+ - [`tools/records.md`](tools/records.md) — record CRUD, generic + per-service typed tools (6 + dynamic)
14
+ - [`tools/data-services.md`](tools/data-services.md) — data-service definitions (7 tools)
15
+ - [`tools/connectors.md`](tools/connectors.md) — connector instances + marketplace (3 tools)
16
+ - [`tools/plugins.md`](tools/plugins.md) — workflow-node plugins from marketplace (5 tools)
17
+ - [`tools/data-pipes.md`](tools/data-pipes.md) — flows: triggers, processes, mappings, branching (10 tools)
18
+ - [`tools/deployment-groups.md`](tools/deployment-groups.md) — K8s deployment lifecycle (12 tools)
19
+
20
+ ### Recipes
21
+ - [`workflows.md`](workflows.md) — end-to-end flows that combine multiple tools.
22
+
23
+ ### Design history
24
+ - [`superpowers/specs/`](superpowers/specs/) — design docs for past restructures.
25
+
26
+ ## How the docs are organized
27
+
28
+ Each `tools/<domain>.md` file lists every tool in that domain with:
29
+ - the tool name as registered with the MCP server,
30
+ - a one-line purpose,
31
+ - the inputs (parameters & types),
32
+ - behaviour notes (validation, auto-injection, server-side defaults),
33
+ - the underlying HTTP endpoint hit on the DNIO platform.
34
+
35
+ The docs intentionally describe **only what is in the code today**. Stub domains (functions, formulas, users, user-groups, api-keys, bots, data-formats) are not documented because no tools are registered for them yet.
@@ -0,0 +1,171 @@
1
+ # Architecture
2
+
3
+ ## Two parallel trees
4
+
5
+ The codebase splits around two parallel concerns:
6
+
7
+ ```
8
+ src/
9
+ ├── clients/ # HTTP layer, one file per product domain
10
+ │ ├── base-client.js # shared got + token mgmt
11
+ │ ├── apps.js
12
+ │ ├── services.js
13
+ │ ├── records.js
14
+ │ ├── connectors.js
15
+ │ ├── plugins.js
16
+ │ ├── data-pipes.js
17
+ │ ├── deployment-groups.js
18
+ │ └── <stubs>.js # data-formats, formulas, functions, users, …
19
+ └── tools/ # MCP tool registrations, one file per product domain
20
+ ├── _helpers.js # toolError + resolveServiceOrError
21
+ ├── mcp-tools-registry.js # master: imports every domain registrar
22
+ ├── apps.js
23
+ ├── services.js
24
+ ├── records.js
25
+ ├── connectors.js
26
+ ├── plugins.js
27
+ ├── data-pipes.js
28
+ ├── deployment-groups.js
29
+ ├── data-service-registry.js # generates per-service typed tools dynamically
30
+ └── <stubs>.js
31
+ ```
32
+
33
+ Each domain owns:
34
+ - a **client class** in `src/clients/<domain>.js` that defines the HTTP methods,
35
+ - a **tool registrar** in `src/tools/<domain>.js` that exports a `(ctx) => void` function registering MCP tools.
36
+
37
+ The masters (`src/services/dnio-client.js` and `src/tools/mcp-tools-registry.js`) just compose the per-domain modules.
38
+
39
+ ## Master client
40
+
41
+ `src/services/dnio-client.js`:
42
+
43
+ ```js
44
+ class DNIOClient extends BaseClient {
45
+ constructor(opts) {
46
+ super(opts);
47
+ this.apps = new AppsClient(this);
48
+ this.services = new ServicesClient(this);
49
+ this.records = new RecordsClient(this);
50
+ this.connectors = new ConnectorsClient(this);
51
+ this.plugins = new PluginsClient(this);
52
+ this.dataPipes = new DataPipesClient(this);
53
+ this.deploymentGroups = new DeploymentGroupsClient(this);
54
+ // stubs
55
+ this.functions = new FunctionsClient(this);
56
+ this.dataFormats = new DataFormatsClient(this);
57
+ this.formulas = new FormulasClient(this);
58
+ this.users = new UsersClient(this);
59
+ this.userGroups = new UserGroupsClient(this);
60
+ this.apiKeys = new ApiKeysClient(this);
61
+ this.bots = new BotsClient(this);
62
+ }
63
+ }
64
+ ```
65
+
66
+ `BaseClient` (in `src/clients/base-client.js`) owns:
67
+ - the `got` instance (with `prefixUrl`, timeout, default headers),
68
+ - `setToken(token)` — rebuilds the `got` instance with the new `Authorization` header,
69
+ - `_request(method, path, options)` — internal request helper with error normalization,
70
+ - `get` / `post` / `put` / `delete` — exposed HTTP verbs,
71
+ - `_logRequest(method, url, options)` — emits one `logger.debug` line per outbound request, with method, decoded query params, and JSON-stringified body. Lives in one place so every domain client gets it for free.
72
+
73
+ Each domain client receives the master in its constructor and uses `this.http.get/post/...` for HTTP. Domain clients are stateless w.r.t. auth — `dnioClient.setToken(...)` mutates the master and every domain call automatically picks up the new token.
74
+
75
+ Cross-domain calls go through the master. Example: `services.verifyPod(app, path)` calls `this.http.records.count(app, path)` to test whether the K8s pod for a service is up.
76
+
77
+ ## Master tool registrar
78
+
79
+ `src/tools/mcp-tools-registry.js`:
80
+
81
+ ```js
82
+ function registerAllTools(server, dnioClient, authManager, registry, userContext) {
83
+ const ctx = {server, dnioClient, authManager, registry, userContext};
84
+
85
+ registerAppsTools(ctx);
86
+ registerServicesTools(ctx);
87
+ registerRecordsTools(ctx);
88
+ registerConnectorsTools(ctx);
89
+ registerPluginsTools(ctx);
90
+ registerDataPipesTools(ctx);
91
+ registerDeploymentGroupsTools(ctx);
92
+ // stubs (no-op until those domains get tools):
93
+ registerFunctionsTools(ctx);
94
+ registerDataFormatsTools(ctx);
95
+ registerFormulasTools(ctx);
96
+ registerUsersTools(ctx);
97
+ registerUserGroupsTools(ctx);
98
+ registerApiKeysTools(ctx);
99
+ registerBotsTools(ctx);
100
+ }
101
+ ```
102
+
103
+ Each domain registrar destructures from the same `ctx`, so they all share the same `registry` instance — when `select_app` mutates `registry.selectedApp`, every other tool sees it.
104
+
105
+ ## App-state model
106
+
107
+ The `ServiceRegistry` (in `src/services/service-registry.js`) is the single source of truth for the currently selected app:
108
+
109
+ - `registry.selectedApp` — the app name (`null` until `select_app` succeeds).
110
+ - `registry.services` — `Map<serviceId, ServiceEntry>` of every service discovered in that app.
111
+ - `registry.prefixToServiceId`, `registry.nameToServiceId` — fast lookups for `resolveService(identifier)`.
112
+
113
+ `select_app` triggers `registry.loadApp(appName, adminToken, userToken)`, which:
114
+ 1. Lists active services via `client.services.list(appName, {filter: {status: 'Active'}, …})`.
115
+ 2. For each service, fetches its full schema if the list response didn't include it.
116
+ 3. Computes a `toolPrefix` (slugified service name).
117
+ 4. Stores everything in the registry maps.
118
+ 5. Triggers `data-service-registry.js` to register per-service typed CRUD tools.
119
+
120
+ `refresh_services` re-runs the same logic without restarting.
121
+
122
+ ## Static vs. dynamic tools
123
+
124
+ There are two layers of record CRUD tools:
125
+
126
+ - **Static, generic** — `list_records`, `get_record`, `create_record`, `update_record`, `delete_record`, `count_records` (in `tools/records.js`). They take a `serviceName` argument and resolve it via `resolveServiceOrError(registry, serviceName)`.
127
+ - **Dynamic, typed** — registered by `tools/data-service-registry.js` after `select_app`. Each service gets six tools named `<toolPrefix>_list/_get/_create/_update/_delete/_count`. Their input schemas are converted from the service's `definition` array via `src/schemas/schema-converter.js`.
128
+
129
+ Both layers exist so the agent has the option of working generically against any service (when it doesn't know the schema yet) or with strongly-typed inputs once the service is known.
130
+
131
+ ## Transports
132
+
133
+ `src/index.js` supports two transports:
134
+
135
+ ### stdio (`TRANSPORT=stdio`, default)
136
+ - Single shared `DNIOClient`, `ServiceRegistry`, and MCP server for the lifetime of the process.
137
+ - Used by Claude Desktop's local MCP integration and Cursor's MCP config.
138
+
139
+ ### HTTP (`TRANSPORT=http`)
140
+ - An Express server at `MCP_PORT` (default 3100).
141
+ - Per-session `DNIOClient` + `ServiceRegistry` + MCP server, keyed by `Mcp-Session-Id` header.
142
+ - `SessionManager` (in `src/services/session-manager.js`) handles session creation, expiry (`SESSION_TTL`, default 2h), and cleanup.
143
+ - Routes:
144
+ - `POST /mcp` — tool calls / MCP requests; creates a new session if no header present.
145
+ - `GET /mcp` — SSE notifications (requires session).
146
+ - `DELETE /mcp` — close session.
147
+ - `GET /health` — health + active session count.
148
+ - `GET /sessions?key=<admin_pass>` — debug listing of active sessions.
149
+ - `GET /.well-known/oauth-*` — return 404; the server is authless.
150
+
151
+ ## Authentication
152
+
153
+ All MCP-server-to-DNIO API calls use a JWT in the `Authorization: JWT <token>` header. The token is set on the master client via `setToken`. There are two tokens, both managed by `src/services/auth-manager.js`:
154
+
155
+ - **Admin token** — for management endpoints (listing apps, fetching schemas, creating data services, deploying flows).
156
+ - **MCP-user token** — for data plane (record CRUD).
157
+
158
+ See [`authentication.md`](authentication.md) for the lifecycle.
159
+
160
+ ## Where things live (cheat sheet)
161
+
162
+ | Concern | File |
163
+ |---|---|
164
+ | Add a new domain client | `src/clients/<domain>.js` (plus mount in `services/dnio-client.js`) |
165
+ | Add a new domain tool file | `src/tools/<domain>.js` (plus require + call in `tools/mcp-tools-registry.js`) |
166
+ | HTTP plumbing / token lifecycle | `src/clients/base-client.js`, `src/services/auth-manager.js` |
167
+ | App / service discovery state | `src/services/service-registry.js` |
168
+ | Per-service typed tools | `src/tools/data-service-registry.js` |
169
+ | HTTP-transport sessions | `src/services/session-manager.js`, `src/index.js` |
170
+ | Shared tool helpers | `src/tools/_helpers.js` (`toolError`, `resolveServiceOrError`) |
171
+ | Spec / docs surfaced to the LLM | `src/utils/constants.js` (data-service creation spec, connector/role docs) |
@@ -0,0 +1,74 @@
1
+ # Authentication
2
+
3
+ The MCP server manages two separate JWTs against the DNIO platform and switches between them based on the operation. Tokens auto-refresh; consumers of the MCP tools never see them.
4
+
5
+ ## Two tokens
6
+
7
+ | Token | Used for | Provisioned by |
8
+ |---|---|---|
9
+ | **Admin token** | Management / control plane: `list_apps`, `get_service_schema`, anything that lists apps or fetches data-service definitions across apps. | `DNIO_USERNAME` / `DNIO_PASSWORD` env vars. |
10
+ | **MCP-user token** | Data plane: every record CRUD, plus most domain-specific operations (creating connectors, designing flows, managing deployment groups). | `MCP_USER_EMAIL` / `MCP_USER_PASSWORD` env vars — the server looks up this account; if it doesn't exist on the platform, it creates it on first boot. |
11
+
12
+ `auth-manager.js` (`src/services/auth-manager.js`) owns both lifecycles. It exits the process at startup if `MCP_USER_EMAIL` or `MCP_USER_PASSWORD` is unset; `src/index.js` does the same for `DNIO_BASE_URL` / `DNIO_USERNAME` / `DNIO_PASSWORD`. There are no hardcoded credentials anywhere in the code.
13
+
14
+ ## Boot sequence
15
+
16
+ 1. **Login as admin.** POST `/api/a/rbac/auth/login` with `{username, password, isSuperAdmin: true}`. Stores the admin token + computes its expiry from `DNIO_TOKEN_TTL`.
17
+ 2. **Look up MCP user.** GET `/api/a/rbac/admin/user?filter={"email":"mcp-user@dnio.com"}` (with admin token). If found, reuse; otherwise:
18
+ 3. **Create MCP user.** POST `/api/a/rbac/${DNIO_NAMESPACE}/user` with the MCP user payload. Records the user's `_id`.
19
+ 4. **Add MCP user to all apps.** GET `/api/a/rbac/admin/app?count=-1&select=_id` (admin token), then PUT `/api/a/rbac/admin/user/utils/addToApps/mcp-user@dnio.com` with the full app list. This is what gives the MCP user data-plane access across the platform.
20
+ 5. **Login as MCP user.** Same `/auth/login` endpoint with the MCP user's stored credentials. Stores the MCP-user token + expiry.
21
+
22
+ After step 5, the server is ready; both tokens are warm.
23
+
24
+ ## Per-tool token switching
25
+
26
+ Tools call `dnioClient.setToken(token)` before each HTTP request to point the master client at the right JWT for that operation.
27
+
28
+ - `tools/apps.js` `list_apps` — uses admin token, then resets to MCP-user token before returning.
29
+ - `tools/apps.js` `select_app` — uses both: admin to list services + fetch schemas, MCP-user for pod verification.
30
+ - `tools/apps.js` `get_service_schema` — admin token (then resets).
31
+ - Almost every other tool — MCP-user token.
32
+
33
+ The pattern is always `dnioClient.setToken(...)` immediately before the API call inside the tool handler. Because every domain client shares the same `BaseClient` `got` instance, one `setToken` updates the auth header for every subsequent call.
34
+
35
+ ## Refresh
36
+
37
+ `AuthManager` schedules a refresh just before each token expires (`DNIO_TOKEN_TTL`, default 1800 s):
38
+
39
+ - For the admin token: re-run the admin login.
40
+ - For the MCP-user token: re-run the MCP-user login.
41
+
42
+ If a tool is mid-flight when refresh fires, the in-flight call uses whatever token the master client had at the moment of the request. Subsequent calls pick up the refreshed token because `setToken` rebuilds the `got` instance with the new header.
43
+
44
+ If the admin password changes externally, restart the server — there's no UI for re-prompting credentials.
45
+
46
+ ## HTTP-transport sessions
47
+
48
+ In HTTP mode (`TRANSPORT=http`), every Mcp-Session creates its own `DNIOClient` initialized with the current MCP-user token, and that per-session client lives inside `SessionManager`. Token refresh on `AuthManager` does not propagate into already-issued session clients — a session that lives for hours will keep using its initial token until either (a) a tool inside that session calls `setToken` again with the latest from `authManager.getUserToken()`, or (b) the session expires (`SESSION_TTL`, default 7200 s).
49
+
50
+ Practically every tool handler does call `dnioClient.setToken(userContext.token)` and `userContext.token` is refreshed on `select_app`, so this rarely surfaces. If you see auth failures after a session has been idle for >30 minutes, the `SESSION_TTL` cleanup is the simplest fix.
51
+
52
+ ## stdio-transport
53
+
54
+ In stdio mode there's a single `DNIOClient`, `ServiceRegistry`, and MCP server for the process. Token refresh on `AuthManager` is enough — every tool handler calls `setToken` against that single client.
55
+
56
+ ## Endpoints used
57
+
58
+ All against `${DNIO_BASE_URL}`:
59
+
60
+ | Method | Path | Purpose |
61
+ |---|---|---|
62
+ | POST | `/api/a/rbac/auth/login` | Admin and MCP-user login |
63
+ | GET | `/api/a/rbac/admin/user?filter=…` | Find the MCP user |
64
+ | POST | `/api/a/rbac/${namespace}/user` | Create MCP user |
65
+ | GET | `/api/a/rbac/admin/app?count=-1&select=_id` | List apps for provisioning |
66
+ | PUT | `/api/a/rbac/admin/user/utils/addToApps/${email}` | Grant MCP user app access |
67
+
68
+ The MCP user's password is generated on first creation and persisted by the platform; the server doesn't store it locally beyond memory.
69
+
70
+ ## Security notes
71
+
72
+ - The MCP server's HTTP transport is **authless** — anyone with the URL can connect. If you deploy it externally, put it behind a network policy or auth proxy.
73
+ - `GET /sessions?key=<admin_pass>` is a debug endpoint that uses the admin password as a shared secret. Disable it in production by removing the route or wrapping it in middleware.
74
+ - Tokens are kept in memory only. They never hit disk and aren't logged (the request logger logs path/query/body but never headers).
@@ -0,0 +1,59 @@
1
+ # Apps & Service Discovery
2
+
3
+ Tools registered by `src/tools/apps.js`. They drive the entry-point flow (`list_apps` → `select_app`) and provide read-only inspection of services in the selected app.
4
+
5
+ Backed by `AppsClient` (`src/clients/apps.js`) and `ServicesClient.getSchema` (`src/clients/services.js`).
6
+
7
+ ## `list_apps`
8
+
9
+ | | |
10
+ |---|---|
11
+ | **Purpose** | List every app on the platform. The first tool to run in any session. |
12
+ | **Inputs** | (none) |
13
+ | **Endpoint** | `GET /api/a/rbac/admin/app?count=-1&select=_id,description` (admin token) |
14
+ | **Auth** | Admin token, then resets to MCP-user token before returning. |
15
+ | **Returns** | `{ platform, user, selectedApp, apps: [{ appName, description }] }` |
16
+
17
+ ## `select_app`
18
+
19
+ | | |
20
+ |---|---|
21
+ | **Purpose** | Switch the active app. Discovers every active data service in the app, verifies pods, loads schemas, and registers per-service typed CRUD tools. Required before any data-plane tool. |
22
+ | **Inputs** | `appName` (string, required) |
23
+ | **Behaviour** | 1. Calls `authManager.ensureUserAppAccess(appName)` to make sure the MCP user has access. 2. Refreshes `userContext.token`. 3. Calls `registry.loadApp(appName, adminToken, userToken)`, which lists active services, fetches each service's `definition`, and stores them in the registry. 4. Triggers per-service tool registration via `data-service-registry.js`. |
24
+ | **Endpoints** | `GET /api/a/sm/${app}/service?filter={"app":"${app}","status":"Active"}&count=-1&select=…` (admin) for listing; `GET /api/a/sm/${app}/service/${serviceId}` (admin) per service that needs schema fetch. |
25
+ | **Returns** | `{ action: 'app_selected', appName, services: [...], skipped: [...]?, totalLoaded, usage }` |
26
+
27
+ ## `list_services`
28
+
29
+ | | |
30
+ |---|---|
31
+ | **Purpose** | Show every loaded data service for the currently selected app, including the parsed schema description used for tool generation. Read-only — uses the in-memory `ServiceRegistry`. |
32
+ | **Inputs** | (none) |
33
+ | **Endpoint** | (none — reads `registry.getServiceList()`) |
34
+ | **Returns** | `{ appName, services: [{ name, serviceId, apiPath, schema }] }` |
35
+
36
+ ## `refresh_services`
37
+
38
+ | | |
39
+ |---|---|
40
+ | **Purpose** | Re-scan the selected app for new/changed services without restarting the server. Useful after creating a new data service in the same session. |
41
+ | **Inputs** | (none) |
42
+ | **Behaviour** | Re-runs `registry.loadApp` for the currently selected app. |
43
+ | **Returns** | `{ action: 'refreshed', appName, loaded: [name…], skipped: [...] }` |
44
+
45
+ ## `get_service_schema`
46
+
47
+ | | |
48
+ |---|---|
49
+ | **Purpose** | Fetch the full schema of a single service — useful before constructing a record payload for `create_record`. |
50
+ | **Inputs** | `serviceName` (string, required) — name, slug prefix, or `_id`. |
51
+ | **Behaviour** | Resolves `serviceName` via `registry.resolveService` (matches by `_id`, lowercase name, or slugified prefix). If not found, returns the available list. |
52
+ | **Endpoint** | `GET /api/a/sm/${app}/service/${serviceId}` (admin token) |
53
+ | **Returns** | `{ serviceId, name, api, attributeCount, status, definition }` |
54
+
55
+ ## Notes
56
+
57
+ - `select_app` is the only tool in this domain that mutates server-side state — it sets `registry.selectedApp` and rebuilds the per-service typed tool set.
58
+ - `list_services` and `get_service_schema` will return errors when no app is selected.
59
+ - `select_app` fetches schemas individually only when the list response did not already include `definition`. The platform's list endpoint generally returns it; the per-service GET is a safety net.
@@ -0,0 +1,76 @@
1
+ # Connectors
2
+
3
+ Tools registered by `src/tools/connectors.js`. A **connector** is a configured backing system (a database, an S3 bucket, an SFTP server, an SMTP relay, an ActiveMQ queue, …) that data services and flow nodes bind to.
4
+
5
+ The platform separates **connector types** (templates from a marketplace catalog) from **connector instances** (concrete configured ones in the selected app).
6
+
7
+ Backed by `ConnectorsClient` (`src/clients/connectors.js`).
8
+
9
+ ## Where connectors come from
10
+
11
+ ```
12
+ list_connector_types → marketplace catalog (templates)
13
+
14
+
15
+ create_connector → POST /api/a/bm/${app}/connector
16
+ │ creates an instance in this app
17
+
18
+ list_connectors → GET /api/a/rbac/${app}/connector
19
+ lists existing instances
20
+ ```
21
+
22
+ The instance API and the marketplace API live under different namespaces (`/api/a/rbac` vs `/api/a/bm`).
23
+
24
+ ## Tool reference
25
+
26
+ ### `list_connectors`
27
+
28
+ | | |
29
+ |---|---|
30
+ | **Purpose** | List existing connector instances in the selected app. Used by `create_data_service` (auto-fill) and as the source for connector IDs throughout the platform. |
31
+ | **Inputs** | `category` (optional, one of `DB` or `STORAGE`). Omit for all categories (`MESSAGING`, `STORAGE`, `DB`, etc.). |
32
+ | **Endpoint** | `GET /api/a/rbac/${app}/connector?filter={"app":"${app}"[, "category":"…"]}&count=-1&select=_id,name,category,subCategory,type,options,_metadata` |
33
+ | **Returns** | `{ app, count, connectors: [{ _id, name, category, subCategory, type, isDefault, isValid }], usage }` |
34
+
35
+ `isDefault` is true for the platform's pre-provisioned default connectors (a default MongoDB DB connector and a default GridFS storage connector). `create_data_service` auto-attaches these when the LLM doesn't specify a connector.
36
+
37
+ ### `list_connector_types`
38
+
39
+ | | |
40
+ |---|---|
41
+ | **Purpose** | List connector **templates** in the marketplace. Each item shows the marketplace `_id` (used as `marketItemId` for `create_connector`), the `type` / `label` / `category`, and a `fields[]` schema describing what credentials each type needs. |
42
+ | **Inputs** | `category` (optional, e.g. `DB`, `STORAGE`, `MESSAGING`), `search` (optional, substring on label/type/tags). |
43
+ | **Endpoint** | `GET /api/a/bm/${app}/marketplace/connector?count=1000&select=label,thumbnail,type,fields,category,tags,version` |
44
+ | **Behaviour** | Strips the `thumbnail` SVG from the response to keep payloads small. Filtering is client-side. |
45
+ | **Returns** | `{ app, count, types: [{ marketItemId, type, label, category, tags, version, fields: [{ key, label, type, htmlInputType, required, encrypted }] }], usage }` |
46
+
47
+ The `fields[]` schema tells the agent exactly what to ask the user for. Examples seen in the wild:
48
+
49
+ | Type | Fields |
50
+ |---|---|
51
+ | `MONGODB` | `connectionString` (encrypted) |
52
+ | `S3` | `accessKeyId`, `secretAccessKey` (encrypted), `region`, `bucket` |
53
+ | `ACTIVEMQ` | `host`, `port`, `username`, `password` (encrypted) |
54
+ | `SFTP` / `SMTP` / etc. | various |
55
+
56
+ ### `create_connector`
57
+
58
+ | | |
59
+ |---|---|
60
+ | **Purpose** | Create a new connector instance in the selected app. Always preceded by `list_connector_types`. |
61
+ | **Inputs** | `name` (required, display name), `marketItemId` (required, from `list_connector_types`), `values` (required, JSON string keyed by each field's `key`). |
62
+ | **Behaviour** | Builds payload `{ values, name, app: registry.selectedApp, marketItemId }` — the `app` field is server-injected from the selected app, regardless of what the LLM passes. Encrypted fields (e.g. passwords, secret keys) are sent as-is; the platform encrypts them at rest. |
63
+ | **Endpoint** | `POST /api/a/bm/${app}/connector` |
64
+ | **Returns** | The platform's response (the created connector). |
65
+
66
+ ## Typical sequence
67
+
68
+ ```
69
+ list_connector_types(category: 'DB', search: 'mongo')
70
+ → user picks one (marketItemId, fields)
71
+ → ask the user for each field's value (passwords for encrypted ones)
72
+ create_connector(name, marketItemId, values)
73
+ list_connectors # confirm it shows up
74
+ ```
75
+
76
+ The created instance can then be used as `connectors.data._id` (for DB) or `connectors.file._id` (for STORAGE) when calling `create_data_service`.