create_status_watch
Register a webhook watch to monitor AI service status transitions. When a provider's status becomes operational, degraded, or down, or changes, your callback URL receives a POST notification. Each watch costs 1 credit and lasts 90 days.
Instructions
Register a webhook watch on a service status transition (e.g. anthropic becomes down). Costs 1 credit. Watch lives 90 days.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| provider | Yes | Provider name (e.g. anthropic, openai) | |
| op | Yes | becomes = transitions to a specific value; changes = any transition | |
| value | No | Required when op is becomes | |
| callback_url | Yes | HTTPS URL to POST to when the watch fires | |
| secret | No | Optional HMAC shared secret |
Implementation Reference
- mcp-server/src/index.ts:842-873 (handler)The 'create_status_watch' tool is defined via server.tool(). It accepts provider, op, value, callback_url, and optional secret. It POSTs to /premium/watches with a spec of type 'status' and returns the created watch ID, expiry, and remaining credits.
// ── Tool: create_status_watch (1 credit) ──────────────────────────── server.tool( 'create_status_watch', 'Register a webhook watch on a service status transition (e.g. anthropic becomes down). Costs 1 credit. Watch lives 90 days.', { provider: z.string().describe('Provider name (e.g. anthropic, openai)'), op: z.enum(['becomes', 'changes']).describe('becomes = transitions to a specific value; changes = any transition'), value: z.enum(['operational', 'degraded', 'down']).optional().describe('Required when op is becomes'), callback_url: z.string().describe('HTTPS URL to POST to when the watch fires'), secret: z.string().optional().describe('Optional HMAC shared secret'), }, async ({ provider, op, value, callback_url, secret }) => { const body: Record<string, unknown> = { spec: { type: 'status', provider, op, ...(value ? { value } : {}) }, callback_url, }; if (secret !== undefined) body.secret = secret; const data = (await fetchJSON('/premium/watches', { method: 'POST', body, auth: true })) as { watch: { id: string; expires_at: string }; billing?: { credits_remaining?: number }; }; return { content: [ { type: 'text' as const, text: `Created watch ${data.watch.id} (expires ${data.watch.expires_at}). Credits remaining: ${data.billing?.credits_remaining ?? '?'}`, }, ], }; }, ); - mcp-server/src/index.ts:844-873 (registration)The tool is registered with the McpServer instance on line 844 using server.tool() with the name 'create_status_watch'.
server.tool( 'create_status_watch', 'Register a webhook watch on a service status transition (e.g. anthropic becomes down). Costs 1 credit. Watch lives 90 days.', { provider: z.string().describe('Provider name (e.g. anthropic, openai)'), op: z.enum(['becomes', 'changes']).describe('becomes = transitions to a specific value; changes = any transition'), value: z.enum(['operational', 'degraded', 'down']).optional().describe('Required when op is becomes'), callback_url: z.string().describe('HTTPS URL to POST to when the watch fires'), secret: z.string().optional().describe('Optional HMAC shared secret'), }, async ({ provider, op, value, callback_url, secret }) => { const body: Record<string, unknown> = { spec: { type: 'status', provider, op, ...(value ? { value } : {}) }, callback_url, }; if (secret !== undefined) body.secret = secret; const data = (await fetchJSON('/premium/watches', { method: 'POST', body, auth: true })) as { watch: { id: string; expires_at: string }; billing?: { credits_remaining?: number }; }; return { content: [ { type: 'text' as const, text: `Created watch ${data.watch.id} (expires ${data.watch.expires_at}). Credits remaining: ${data.billing?.credits_remaining ?? '?'}`, }, ], }; }, ); - mcp-server/src/index.ts:847-853 (schema)Input schema defined inline using Zod: provider (string), op (enum: becomes/changes), value (optional enum: operational/degraded/down), callback_url (string), secret (optional string).
{ provider: z.string().describe('Provider name (e.g. anthropic, openai)'), op: z.enum(['becomes', 'changes']).describe('becomes = transitions to a specific value; changes = any transition'), value: z.enum(['operational', 'degraded', 'down']).optional().describe('Required when op is becomes'), callback_url: z.string().describe('HTTPS URL to POST to when the watch fires'), secret: z.string().optional().describe('Optional HMAC shared secret'), }, - mcp-server/src/index.ts:19-59 (helper)The fetchJSON helper function handles all HTTP calls to the TensorFeed API, including auth via TENSORFEED_TOKEN, Content-Type headers, error handling for 402/401, and JSON parsing. It is used by create_status_watch to POST to /premium/watches.
async function fetchJSON(path: string, opts: FetchOptions = {}): Promise<unknown> { const headers: Record<string, string> = { 'User-Agent': `TensorFeed-MCP/${SDK_VERSION}`, }; if (opts.body !== undefined) headers['Content-Type'] = 'application/json'; if (opts.auth) { const token = process.env.TENSORFEED_TOKEN; if (!token) { throw new Error( 'TENSORFEED_TOKEN env var is not set. Premium MCP tools require a bearer token. ' + 'Buy credits at https://tensorfeed.ai/developers/agent-payments and pass the returned tf_live_... token via the TENSORFEED_TOKEN env var in your MCP client config.', ); } headers['Authorization'] = `Bearer ${token}`; } const res = await fetch(`${API_BASE}${path}`, { method: opts.method ?? 'GET', headers, ...(opts.body !== undefined ? { body: JSON.stringify(opts.body) } : {}), }); if (!res.ok) { let errPayload: unknown; try { errPayload = await res.json(); } catch { errPayload = await res.text().catch(() => ''); } if (res.status === 402) { throw new Error( `Payment required (402). Your token may be out of credits. Top up at https://tensorfeed.ai/developers/agent-payments. Detail: ${JSON.stringify(errPayload)}`, ); } if (res.status === 401) { throw new Error( `Token rejected (401). Check that TENSORFEED_TOKEN is set to a valid tf_live_... token. Detail: ${JSON.stringify(errPayload)}`, ); } throw new Error(`API error ${res.status}: ${JSON.stringify(errPayload)}`); } return res.json(); }