PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.0 2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 All 43 releases
← All changes | app/Http/Controllers/MCPSettingsController.php +22 -135 2.0.15 → 2.2.0 View file →
@@ -2,8 +2,9 @@
2 2
3 3 namespace FluentBoards\App\Http\Controllers;
4 4
5 5 use FluentBoards\App\Modules\MCP\MCPInit;
6 +use FluentBoards\App\Services\MCPAccessService;
6 7 use FluentBoards\Framework\Http\Request\Request;
7 8
8 9 /**
9 10 * Settings endpoints for connecting Fluent Boards MCP tools to AI agents.
@@ -45,14 +46,14 @@
45 46 'abilities_api_loaded' => $abilitiesAvailable,
46 47 'endpoint_url' => MCPInit::getEndpointUrl(),
47 48 'tools_count' => $abilitiesAvailable ? MCPInit::getToolsCount() : 0,
48 49 'mcp_enabled' => fluent_boards_get_option('mcp_enabled', 'yes') === 'yes',
49 - 'app_passwords_url' => admin_url('profile.php#application-passwords-section'),
50 + 'mcp_member_access' => MCPAccessService::isMemberAccessEnabled(),
50 51 'plugins_url' => admin_url('plugins.php'),
51 52 'can_auto_install_adapter' => $canAutoInstall,
52 53 'toolkit_download_url' => 'https://github.com/WPManageNinja/fluent-toolkit',
53 54 'current_user_login' => $currentUser ? $currentUser->user_login : '',
54 - 'is_local_dev' => self::detectLocalDevEnvironment(),
55 + 'is_local_dev' => MCPAccessService::isLocalDev(),
55 56 ]);
56 57 }
57 58
58 59 public function toggle(Request $request)
@@ -70,8 +71,27 @@
70 71 : __('MCP tools disabled. The adapter will no longer report Fluent Boards abilities.', 'fluent-boards'),
71 72 ]);
72 73 }
73 74
75 + /**
76 + * All-or-none switch: when on, every board member can use MCP and create keys from Account.
77 + * Turning it off blocks members immediately; their keys are kept but stop working.
78 + */
79 + public function toggleMemberAccess(Request $request)
80 + {
81 + $value = $request->get('mcp_member_access');
82 + $enabled = is_string($value) ? in_array($value, ['yes', 'true', '1'], true) : (bool) $value;
83 +
84 + fluent_boards_update_option('mcp_member_access', $enabled ? 'yes' : 'no');
85 +
86 + return $this->sendSuccess([
87 + 'mcp_member_access' => $enabled,
88 + 'message' => $enabled
89 + ? __('Board members can now create their own MCP connections.', 'fluent-boards')
90 + : __('MCP is now limited to administrators. Member connections are blocked.', 'fluent-boards'),
91 + ]);
92 + }
93 +
74 94 public function installAdapter()
75 95 {
76 96 if (!current_user_can('install_plugins')) {
77 97 return $this->sendError([
@@ -118,141 +138,8 @@
118 138 'toolkit_active' => $toolkitActive,
119 139 'toolkit_adapter_available' => $toolkitAdapterAvailable,
120 140 'message' => $message,
121 141 ]);
122 - }
123 -
124 - public function getConfigSnippet(Request $request)
125 - {
126 - $client = sanitize_key((string) $request->get('client', 'claude-code'));
127 - $endpoint = MCPInit::getEndpointUrl();
128 - $isLocalDev = $this->resolveLocalDevOverride($request);
129 -
130 - $basicPlaceholder = '<base64(your-username:application-password)>';
131 - $usernamePlaceholder = '<your-username>';
132 - $passwordPlaceholder = '<your-application-password>';
133 - $appPasswordsUrl = admin_url('profile.php#application-passwords-section');
134 -
135 - switch ($client) {
136 - case 'codex':
137 - $snippet = sprintf(
138 - "Settings > Connect to a custom MCP\n\nName: fluent-boards\nTransport: Streamable HTTP\n\nURL: %s\n\nHeader:\n Key: Authorization\n Value: Basic %s\n\nClick Save.",
139 - $endpoint,
140 - $basicPlaceholder
141 - );
142 - $instructions = sprintf(
143 - __('Open OpenAI Codex settings, connect to a custom MCP, choose Streamable HTTP, then use a WordPress Application Password from %s.', 'fluent-boards'),
144 - $appPasswordsUrl
145 - );
146 - break;
147 -
148 - case 'cursor':
149 - $snippet = wp_json_encode([
150 - 'mcpServers' => [
151 - 'fluent-boards' => [
152 - 'url' => $endpoint,
153 - 'type' => 'http',
154 - 'headers' => [
155 - 'Authorization' => 'Basic ' . $basicPlaceholder,
156 - ],
157 - ],
158 - ],
159 - ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
160 - $instructions = __('Paste this into Cursor Settings > MCP, then restart Cursor.', 'fluent-boards');
161 - break;
162 -
163 - case 'generic':
164 - $snippet = sprintf(
165 - "URL: %s\nAuth: Authorization: Basic %s\n\n# Quick test\ncurl -s -u '%s:%s' \\\n -X POST %s \\\n -H 'Content-Type: application/json' \\\n -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}'",
166 - $endpoint,
167 - $basicPlaceholder,
168 - $usernamePlaceholder,
169 - $passwordPlaceholder,
170 - $endpoint
171 - );
172 - $instructions = __('Use the URL and Basic Auth header with any HTTP MCP client. The endpoint speaks MCP over JSON-RPC.', 'fluent-boards');
173 - break;
174 -
175 - case 'claude-desktop':
176 - $env = [
177 - 'WP_API_URL' => $endpoint,
178 - 'WP_API_USERNAME' => $usernamePlaceholder,
179 - 'WP_API_PASSWORD' => $passwordPlaceholder,
180 - 'OAUTH_ENABLED' => 'false',
181 - 'NODE_TLS_REJECT_UNAUTHORIZED' => '0',
182 - ];
183 -
184 - $snippet = wp_json_encode([
185 - 'mcpServers' => [
186 - 'fluent-boards' => [
187 - 'command' => 'npx',
188 - 'args' => ['-y', '@automattic/mcp-wordpress-remote@latest'],
189 - 'env' => $env,
190 - ],
191 - ],
192 - ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
193 -
194 - $instructions = __('Paste into the Claude Desktop config file, then restart Claude Desktop.', 'fluent-boards');
195 - break;
196 -
197 - case 'claude-code':
198 - default:
199 - $snippet = sprintf(
200 - "claude mcp add \\\n --transport http \\\n fluent-boards %s \\\n --header \"Authorization: Basic %s\"",
201 - $endpoint,
202 - $basicPlaceholder
203 - );
204 - $instructions = __('Fill in your username and application password above, then paste the command into your terminal.', 'fluent-boards');
205 - $client = 'claude-code';
206 - break;
207 - }
208 -
209 - return $this->sendSuccess([
210 - 'client' => $client,
211 - 'snippet' => $snippet,
212 - 'instructions' => $instructions,
213 - 'endpoint' => $endpoint,
214 - 'app_passwords_url' => $appPasswordsUrl,
215 - 'is_local_dev' => $isLocalDev,
216 - ]);
217 - }
218 -
219 - private function resolveLocalDevOverride(Request $request)
220 - {
221 - $forceLocalDev = $request->get('local_dev');
222 - if ($forceLocalDev === 'yes' || $forceLocalDev === '1' || $forceLocalDev === 'true') {
223 - return true;
224 - }
225 -
226 - if ($forceLocalDev === 'no' || $forceLocalDev === '0' || $forceLocalDev === 'false') {
227 - return false;
228 - }
229 -
230 - return self::detectLocalDevEnvironment();
231 - }
232 -
233 - private static function detectLocalDevEnvironment()
234 - {
235 - $host = wp_parse_url(home_url(), PHP_URL_HOST);
236 - $host = strtolower((string) $host);
237 -
238 - $isDev = false;
239 - foreach (['.test', '.lab', '.local', '.localhost', '.docker', '.dev'] as $tld) {
240 - if (substr($host, -strlen($tld)) === $tld) {
241 - $isDev = true;
242 - break;
243 - }
244 - }
245 -
246 - if (!$isDev && ($host === 'localhost' || $host === '127.0.0.1' || $host === '::1')) {
247 - $isDev = true;
248 - }
249 -
250 - if (!$isDev && filter_var($host, FILTER_VALIDATE_IP)) {
251 - $isDev = !filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
252 - }
253 -
254 - return (bool) apply_filters('fluent_boards/mcp_is_local_dev', $isDev, $host);
255 142 }
256 143
257 144 private function isAdapterPresent()
258 145 {