mcpField
S
stitch-sdk-development

stitch-sdk-development

github.com/google-labs-code开发1.8k206 次安装4 周前更新
代码仓库

关于 stitch-sdk-development

面向 `@google/stitch-sdk` 贡献者的开发技能,讲解 SDK 生成流程、架构边界和实现实践。

主要功能

  1. 01三阶段 SDK 生成流程
  2. 02MCP 工具到领域对象的绑定指引
  3. 03生成代码完整性检查
  4. 04副作用功能实现模式
  5. 05红绿黄测试流程

适用场景

  1. 01将 Stitch 新工具加入 SDK
  2. 02设计领域类和方法绑定
  3. 03实现文件系统或网络扩展
  4. 04测试并验证 SDK 变更

MCP 相关

介绍如何从 Stitch MCP 服务捕获工具模式,并映射为生成的 SDK 类;也说明 `StitchToolClient` 的传输机制和 `StitchProxy` MCP 代理服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/google-labs-code/stitch-sdk --skill stitch-sdk-development

安装后在 Claude Code 中输入/stitch-sdk-development确认已加载。

详细介绍

Stitch SDK 开发

此技能涵盖开发 @google/stitch-sdk 所需的专业知识——核心系统、模式和理念。它不会枚举每个方法(代码库才是事实来源),而是教你如何理解这个系统。


生成流水线

领域层完全由生成器生成。不包含手写的领域类。流水线分为 3 个阶段:

