MCP使用 MYEQ 构建

MYEQ MCP 概览

MCP 在与 Studio/HTTP API 相同的服务器权限上提供语义化 tools。

API / MCP 成熟度

文档页面是公开的,但 API/MCP 能力是否可用由实时产品 Manifest 和账户权限决定。foundation / experimental 不等于稳定承诺。

MCP 是传输,不是第二个产品

MCP client 从不是 source of truth。访问、计划、费用、确认、幂等、执行与收据由 MYEQ server 验证。

与 Host 解耦

stdio server 可用于 Claude 客户端、OpenAI 兼容 MCP host 和企业客户端。

用户八种语言,技术 schema 使用英语

Tool 名称和字段保持英语以保证互操作;制作语言独立指定。

不要把大媒体塞进 MCP JSON

先授权上传/注册 Asset,再传持久 assetId。

Studio、API 和 MCP 的 24 / 30 / 60 FPS

三个接口使用同一份已确认的场景 snapshot 和准入检查。保留请求的 FPS,不会自动回退到 24 FPS。可用性取决于已批准的 worker 和场景的准确条件。

START/END 画布为 704×1280、1280×704 或 960×960。I2V 可生成音频或无音频;A2V 要求有使用权限的源音频,并保留所选起始偏移。本表不代表 ingredients 或 V2V 支持高 FPS。seed 必须是 0–2147483647 的整数。 I2V 和 A2V 在已部署服务明确准入时,支持 24、30、60 FPS 的仅 END 输入。END 引导最后一帧,开头根据提示词生成。保持 start 为空,将图片放在 end 中。这不保证像素完全一致,也不会倒放视频。 A2V 始终需要有使用权限的源音频,以及至少一张 START 或 END 图片;不支持仅音频生成。

FPS可准入类别物理限制
24默认值;所选模态仍需通过自身检查时长、音频和参考取决于所选原生类别
30仅限已批准的 I2V / A2V720p · 2–10 整秒 · 9:16 / 16:9 / 1:1 · I2V/A2V:START、END 或两者;A2V 还需要源音频
60仅限已批准的 I2V / A2V720p · 2–10 整秒 · 9:16 / 16:9 / 1:1 · I2V/A2V:START、END 或两者;A2V 还需要源音频

保存、核对报价,再确认一个场景

创建或读取有权限的项目,通过 PATCH expectedVersion 保存场景,再将相同的 snapshot 和 targetSceneId 发送至 /api/v1/production/snapshots/preflight-scene。检查 data.ready、issues 和 estimatedCredits;此调用不创建 job 或预留积分。使用 confirm=true 和固定 Idempotency-Key 调用 /api/v1/production/snapshots/generate-scene,然后查询返回的 jobId。MCP 使用 myeq.video.preflight_scene 和 myeq.video.generate_scene,付费提交绝不自动重试。场景设置覆盖全局默认值;保留匹配的已确认 sceneContracts。

旧 /video/start、/video/create、/video/create-job 和 /video/preflight 已退役:默认/24 返回 410;30/60 返回 422,要求迁移到 snapshot。25/48/50 不受支持。preflight 失败不会更改 FPS 或收费。检查成功也不预留可用资源或账户余额。

const base = process.env.MYEQ_BASE_URL || 'https://myeq.pro';
const headers = { Authorization: 'Bearer ' + process.env.MYEQ_API_KEY, 'Content-Type': 'application/json' };
async function api(path, method, body, extra = {}) {
  const response = await fetch(base + path, { method, headers: { ...headers, ...extra },
    ...(body === undefined ? {} : { body: JSON.stringify(body) }) });
  const value = await response.json();
  if (!response.ok) throw new Error(JSON.stringify(value));
  return value;
}
const project = await api('/api/v1/projects', 'POST', { title: '60 FPS', aspectRatio: '9:16', duration: 4 });
const sourceAudioUrl = process.env.SOURCE_AUDIO_URL;
const generationInputs = { videoProvider: 'myeq_v2', videoModelSelection: 'myeq_v2',
  inputModality: sourceAudioUrl ? 'audio_to_video' : 'image_to_video', durationSeconds: 4,
  fps: 60, outputResolution: '720p', includeAudio: Boolean(sourceAudioUrl), seed: 12345,
  ...(sourceAudioUrl ? { sourceAudioUrl, sourceAudioStartTime: 0 } : {}) };
const scene = { id: 'scene-1', prompt: 'A slow camera move. Preserve the subject.',
  settings: { fps: 60, durationSeconds: 4 },
  start: process.env.START_URL ? [{ name: 'START', url: process.env.START_URL }] : [],
  end: process.env.END_URL ? [{ name: 'END', url: process.env.END_URL }] : [], context: [], avatar: [] };
const snapshot = { id: crypto.randomUUID(), version: 1, projectId: project.id,
  ownerId: project.ownerUserId, sourceEditorStateVersion: project.version + 1,
  createdAt: new Date().toISOString(), projectTitle: project.title,
  aspectRatio: '9:16', resolution: '720p', durationSeconds: 4, fps: 60,
  generationInputs, scenes: [scene], avatars: [], assetsSummary: [],
  sourceAudio: sourceAudioUrl ? { url: sourceAudioUrl, durationSeconds: null } : null, provenance: { source: 'ui' } };
await api('/api/v1/projects/' + project.id, 'PATCH', { expectedVersion: project.version,
  editorState: { ...project.editorState, generationInputs,
    sceneStoryboard: { scenes: [scene] }, productionSnapshot: snapshot } });
const input = { snapshot, targetSceneId: scene.id };
const quote = await api('/api/v1/production/snapshots/preflight-scene', 'POST', input);
console.log(quote);
if (quote.data?.ready && process.env.CONFIRM_PAID === 'true') {
  const idempotencyKey = process.env.SAVED_IDEMPOTENCY_KEY;
  if (!idempotencyKey) throw new Error('Persist one stable key before submitting');
  const result = await api('/api/v1/production/snapshots/generate-scene', 'POST',
    { ...input, confirm: true }, { 'Idempotency-Key': idempotencyKey });
  console.log(result);
  const jobId = result.data?.pendingTake?.orchestrationJobId || result.data?.asset?.metadata?.jobId;
  if (jobId) console.log(await api('/api/v1/production/jobs/' + encodeURIComponent(jobId), 'GET'));
}

MCP · 24 / 30 / 60 FPS

// Reuse the full saved snapshot from the API example.
{ name: 'myeq.video.preflight_scene', arguments: { snapshot, targetSceneId: 'scene-1' } }
// Review data.ready, issues and estimatedCredits before confirming.
{ name: 'myeq.video.generate_scene', arguments: {
  snapshot, targetSceneId: 'scene-1', confirm: true,
  idempotencyKey: 'persisted-scene-request-0001'
} }
{ name: 'myeq.job.status', arguments: { jobId: 'returned-orchestration-job-id' } }
Workspace · Project · Asset · Entity · Storyboard · Plan · Job已生成 ≠ 已认证