Saltar para o conteúdo principal
Versão: Próximo

MCPContext

The MCPContext class provides information about the current call of a tool of the MCP server, and lets the tool ask the user for a confirmation or for values before running an action (see Asking the user for confirmation).

History
ReleaseChanges
21 R6Class added

MCPContext Object​

MCPContext objects are returned by the MCP command.

The object is attached to the process while a custom tool function runs, and it is available in the methods and functions called by this function. Anywhere else (for example in a REST request or in a method run from the 4D environment), the object is inert: its functions do nothing and its properties are empty.

Summary​

.bound : any
the bind value passed to .requireInput() when the input was asked, as verified by 4D
.canElicit : Boolean
True if the MCP client can display input forms
.clientInfo : Object
information about the MCP client that sent the request
.error( message : Text )
makes the current tool call return an error result with message
.hasInput( name : Text ) : Boolean
returns True if the current call contains a verified answer of the user for the name field
.input : Object
the verified answers of the user, one property per field requested with .requireInput()
.requireInput( fields : Object {; bind : any} ) : Object
asks the user, through the MCP client, to fill in a form before the tool continues
.toolName : Text
the name of the MCP tool being called

.bound​

.bound : any

Description​

The .bound property contains the bind value passed to .requireInput() when the input was asked, as verified by 4D.

The value comes back signed with the user's answers, so the function can compare it with the current value and detect a change that occurred while the user was answering (for example, a modified entity). It is empty when the call does not carry verified answers.

The bind value is signed, not encrypted: the client can read it.

This property is read-only.

Example​

You check that the entity was not modified while the user was confirming its deletion:

If (MCP.bound#This.getStamp())
MCP.error("The record was modified, please try again")
return
End if

.canElicit​

.canElicit : Boolean

Description​

The .canElicit property contains True if the MCP client can display input forms (it declared the elicitation capability in the request), and False otherwise or outside an MCP tool call.

When .canElicit is False, .requireInput() asks nothing and the call returns the error "This action requires a confirmation your client cannot display".

This property is read-only.

Example​

You return a clear message when the client cannot display the confirmation:

If (Not(MCP.canElicit))
MCP.error("Please confirm this action from the application")
return
End if

.clientInfo​

.clientInfo : Object

Description​

The .clientInfo property contains information about the MCP client that sent the request, as provided in the metadata (_meta) of the request, for example its name and version. It is Null outside an MCP tool call.

This property is read-only.

Example​

You log the client that called the tool:

var $client:=MCP.clientInfo
If ($client#Null)
LOG EVENT(Into 4D debug message; "MCP call from "+String($client.name))
End if

.error()​

.error( message : Text )

ParameterTypeDescription
messageText→Error message returned to the client

Description​

The .error() function makes the current tool call return an error result with message. The result has isError: true, and the value returned by the function is ignored.

.error() does not stop the execution of the function: call return after it if needed.

Outside an MCP tool call, .error() does nothing.

Example​

You refuse an amount that is too high:

exposed MCP Function refund($amount : Real) : Text
If ($amount>1000)
MCP.error("Refunds over 1000 must be done by an accountant")
return
End if
// ...

.hasInput()​

.hasInput( name : Text ) : Boolean

ParameterTypeDescription
nameText→Name of a field requested with .requireInput()
ResultBoolean←True if the user answered this field

Description​

The .hasInput() function returns True if the current call contains a verified answer of the user for the name field.

The answer is verified when the client calls the tool again with the answers and a valid requestState: signed by 4D for the same token, tool, arguments, and fields, less than 10 minutes ago, and since the MCP server was last enabled. Otherwise, .hasInput() returns False.

Outside an MCP tool call, .hasInput() returns False.

Example​

You ask for a confirmation only if the user has not answered yet:

If (Not(MCP.hasInput("confirm")))
MCP.requireInput({confirm: {type: "boolean"; title: "Send the invoice to the customer"}})
return
End if

.input​

.input : Object

Description​

The .input property contains the verified answers of the user, one property per field requested with .requireInput(). Only answers whose type matches the type of the requested field are kept.

It does not contain any answer when the call does not carry verified answers, or outside an MCP tool call.

This property is read-only.

Example​

You use the comment entered by the user:

If (MCP.hasInput("comment"))
This.closingComment:=MCP.input.comment
End if

.requireInput()​

.requireInput( fields : Object {; bind : any} ) : Object

ParameterTypeDescription
fieldsObject→Message and fields to display to the user
bindany→Value signed with the answers, returned in .bound
ResultObject←Null when the input is requested

Description​

The .requireInput() function asks the user, through the MCP client, to fill in a form before the tool continues.

In fields, pass an object with:

  • an optional message property (Text): the text displayed to the user,
  • one property per field to display, whose name is the field name and whose value is the JSON Schema of a "boolean", "string", "number", or "integer" field (for example {type: "boolean"; title: "Confirm"}). A field is required unless its schema contains required: False.

When the tool function returns, 4D answers the call with resultType: "input_required", the form, and a requestState signed by 4D. The client displays the form, then calls the tool again with the answers. The function then runs again from the top: .hasInput() returns True for the answered fields and .input contains the answers. If the answers are already there and bind has the same value as when the input was asked, .requireInput() does not ask again.

In bind, you can pass a value to bind to the answers, such as the stamp of an entity: it is signed with the answers and returned in .bound when the client calls the tool again, so that you can check that nothing changed in the meantime. If bind changed, the input is asked again.

If the client cannot display forms (see .canElicit), .requireInput() asks nothing and the call returns the error "This action requires a confirmation your client cannot display".

Outside an MCP tool call, .requireInput() asks nothing and returns Null.

caution

Do not ask for secrets such as passwords with .requireInput(): the answers go through the AI client.

Example​

You ask the user to confirm the closing of a ticket and to enter an optional comment:

// cs.TicketEntity class
Class extends Entity

exposed MCP Function close() : Text
If (Not(MCP.hasInput("confirm")))
MCP.requireInput({message: "Close ticket "+String(This.ID)+"?"; confirm: {type: "boolean"; title: "Close"}; comment: {type: "string"; title: "Comment"; required: False}}; This.getStamp())
return
End if
If (MCP.input.confirm)
This.status:="closed"
This.comment:=String(MCP.input.comment)
This.save()
End if
return This.status

.toolName​

.toolName : Text

Description​

The .toolName property contains the name of the MCP tool being called, for example "OrderManager-getYearTotal". It is an empty string outside an MCP tool call.

This property is read-only.

Example​

You run a method only when it is called by an MCP tool:

If (MCP.toolName#"")
// called from an MCP tool
End if