Sprucely title background

MCP API

概述

Sprucely.io 的 MCP API 通过模型上下文协议(Model Context Protocol,MCP)——一种通过 HTTP 将 AI 模型与工具连接起来的开放标准——将仪表板平台开放给 AI 助手和第三方软件调用。任何兼容 MCP 的客户端都可以以编程方式创建托管仪表板、列出并查看仪表板,以及向其追加数据。通过这些 API 创建的仪表板归属于您的账户,可在服务中进一步分享、嵌入或编辑。若要将生成的仪表板嵌入您自己的网站,请参阅简单的仪表板集成说明。如果您使用 Claude,最快的上手方式是使用Sprucely.io 连接器

连接

MCP 服务器通过 Streamable HTTP 提供服务,接入地址为:

https://www.sprucely.io/mcp

任意 MCP 客户端都可以连接到此接入地址。例如,在 Claude Code 中只需一条命令即可注册该服务器:

claude mcp add --transport http sprucely https://www.sprucely.io/mcp

您也可以直接通过 HTTP 调用 JSON-RPC 2.0 与服务器通信。大多数 MCP 客户端会自动完成协议握手;下面的请求示例使用 API 密钥列出可用工具:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

身份验证

请求通过标准的 Authorization Bearer 请求头进行授权,支持两种凭证类型。

API 密钥 - 在个人资料的MCP 板块中创建 API 密钥。密钥以 spr_mcp_ 开头,仅在创建时显示一次,可随时撤销。适用于脚本、服务器以及无图形界面的 MCP 客户端。

OAuth 2.1 - 交互式 MCP 客户端也可以让用户通过 OAuth 2.1 使用其 Sprucely.io 账户登录。授权服务器支持带 PKCE(必需)的授权码流程、刷新令牌以及动态客户端注册,因此兼容的客户端可以根据资源元数据自动完成配置:

https://www.sprucely.io/.well-known/oauth-protected-resource

可用的授权范围:openid、offline_access、dashboards:read 和 dashboards:write。授权范围按工具分别校验:create_dashboardadd_dataset_sharing 需要 dashboards:write,缺少时会返回错误。其余工具只需 dashboards:read。

对于需要手动配置的客户端,授权服务器的各个接入地址如下:

  • https://www.sprucely.io/oauth/.well-known/openid-configuration - 授权服务器元数据
  • https://www.sprucely.io/oauth/auth - 授权接入地址(需要 PKCE)
  • https://www.sprucely.io/oauth/token - 令牌接入地址
  • https://www.sprucely.io/oauth/reg - 动态客户端注册
  • https://www.sprucely.io/oauth/jwks - 签名密钥(JWKS)
  • https://www.sprucely.io/oauth/token/revocation - 令牌吊销
  • https://www.sprucely.io/oauth/token/introspection - 令牌自省

工具

MCP 服务器共提供八个工具:create_dashboardget_dashboardlist_dashboardsadd_dataget_dataset_schemaset_sharingget_embed_codestorage_status

下文的 dataset 和 dashboard 参数并非 MCP 专属格式——它们与数据格式页面所记录、且在服务内其他各处(独立可嵌入运行时的导入 API、AI 生成的布局,以及仪表板编辑器)通用的 dataset/dashboard JSON 完全相同,因此针对该参考文档编写的内容同样适用于此处。