Stage 1: Capture            Stage 2: Domain Design       Stage 3: Generate
┌──────────────────┐       ┌──────────────────┐        ┌──────────────────────────┐
│ capture-tools.ts │──────▶│  domain-map.json │───────▶│ generate-sdk.ts          │
│                  │       │  (the IR)        │        │                          │
│ Connects to MCP  │       │ Classes, bindings│        │ Deterministic            │
│ server, calls    │       │ arg routing,     │        │ codegen into             │
│ tools/list       │       │ cache, extraction│        │ packages/sdk/generated/  │
└──────────────────┘       └──────────────────┘        └──────────────────────────┘
        │                          │                           │
        ▼                          ▼                           ▼
 tools-manifest.json        domain-map.json          packages/sdk/generated/src/*.ts
 (raw MCP tool schemas)     (tool→class mapping)     (Stitch, Project, Screen)

阶段 1(bun scripts/capture-tools.ts):连接到在线 Stitch MCP 服务,调用 tools/list,并写入 tools-manifest.json。这是现有工具的事实来源。

阶段 2(Agent/人工):读取清单并生成 domain-map.json——中间表示。判断工作就在此进行:每个工具映射到哪个类、哪些参数来自 self、param 或 computed、如何提取返回值,以及缓存哪些数据。

阶段 3(bun scripts/generate-sdk.ts):确定性代码生成。读取清单和 domain-map,在 packages/sdk/generated/src/ 中生成 TypeScript 类。不涉及大模型——纯模板展开。

完整性:stitch-sdk.lock 记录所有输入和输出的 SHA-256 哈希值。bun scripts/validate-generated.ts 用于验证一致性。在 CI 中运行,以防止发布过时的代码。

支持新工具

当 Stitch MCP 服务添加新工具时:

  1. 运行阶段 1,捕获更新后的清单
  2. 运行阶段 2:在 domain-map.json 中为新工具添加绑定
  3. 运行阶段 3,重新生成 SDK 类
  4. 运行 validate-generated.ts,确认一致性
  5. 按需更新测试
Domain Map IR

domain-map.json 表示两件事:

类:存在哪些领域对象,以及如何构造它们。

{
  "Screen": {
    "constructorParams": ["projectId", "screenId"],
    "parentField": "projectId",
    "reference": { "keys": ["projectId", "screenId"] }
  }
}

绑定:MCP 工具如何映射到类方法。

{
  "tool": "generate_screen_from_text",
  "class": "Project",
  "method": "generate",
  "args": {
    "projectId": { "from": "self" },
    "prompt": { "from": "param" },
    "name": {
      "from": "computed",
      "template": "projects/{projectId}/screens/{screenId}"
    }
  },
  "returns": {
    "class": "Screen",
    "projection": [
      { "prop": "outputComponents", "index": 0 },
      { "prop": "design" },
      { "prop": "screens", "index": 0 }
    ]
  }
}

参数路由:self = 从 this 注入,param = 由调用方传入,computed = 在调用时根据模板构建,selfArray = 将 [this.field] 包装为数组。

响应投影:根据 outputSchema 验证的结构化 ProjectionStep[] 数组。单个项目使用 index,数组使用 each。空的 [] = 直接返回。

缓存:方法可以指定带有结构化 projection 的 cache,以便在调用 API 前检查 this.data:

{
  "cache": {
    "projection": [{ "prop": "htmlCode" }, { "prop": "downloadUrl" }],
    "description": "Use cached download URL from generation response"
  }
}

双模态

此 SDK 服务于两类需求各异的使用方:

Agent 模态 — StitchToolClient

适用于 AI Agent 和编排脚本。原始工具管道。Agent 接收工具架构、构建 JSON、发送 JSON,并获取 JSON 响应。无需领域知识。

快速入门(单例)

stitch 单例通过 Proxy 同时提供领域方法和工具方法。无需实例化——它会在首次访问时从环境变量中延迟创建 StitchToolClient。

import { stitch } from "@google/stitch-sdk";

// Discover available tools
const { tools } = await stitch.listTools();

// Call any tool by name with a JSON payload
const result = await stitch.callTool("generate_screen_from_text", {
  projectId: "123",
  prompt: "A login page",
});

// Clean up when done
await stitch.close();

单例从环境中读取 STITCH_API_KEY(或 STITCH_ACCESS_TOKEN + GOOGLE_CLOUD_PROJECT)。设置 STITCH_BASE_URL 可覆盖服务 URL。(STITCH_HOST 是已弃用的别名,将在 2.0 中移除。)

直接实例化

如需显式控制(多个客户端、自定义配置、测试),可直接实例化 StitchToolClient:

import { StitchToolClient } from "@google/stitch-sdk";

const client = new StitchToolClient({ apiKey: "my-key" });
const tools = await client.listTools();
const result = await client.callTool("create_project", { title: "My App" });
await client.close();

配置解析:构造函数参数 → 环境变量 → 默认值。身份验证需要 apiKey,或 accessToken + projectId(构造时通过 Zod 验证)。

连接:callTool 和 listTools 会在首次调用时自动连接。并发调用通过基于 Promise 的锁安全地共享连接。

AI SDK 适配器 — stitchTools()

适用于基于 Vercel AI SDK 构建的 Agent。将 MCP 工具架构转换为兼容 AI SDK 的工具定义,可与 generateText() 即插即用。

import { stitchTools } from "@google/stitch-sdk/ai";
import { generateText } from "ai";
import { google } from "@ai-sdk/google";

const result = await generateText({
  model: google("gemini-2.0-flash"),
  tools: stitchTools(), // all tools
  // or: stitchTools({ include: ["create_project"] })  // filtered
  prompt: "Create a project called My App",
});

stitchTools() 从 /ai 子路径导出,使 ai 依赖保持可选。它在内部使用相同的共享 StitchToolClient 单例。

/tools 子路径提供 O(1) 工具查找,并预先解析参数——静态、无需身份验证、不会发起网络调用:

import { toolMap } from "@google/stitch-sdk/tools";
const tool = toolMap.get("create_project");
tool.params; // ToolParam[] — flat, pre-parsed
tool.params.filter((p) => p.required); // required params only
tool.inputSchema; // raw ToolInputSchema still available

toolDefinitions 和 toolMap 均从 @google/stitch-sdk/tools 子路径导出(不放在根入口中,以保持精简)。

SDK 模态 — 生成的领域类

适用于需要编写精确程序化脚本的开发者。基于 callTool 生成的领域门面。参数带类型,返回领域对象,失败时抛出 StitchError。

const project = await stitch.createProject({ title: "My App" });
const generation = await project.generate("A login page");
const html = await generation.first.getHtml();

两种模态底层共用 StitchToolClient。领域类是在 callTool 之上的类型化层。

错误处理 — 在边界处抛出

所有生成的方法都使用 throw StitchError 处理错误。不采用 Result<T> 模式。

// Generated method pattern (inside each method):
try {
  const raw = await this.client.callTool<any>("tool_name", args);
  return /* extracted result */;
} catch (error) {
  throw StitchError.fromUnknown(error);
}

StitchError.fromUnknown() 确保所有错误都规范化为 StitchError,并包含代码、消息和可恢复性提示。

基础设施(手写)

以下组件仍为手写,因为它们提供基础支撑:

  • StitchToolClient — MCP 传输、身份验证、工具调用
  • StitchError — 带有代码、消息和恢复提示的类型化错误类
  • StitchProxy — MCP 代理服务,用于将 Stitch 重新提供给其他 Agent
  • singleton.ts — 为 stitch 导出提供带环境变量配置的惰性代理
