@ -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