create_dashboard - 根据内联数据集和组件树创建一个托管仪表板,并返回查看链接与嵌入链接。参数:

  • name - 仪表板标题(必填)
  • dataset - 待可视化的数据集:nameheaders(列名)、types(每个表头对应一个数据库类型——VARCHARBOOLEANINTEGERBIGINTFLOATDOUBLEDATETIMESTAMP 之一)以及 entries(数据行,每行是一个按表头顺序排列的值数组),每次调用最多支持 100 列和 50,000 条未经聚合的原始行级记录(必填)。数据不得预先聚合:请为每条底层记录发送一行,并让每个图表的 dataFunction 在渲染时计算计数、求和、平均值等结果。
  • dashboard - 1 至 40 个顶层组件,从上到下排列(必填)。每个组件可以是 dash_chart(包含图表类型——areabarcelldothexbinline——xydr 的列映射、可选的 dataFunction 以及可选标题)、dash_tabledash_text 文本块、dash_spacer,或是 dash_stacker_hor/dash_stacker_ver 容器。堆叠容器支持递归嵌套——其子组件本身也可以是堆叠容器——从而将组件排列成任意深度的行与列。各图表类型的 x/y/d/r 维度分别接受哪些列类别(分类型、连续型或日期/时间型),以及如何通过 seasonX/seasonY 对日期列按时间分组、使其变为分类型,均已在 tools/list 中针对每个字段作出说明,数据格式页面中也有记录。
  • theme - 可选的仪表板整体配色(背景色、文字颜色、主要/浅化/次要强调色);任何组件仍可单独覆盖自身的颜色或背景色
  • shared - 是否允许任何拥有链接的人查看该仪表板(可选,默认 false)。新建的仪表板默认私有,直到您将此项设为 true,或之后调用 set_sharing

返回结果包含新仪表板的 dashboardIddatasetId(供之后调用 add_dataget_dataset_schemaset_sharingget_embed_code 时使用),以及其 urlviewUrliframe 嵌入代码片段。示例——创建一个包含柱状图并设置了整体强调色的仪表板:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "create_dashboard",
      "arguments": {
        "name": "Regional Sales",
        "dataset": {
          "name": "Sales",
          "headers": ["region", "revenue"],
          "types": ["VARCHAR", "DOUBLE"],
          "entries": [
            ["North", 1250.5],
            ["South", 980.25],
            ["East", 1420.0]
          ]
        },
        "dashboard": {
          "type": "dash",
          "children": [
            { "type": "dash_chart", "chartType": "bar", "x": "region", "d": "revenue", "dataFunction": "sum", "title": "Revenue by region" }
          ]
        },
        "theme": { "themePrimary": "#6E2BDC" }
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "dashboardId": "dash_a1b2c3d4",
  "datasetId": "data_e5f6g7h8",
  "name": "Regional Sales",
  "shared": false,
  "rows": 3,
  "columns": 2,
  "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
  "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
  "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
}

get_dashboard - 返回仪表板的名称、分享状态、数据集 ID 及各类链接。参数:dashboardId(必填)。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "get_dashboard",
      "arguments": {
        "dashboardId": "dash_a1b2c3d4"
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "dashboardId": "dash_a1b2c3d4",
  "name": "Regional Sales",
  "shared": false,
  "archived": false,
  "datasetIds": ["data_e5f6g7h8"],
  "source": "mcp",
  "updatedAt": "2026-07-29T10:15:00.000Z",
  "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
  "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
  "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
}

