@datar-platform/cli
v0.1.1
Published
Datar CLI and MCP server — connect any AI harness (Claude Code, etc.) to a Datar org via an API token. Read + discovery in v1.
Maintainers
Readme
@datar-platform/cli
The datar CLI and MCP server — connect any AI harness (Claude Code, Cursor,
etc.) to a Datar organization with a single API token, the way you connect a CLI to a
cloud account. The token is bound server-side to one org and a set of scopes, so once you
authenticate, the harness already knows which org it's in and what it may do — no org
selection, no endpoint guessing.
Built entirely on @datar-platform/sdk. v1 is read + discovery only,
available over two transports that share one tool registry: a local stdio server
(datar mcp, this package) and a remote Streamable HTTP endpoint
(/api/mcp in the web app — no local install needed, just a token).
A layered agent surface
Datar exposes its capabilities as layers — identity, memory, storage, knowledge, runtime — and this CLI/MCP is the tools surface over them:
| Layer | Datar surface | Tools |
| ------------- | ------------------------------------- | ---------------------------------------------- |
| Identity | dt_ token → org + scopes | datar_whoami (reports which layers are live) |
| Memory | stored agent sessions + turns | datar_list_sessions, datar_get_session |
| Knowledge | knowledge base (per-tenant, optional) | datar_kb_search, datar_kb_list_documents |
| Storage | Drive | drive_* |
| Runtime | agents (A2A) | datar_ask (opt-in), datar_describe_service |
Each layer is independently gated — a harness only ever sees what's actually
provisioned for the org. The Knowledge layer especially is optional: on a tenant with
no knowledge base, its tools return { available: false, reason } instead of erroring,
and can be omitted entirely with DATAR_MCP_ENABLE_KB=0 (see below).
Install & authenticate
pnpm add -g @datar-platform/cli # or run via npx
export DATAR_API_TOKEN=dt_... # mint at <baseUrl>/settings/api-tokens
export DATAR_BASE_URL=https://acme.datar.co.za # or http://localhost:3000 for devHow read-only is actually enforced
The read-only guarantee is client-side, not scope-based:
- Every discovery/read tool and
datar_queryissue HTTP GET only, and tRPC refuses mutations over GET — so they physically cannot write, whatever the token's scopes are. datar_askis the only tool that can act (it drives an A2A agent, which may call mutating endpoints). It is opt-in — registered only whenDATAR_MCP_ALLOW_AGENT=1. Default off ⇒ the whole surface is provably read-only.
⚠️ Do not rely on token scopes alone for read-only. Token scope enforcement runs platform-wide today, but treat it as defense-in-depth on top of the client-side guarantee above (GET-only tools,
datar_askoff by default) — not a replacement for it.
Use as a CLI
datar whoami # the org/user this token resolves to
datar ls # list Datar service agents
datar ask "how many open tenders do we have?" # orchestrator routes it
datar ask procurement "list my draft submissions" # target one agent
datar query v2.people.org.getActiveMembers # any read procedure by path
datar projects ls # quick record listings
datar memory ls # stored agent sessions (short-term memory)
datar memory show <sessionId> # a session's prior turns
datar kb search "leave policy" # semantic search over the knowledge base
datar kb ls # indexed/recallable documentsUse as an MCP server (Claude Code)
claude mcp add datar \
--env DATAR_API_TOKEN=dt_... \
--env DATAR_BASE_URL=https://acme.datar.co.za \
-- npx -y @datar-platform/cli mcpThen ask Claude things like "list Datar services", "show my projects", or "what PayFast-backed transactions came in this month?" — it will call the tools below.
Use remotely — no local install (Streamable HTTP)
Any MCP-capable harness can connect straight to a Datar tenant with nothing but a token —
the platform exposes the same tool registry over the MCP Streamable HTTP transport
(stateless — a fresh McpServer per request, as the SDK recommends for serverless):
claude mcp add datar-remote --transport http \
https://acme.datar.co.za/api/mcp \
--header "Authorization: Bearer dt_..."Auth is the same bearer-token model as everywhere else in the platform (dt_ API token /
sk_ access key), validated with the same check the A2A gateway uses
(resolveA2AAuth) — a missing/invalid token gets a 401 before any MCP handling happens.
Every tool call then re-enters the app's own tRPC endpoints under the caller's real
identity, exactly like the local CLI does (the SDK client is just pointed at the request's
own origin instead of an env var). Same DATAR_MCP_ALLOW_AGENT=1 gate controls whether
datar_ask is registered on the remote endpoint too.
Tools exposed (30 read-only by default; +datar_ask = 31 with DATAR_MCP_ALLOW_AGENT=1)
- Discovery —
datar_whoami(identity + which harness layers are live for this org),datar_list_services,datar_describe_service(skills + input/output JSON schemas from each agent card — the catalog that makes downstream calls precise). - Memory (short-term) —
datar_list_sessions,datar_get_session(the caller's stored agent sessions and their prior turns — the same history the agent replays). - Knowledge (long-term recall, capability-gated) —
datar_kb_search(raw semantic retrieval),datar_kb_list_documents(what's indexed). Return{ available: false }when the org has no KB; omit entirely withDATAR_MCP_ENABLE_KB=0. - Typed reads (deterministic, no nested-LLM cost) —
drive_list_files,drive_get_file,drive_list_folders,projects_list,projects_get,projects_metrics,tasks_list,people_list,requests_list,requests_pending_approvals,transact_list_accounts,transact_list_transactions,procurement_list_tenders,procurement_list_public_tenders,procurement_list_suppliers,inventory_list_items,inventory_low_stock,isms_list_risks,isms_list_controls,invoicing_list_invoices,invoicing_list_clients,messages_list. - Natural-language fallback —
datar_ask(forwards to any agent / the orchestrator; reuses tool-calling, KB grounding, cross-service routing). Opt-in / can act: only registered whenDATAR_MCP_ALLOW_AGENT=1; omitted by default so the surface stays read-only. - Read escape hatch —
datar_query(anyv2.*tRPC query by path; mutation-looking paths are refused, andclient.query()only issues GETs, which tRPC never serves for mutations).
Verify locally
pnpm -F @datar-platform/cli build && pnpm -F @datar-platform/cli test
# Drive it interactively with the MCP inspector:
npx @modelcontextprotocol/inspector node packages/cli/dist/index.js mcpArchitecture notes
- The tool registry (exported as
@datar-platform/cli/mcp/tools) is transport-agnostic — aToolDef[]with no MCP/stdio/HTTP types. A sharedcreateDatarMcpServer(client, tools)(exported as@datar-platform/cli/mcp) builds anMcpServerfrom it and is reused verbatim by both transports:startStdioServer()(this package'sdatar mcpcommand).- The platform's remote endpoint, stateless (fresh server + transport per request; the SDK's own guidance for serverless — reusing one across requests causes message-ID collisions between clients).
- Everything routes through one
DatarSDK client. No direct database access; the CLI (and the remote endpoint) are pure API consumers.
More write capabilities, richer onboarding, and additional integrations are on the roadmap.
