add(new SiteInfoTool(static fn(): array => array_keys(array_filter($plugin->modules->all(), static fn($m): bool => $plugin->modules->isEnabled($m->id())))), true); $catalog->add(new ListContentTool(), true); $catalog->add(new GetContentTool(), true); // Another plugin's code cannot be verified to be read-only, whatever it declares. Its tools are not even asked for unless the site's own // code opts in; after that each one still needs the administrator's tick and passes the same authorization, bounds and error handling. if (!apply_filters('aiwend_mcp_allow_third_party_tools', false)) { return $catalog; } try { $extra = apply_filters('aiwend_mcp_register_tools', []); foreach (is_array($extra) ? array_slice($extra, 0, 50) : [] as $tool) { if ($tool instanceof McpTool) { try { $catalog->add($tool); } catch (\Throwable) { // a tool that throws while describing itself is skipped; it never blocks the others or the endpoint } } } } catch (\Throwable) { // another plugin's filter failed: the built-in tools stay available } return $catalog; } /** @return list names of registered tools the administrator switched on for this site */ public static function enabled(ToolCatalog $catalog): array { $stored = get_option(self::OPTION_TOOLS, []); $names = is_array($stored) ? array_filter($stored, 'is_string') : []; return array_values(array_intersect(array_keys($catalog->all()), $names)); } /** @param list $names */ public static function saveEnabled(ToolCatalog $catalog, array $names): void { update_option(self::OPTION_TOOLS, array_values(array_intersect(array_keys($catalog->all()), $names)), false); } public static function server(Plugin $plugin, ToolCatalog $catalog): McpServer { $runner = new ToolRunner($plugin->policy, $plugin->clock, hash('sha256', wp_salt('auth') . '|aiwend-mcp')); foreach ($catalog->all() as $tool) { $runner->register($tool); } $site = get_current_blog_id(); return new McpServer( $catalog, $runner, static fn(): array => self::enabled($catalog), static function (string $action, string $object, string $outcome) use ($plugin, $site): void { $plugin->audit->record($site, $plugin->currentPrincipal()->actorRef(), $action, $object, $outcome); }, defined('AIWEND_VERSION') ? (string) AIWEND_VERSION : '0' ); } public static function endpointUrl(): string { return rest_url(self::NS . self::ROUTE); } }