Entropic 2.11.1
Local-first agentic inference engine
Loading...
Searching...
No Matches
mcp_key_set.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
10
11#include <nlohmann/json.hpp>
12
13static auto logger = entropic::log::get("mcp.key_set");
14
15namespace entropic {
16
24void MCPKeySet::grant(const std::string& pattern,
25 MCPAccessLevel level) {
26 std::lock_guard<std::mutex> lock(key_mutex_);
27 keys_[pattern] = level;
28 logger->info("Granted {}:{}", pattern,
30}
31
39bool MCPKeySet::revoke(const std::string& pattern) {
40 std::lock_guard<std::mutex> lock(key_mutex_);
41 auto it = keys_.find(pattern);
42 if (it == keys_.end()) {
43 return false;
44 }
45 keys_.erase(it);
46 logger->info("Revoked {}", pattern);
47 return true;
48}
49
66bool MCPKeySet::has_access(const std::string& tool_name,
67 MCPAccessLevel required) const {
68 std::lock_guard<std::mutex> lock(key_mutex_);
69 auto granted = find_best_match(tool_name);
70 return static_cast<uint8_t>(granted) >=
71 static_cast<uint8_t>(required);
72}
73
80std::vector<MCPKey> MCPKeySet::list() const {
81 std::lock_guard<std::mutex> lock(key_mutex_);
82 std::vector<MCPKey> result;
83 result.reserve(keys_.size());
84 for (const auto& [pattern, level] : keys_) {
85 result.push_back(MCPKey{pattern, level});
86 }
87 return result;
88}
89
96size_t MCPKeySet::size() const {
97 std::lock_guard<std::mutex> lock(key_mutex_);
98 return keys_.size();
99}
100
107 std::lock_guard<std::mutex> lock(key_mutex_);
108 keys_.clear();
109}
110
117std::string MCPKeySet::serialize() const {
118 std::lock_guard<std::mutex> lock(key_mutex_);
119 nlohmann::json arr = nlohmann::json::array();
120 for (const auto& [pattern, level] : keys_) {
121 arr.push_back({
122 {"pattern", pattern},
123 {"level", mcp_access_level_name(level)}
124 });
125 }
126 return arr.dump();
127}
128
136bool MCPKeySet::deserialize(const std::string& json) {
137 nlohmann::json arr;
138 try {
139 arr = nlohmann::json::parse(json);
140 } catch (const nlohmann::json::exception& e) {
141 logger->warn("Deserialize failed: {}", e.what());
142 return false;
143 }
144 if (!arr.is_array()) {
145 logger->warn("Deserialize: expected JSON array");
146 return false;
147 }
148 std::lock_guard<std::mutex> lock(key_mutex_);
149 keys_.clear();
150 for (const auto& entry : arr) {
151 if (!entry.contains("pattern") || !entry.contains("level")) {
152 logger->warn("Skipping entry: missing fields");
153 continue;
154 }
155 MCPAccessLevel level{};
156 auto level_str = entry["level"].get<std::string>();
157 if (!parse_mcp_access_level(level_str, level)) {
158 logger->warn("Skipping entry: unknown level '{}'",
159 level_str);
160 continue;
161 }
162 keys_[entry["pattern"].get<std::string>()] = level;
163 }
164 return true;
165}
166
167// ── Private helpers ──────────────────────────────────────
168
176std::string MCPKeySet::server_wildcard(
177 const std::string& tool_name) {
178 auto dot = tool_name.find('.');
179 if (dot == std::string::npos) {
180 return "";
181 }
182 return tool_name.substr(0, dot) + ".*";
183}
184
198MCPAccessLevel MCPKeySet::find_best_match(
199 const std::string& tool_name) const {
200 auto result = MCPAccessLevel::NONE;
201 // 1. Exact match (most specific)
202 auto it = keys_.find(tool_name);
203 if (it != keys_.end()) {
204 result = it->second;
205 } else if (auto wc = server_wildcard(tool_name);
206 !wc.empty() &&
207 (it = keys_.find(wc)) != keys_.end()) {
208 // 2. Server wildcard (e.g., "filesystem.*")
209 result = it->second;
210 } else if ((it = keys_.find("*")) != keys_.end()) {
211 // 3. Full wildcard
212 result = it->second;
213 }
214 return result;
215}
216
217} // namespace entropic
bool has_access(const std::string &tool_name, MCPAccessLevel required) const
Check if a specific tool is authorized at the required level.
void clear()
Remove all granted keys.
bool revoke(const std::string &pattern)
Revoke a tool key entirely.
bool deserialize(const std::string &json)
Deserialize key set from JSON string.
std::string serialize() const
Serialize key set to JSON string.
std::vector< MCPKey > list() const
List all granted keys.
size_t size() const
Number of granted keys.
void grant(const std::string &pattern, MCPAccessLevel level)
Grant a tool key with an access level.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Per-identity set of authorized MCP tool keys.
Activate model on GPU (WARM → ACTIVE).
const char * mcp_access_level_name(MCPAccessLevel level)
Convert MCPAccessLevel to string representation.
Definition config.cpp:21
MCPAccessLevel
MCP tool access level for per-identity authorization.
Definition config.h:38
@ NONE
No access (default for ungranted keys)
bool parse_mcp_access_level(const std::string &name, MCPAccessLevel &out)
Parse MCPAccessLevel from string.
Definition config.cpp:35
A single authorized MCP key with access level.
Definition config.h:48