Skip to main content
Glama

create_form

Create Tally forms by converting simple field definitions into structured blocks automatically. Specify title, fields, and optional status to generate forms for surveys, feedback, or data collection.

Instructions

Create a new Tally form with specified fields and configuration. This tool converts simple field definitions into Tally's complex blocks-based structure automatically. The status field is optional and defaults to DRAFT if not specified.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
titleYesForm title (required) - will be displayed as the main form heading
descriptionNoOptional form description - displayed below the title to provide context
statusNoForm publication status. Use DRAFT for unpublished forms that are being worked on, or PUBLISHED for live forms. Defaults to DRAFT if not specified.DRAFT
fieldsYesArray of form fields/questions. Each field will be converted to appropriate Tally blocks automatically.

Implementation Reference

  • The main execution handler for form creation. Processes input arguments to generate a FormConfig (via direct config, template, or NLP), calls TallyApiService.createForm to create the form, extracts form URL/ID, and generates enriched field configurations using block builder utilities.
    public async execute(args: FormCreationArgs): Promise<FormCreationResult> { console.log(`Executing form creation tool with args: ${JSON.stringify(args)}`); let formConfig: FormConfig | undefined; // 1. Highest priority: direct FormConfig if (args.formConfig) { formConfig = { ...args.formConfig }; if (args.formTitle) { formConfig.title = args.formTitle; } } // 2. Template instantiation (if no direct config) if (!formConfig && args.templateId) { formConfig = this.templateService.instantiateTemplate(args.templateId, args.formTitle); if (!formConfig) { throw new Error(`Template with ID '${args.templateId}' not found.`); } } // 3. Natural-language prompt (if neither of the above) if (!formConfig && args.naturalLanguagePrompt) { formConfig = this.nlpService.generateFormConfig(args.naturalLanguagePrompt); if (args.formTitle) { formConfig.title = args.formTitle; } } if (!formConfig) { throw new Error('One of formConfig, naturalLanguagePrompt, or templateId must be provided.'); } let createdTallyForm; try { createdTallyForm = await this.tallyApiService.createForm(formConfig); } catch (err: any) { console.error('[FormCreationTool] createForm error', err?.response?.data || err?.message || err); throw err; } console.log('[FormCreationTool] Created form response:', JSON.stringify(createdTallyForm, null, 2)); // Try to capture any possible share link fields let formUrl: string | undefined = (createdTallyForm as any).url || (createdTallyForm as any).shareUrl || (createdTallyForm as any).share_url || (createdTallyForm as any).publicUrl; if (!formUrl && createdTallyForm.id) { formUrl = `https://tally.so/forms/${createdTallyForm.id}/edit`; } // Generate enriched field configurations using enhanced BlockBuilder const blockResult = buildBlocksForFormWithMapping(formConfig); const enrichedFieldConfigurations = generateEnrichedFieldConfigurations(formConfig, blockResult.fieldBlockMapping); return { formUrl, formId: createdTallyForm.id, formConfig, generatedFieldIds: blockResult.fieldIds, enrichedFieldConfigurations, }; }
  • JSON Schema definition for the 'create_form' tool input parameters, including title, optional description/status, and detailed fields array with supported types, used in MCP tools/list response.
    { name: 'create_form', description: 'Create a new Tally form with specified fields and configuration. This tool converts simple field definitions into Tally\'s complex blocks-based structure automatically. The form status defaults to DRAFT if not specified.', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Form title (required) - will be displayed as the main form heading', minLength: 1, maxLength: 100 }, description: { type: 'string', description: 'Optional form description - displayed below the title to provide context' }, status: { type: 'string', enum: ['DRAFT', 'PUBLISHED'], description: 'Form publication status. Use DRAFT for unpublished forms that are being worked on, or PUBLISHED for live forms. Defaults to DRAFT if not specified.', default: 'DRAFT' }, fields: { type: 'array', description: 'Array of form fields/questions. Each field will be converted to appropriate Tally blocks automatically.', minItems: 1, items: { type: 'object', properties: { type: { type: 'string', enum: ['text', 'email', 'number', 'textarea', 'select', 'checkbox', 'radio'], description: 'Field input type. Maps to Tally blocks: text→INPUT_TEXT, email→INPUT_EMAIL, number→INPUT_NUMBER, textarea→TEXTAREA, select→DROPDOWN, checkbox→CHECKBOXES, radio→MULTIPLE_CHOICE' }, label: { type: 'string', description: 'Field label/question text - what the user will see', minLength: 1 }, required: { type: 'boolean', description: 'Whether this field must be filled out before form submission', default: false }, options: { type: 'array', items: { type: 'string' }, description: 'Available options for select, checkbox, or radio field types. Required for select/checkbox/radio fields.' } }, required: ['type', 'label'], additionalProperties: false } } }, required: ['title', 'fields'], additionalProperties: false, examples: [ { title: "Customer Feedback Survey", description: "Help us improve our service", status: "DRAFT", fields: [ { type: "text", label: "What is your name?", required: true }, { type: "email", label: "Email address", required: true }, { type: "select", label: "How would you rate our service?", required: false, options: ["Excellent", "Good", "Fair", "Poor"] } ] } ] }
  • Initializes and registers the FormCreationTool instance as 'form_creation' in the server's tools object, mapping it to handle 'create_form' tool calls (though switch case pending).
    private initializeTools(): void { this.log('info', 'Initializing tools...'); const apiClientConfig: TallyApiClientConfig = { accessToken: env.TALLY_API_KEY }; const tallyApiClient = new TallyApiClient(apiClientConfig); this.tools = { workspaceManagement: new WorkspaceManagementTool(apiClientConfig), template: new TemplateTool(), form_creation: new FormCreationTool(apiClientConfig), form_modification: new FormModificationTool(apiClientConfig), form_retrieval: new FormRetrievalTool(apiClientConfig), form_sharing: new FormSharingTool(tallyApiClient), form_permissions: new FormPermissionManager(apiClientConfig), submission_analysis: new SubmissionAnalysisTool(apiClientConfig), diagnostic: new DiagnosticTool(), }; this.log('info', 'Tools initialized.'); }
  • Core helper method that performs the actual HTTP request to Tally API to create a form from FormConfig, called by FormCreationTool.execute.
    public async createForm(formConfig: FormConfig): Promise<TallyForm> { // The Tally API endpoint for creating forms const endpoint = '/forms'; // Map our FormConfig to the payload expected by the Tally API const payload = this.mapFormConfigToPayload(formConfig); // Validate the payload before sending to ensure it meets Tally API requirements const validatedPayload = TallyFormCreatePayloadSchema.parse(payload); return this.apiClient.requestWithValidation('POST', endpoint, TallyFormSchema, validatedPayload); } /** * Retrieves a specific form by its ID from Tally. * @param formId The ID of the form to retrieve. * @returns The Tally form data. */ public async getForm(formId: string): Promise<TallyForm> { return this.apiClient.getForm(formId); } /** * Retrieves a list of forms from Tally. * @param options Options for filtering and pagination. * @returns The list of forms response. */ public async getForms(options: { page?: number; limit?: number; workspaceId?: string; } = {}): Promise<TallyFormsResponse> { return this.apiClient.getForms(options); } /** * Updates an existing form in Tally. * @param formId The ID of the form to update. * @param formConfig The updated configuration of the form. * @returns The updated Tally form. */ public async updateForm(formId: string, formConfig: Partial<FormConfig>): Promise<TallyForm> { const endpoint = `/forms/${formId}`; // Map the FormConfig to the payload expected by the Tally API const payload = this.mapToTallyUpdatePayload(formConfig); // Validate the payload before sending to ensure it meets Tally API requirements const validatedPayload = TallyFormUpdatePayloadSchema.parse(payload); return this.apiClient.requestWithValidation('PUT', endpoint, TallyFormSchema, validatedPayload); } /** * Partially updates an existing form in Tally. * @param formId The ID of the form to update. * @param updates Partial updates to apply to the form. * @returns The updated Tally form. */ public async patchForm(formId: string, updates: Record<string, any>): Promise<TallyForm> { const endpoint = `/forms/${formId}`; return this.apiClient.requestWithValidation('PATCH', endpoint, TallyFormSchema, updates); } /** * Maps our internal FormConfig to the payload expected by the Tally API. * This is a placeholder and will be implemented in detail later. * @param formConfig The internal form configuration. * @returns The payload for the Tally API. */ private mapFormConfigToPayload(formConfig: FormConfig): TallyFormCreatePayload { // Build Tally-compatible blocks using our utility const blocks = buildBlocksForForm(formConfig); const payload = { status: 'PUBLISHED' as const, name: formConfig.title, blocks: blocks as any, // Cast to any to resolve type compatibility }; // DEBUG: log payload for development if (process.env.DEBUG_TALLY_PAYLOAD === '1') {
  • The FormCreationTool class definition, implementing the Tool interface, with dependencies injected for NLP, Tally API, and templates, serving as the core handler for create_form operations.
    export class FormCreationTool implements Tool<FormCreationArgs, FormCreationResult> { public readonly name = 'form_creation_tool'; public readonly description = 'Creates a Tally form from a natural language description or a template.'; private nlpService: NlpService; private tallyApiService: TallyApiService; private templateService: TemplateService; constructor(apiClientConfig: TallyApiClientConfig) { this.nlpService = new NlpService(); this.tallyApiService = new TallyApiService(apiClientConfig); this.templateService = new TemplateService(); } public async execute(args: FormCreationArgs): Promise<FormCreationResult> { console.log(`Executing form creation tool with args: ${JSON.stringify(args)}`); let formConfig: FormConfig | undefined; // 1. Highest priority: direct FormConfig if (args.formConfig) { formConfig = { ...args.formConfig }; if (args.formTitle) { formConfig.title = args.formTitle; } } // 2. Template instantiation (if no direct config) if (!formConfig && args.templateId) { formConfig = this.templateService.instantiateTemplate(args.templateId, args.formTitle); if (!formConfig) { throw new Error(`Template with ID '${args.templateId}' not found.`); } } // 3. Natural-language prompt (if neither of the above) if (!formConfig && args.naturalLanguagePrompt) { formConfig = this.nlpService.generateFormConfig(args.naturalLanguagePrompt); if (args.formTitle) { formConfig.title = args.formTitle; } } if (!formConfig) { throw new Error('One of formConfig, naturalLanguagePrompt, or templateId must be provided.'); } let createdTallyForm; try { createdTallyForm = await this.tallyApiService.createForm(formConfig); } catch (err: any) { console.error('[FormCreationTool] createForm error', err?.response?.data || err?.message || err); throw err; } console.log('[FormCreationTool] Created form response:', JSON.stringify(createdTallyForm, null, 2)); // Try to capture any possible share link fields let formUrl: string | undefined = (createdTallyForm as any).url || (createdTallyForm as any).shareUrl || (createdTallyForm as any).share_url || (createdTallyForm as any).publicUrl; if (!formUrl && createdTallyForm.id) { formUrl = `https://tally.so/forms/${createdTallyForm.id}/edit`; } // Generate enriched field configurations using enhanced BlockBuilder const blockResult = buildBlocksForFormWithMapping(formConfig); const enrichedFieldConfigurations = generateEnrichedFieldConfigurations(formConfig, blockResult.fieldBlockMapping); return { formUrl, formId: createdTallyForm.id, formConfig, generatedFieldIds: blockResult.fieldIds, enrichedFieldConfigurations, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/learnwithcc/tally-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server