@centrali-io/centrali-mcp

中文文档
9.10.0发布于 2026/11/09ISCTypeScriptCommonJS近 30 天下载 2683

Centrali MCP Server - AI assistant integration for Centrali workspaces

原始使用文档
文档目录27 节
  1. File uploads
  2. Connection options
  3. Option 1: Hosted MCP Server (recommended)
  4. Option 2: Stdio with Service Account (CI/automation)
  5. Migrating from OAuth stdio to hosted
  6. Environment Variables (stdio mode only)
  7. Service Account Permissions
  8. Getting Started
  9. Available Tools
  10. Discovery (call these first)
  11. Collections
  12. Records
  13. Compute
  14. Saved Queries
  15. Alerts
  16. Orchestrations
  17. Insights (Anomaly Detection)
  18. Validation (Data Quality)
  19. Service Accounts & IAM
  20. Webhook Subscriptions
  21. Publishable Keys (Frontend)
  22. Identity
  23. Structures (Deprecated)
  24. Resources
  25. Development
  26. Service-account identifiers
  27. Development tests

@centrali-io/centrali-mcp

MCP (Model Context Protocol) server for the Centrali platform. Lets AI assistants (Claude, Cursor, etc.) interact with Centrali workspaces — query data, manage records, search, trigger compute functions, inspect execution results, build orchestrations, and more.

Full documentation: docs.centrali.io — SDK guide, API reference, compute functions, orchestrations, and more.

File uploads

Both hosted and stdio servers provide upload_file. It uploads a standalone Storage file through the existing SDK and Storage API, using the authenticated workspace and its existing folder permissions. Node.js 22 or newer is required for stdio.

{
  "filename": "hello.txt",
  "contentType": "text/plain",
  "contentEncoding": "utf8",
  "content": "Hello from MCP"
}

For binary files use contentEncoding: "base64" with canonical padded base64 (no data URL prefix or whitespace). The decoded limit is 256 KiB, including UTF-8 byte length for text. Empty files are supported. The serialized content JSON string also has a 768 KiB limit so JSON escaping leaves room within the hosted server's 1 MB request limit. For heavily escaped text (such as control characters), encode the exact UTF-8 bytes as base64 instead. location defaults to /root/shared; custom folders must already exist. Files are private unless isPublic: true is explicitly set. Public uploads allow only PNG, JPEG, GIF, WebP, plain text, JSON, MPEG/OGG/WAV audio, and MP4/WebM video MIME types. HTML, SVG, XML and other active document types cannot be made public through this tool because Storage serves the supplied MIME type inline on the API origin. Private uploads retain support for arbitrary MIME types. The SDK prefixes stored filenames with the workspace and a timestamp.

The result contains renderId, sizeBytes, contentType, isPublic, renderUrl and downloadUrl. Private URLs still require normal authentication. Attach the returned render ID using a separate record update; an attachment failure leaves the uploaded file in Storage. Repeating an upload can create another file.

The tool accepts content supplied by the client. It cannot read local paths, fetch source URLs, or access chat attachments/generated images hidden by the host. Never reconstruct image bytes through model transcription. Files larger than 256 KiB must use the existing SDK/HTTP multipart upload API.

Connection options

The easiest way to connect any AI client to Centrali. Add a single URL — authentication happens in the browser via OAuth.

Claude Desktop / Claude Code / Cursor:

{
  "mcpServers": {
    "centrali": {
      "type": "url",
      "url": "https://mcp.centrali.io"
    }
  }
}

On first use, your AI client opens a browser for login and workspace selection. No client ID, secret, or workspace slug needed.

Option 2: Stdio with Service Account (CI/automation)

For headless environments (CI pipelines, automation scripts, cron jobs) where browser login isn't possible. Uses service account credentials with RBAC permissions.

{
  "mcpServers": {
    "centrali": {
      "command": "npx",
      "args": ["@centrali-io/centrali-mcp"],
      "env": {
        "CENTRALI_URL": "https://centrali.io",
        "CENTRALI_CLIENT_ID": "<service-account-client-id>",
        "CENTRALI_CLIENT_SECRET": "<service-account-secret>",
        "CENTRALI_WORKSPACE": "my-workspace"
      }
    }
  }
}

Migrating from OAuth stdio to hosted

If you were previously using CENTRALI_OAUTH_CLIENT_ID with the stdio package, switch to the hosted URL:

  1. Remove the old command/args/env configuration
  2. Replace with: { "type": "url", "url": "https://mcp.centrali.io" }
  3. On next connection, authenticate in the browser

Environment Variables (stdio mode only)

