feat(mcp): accept field-fill params on send_documents tool

Mirror the REST API by accepting values, fields, readonly_fields,
metadata, external_id, completed, role and message per submitter.
Input is normalized via Submissions::NormalizeParamUtils so field
names resolve to UUIDs and default_value entries merge into values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pull/635/head
Ortes 2 weeks ago
parent 911e55ccc3
commit 1a503fdfff

@ -3,6 +3,11 @@
module Mcp module Mcp
module Tools module Tools
module SendDocuments module SendDocuments
SUBMITTER_KEYS = %w[
email name phone role completed external_id
metadata values readonly_fields message fields
].freeze
SCHEMA = { SCHEMA = {
name: 'send_documents', name: 'send_documents',
title: 'Send Documents', title: 'Send Documents',
@ -31,6 +36,60 @@ module Mcp
phone: { phone: {
type: 'string', type: 'string',
description: 'Submitter phone number in E.164 format' description: 'Submitter phone number in E.164 format'
},
role: {
type: 'string',
description: 'Template role name (required when the template has multiple roles)'
},
completed: {
type: 'boolean',
description: 'Mark this submitter as already completed (skips the signing UI)'
},
external_id: {
type: 'string',
description: 'Your application identifier for this submitter'
},
metadata: {
type: 'object',
description: 'Arbitrary key/value metadata stored on the submitter',
additionalProperties: true
},
values: {
type: 'object',
description: 'Pre-fill field values, keyed by field UUID or field name',
additionalProperties: true
},
readonly_fields: {
type: 'array',
description: 'Field names to mark read-only for this submitter',
items: { type: 'string' }
},
message: {
type: 'object',
description: 'Custom email subject/body sent to this submitter',
properties: {
subject: { type: 'string' },
body: { type: 'string' }
}
},
fields: {
type: 'array',
description: 'Per-field overrides (default_value, title, required, validation, etc.)',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Field name as defined in the template' },
uuid: { type: 'string', description: 'Field UUID (use instead of name to target a specific field)' },
default_value: { description: 'Pre-filled value the submitter can still edit; string or array depending on field type' },
value: { description: 'Locked value (cannot be edited); string or array depending on field type' },
title: { type: 'string' },
description: { type: 'string' },
readonly: { type: 'boolean' },
required: { type: 'boolean' },
validation_pattern: { type: 'string' },
invalid_message: { type: 'string' }
}
}
} }
} }
} }
@ -48,7 +107,7 @@ module Mcp
module_function module_function
# rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
def call(arguments, current_user, current_ability) def call(arguments, current_user, current_ability)
template = Template.accessible_by(current_ability).find_by(id: arguments['template_id']) template = Template.accessible_by(current_ability).find_by(id: arguments['template_id'])
@ -59,17 +118,19 @@ module Mcp
return { content: [{ type: 'text', text: 'Template has no fields' }], isError: true } if template.fields.blank? return { content: [{ type: 'text', text: 'Template has no fields' }], isError: true } if template.fields.blank?
submitters = (arguments['submitters'] || []).map do |s| submitters = (arguments['submitters'] || []).map do |s|
s.slice('email', 'name', 'role', 'phone') s.slice(*SUBMITTER_KEYS).compact.with_indifferent_access
.compact_blank
.with_indifferent_access
end end
submissions_attrs = [{ submitters: submitters }.with_indifferent_access]
Submissions::NormalizeParamUtils.normalize_submissions_params!(submissions_attrs, template, purpose: :api)
submissions = Submissions.create_from_submitters( submissions = Submissions.create_from_submitters(
template:, template:,
user: current_user, user: current_user,
source: :api, source: :api,
submitters_order: 'random', submitters_order: 'random',
submissions_attrs: { submitters: submitters }, submissions_attrs:,
params: { 'send_email' => true, 'submitters' => submitters } params: { 'send_email' => true, 'submitters' => submitters }
) )
@ -105,10 +166,11 @@ module Mcp
} }
] ]
} }
rescue Submissions::CreateFromSubmitters::BaseError => e rescue Submitters::NormalizeValues::BaseError, Submissions::CreateFromSubmitters::BaseError,
DownloadUtils::UnableToDownload => e
{ content: [{ type: 'text', text: e.message }], isError: true } { content: [{ type: 'text', text: e.message }], isError: true }
end end
# rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
end end
end end
end end

Loading…
Cancel
Save