41require
'../../main.inc.php';
51require_once DOL_DOCUMENT_ROOT .
'/core/lib/admin.lib.php';
52require_once DOL_DOCUMENT_ROOT .
'/core/class/html.form.class.php';
53require_once DOL_DOCUMENT_ROOT .
'/ai/lib/ai.lib.php';
54require_once DOL_DOCUMENT_ROOT .
'/ai/class/mcp.class.php';
55require_once DOL_DOCUMENT_ROOT .
'/core/lib/functions2.lib.php';
57$langs->loadLangs(array(
'admin',
'other',
'main'));
68$action =
GETPOST(
'action',
'aZ09');
69$toolcontext =
GETPOST(
'toolcontext',
'alpha');
70$toolname =
GETPOST(
'toolname',
'alpha');
71$mode =
GETPOST(
'mode',
'alpha');
72$backtopage =
GETPOST(
'backtopage',
'alpha');
75$mcpHandler =
new McpHandler($db, $user,
$conf, McpHandler::CTX_ASSISTANT);
76$mcpHandler->loadTools();
78$unfilteredSchema = $mcpHandler->getToolsSchemaUnfiltered();
81$allDiscoveredTools = array();
82$groupedNormalTools = array();
83$groupedSystemTools = array();
85if (!empty($unfilteredSchema) && is_array($unfilteredSchema)) {
86 foreach ($unfilteredSchema as $def) {
88 $isSystem = !empty($def[
'is_system']);
89 $classNameKey = !empty($def[
'class_name']) ? (string) $def[
'class_name'] :
'DefaultTools';
92 $allDiscoveredTools[] = $name;
93 $groupedNormalTools[$classNameKey][] = $def;
95 $groupedSystemTools[$classNameKey][] = $def;
109if ($action ==
'addrights' || $action ==
'delrights') {
110 if (
GETPOST(
'token',
'alpha') !== $_SESSION[
'token']) {
114 if (!empty($toolcontext) && !empty($toolname)) {
115 if ($toolcontext ===
'ast') {
116 if ($action ==
'addrights') {
117 if (!in_array($toolname, $astAllowed,
true)) {
118 $astAllowed[] = $toolname;
121 $astAllowed = array_values(array_diff($astAllowed, array($toolname)));
123 $val = empty($astAllowed) ?
'NONE' : implode(
',', $astAllowed);
127 if ($toolcontext ===
'mcp') {
128 if ($action ==
'addrights') {
129 if (!in_array($toolname, $mcpAllowed,
true)) {
130 $mcpAllowed[] = $toolname;
133 $mcpAllowed = array_values(array_diff($mcpAllowed, array($toolname)));
135 $val = empty($mcpAllowed) ?
'NONE' : implode(
',', $mcpAllowed);
140 header(
'Location: ' . $_SERVER[
'PHP_SELF']);
144if ($action ==
'apply_preset' && !empty($toolcontext) && !empty($mode)) {
145 if (
GETPOST(
'token',
'alpha') !== $_SESSION[
'token']) {
149 $resultSet = array();
151 if ($mode ===
'all') {
152 $resultSet = $allDiscoveredTools;
153 } elseif ($mode ===
'none') {
154 $resultSet = array();
155 } elseif ($mode ===
'readonly') {
156 foreach ($allDiscoveredTools as $tName) {
160 if (!preg_match(
'/^(create|update|delete|add|remove|change|write|edit|validate|pay|send)/i', $tName)) {
161 $resultSet[] = $tName;
166 $val = empty($resultSet) ?
'NONE' : implode(
',', $resultSet);
167 $constTarget = ($toolcontext ===
'mcp') ?
'AI_MCP_SERVER_ALLOWED_TOOLS' :
'AI_ASSISTANT_ALLOWED_TOOLS';
170 header(
'Location: ' . $_SERVER[
'PHP_SELF']);
181llxHeader(
'', $langs->trans($title),
'',
'', 0, 0, array(
'/ai/js/ai.js'), array(
'/ai/css/ai.css'),
'',
'mod-ai page-admin');
183$linkback =
'<a href="' . ($backtopage ? $backtopage : DOL_URL_ROOT .
'/admin/modules.php?restore_lastsearch_values=1') .
'">' . img_picto($langs->trans(
"BackToModuleList"),
'back',
'class="pictofixedwidth"') .
'<span class="hideonsmartphone">' . $langs->trans(
"BackToModuleList") .
'</span></a>';
190print
'<!-- Tools quick setup -->';
191print
'<span class="opacitymedium">' . $langs->trans(
"ToolAccessControlHelp") .
'</span><br><br>';
193print
'<div class="marginleftonly" style="display:flex; flex-wrap:wrap; gap:40px; margin-top:15px; padding-top:15px;">';
197print
'<strong>' . $langs->trans(
'PresetsForChatAssistant') .
':</strong><br>';
198print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'ast',
'mode' =>
'all'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'AllTools') .
'</a>';
199print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'ast',
'mode' =>
'readonly'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'ViewOnly') .
'</a>';
200print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'ast',
'mode' =>
'none'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'None') .
'</a>';
205print
'<strong>' . $langs->trans(
'PresetsForMcpServer') .
':</strong><br>';
206print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'mcp',
'mode' =>
'all'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'AllTools') .
'</a>';
207print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'mcp',
'mode' =>
'readonly'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'ViewOnly') .
'</a>';
208print
'<a class="button" href="' .
dolBuildUrl($_SERVER[
'PHP_SELF'], array(
'action' =>
'apply_preset',
'toolcontext' =>
'mcp',
'mode' =>
'none'),
true) .
'" style="margin:4px 2px;">' . $langs->trans(
'None') .
'</a>';
216print
'<div class="div-table-responsive-no-min">';
217print
'<table class="noborder centpercent" id="toolsTable">';
218print
'<tr class="liste_titre">';
219print
'<td class="tdoverflowmax200" style="min-width: 130px;">' . $langs->trans(
'Tool') .
'</td>';
220print
'<td class="hideonsmartphone">' . $langs->trans(
'ToolDescription') .
'</td>';
221print
'<td class="center" style="min-width: 60px;">' . $langs->trans(
'ToolActionType') .
'</td>';
222print
'<td class="center nowraponall">' . $langs->trans(
'ChatAssistant') .
'</td>';
223print
'<td class="center nowraponall">' . $langs->trans(
'McpServer') .
'</td>';
226if (empty($groupedNormalTools) && empty($groupedSystemTools)) {
227 print
'<tr class="oddeven"><td colspan="5" class="opacitymedium">' . $langs->trans(
'NoMcpToolsDiscovered') .
'</td></tr>';
230 $finalGroupsList = array_merge($groupedNormalTools, $groupedSystemTools);
232 foreach ($finalGroupsList as $categoryName => $definitions) {
235 print
'<tr class="trgroup trforbreaknobg" data-group="group-' . $groupId .
'">';
236 print
'<td colspan="5" class="mcp-trigger-collapse" style="cursor:pointer;">';
241 foreach ($definitions as $def) {
242 $name = $def[
'name'];
243 $desc = !empty($def[
'description']) ? $def[
'description'] :
'-';
244 $isSystem = !empty($def[
'is_system']);
246 $isAstOn = $isSystem ? true : in_array($name, $astAllowed,
true);
247 $isMcpOn = $isSystem ? true : in_array($name, $mcpAllowed,
true);
249 if (preg_match(
'/^(create|update|delete|add|remove|change|write|edit|validate|pay|send)/i', $name)) {
251 $typeBadge =
'<span class="badge badge-status2" style="display: inline-block;">' . $langs->trans(
'Modify') .
'</span>';
254 $typeBadge =
'<span class="badge badge-status4" style="display: inline-block;">' . $langs->trans(
'ViewOnly') .
'</span>';
257 print
'<tr class="oddeven group-' . $groupId .
'" data-tool-name="' .
dol_escape_htmltag($name) .
'" data-tool-type="' . $type .
'">';
260 print
'<td style="padding-left:20px; min-width: 130px; word-break: break-all;" class="tdoverflowmax200">';
263 print
'<br><span class="badgeneutral">' . $langs->trans(
'System') .
'</span>';
268 print
'<td class="small opacitymedium hideonsmartphone">' .
dol_escape_htmltag($desc) .
'</td>';
271 print
'<td class="center">' . $typeBadge .
'</td>';
274 $lockCssClass = $isSystem ?
' opacitymedium disabled' :
'';
277 print
'<td class="center nowraponall">';
279 print img_picto($langs->trans(
'Active'),
'switch_on',
'', 0, 0, 0,
'',
'opacitymedium');
281 $actAst = $isAstOn ?
'delrights' :
'addrights';
282 $pictoAst = $isAstOn ?
'switch_on'.($type ==
'write' ?
'_warning' :
'') :
'switch_off';
285 'toolcontext' =>
'ast',
289 print
'<a class="ctx-ast-link reposition' . $lockCssClass .
'" href="' . $urlAst .
'">';
290 print img_picto($langs->trans($isAstOn ?
'Remove' :
'Add'), $pictoAst,
'', 0, 0, 0,
'', !$isAstOn ?
'font-status6' : ($type ==
'write' ?
'font-status2' :
'font-status4'));
296 print
'<td class="center nowraponall">';
298 print img_picto($langs->trans(
'Active'),
'switch_on',
'', 0, 0, 0,
'',
'opacitymedium');
300 $actMcp = $isMcpOn ?
'delrights' :
'addrights';
301 $pictoMcp = $isMcpOn ?
'switch_on'.($type ==
'write' ?
'_warning' :
'') :
'switch_off';
304 'toolcontext' =>
'mcp',
308 print
'<a class="ctx-mcp-link reposition' . $lockCssClass .
'" href="' . $urlMcp .
'">';
309 print img_picto($langs->trans($isMcpOn ?
'Remove' :
'Add'), $pictoMcp,
'', 0, 0, 0,
'', !$isMcpOn ?
'font-status6' : ($type ==
'write' ?
'font-status2' :
'font-status4'));
314 print
'</tr>' .
"\n";
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
aiAdminPrepareHead()
Prepare admin pages header.
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Class to handle MCP (Model Context Protocol).
static resolveAllowList($raw, $allDiscoveredTools)
Resolves a raw allow-list constant value into an explicit PHP array of tool names.
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.