VariableRequiredDescription
CENTRALI_URLYesCentrali instance URL (e.g., https://centrali.io)
CENTRALI_WORKSPACEYesWorkspace slug to operate in
CENTRALI_CLIENT_IDYesService account client ID
CENTRALI_CLIENT_SECRETYesService account client secret

Service Account Permissions

A freshly created service account has no permissions by default. You must assign it a role before the MCP server can do anything useful, otherwise every tool call will return 403 Forbidden.

Quickest setup — full admin access:

  1. In the Console, go to Settings > Service Accounts
  2. Create your service account and save the client secret
  3. Open the service account, go to the Groups tab
  4. Add it to the workspace_administrators group

Least-privilege setup: Create a custom group with a policy scoped to the resources you need. See the Policies and Permissions guide for details.

Getting Started

After connecting, call describe_centrali first — it returns the full capability map, feature matrix, and SDK integration guidance. Then use the specific describe_* tools for deeper schema details on any domain.

Available Tools

Discovery (call these first)

ToolDescription
describe_centraliPlatform overview, feature matrix, SDK integration guidance, and list of all tools
describe_collectionsSchema reference for collections (data models, field types, constraints)
describe_recordsSchema reference for record operations (filters, sorting, pagination, expand)
describe_computeCompute function reference (input contract, secrets, async execution, api object)
describe_saved_queriesSaved-query schema reference (parameterized queries, variables)
describe_orchestrationsOrchestration reference (multi-step workflows, encrypted params)
describe_insightsAnomaly insights reference
describe_validationData validation reference
describe_auth_providersAuth provider reference (BYOT setup, claim mappings)
describe_service_accountsService account & IAM reference (SA setup, roles, groups, permissions)
describe_webhooksOutbound webhook reference (subscription shape, signature, retry/replay)

Collections

ToolDescription
list_collectionsList all data collections (schemas) in the workspace
get_collectionGet full schema for a collection by record slug
create_collectionCreate a new collection with typed properties
update_collectionUpdate an existing collection
delete_collectionDelete a collection and all its records

Records

ToolDescription
query_recordsQuery records using the canonical Centrali query language (POST /records/query). Accepts a QueryDefinition body (where, text, sort, page, select).
get_recordGet a single record by ID
get_records_by_idsGet multiple records by IDs
create_recordCreate a new record
update_recordUpdate an existing record
upsert_recordCreate or update a record
delete_recordSoft or hard delete a record
restore_recordRestore a soft-deleted record

Compute

ToolDescription
list_functionsList compute functions
get_functionGet a function by ID (includes code)
create_functionCreate a new compute function
update_functionUpdate a function (code, name, timeout)
delete_functionDelete a compute function
test_functionTest execute code without saving
list_triggersList function triggers (on-demand, event-driven, scheduled, http-trigger)
get_triggerGet a trigger by ID
create_triggerCreate a new trigger
update_triggerUpdate a trigger
delete_triggerDelete a trigger
invoke_triggerInvoke an on-demand trigger (returns job ID — async)
pause_triggerPause a trigger
resume_triggerResume a paused trigger
test_send_triggerSend a signed synthetic test event through an http-trigger's real verify/dispatch path
get_function_runGet execution result by run ID (status, output, errors)
list_function_runsList runs by trigger or function ID (execution history)
get_compute_job_statusCheck async job status by job ID (poll after invoke_trigger)
list_allowed_domainsList allowed domains for outbound HTTP
add_allowed_domainAdd a domain to the allowlist
invoke_endpointCall a sync compute endpoint by path (returns response inline)
remove_allowed_domainRemove a domain from the allowlist

Saved Queries

Saved queries store a canonical QueryDefinition plus optional variables and an optional multi-collection joins[] clause.

ToolDescription
list_saved_queriesList saved queries, optionally by collection
get_saved_queryGet a saved query by ID
create_saved_queryCreate a reusable parameterized query (canonical body)
update_saved_queryUpdate a saved query (canonical body)
delete_saved_queryDelete a saved query
execute_saved_queryExecute a saved query with optional variables
test_saved_queryTest a canonical query definition without saving

Typed parameter discovery → execute. Saved queries authored with typed parameters expose their parameter shape through describe_saved_queries (schema reference) and get_saved_query / list_saved_queries (per-row variables declarations). The expected discover-then-execute flow:

  1. Discover schema (one-shot) — describe_saved_queries returns the QueryVariableDefinition shape (type, required?, default?, description?) and the supported VariableType union (string | number | boolean | datetime | id | { array: T } | { reference: collectionSlug }).
  2. Discover the query — get_saved_query returns the row including variables. Read each entry to learn what to bind. The canonical response includes queryDefinition.resource (always equal to the row's recordSlug):
    {
      "id": "…",
      "name": "Monthly revenue",
      "recordSlug": "orders",
      "queryDefinition": {
        "resource": "orders",
        "where": { "and": [
          { "data.month": { "eq": "${month}" } },
          { "data.region": { "eq": "${region}" } }
        ]},
        "sort": [{ "field": "data.amount", "direction": "desc" }],
        "page": { "limit": 100 }
      },
      "variables": {
        "month":  { "type": "datetime", "required": true, "description": "Month bucket (UTC)" },
        "region": { "type": "string",   "required": true }
      }
    }
    
  3. Execute typed — pass concrete values via execute_saved_query's variables arg. The server validates each value against its declared type (no coercion — "123" will not be accepted for a number declaration) and then substitutes. datetime accepts an ISO-8601 string:
    {
      "recordSlug": "orders",
      "queryId": "…",
      "variables": { "month": "2026-04-01T00:00:00Z", "region": "us-east" }
    }
    
    Typed errors surface as variable_type_mismatch, missing_required_variable, or extra_variable. Untyped (legacy) rows have variables: null and accept any keys; values are stringified before substitution. The untyped fallback is also taken by post-backfill rows (canonical body, no declarations yet) until an author promotes them.

The MCP test_saved_query tool intentionally does not expose variableDeclarations — its dry-run path falls back to legacy string substitution and does not enforce typed declarations. Round-trip via create_saved_query + execute_saved_query to validate typed parameters end-to-end.

Multi-collection joins. Saved queries support an optional joins[] clause inside queryDefinition (max 4 entries). Each entry joins another collection to the primary record set:

{
  "resource": "orders",
  "where": { "data.status": { "eq": "open" } },
  "joins": [
    {
      "foreignSlug": "customers",
      "localField": "data.customerId",
      "foreignField": "id",
      "joinType": "left",
      "select": ["id", "data.name", "data.email"],
      "alias": "customer"
    }
  ],
  "sort": [{ "field": "createdAt", "direction": "desc" }],
  "page": { "limit": 50 }
}

Constraints (validated by @centrali/query):

  • joinType must be 'inner' or 'left' — 'right' and 'full' are rejected by the executor with unsupported_clause.
  • text and joins cannot appear in the same query (unsupported_combination).
  • Aliases (or implicit foreignSlug) must be unique within joins[] (duplicate_join_alias).
  • Cap of 4 entries (joins_length_exceeded).
  • localField may use <priorAlias>.<field> to chain a join through an earlier alias.

execute_saved_query returns { rows, meta, fields }. Each entry in rows carries joined data under a top-level _joined key:

{
  "rows": [
    {
      "id": "order-123",
      "data": { "status": "open" },
      "_joined": {
        "customer": { "id": "cust-1", "data": { "name": "Acme" } }
      }
    }
  ],
  "meta": { "limit": 50, "offset": 0, "total": 1 },
  "fields": [{ "name": "id" }, { "name": "data" }, { "name": "_joined" }]
}

LEFT joins surface null for unmatched rows.

Authorization (SECURITY DEFINER, locked 2026-05-04). Saved queries are author-bound — the AUTHOR's permissions define what the query can read; the executor only needs an execute check on the saved-query resource at runtime.

  • Author time (create_saved_query / update_saved_query / test_saved_query): the caller must hold records:list on the primary collection AND on every collection referenced in joins[]. The data service returns 403 if any access is missing.
  • Execute time (execute_saved_query): only execute on the saved-query resource is checked; there is no per-collection re-check, and field-level redaction follows the author's permissions, not the executor's. Secret-masking still applies unconditionally.

AI assistants should not propose saved queries (or join chains) against collections the author can't read — execute will succeed for less-privileged callers, but authoring will fail.

Reserved clauses. Saved-query create/update/test surfaces reject text (full-text search) and include (relation expansion) with 422 unsupported_clause. Those clauses are available on the ad-hoc POST /records/query surface only — don't author saved queries that use them.

Alerts

Run a saved query on a cron and notify people when its result meets a condition.

ToolDescription
list_alertsList alerts, optionally filtered to one saved query
get_alertGet an alert by ID, including its evaluation history
create_alertCreate a scheduled alert on a saved query
update_alertUpdate an alert's schedule, condition, recipients, bindings, or enabled state
delete_alertDelete an alert and unschedule its job

Conditions. Two kinds ship today — { kind: 'rowCount', op, value } (op one of eq/neq/gt/gte/lt/lte) and { kind: 'rowsChanged' }, which fires when the row count differs from the previous evaluation and never fires on its first run (it only seeds the baseline). There is no aggregate kind: an alert reasons about how many rows came back, not about a sum or average of their contents. To alert on an aggregate, author the saved query so the rows it returns are the exception set and alert on rowCount.

Scheduling. cronExpression is a 5-field cron expression interpreted in timezone (IANA name, default UTC). Notifications are throttled to 1 per recipient per 15 minutes per alert, so a sub-15-minute cron evaluates more often than it can notify.

Recipients. recipients is an explicit list — [{ type: 'user', id: '<userId>' }] — not a subscription list. No MCP tool enumerates workspace users, so an assistant must ask the user for IDs rather than constructing them.

Binding variables — stricter than execute. If the saved query declares parameters, bind them via variables. The server validates the map on create and on any update that submits it, and requires every declaration the query body references that has no default, regardless of required:

{
  "savedQueryId": "…",
  "name": "Failed payments spiked",
  "cronExpression": "0 * * * *",
  "condition": { "kind": "rowCount", "op": "gt", "value": 10 },
  "recipients": [{ "type": "user", "id": "…" }],
  "variables": { "status": "failed" }
}

execute_saved_query accepts an unbound optional and leaves the raw ${name} in the body; the query then filters on the literal placeholder, matches nothing, and reports no error. Interactively that's visible — the caller sees an empty result. On a cron nobody is watching, so the alert would simply never fire and lastEvaluatedAt would keep advancing as though healthy. Authoring is the last point where the gap is noticeable, so it fails there with a 400 naming each offending variable.

Diagnosing "it never fired". get_alert exposes lastEvaluatedAt, lastTriggeredAt, lastRowCount, and the health fields consecutiveFailures, lastError, lastErrorAt.

Check consecutiveFailures first. Non-zero means the saved query behind the alert is erroring, so the alert is scheduled and enabled but cannot fire; lastError carries the sanitized reason and lastErrorAt when it last happened. The commonest cause is a collection or field renamed out from under the query. The counter is a run length that resets on the first successful evaluation, so a 0 rules the entire failure class out rather than merely suggesting health.

With consecutiveFailures at 0, a null or stale lastEvaluatedAt means the alert is disabled or was never scheduled. A current lastEvaluatedAt with a null lastTriggeredAt means the query runs fine and the condition isn't matching — compare the alert's variables against the saved query's declarations.

Orchestrations

ToolDescription
list_orchestrationsList all orchestrations in the workspace
get_orchestrationGet orchestration details including step definitions
create_orchestrationCreate a multi-step workflow
update_orchestrationUpdate an orchestration (steps, triggers, encrypted params)
delete_orchestrationDelete an orchestration and its runs
activate_orchestrationActivate an orchestration (enable triggers)
pause_orchestrationPause an orchestration (disable triggers)
trigger_orchestrationTrigger a run with optional input data
list_orchestration_runsList runs for an orchestration
get_orchestration_runGet run details (use includeSteps=true for step-by-step debugging)

Insights (Anomaly Detection)

ToolDescription
trigger_anomaly_analysisStart an anomaly detection scan
list_insightsList anomaly insights
get_insightGet a single insight
acknowledge_insightMark an insight as reviewed
dismiss_insightDismiss an insight
get_insights_summaryGet insights summary counts

Validation (Data Quality)

ToolDescription
trigger_validation_scanStart a data quality scan
list_validation_suggestionsList validation suggestions
accept_validation_suggestionAccept a fix (applies to record)
reject_validation_suggestionReject a suggestion
get_validation_summaryGet validation summary counts

Service Accounts & IAM

ToolDescription
list_service_accountsList all service accounts
get_service_accountGet service account details
create_service_accountCreate a service account (returns clientId + clientSecret)
update_service_account_nameUpdate SA display name
update_service_account_descriptionUpdate SA description
delete_service_accountPermanently delete a service account
rotate_service_account_secretRotate client secret (old one immediately invalidated)
revoke_service_accountPermanently revoke a service account
generate_dev_tokenGenerate a short-lived dev token for testing
scan_service_account_permissionsFull access matrix audit (Allow/Deny per resource+action)
simulate_service_account_permissionSimulate an authorization check with evaluation trace
generate_remediationGenerate options to grant missing permissions (role, group, or new policy)
preview_remediationPreview what changes a remediation option would make
apply_remediationApply a remediation option to grant access
list_service_account_rolesList roles assigned to a SA
assign_role_to_service_accountAssign a role to a SA
remove_role_from_service_accountRemove a role from a SA
list_service_account_groupsList groups a SA belongs to
add_service_account_to_groupAdd SA to a group
remove_service_account_from_groupRemove SA from a group
list_rolesList all roles in the workspace
get_roleGet role details with permissions
create_roleCreate a role with permissions
update_roleUpdate a role
delete_roleDelete a role
list_groupsList all groups
get_groupGet group details
create_groupCreate a group
update_groupUpdate a group
delete_groupDelete a group

Webhook Subscriptions

ToolDescription
list_webhook_subscriptionsList all outbound webhook subscriptions
get_webhook_subscriptionGet a subscription by ID (secret not included)
create_webhook_subscriptionCreate a subscription — response returns the whsec_ signing secret once
update_webhook_subscriptionUpdate name, URL, events, recordSlugs, or active flag
delete_webhook_subscriptionDelete a subscription (delivery history retained)
rotate_webhook_subscription_secretRegenerate the signing secret (immediate cutover)
publish_webhook_eventPublish a named business event (e.g. invoice.paid) and fan it out to matching subscriptions
list_webhook_deliveriesList delivery history for a subscription (trimmed rows)
get_webhook_deliveryGet a single delivery with full payload and response body
retry_webhook_deliveryReplay a delivery — reuses the original payload and signature
cancel_webhook_deliveryCancel a retrying delivery (flips to failed with distinctive marker)

Publishable Keys (Frontend)

ToolDescription
list_publishable_keysList all publishable keys
get_publishable_keyGet key details with scopes
create_publishable_keyCreate a scoped frontend key (pk_live_...)
update_publishable_keyUpdate label or scopes
revoke_publishable_keyRevoke a key (immediate, irreversible)

Identity

ToolDescription
get_current_identityGet the current authenticated MCP identity (service account or OAuth user)

Structures (Deprecated)

ToolDescription
list_structuresDeprecated: use list_collections
get_structureDeprecated: use get_collection

Resources

URIDescription
centrali://collectionsList of all collections with name, slug, description
centrali://collections/{slug}Full schema for a specific collection

Development

# Install dependencies
npm install

# Build
npm run build

# Test with MCP inspector
CENTRALI_URL=https://centrali.io \
CENTRALI_CLIENT_ID=... \
CENTRALI_CLIENT_SECRET=... \
CENTRALI_WORKSPACE=my-workspace \
npx @modelcontextprotocol/inspector node dist/index.js

Service-account identifiers

Account-path tools use the string clientId returned by create_service_account / list_service_accounts, including get, update, rotate, revoke, delete, dev-token, role/group membership, and permission scan/simulate. They no longer accept numeric serviceAccountId inputs. Existing legacy client IDs are supported. Upgrade this package alongside IAM when deploying the client-ID route change.

The separate generate_remediation, preview_remediation, and apply_remediation tools retain their numeric serviceAccountId argument for the access API's targetId contract. Account responses continue to include both id and clientId.

Development tests

npm test builds the sibling SDK first when running in the monorepo, then builds MCP and runs its tests. The health regression uses the real SDK normalization, so its runtime distribution must exist even on a fresh checkout. Outside the monorepo, tests use the installed SDK distribution instead.

版本与发布记录

@centrali-io/centrali-mcp 共发布 129 个版本,首次发布于 2026/02/17;过去 12 个月发布了 129 个版本。

版本发布日期距今
9.10.0latest2026/11/09今天
9.9.02026/11/09今天
9.8.02026/11/081 天前
9.7.02026/11/072 天前
9.6.02026/11/054 天前
9.5.22026/10/2812 天前

其他发布通道:rc → 4.4.8-rc.9。

关于 @centrali-io/centrali-mcp 的常见问题

@centrali-io/centrali-mcp 是什么?

Centrali MCP Server - AI assistant integration for Centrali workspaces

如何安装 @centrali-io/centrali-mcp?

在项目目录运行 npm install @centrali-io/centrali-mcp,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 centrali-mcp,可以用 npx centrali-mcp 直接运行。

@centrali-io/centrali-mcp 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@centrali-io/centrali-mcp 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@centrali-io/centrali-mcp 可以商用吗?

@centrali-io/centrali-mcp 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@centrali-io/centrali-mcp 的下载量有多少?

根据 npm 官方下载统计,@centrali-io/centrali-mcp 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,683 次,日均约 89 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@centrali-io/centrali-mcp 还在维护吗?

最新版本 9.10.0 发布于 2026/11/09(今天);至今共发布 129 个版本,其中过去 12 个月发布了 129 个;首次发布于 2026/02/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。