PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / trunk
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration vtrunk
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 1.41 1.45 All 41 releases
fluent-boards / app / Modules / MCP / Tools / ContextTools.php

ContextTools.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration trunk, at app/Modules/MCP/Tools/ContextTools.php

130 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\App\Modules\MCP\Tools;
4
5 use FluentBoards\App\Models\Board;
6 use FluentBoards\App\Models\Stage;
7 use FluentBoards\App\Models\Task;
8 use FluentBoards\App\Modules\MCP\Helpers\MCPHelper;
9
10 /**
11 * Discovery context for MCP agents.
12 */
13 class ContextTools
14 {
15 const CACHE_TTL = 60;
16
17 public static function getContext($params = [])
18 {
19 $userId = get_current_user_id();
20 $cacheKey = 'fluent_boards_mcp_context_' . $userId;
21
22 $cached = get_transient($cacheKey);
23 if (is_array($cached)) {
24 return $cached;
25 }
26
27 $context = self::buildContext();
28 set_transient($cacheKey, $context, self::CACHE_TTL);
29
30 return $context;
31 }
32
33 public static function invalidateCache()
34 {
35 global $wpdb;
36
37 $like = $wpdb->esc_like('_transient_fluent_boards_mcp_context_') . '%';
38 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $like));
39
40 $like = $wpdb->esc_like('_transient_timeout_fluent_boards_mcp_context_') . '%';
41 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $like));
42 }
43
44 private static function buildContext()
45 {
46 $boardIds = \FluentBoards\App\Services\PermissionManager::getBoardIdsForUser();
47
48 return [
49 'you' => MCPHelper::currentUser(),
50 'site' => [
51 'site_url' => site_url(),
52 'fluent_boards_version' => defined('FLUENT_BOARDS_PLUGIN_VERSION') ? FLUENT_BOARDS_PLUGIN_VERSION : null,
53 'timezone' => wp_timezone_string(),
54 'current_time' => current_time('mysql'),
55 'mcp_endpoint' => \FluentBoards\App\Modules\MCP\MCPInit::getEndpointUrl(),
56 ],
57 'stats' => [
58 'accessible_boards' => count($boardIds),
59 'active_boards' => $boardIds ? (int) Board::whereIn('id', $boardIds)->whereNull('archived_at')->count() : 0,
60 'active_stages' => $boardIds ? (int) Stage::whereIn('board_id', $boardIds)->whereNull('archived_at')->count() : 0,
61 'active_tasks' => $boardIds ? (int) Task::whereIn('board_id', $boardIds)->whereNull('archived_at')->whereNull('parent_id')->count() : 0,
62 ],
63 'enums' => [
64 'board_types' => ['to-do', 'roadmap'],
65 'task_statuses' => ['open', 'closed', 'archived'],
66 'stage_statuses' => ['open', 'closed'],
67 'priorities' => ['', 'urgent', 'high', 'medium', 'low'],
68 'comment_privacy' => ['private', 'public'],
69 'sort_directions' => ['ASC', 'DESC', 'asc', 'desc'],
70 ],
71 'safety_levels' => self::buildSafetyLevels(),
72 'rate_hints' => [
73 'fluent-boards/list-boards' => ['max_per_page' => 100],
74 'fluent-boards/list-tasks' => ['max_per_page' => 100],
75 'fluent-boards/get-board' => ['include_tasks_limited_to' => 100],
76 ],
77 'mcp_capabilities'=> [
78 'version' => '1.0.0',
79 'supports' => [
80 'dedicated_mcp_server',
81 'board_access_scoping',
82 'board_create',
83 'viewer_only_write_block',
84 'task_create_update_move_archive',
85 'task_comments',
86 'board_label_management',
87 'task_label_assignment',
88 'stage_management',
89 'task_assignment',
90 'cross_board_task_queries',
91 'compact_context',
92 ],
93 ],
94 'guidelines' => [
95 'Call get-fluentboards-context once per session before choosing write tools.',
96 'Use list-boards before board-scoped tools unless the user already gave a board_id.',
97 'Write tools follow Fluent Boards permissions: viewer-only board users can read but cannot mutate.',
98 'Use get-task before risky edits when the requested task identity is ambiguous.',
99 ],
100 ];
101 }
102
103 private static function buildSafetyLevels()
104 {
105 return [
106 'fluent-boards/get-fluentboards-context' => 'readonly',
107 'fluent-boards/list-boards' => 'readonly',
108 'fluent-boards/get-board' => 'readonly',
109 'fluent-boards/create-board' => 'creates_or_mutates',
110 'fluent-boards/list-tasks' => 'readonly',
111 'fluent-boards/get-task' => 'readonly',
112 'fluent-boards/create-task' => 'creates_or_mutates',
113 'fluent-boards/update-task' => 'creates_or_mutates',
114 'fluent-boards/move-task' => 'creates_or_mutates',
115 'fluent-boards/archive-task' => 'creates_or_mutates',
116 'fluent-boards/add-comment' => 'creates_or_mutates',
117 'fluent-boards/list-labels' => 'readonly',
118 'fluent-boards/save-label' => 'creates_or_mutates',
119 'fluent-boards/delete-label' => 'deletes',
120 'fluent-boards/add-task-label' => 'creates_or_mutates',
121 'fluent-boards/remove-task-label' => 'creates_or_mutates',
122 'fluent-boards/list-my-tasks' => 'readonly',
123 'fluent-boards/search-tasks' => 'readonly',
124 'fluent-boards/save-stage' => 'creates_or_mutates',
125 'fluent-boards/archive-stage' => 'creates_or_mutates',
126 'fluent-boards/assign-task' => 'creates_or_mutates',
127 ];
128 }
129 }
130