@datar-platform/cli 0.1.0-alpha.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 (42) hide show
  1. package/README.md +131 -0
  2. package/dist/config.d.ts +24 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +50 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/http.d.ts +9 -0
  7. package/dist/http.d.ts.map +1 -0
  8. package/dist/http.js +22 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +166 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/mcp/registry.d.ts +26 -0
  15. package/dist/mcp/registry.d.ts.map +1 -0
  16. package/dist/mcp/registry.js +18 -0
  17. package/dist/mcp/registry.js.map +1 -0
  18. package/dist/mcp/server.d.ts +20 -0
  19. package/dist/mcp/server.d.ts.map +1 -0
  20. package/dist/mcp/server.js +75 -0
  21. package/dist/mcp/server.js.map +1 -0
  22. package/dist/mcp/tools/ask.d.ts +14 -0
  23. package/dist/mcp/tools/ask.d.ts.map +1 -0
  24. package/dist/mcp/tools/ask.js +66 -0
  25. package/dist/mcp/tools/ask.js.map +1 -0
  26. package/dist/mcp/tools/discovery.d.ts +10 -0
  27. package/dist/mcp/tools/discovery.d.ts.map +1 -0
  28. package/dist/mcp/tools/discovery.js +76 -0
  29. package/dist/mcp/tools/discovery.js.map +1 -0
  30. package/dist/mcp/tools/index.d.ts +23 -0
  31. package/dist/mcp/tools/index.d.ts.map +1 -0
  32. package/dist/mcp/tools/index.js +29 -0
  33. package/dist/mcp/tools/index.js.map +1 -0
  34. package/dist/mcp/tools/query.d.ts +16 -0
  35. package/dist/mcp/tools/query.d.ts.map +1 -0
  36. package/dist/mcp/tools/query.js +87 -0
  37. package/dist/mcp/tools/query.js.map +1 -0
  38. package/dist/mcp/tools/reads.d.ts +9 -0
  39. package/dist/mcp/tools/reads.d.ts.map +1 -0
  40. package/dist/mcp/tools/reads.js +177 -0
  41. package/dist/mcp/tools/reads.js.map +1 -0
  42. package/package.json +78 -0
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # @datar-platform/cli
2
+
3
+ The **`datar` CLI** and **MCP server** — connect any AI harness (Claude Code, Cursor,
4
+ etc.) to a Datar organization with a single API token, the way you connect a CLI to a
5
+ cloud account. The token is bound server-side to one org and a set of scopes, so once you
6
+ authenticate, the harness already knows _which org_ it's in and _what it may do_ — no org
7
+ selection, no endpoint guessing.
8
+
9
+ Built entirely on [`@datar-platform/sdk`](../sdk). **v1 is read + discovery only,**
10
+ available over two transports that share one tool registry: a **local stdio** server
11
+ (`datar mcp`, this package) and a **remote Streamable HTTP** endpoint
12
+ (`/api/mcp` in the web app — no local install needed, just a token).
13
+
14
+ ## Install & authenticate
15
+
16
+ ```bash
17
+ pnpm add -g @datar-platform/cli # or run via npx
18
+
19
+ export DATAR_API_TOKEN=dt_... # mint at <baseUrl>/settings/api-tokens
20
+ export DATAR_BASE_URL=https://acme.datar.co.za # or http://localhost:3000 for dev
21
+ ```
22
+
23
+ ### How read-only is actually enforced
24
+
25
+ The read-only guarantee is **client-side**, not scope-based:
26
+
27
+ - Every discovery/read tool and `datar_query` issue **HTTP GET** only, and tRPC refuses
28
+ mutations over GET — so they physically cannot write, whatever the token's scopes are.
29
+ - `datar_ask` is the **only** tool that can act (it drives an A2A agent, which may call
30
+ mutating endpoints). It is **opt-in** — registered only when `DATAR_MCP_ALLOW_AGENT=1`.
31
+ Default off ⇒ the whole surface is provably read-only.
32
+
33
+ > ⚠️ **Do not rely on token scopes alone for read-only.** Historically most endpoints were
34
+ > built on `serviceProcedure`, which did **not** run the API-token scope-enforcement
35
+ > middleware (only `orgProtectedProcedure` did) — a "read-scoped" `dt_` token could still
36
+ > write through those endpoints. This has since been fixed: `serviceProcedure`,
37
+ > `serviceAdminProcedure`, `memberRoleProcedure`, and `marketplaceRoleProcedure` all now run
38
+ > `.use(apiScopeMiddleware)` (`packages/api/src/trpc.ts`), with a regression test at
39
+ > `packages/api/tests/services/trpc.service-procedure-scope.test.ts`. Scope-based read-only
40
+ > is now real, but this client-side guarantee (GET-only tools, `datar_ask` off) remains the
41
+ > primary one — treat token scoping as defense-in-depth on top of it, not a replacement.
42
+
43
+ ## Use as a CLI
44
+
45
+ ```bash
46
+ datar whoami # the org/user this token resolves to
47
+ datar ls # list Datar service agents
48
+ datar ask "how many open tenders do we have?" # orchestrator routes it
49
+ datar ask procurement "list my draft submissions" # target one agent
50
+ datar query v2.people.org.getActiveMembers # any read procedure by path
51
+ datar projects ls # quick record listings
52
+ ```
53
+
54
+ ## Use as an MCP server (Claude Code)
55
+
56
+ ```bash
57
+ claude mcp add datar \
58
+ --env DATAR_API_TOKEN=dt_... \
59
+ --env DATAR_BASE_URL=https://acme.datar.co.za \
60
+ -- npx -y @datar-platform/cli mcp
61
+ ```
62
+
63
+ Then ask Claude things like _"list Datar services"_, _"show my projects"_, or _"what
64
+ PayFast-backed transactions came in this month?"_ — it will call the tools below.
65
+
66
+ ## Use remotely — no local install (Streamable HTTP)
67
+
68
+ Any MCP-capable harness can connect straight to a Datar tenant with nothing but a token —
69
+ `apps/web/app/api/mcp/route.ts` exposes the **same tool registry** over the MCP Streamable
70
+ HTTP transport (stateless — a fresh `McpServer` per request, as the SDK recommends for
71
+ serverless):
72
+
73
+ ```bash
74
+ claude mcp add datar-remote --transport http \
75
+ https://acme.datar.co.za/api/mcp \
76
+ --header "Authorization: Bearer dt_..."
77
+ ```
78
+
79
+ Auth is the same bearer-token model as everywhere else in the platform (`dt_` API token /
80
+ `sk_` access key), validated with the same check the A2A gateway uses
81
+ (`resolveA2AAuth`) — a missing/invalid token gets a `401` before any MCP handling happens.
82
+ Every tool call then re-enters the app's own tRPC endpoints under the caller's real
83
+ identity, exactly like the local CLI does (the SDK client is just pointed at the request's
84
+ own origin instead of an env var). Same `DATAR_MCP_ALLOW_AGENT=1` gate controls whether
85
+ `datar_ask` is registered on the remote endpoint too.
86
+
87
+ ### Tools exposed (26 read-only by default; +`datar_ask` = 27 with `DATAR_MCP_ALLOW_AGENT=1`)
88
+
89
+ - **Discovery** — `datar_whoami`, `datar_list_services`, `datar_describe_service`
90
+ (skills + input/output JSON schemas from each agent card — the catalog that makes
91
+ downstream calls precise).
92
+ - **Typed reads** (deterministic, no nested-LLM cost) — `drive_list_files`,
93
+ `drive_get_file`, `drive_list_folders`, `projects_list`, `projects_get`,
94
+ `projects_metrics`, `tasks_list`, `people_list`, `requests_list`,
95
+ `requests_pending_approvals`, `transact_list_accounts`, `transact_list_transactions`,
96
+ `procurement_list_tenders`, `procurement_list_public_tenders`,
97
+ `procurement_list_suppliers`, `inventory_list_items`, `inventory_low_stock`,
98
+ `isms_list_risks`, `isms_list_controls`, `invoicing_list_invoices`,
99
+ `invoicing_list_clients`, `messages_list`.
100
+ - **Natural-language fallback** — `datar_ask` (forwards to any agent / the orchestrator;
101
+ reuses tool-calling, KB grounding, cross-service routing). **Opt-in / can act:** only
102
+ registered when `DATAR_MCP_ALLOW_AGENT=1`; omitted by default so the surface stays read-only.
103
+ - **Read escape hatch** — `datar_query` (any `v2.*` tRPC query by path; mutation-looking
104
+ paths are refused, and `client.query()` only issues GETs, which tRPC never serves for
105
+ mutations).
106
+
107
+ ## Verify locally
108
+
109
+ ```bash
110
+ pnpm -F @datar-platform/cli build && pnpm -F @datar-platform/cli test
111
+ # Drive it interactively with the MCP inspector:
112
+ npx @modelcontextprotocol/inspector node packages/cli/dist/index.js mcp
113
+ ```
114
+
115
+ ## Architecture notes
116
+
117
+ - The tool registry (`src/mcp/tools/`, exported as `@datar-platform/cli/mcp/tools`) is
118
+ **transport-agnostic** — a `ToolDef[]` with no MCP/stdio/HTTP types. `src/mcp/server.ts`'s
119
+ `createDatarMcpServer(client, tools)` (exported as `@datar-platform/cli/mcp`) builds an
120
+ `McpServer` from it and is reused verbatim by both transports:
121
+ - `startStdioServer()` (this package's `datar mcp` command) — `StdioServerTransport`.
122
+ - `apps/web/app/api/mcp/route.ts` — `WebStandardStreamableHTTPServerTransport`, stateless
123
+ (fresh server + transport per request; the SDK's own guidance for serverless/Fluid
124
+ Compute — reusing one across requests causes message-ID collisions between clients).
125
+ - Everything routes through one `Datar` SDK client. No direct DynamoDB / tRPC-server
126
+ access; the CLI (and the remote endpoint) are pure API consumers — the remote endpoint's
127
+ client just points at the incoming request's own origin instead of an env var.
128
+
129
+ **Roadmap (not in v1):** curated writes behind `api.*.write` scopes (once scope enforcement
130
+ lands platform-wide, see the warning above) · per-tenant MCP-token onboarding UI + usage
131
+ metering · external connectors (multi-store Shopify, cloud-drive sources, CRM).
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Resolves the Datar API token + tenant base URL from the environment (and,
3
+ * optionally, a `~/.datar/config.json` written by `datar login`).
4
+ *
5
+ * Auth model: the `dt_` API token is bound server-side to an organization and
6
+ * a set of scopes, so once resolved here the caller's tenant and permissions
7
+ * are already fixed — no org selection needed on the client. Mint tokens in the
8
+ * Datar web UI at /settings/api-tokens. For the read-only MCP server, scope the
9
+ * token to `api.*.read` + `a2a.*` only; that is the real read-only guarantee.
10
+ */
11
+ import type { DatarOptions } from "@datar-platform/sdk";
12
+ export interface ResolvedConfig extends DatarOptions {
13
+ /** Where the token/baseUrl were resolved from — for `datar whoami` output. */
14
+ source: "env" | "config-file";
15
+ }
16
+ declare const CONFIG_PATH: string;
17
+ /**
18
+ * Resolve credentials with precedence: env vars first (so CI / MCP-host env
19
+ * always wins), then the on-disk config file. Throws a clear, actionable error
20
+ * when neither yields a usable token + baseUrl.
21
+ */
22
+ export declare function resolveConfig(): ResolvedConfig;
23
+ export { CONFIG_PATH };
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,8EAA8E;IAC9E,MAAM,EAAE,KAAK,GAAG,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,QAA2C,CAAC;AAe7D;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,cAAc,CA6B9C;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Resolves the Datar API token + tenant base URL from the environment (and,
3
+ * optionally, a `~/.datar/config.json` written by `datar login`).
4
+ *
5
+ * Auth model: the `dt_` API token is bound server-side to an organization and
6
+ * a set of scopes, so once resolved here the caller's tenant and permissions
7
+ * are already fixed — no org selection needed on the client. Mint tokens in the
8
+ * Datar web UI at /settings/api-tokens. For the read-only MCP server, scope the
9
+ * token to `api.*.read` + `a2a.*` only; that is the real read-only guarantee.
10
+ */
11
+ import { readFileSync } from "node:fs";
12
+ import { homedir } from "node:os";
13
+ import { join } from "node:path";
14
+ const CONFIG_PATH = join(homedir(), ".datar", "config.json");
15
+ function readFileConfig() {
16
+ try {
17
+ return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
18
+ }
19
+ catch {
20
+ return {};
21
+ }
22
+ }
23
+ /**
24
+ * Resolve credentials with precedence: env vars first (so CI / MCP-host env
25
+ * always wins), then the on-disk config file. Throws a clear, actionable error
26
+ * when neither yields a usable token + baseUrl.
27
+ */
28
+ export function resolveConfig() {
29
+ const file = readFileConfig();
30
+ const apiToken = process.env.DATAR_API_TOKEN ?? file.apiToken;
31
+ const baseUrl = process.env.DATAR_BASE_URL ?? file.baseUrl;
32
+ const source = process.env.DATAR_API_TOKEN
33
+ ? "env"
34
+ : "config-file";
35
+ if (!apiToken) {
36
+ throw new Error("No Datar API token found. Set DATAR_API_TOKEN (recommended for MCP) " +
37
+ `or run \`datar login\`. Mint a token at <baseUrl>/settings/api-tokens.`);
38
+ }
39
+ if (!baseUrl) {
40
+ throw new Error("No Datar base URL found. Set DATAR_BASE_URL (e.g. https://acme.datar.co.za " +
41
+ "or http://localhost:3000) or run `datar login`.");
42
+ }
43
+ if (!apiToken.startsWith("dt_")) {
44
+ // Non-fatal shape check — access keys (sk_) also work, but dt_ is the norm.
45
+ process.stderr.write(`[datar] warning: API token does not start with "dt_"; continuing anyway.\n`);
46
+ }
47
+ return { apiToken, baseUrl: baseUrl.replace(/\/$/, ""), source };
48
+ }
49
+ export { CONFIG_PATH };
50
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAO7D,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAe,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAE9B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,CAAC;IAC3D,MAAM,MAAM,GAA6B,OAAO,CAAC,GAAG,CAAC,eAAe;QAClE,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,aAAa,CAAC;IAElB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,sEAAsE;YACpE,wEAAwE,CAC3E,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,iDAAiD,CACpD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,4EAA4E;QAC5E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;AACnE,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Minimal authenticated GET helper for Datar endpoints that are NOT tRPC —
3
+ * specifically the A2A agent-card surface (`/api/a2a/agents` and each agent's
4
+ * `/.well-known/agent.json`). tRPC calls go through the SDK's transport; this
5
+ * covers the discovery routes the SDK doesn't wrap.
6
+ */
7
+ import type { ResolvedConfig } from "./config.js";
8
+ export declare function datarGet<T = unknown>(config: ResolvedConfig, path: string): Promise<T>;
9
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,CAAC,CAgBZ"}
package/dist/http.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Minimal authenticated GET helper for Datar endpoints that are NOT tRPC —
3
+ * specifically the A2A agent-card surface (`/api/a2a/agents` and each agent's
4
+ * `/.well-known/agent.json`). tRPC calls go through the SDK's transport; this
5
+ * covers the discovery routes the SDK doesn't wrap.
6
+ */
7
+ export async function datarGet(config, path) {
8
+ const url = `${config.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
9
+ const res = await fetch(url, {
10
+ method: "GET",
11
+ headers: {
12
+ Authorization: `Bearer ${config.apiToken}`,
13
+ Accept: "application/json",
14
+ },
15
+ });
16
+ if (!res.ok) {
17
+ const body = await res.text().catch(() => "");
18
+ throw new Error(`GET ${path} failed (${res.status}): ${body.slice(0, 300)}`);
19
+ }
20
+ return (await res.json());
21
+ }
22
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAsB,EACtB,IAAY;IAEZ,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IAC3E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,QAAQ,EAAE;YAC1C,MAAM,EAAE,kBAAkB;SAC3B;KACF,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,OAAO,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAC5D,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;AACjC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `datar` CLI entry point.
4
+ *
5
+ * Subcommands (v1, read + discovery only):
6
+ * datar mcp Start the stdio MCP server (for Claude Code etc.)
7
+ * datar whoami Show the org/user this token resolves to
8
+ * datar ls List available service agents
9
+ * datar ask [service] <text> Ask an agent (defaults to the orchestrator)
10
+ * datar query <path> [json] Call a tRPC query by path (read-only)
11
+ * datar <service> ls List a service's primary records (drive, projects, …)
12
+ *
13
+ * All commands authenticate with DATAR_API_TOKEN + DATAR_BASE_URL (or `datar login`).
14
+ */
15
+ import { Datar } from "@datar-platform/sdk";
16
+ import { resolveConfig } from "./config.js";
17
+ import { startStdioServer } from "./mcp/server.js";
18
+ import { rejectIfMutation } from "./mcp/tools/query.js";
19
+ async function main(argv) {
20
+ const [cmd, ...rest] = argv;
21
+ switch (cmd) {
22
+ case undefined:
23
+ case "help":
24
+ case "-h":
25
+ case "--help":
26
+ return printHelp();
27
+ case "mcp":
28
+ return startStdioServer();
29
+ case "whoami": {
30
+ const { client, config } = connect();
31
+ const [profile, tenants] = await Promise.allSettled([
32
+ client.query("v2.auth.getProfile"),
33
+ client.query("v2.auth.resolveTenantsForSession"),
34
+ ]);
35
+ print({
36
+ baseUrl: config.baseUrl,
37
+ credentialSource: config.source,
38
+ user: profile.status === "fulfilled" ? profile.value : null,
39
+ tenants: tenants.status === "fulfilled" ? tenants.value : null,
40
+ });
41
+ return;
42
+ }
43
+ case "ls":
44
+ case "services": {
45
+ const { client } = connect();
46
+ print(await client.query("v2.ai.agents.listServices"));
47
+ return;
48
+ }
49
+ case "ask": {
50
+ const { client } = connect();
51
+ // `datar ask projects "how many open tasks"` OR `datar ask "…"` (orchestrator)
52
+ const known = new Set([
53
+ "orchestrator",
54
+ "drive",
55
+ "projects",
56
+ "people",
57
+ "requests",
58
+ "inventory",
59
+ "messages",
60
+ "social",
61
+ "procurement",
62
+ "transact",
63
+ "isms",
64
+ "advice",
65
+ ]);
66
+ let service = "orchestrator";
67
+ let words = rest;
68
+ if (rest.length > 1 && known.has(rest[0])) {
69
+ service = rest[0];
70
+ words = rest.slice(1);
71
+ }
72
+ const message = words.join(" ").trim();
73
+ if (!message)
74
+ throw new Error("Usage: datar ask [service] <question>");
75
+ const res = await client.ai.ask({ service: service, message });
76
+ process.stdout.write(`${res.text}\n`);
77
+ if (res.data)
78
+ print(res.data);
79
+ return;
80
+ }
81
+ case "query": {
82
+ const { client } = connect();
83
+ const path = rest[0];
84
+ if (!path)
85
+ throw new Error("Usage: datar query <v2.path> [json-input]");
86
+ const reason = rejectIfMutation(path);
87
+ if (reason)
88
+ throw new Error(reason);
89
+ const input = rest[1] ? JSON.parse(rest[1]) : undefined;
90
+ print(await client.query(path, input));
91
+ return;
92
+ }
93
+ // `datar <service> ls` — thin listing shortcuts over the SDK.
94
+ case "drive":
95
+ case "projects":
96
+ case "requests":
97
+ case "transact":
98
+ case "procurement":
99
+ case "inventory":
100
+ case "isms":
101
+ case "invoicing":
102
+ case "messages":
103
+ return serviceList(cmd, rest);
104
+ default:
105
+ process.stderr.write(`Unknown command: ${cmd}\n\n`);
106
+ printHelp();
107
+ process.exitCode = 1;
108
+ }
109
+ }
110
+ /** `datar <service> ls` dispatch. */
111
+ async function serviceList(service, rest) {
112
+ const sub = rest[0] ?? "ls";
113
+ if (sub !== "ls") {
114
+ throw new Error(`Unknown subcommand: datar ${service} ${sub} (only 'ls' in v1)`);
115
+ }
116
+ const { client } = connect();
117
+ const listers = {
118
+ drive: () => client.drive.listFiles(),
119
+ projects: () => client.projects.list(),
120
+ requests: () => client.requests.getAll(),
121
+ transact: () => client.transact.listAccounts(),
122
+ procurement: () => client.procurement.listTenders(),
123
+ inventory: () => client.inventory.listItems(),
124
+ isms: () => client.isms.listRisks(),
125
+ invoicing: () => client.invoicing.listInvoices(),
126
+ messages: () => client.messages.list(),
127
+ };
128
+ const fn = listers[service];
129
+ if (!fn)
130
+ throw new Error(`No 'ls' for service '${service}'`);
131
+ print(await fn());
132
+ }
133
+ function connect() {
134
+ const config = resolveConfig();
135
+ const client = new Datar({
136
+ apiToken: config.apiToken,
137
+ baseUrl: config.baseUrl,
138
+ });
139
+ return { client, config };
140
+ }
141
+ function print(value) {
142
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
143
+ }
144
+ function printHelp() {
145
+ process.stdout.write([
146
+ "datar — CLI + MCP server for the Datar platform (v1: read + discovery)",
147
+ "",
148
+ "Usage:",
149
+ " datar mcp Start the stdio MCP server (for Claude Code)",
150
+ " datar whoami Show the org/user this token resolves to",
151
+ " datar ls List available service agents",
152
+ " datar ask [service] <text> Ask an agent (default: orchestrator)",
153
+ " datar query <v2.path> [json] Call a tRPC query by path (read-only)",
154
+ " datar <service> ls List records (drive|projects|requests|transact|",
155
+ " procurement|inventory|isms|invoicing|messages)",
156
+ "",
157
+ "Auth: set DATAR_API_TOKEN and DATAR_BASE_URL. Mint a token at",
158
+ " <baseUrl>/settings/api-tokens (scope it to reads for v1).",
159
+ "",
160
+ ].join("\n"));
161
+ }
162
+ main(process.argv.slice(2)).catch((err) => {
163
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
164
+ process.exitCode = 1;
165
+ });
166
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Transport-agnostic tool registry.
3
+ *
4
+ * A `ToolDef` is a plain description of one MCP tool: its name, human/agent-
5
+ * facing description, a Zod raw-shape input schema, and a handler that receives
6
+ * the shared `Datar` SDK client plus the parsed args. The stdio server
7
+ * (`server.ts`) adapts these into `registerTool` calls; a future remote HTTP
8
+ * endpoint can consume the SAME array — hence no MCP or stdio types leak in here.
9
+ *
10
+ * v1 invariant: READ ONLY. Every handler here must only ever call SDK read
11
+ * methods or `client.query(...)` (tRPC GET). None may call a mutation. This is
12
+ * defense-in-depth on top of the real guard, which is the token's scopes.
13
+ */
14
+ import type { ZodRawShape } from "zod";
15
+ import type { Datar } from "@datar-platform/sdk";
16
+ export interface ToolDef<Shape extends ZodRawShape = ZodRawShape> {
17
+ name: string;
18
+ description: string;
19
+ /** Zod raw shape (object of zod validators). Empty object = no args. */
20
+ inputSchema: Shape;
21
+ /** Read-only handler. Returns any JSON-serialisable value. */
22
+ handler: (client: Datar, args: Record<string, unknown>) => Promise<unknown>;
23
+ }
24
+ /** Helper to define a tool with inferred shape while keeping the union homogeneous. */
25
+ export declare function tool<Shape extends ZodRawShape>(def: ToolDef<Shape>): ToolDef;
26
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAEvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,WAAW,OAAO,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,WAAW,EAAE,KAAK,CAAC;IACnB,8DAA8D;IAC9D,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7E;AAED,uFAAuF;AACvF,wBAAgB,IAAI,CAAC,KAAK,SAAS,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAE5E"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Transport-agnostic tool registry.
3
+ *
4
+ * A `ToolDef` is a plain description of one MCP tool: its name, human/agent-
5
+ * facing description, a Zod raw-shape input schema, and a handler that receives
6
+ * the shared `Datar` SDK client plus the parsed args. The stdio server
7
+ * (`server.ts`) adapts these into `registerTool` calls; a future remote HTTP
8
+ * endpoint can consume the SAME array — hence no MCP or stdio types leak in here.
9
+ *
10
+ * v1 invariant: READ ONLY. Every handler here must only ever call SDK read
11
+ * methods or `client.query(...)` (tRPC GET). None may call a mutation. This is
12
+ * defense-in-depth on top of the real guard, which is the token's scopes.
13
+ */
14
+ /** Helper to define a tool with inferred shape while keeping the union homogeneous. */
15
+ export function tool(def) {
16
+ return def;
17
+ }
18
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,uFAAuF;AACvF,MAAM,UAAU,IAAI,CAA4B,GAAmB;IACjE,OAAO,GAAyB,CAAC;AACnC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Datar MCP server (stdio transport).
3
+ *
4
+ * Holds exactly one `Datar` SDK client (authenticated by the resolved `dt_`
5
+ * token) and registers the v1 read + discovery tool registry against an
6
+ * `McpServer`. Errors are returned as `isError` tool results so the harness can
7
+ * see and recover from them rather than the whole server crashing.
8
+ *
9
+ * The registry (./tools) is transport-agnostic — a future remote HTTP MCP
10
+ * endpoint can register the same `ToolDef[]` against a StreamableHTTP transport.
11
+ */
12
+ import { Datar } from "@datar-platform/sdk";
13
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
+ import type { ResolvedConfig } from "../config.js";
15
+ import type { ToolDef } from "./registry.js";
16
+ /** Build an `McpServer` with the given client + tools registered. */
17
+ export declare function createDatarMcpServer(client: Datar, tools: ToolDef[]): McpServer;
18
+ /** Entry point for `datar mcp`: resolve config, wire the client, serve on stdio. */
19
+ export declare function startStdioServer(config?: ResolvedConfig): Promise<void>;
20
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAO7C,qEAAqE;AACrE,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,KAAK,EACb,KAAK,EAAE,OAAO,EAAE,GACf,SAAS,CAgCX;AAED,oFAAoF;AACpF,wBAAsB,gBAAgB,CACpC,MAAM,GAAE,cAAgC,GACvC,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Datar MCP server (stdio transport).
3
+ *
4
+ * Holds exactly one `Datar` SDK client (authenticated by the resolved `dt_`
5
+ * token) and registers the v1 read + discovery tool registry against an
6
+ * `McpServer`. Errors are returned as `isError` tool results so the harness can
7
+ * see and recover from them rather than the whole server crashing.
8
+ *
9
+ * The registry (./tools) is transport-agnostic — a future remote HTTP MCP
10
+ * endpoint can register the same `ToolDef[]` against a StreamableHTTP transport.
11
+ */
12
+ import { Datar } from "@datar-platform/sdk";
13
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
+ import { resolveConfig } from "../config.js";
16
+ import { buildRegistry } from "./tools/index.js";
17
+ const SERVER_NAME = "datar";
18
+ const SERVER_VERSION = "0.1.0";
19
+ /** Build an `McpServer` with the given client + tools registered. */
20
+ export function createDatarMcpServer(client, tools) {
21
+ const server = new McpServer({
22
+ name: SERVER_NAME,
23
+ version: SERVER_VERSION,
24
+ });
25
+ for (const def of tools) {
26
+ server.registerTool(def.name, { description: def.description, inputSchema: def.inputSchema }, async (args) => {
27
+ try {
28
+ const result = await def.handler(client, args ?? {});
29
+ return {
30
+ content: [{ type: "text", text: safeStringify(result) }],
31
+ };
32
+ }
33
+ catch (err) {
34
+ return {
35
+ isError: true,
36
+ content: [
37
+ {
38
+ type: "text",
39
+ text: `Error in ${def.name}: ${errMessage(err)}`,
40
+ },
41
+ ],
42
+ };
43
+ }
44
+ });
45
+ }
46
+ return server;
47
+ }
48
+ /** Entry point for `datar mcp`: resolve config, wire the client, serve on stdio. */
49
+ export async function startStdioServer(config = resolveConfig()) {
50
+ const client = new Datar({
51
+ apiToken: config.apiToken,
52
+ baseUrl: config.baseUrl,
53
+ });
54
+ const server = createDatarMcpServer(client, buildRegistry(config));
55
+ const transport = new StdioServerTransport();
56
+ await server.connect(transport);
57
+ // stderr is safe (stdout is the MCP channel); stdout must stay JSON-RPC only.
58
+ process.stderr.write(`[datar-mcp] connected to ${config.baseUrl} — read + discovery tools ready.\n`);
59
+ }
60
+ function safeStringify(value) {
61
+ if (typeof value === "string")
62
+ return value;
63
+ try {
64
+ return JSON.stringify(value, null, 2);
65
+ }
66
+ catch {
67
+ return String(value);
68
+ }
69
+ }
70
+ function errMessage(err) {
71
+ if (err instanceof Error)
72
+ return err.message;
73
+ return String(err);
74
+ }
75
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAIjF,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,GAAG,OAAO,CAAC;AAC5B,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,qEAAqE;AACrE,MAAM,UAAU,oBAAoB,CAClC,MAAa,EACb,KAAgB;IAEhB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,CAAC,YAAY,CACjB,GAAG,CAAC,IAAI,EACR,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,EAC9D,KAAK,EAAE,IAA6B,EAAE,EAAE;YACtC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;gBACrD,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;iBAClE,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,YAAY,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,GAAG,CAAC,EAAE;yBACjD;qBACF;iBACF,CAAC;YACJ,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAyB,aAAa,EAAE;IAExC,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,8EAA8E;IAC9E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4BAA4B,MAAM,CAAC,OAAO,oCAAoC,CAC/E,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Natural-language fallback — forward a free-form question to a Datar A2A agent
3
+ * (or the orchestrator, which routes for you). This reuses the whole agent
4
+ * stack (tool-calling, KB grounding, cross-service delegation) for anything the
5
+ * typed read tools don't cover.
6
+ *
7
+ * THIS TOOL CAN ACT. The agent may call mutating endpoints, and token scopes do
8
+ * NOT reliably stop it (serviceProcedure endpoints skip the scope middleware).
9
+ * So it is registered only when DATAR_MCP_ALLOW_AGENT=1 — the default read-only
10
+ * surface omits it entirely. See ./index.ts and the CLI README.
11
+ */
12
+ import type { ToolDef } from "../registry.js";
13
+ export declare const askTool: ToolDef;
14
+ //# sourceMappingURL=ask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/ask.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoB9C,eAAO,MAAM,OAAO,EAAE,OAyCpB,CAAC"}