list_dashboards - 按最近更新时间列出您账户中的仪表板,每个仪表板都附带自己的 datasetIds,因此可以直接将数据集传给 get_dataset_schemaadd_data,无需再单独调用 get_dashboard。参数:用于分页的 limitoffset,以及用于不区分大小写名称筛选的 query(均为可选)。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 4,
    "method": "tools/call",
    "params": {
      "name": "list_dashboards",
      "arguments": {
        "limit": 10,
        "query": "sales"
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "total": 1,
  "limit": 10,
  "offset": 0,
  "hasMore": false,
  "dashboards": [
    {
      "dashboardId": "dash_a1b2c3d4",
      "name": "Regional Sales",
      "shared": false,
      "datasetIds": ["data_e5f6g7h8"],
      "source": "mcp",
      "updatedAt": "2026-07-29T10:15:00.000Z",
      "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
      "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
      "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
    }
  ]
}

add_data - 向已有仪表板的数据集追加数据行;所有使用该数据集的仪表板都会自动刷新。参数:

  • dashboardId - 要追加数据的目标仪表板(必填)
  • entries - 与数据集表头按位置对齐的数据行,每次调用最多 50,000 条(必填)——适用与 create_dashboard 相同的原始、行级数据规则。如果不确定仪表板的确切列名/顺序,请先调用 get_dataset_schema。可用于分批加载大型数据集,或让仪表板保持最新。
  • run_id - 本批次专用的幂等键(可选)。如果此前已有一次使用相同 dashboardIdrun_idadd_data 调用成功执行,再次调用会直接返回该次调用的结果,而不会重复追加数据行,因此在超时或连接中断后可以安全地重试同一批次——请为每个不同的批次使用新的 run_id(例如 UUID 或该批次内容的哈希值)。

示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 5,
    "method": "tools/call",
    "params": {
      "name": "add_data",
      "arguments": {
        "dashboardId": "dash_a1b2c3d4",
        "entries": [
          ["West", 875.0]
        ],
        "run_id": "batch-2026-07-29T10:20:00Z"
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "dashboardId": "dash_a1b2c3d4",
  "datasetId": "data_e5f6g7h8",
  "addedRows": 1,
  "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
  "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
  "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
}
# Calling again later with the same dashboardId + run_id (e.g. after a dropped
# connection) is safe: the rows are not appended twice, and the response also
# carries "duplicate": true instead of appending again.

get_dataset_schema - 返回数据集的列名及类型。当您不确定确切的列名/顺序/类型时——例如在新的会话中,或仪表板由其他智能体创建——请先调用此工具,再调用 add_data(或针对同一数据集构建新图表)。参数:datasetId(必填)。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 6,
    "method": "tools/call",
    "params": {
      "name": "get_dataset_schema",
      "arguments": {
        "datasetId": "data_e5f6g7h8"
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "datasetId": "data_e5f6g7h8",
  "headers": ["region", "revenue"],
  "types": ["VARCHAR", "DOUBLE"]
}

set_sharing - 开启或关闭仪表板的公开链接。关闭时会同时撤销该仪表板所有历史版本的访问权限,因此以前分享过的链接也会随之失效。参数:dashboardIdshared(均为必填)。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
      "name": "set_sharing",
      "arguments": {
        "dashboardId": "dash_a1b2c3d4",
        "shared": true
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "dashboardId": "dash_a1b2c3d4",
  "shared": true,
  "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
  "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
  "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
}

get_embed_code - 返回某个仪表板的可分享查看链接及 iframe 嵌入代码片段——即 create_dashboardset_sharing 已经返回过的同一份链接/嵌入代码,供之后单独再次需要时使用。该链接仅在仪表板处于分享状态时对他人有效。参数:dashboardId(必填)。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 8,
    "method": "tools/call",
    "params": {
      "name": "get_embed_code",
      "arguments": {
        "dashboardId": "dash_a1b2c3d4"
      }
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "dashboardId": "dash_a1b2c3d4",
  "shared": true,
  "url": "https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4",
  "viewUrl": "https://www.sprucely.io/service/dashboards/view/123/dash_a1b2c3d4",
  "iframe": "<iframe src=\"https://www.sprucely.io/service/dashboards/embed/123/dash_a1b2c3d4\" style=\"width:100%;height:640px;border:0\" title=\"Sprucely dashboard\" loading=\"lazy\"></iframe>"
}

storage_status - 报告账户已使用及剩余的存储空间,适合在调用规模较大、可能触及套餐存储上限的 create_dashboardadd_data 之前查看。无需参数。示例:

curl -X POST https://www.sprucely.io/mcp \
  -H "Authorization: Bearer spr_mcp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 9,
    "method": "tools/call",
    "params": {
      "name": "storage_status",
      "arguments": {}
    }
  }'

# Result (result.structuredContent in the JSON-RPC response):
{
  "used": 5242880,
  "limit": 104857600,
  "percent": 5,
  "plan": "Regular",
  "over": 0,
  "blocked": false
}

限制与错误

  • MCP 接入地址每个客户端每分钟最多接受 25 次请求,请求体最大为 25 MB——更大的数据集请通过 add_data 分批加载。
  • 数据集每次调用最多支持 100 列和 50,000 行,每层嵌套中的仪表板最多支持 40 个组件。已保存的仪表板会计入您套餐的存储配额——在进行大规模的 create_dashboardadd_data 调用前,可先调用 storage_status 查看剩余空间。
  • 系统使用标准 HTTP 状态码:401 表示凭证缺失或无效(并附带指向资源元数据的 WWW-Authenticate 质询),403 表示凭证已被撤销或权限不足,413 表示请求体过大,429 表示已触发速率限制。