副作用边界

SDK 分为两个半球,由正式边界隔开:

  • 生成半球 — 每个 MCP 工具调用、响应投影、参数路由和类构造函数。若发送 JSON 并接收 JSON,则必须生成。
  • 手写半球 — 会影响现实世界的操作:文件系统 I/O、二进制流、非 MCP REST 端点。若涉及磁盘或使用私有 API,则必须手写。

该边界通过 domain-map.json 中任意带有 extensionPath 的类的 sideEffects 声明:

{
  "Project": {
    "extensionPath": "../../src/project-ext.js",
    "sideEffects": [
      {
        "method": "upload",
        "reason": "private_rest",
        "specPath": "src/spec/upload.ts"
      },
      {
        "method": "downloadAssets",
        "reason": "filesystem_io",
        "specPath": "src/spec/download.ts"
      }
    ]
  }
}

有效的 reason 值:filesystem_io、binary_data、private_rest、complex_orchestration。

生成器在第 3 阶段进行验证:

  1. 没有 sideEffect.method 与生成的绑定方法名称冲突
  2. 每个 specPath 都指向现有文件
添加新的副作用方法

遵循 Spec → Handler → Extension 模式:

  1. 创建 Spec(src/spec/my-operation.ts):定义输入架构(Zod)、错误代码、Result 类型和接口。Handler 必须实现此接口,且不得抛出异常。

  2. 创建 Handler(src/my-operation-handler.ts):实现 Spec 接口。所有失败都返回 Result<T>,绝不使用 throw。副作用逻辑(磁盘、网络、二进制数据)在此处实现。

  3. 添加到 Extension(src/project-ext.ts):编写精简适配器(每个方法体少于 15 行),用于解析输入、调用 Handler,并在失败时将 Result 映射为 throw StitchError。

  4. 在 domain-map.json 中声明:添加包含 method、reason 和 specPath 的 sideEffect 条目。

  5. 重新生成:运行 bun scripts/generate-sdk.ts — 生成器会验证该声明。

规则
规则理由
Extension 方法不得覆盖生成的方法防止静默遮蔽
Extension 方法必须委托给 Handler防止内联业务逻辑
Handler 必须实现 Spec 接口类型化服务契约
Handler 必须返回 Result,绝不抛出保持错误接口一致
Extension 不得从 singleton.ts 导入防止循环依赖

交通灯实现(红 → 绿 → 黄)

实现新功能或修复错误时,请遵循交通灯模式:

🔴 红色 — 编写失败测试

先编写测试。测试必须失败。这会在实现开始前定义契约。

# Unit tests for generated classes
npx vitest run test/unit/sdk.test.ts
# → FAIL (new method doesn't exist yet)

# E2E test for the public API
bun scripts/e2e-test.ts
# → FAIL (method doesn't exist yet)
🟢 绿色 — 实现
  1. 在 domain-map.json 中添加绑定(阶段 2)
  2. 运行 bun scripts/generate-sdk.ts(阶段 3)
  3. 更新测试以验证行为正确
npx vitest run  # All tests pass
bun scripts/e2e-test.ts  # E2E passes
🟡 黄色 — 重构 / 优化 / 复查

以通过的测试作为安全保障:

  • 为清晰起见进行重构(提取辅助函数、简化参数)
  • 添加边界情况测试
  • 运行 npx tsc 验证类型安全性
  • 运行 bun scripts/validate-generated.ts 验证流水线完整性

熟悉代码库

直接阅读代码库,了解当前状态。关键入口包括:

  • 公共接口:从 packages/sdk/src/index.ts 开始——这里列出了所有公共导出
  • 生成的类:packages/sdk/generated/src/ — Stitch、Project、Screen、DesignSystem
  • 流水线产物:packages/sdk/generated/domain-map.json、packages/sdk/generated/tools-manifest.json
  • 基础设施:packages/sdk/src/client.ts、packages/sdk/src/spec/errors.ts、packages/sdk/src/singleton.ts
  • 测试结构:单元测试位于 packages/sdk/test/unit/,实时测试位于 packages/sdk/test/integration/
  • 可用命令:阅读 package.json 中的 scripts 字段

不要依赖缓存的文件或目录树描述。请阅读源代码。

导入约定

为兼容 ESM,请使用 .js 扩展名:

import { StitchError } from "../../src/spec/errors.js"; // ✓
import { StitchError } from "../../src/spec/errors"; // ✗

评论

支持 Markdown