zeph_input
Request text input from users via push notification, blocking until they respond or timeout. Ideal for interactive input in AI workflows.
Instructions
Request text input from the user via push notification. The tool blocks until the user responds or the timeout is reached. Requires ZEPH_HOOK_ID environment variable.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Input request title | |
| body | No | Instructions or context | |
| placeholder | No | Input placeholder hint | |
| inputType | No | Input field type | text |
| timeout | No | Seconds to wait for response (default: 120) |
Implementation Reference
- src/tools/input.ts:36-63 (handler)Handler function for zeph_input tool: triggers a hook with hookType='input', polls for user response, and returns the text value or error.
async ({ title, body, placeholder, inputType, timeout }, ctx): Promise<CallToolResult> => { if (!config.hookId) return hookNotConfiguredError(); try { const trigger = await client.triggerHook(config.hookId, { title, body, timeout, hookType: 'input', metadata: { placeholder, inputType }, }); const event = await pollForResponse( client, config.hookId, trigger.data.eventId, timeout, ctx, ); if (!event) return timeoutError(timeout, 'Try again with a longer timeout'); return textResult({ value: event.data.response?.value ?? '', timedOut: false }); } catch (err) { return formatToolError(err); } }, ); - src/tools/input.ts:20-35 (schema)Zod input schema for zeph_input tool: defines title (required), body, placeholder, inputType (enum: text/password/multiline, default text), and timeout (number 10-600, default 120).
inputSchema: { title: z.string().describe('Input request title'), body: z.string().optional().describe('Instructions or context'), placeholder: z.string().optional().describe('Input placeholder hint'), inputType: z .enum(['text', 'password', 'multiline']) .default('text') .describe('Input field type'), timeout: z .number() .min(10) .max(600) .default(120) .describe('Seconds to wait for response (default: 120)'), }, }, - src/tools/input.ts:9-63 (registration)Registration function registerInputTool that calls server.registerTool with name 'zeph_input' at src/tools/input.ts.
export const registerInputTool = (server: McpServer, client: ZephApiClient, config: McpServerConfig) => { server.registerTool( 'zeph_input', { description: 'Request text input from the user via push notification. The tool blocks until the user responds or the timeout is reached. Requires ZEPH_HOOK_ID environment variable.', annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true, }, inputSchema: { title: z.string().describe('Input request title'), body: z.string().optional().describe('Instructions or context'), placeholder: z.string().optional().describe('Input placeholder hint'), inputType: z .enum(['text', 'password', 'multiline']) .default('text') .describe('Input field type'), timeout: z .number() .min(10) .max(600) .default(120) .describe('Seconds to wait for response (default: 120)'), }, }, async ({ title, body, placeholder, inputType, timeout }, ctx): Promise<CallToolResult> => { if (!config.hookId) return hookNotConfiguredError(); try { const trigger = await client.triggerHook(config.hookId, { title, body, timeout, hookType: 'input', metadata: { placeholder, inputType }, }); const event = await pollForResponse( client, config.hookId, trigger.data.eventId, timeout, ctx, ); if (!event) return timeoutError(timeout, 'Try again with a longer timeout'); return textResult({ value: event.data.response?.value ?? '', timedOut: false }); } catch (err) { return formatToolError(err); } }, ); - src/index.ts:68-68 (registration)Call to registerInputTool from main index.ts entry point, wiring up the tool.
registerInputTool(server, client, config); - src/api-client.ts:50-67 (helper)Helper - ZephApiClient.triggerHook method used by zeph_input to trigger the input hook via API.
async triggerHook( hookId: string, params: { title: string; body?: string; actions?: { id: string; label: string }[]; timeout?: number; fallback?: string; metadata?: Record<string, unknown>; hookType?: 'one-way' | 'interactive' | 'input'; }, ): Promise<HookTriggerResponse> { return this.request<HookTriggerResponse>('POST', `/hooks/${hookId}/trigger`, params); } async getHookEvent(hookId: string, eventId: string): Promise<HookEventResponse> { return this.request<HookEventResponse>('GET', `/hooks/${hookId}/events/${eventId}`, undefined, POLL_TIMEOUT_MS); }