Entropic 2.3.8
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
58bool MCPKeySet::has_access(const std::string& tool_name,
59 MCPAccessLevel required) const {
60 std::lock_guard<std::mutex> lock(key_mutex_);
61 auto granted = find_best_match(tool_name);
62 return static_cast<uint8_t>(granted) >=
63 static_cast<uint8_t>(required);
64}
65
72std::vector<MCPKey> MCPKeySet::list() const {
73 std::lock_guard<std::mutex> lock(key_mutex_);
74 std::vector<MCPKey> result;
75 result.reserve(keys_.size());
76 for (const auto& [pattern, level] : keys_) {
77 result.push_back(MCPKey{pattern, level});
78 }
79 return result;
80}
81
88size_t MCPKeySet::size() const {
89 std::lock_guard<std::mutex> lock(key_mutex_);
90 return keys_.size();
91}
92
99 std::lock_guard<std::mutex> lock(key_mutex_);
100 keys_.clear();
101}
102
109std::string MCPKeySet::serialize() const {
110 std::lock_guard<std::mutex> lock(key_mutex_);
111 nlohmann::json arr = nlohmann::json::array();
112 for (const auto& [pattern, level] : keys_) {
113 arr.push_back({
114 {"pattern", pattern},
115 {"level", mcp_access_level_name(level)}
116 });
117 }
118 return arr.dump();
119}
120
128bool MCPKeySet::deserialize(const std::string& json) {
129 nlohmann::json arr;
130 try {
131 arr = nlohmann::json::parse(json);
132 } catch (const nlohmann::json::exception& e) {
133 logger->warn("Deserialize failed: {}", e.what());
134 return false;
135 }
136 if (!arr.is_array()) {
137 logger->warn("Deserialize: expected JSON array");
138 return false;
139 }
140 std::lock_guard<std::mutex> lock(key_mutex_);
141 keys_.clear();
142 for (const auto& entry : arr) {
143 if (!entry.contains("pattern") || !entry.contains("level")) {
144 logger->warn("Skipping entry: missing fields");
145 continue;
146 }
147 MCPAccessLevel level{};
148 auto level_str = entry["level"].get<std::string>();
149 if (!parse_mcp_access_level(level_str, level)) {
150 logger->warn("Skipping entry: unknown level '{}'",
151 level_str);
152 continue;
153 }
154 keys_[entry["pattern"].get<std::string>()] = level;
155 }
156 return true;
157}
158
159// ── Private helpers ──────────────────────────────────────
160
168std::string MCPKeySet::server_wildcard(
169 const std::string& tool_name) {
170 auto dot = tool_name.find('.');
171 if (dot == std::string::npos) {
172 return "";
173 }
174 return tool_name.substr(0, dot) + ".*";
175}
176
184MCPAccessLevel MCPKeySet::find_best_match(
185 const std::string& tool_name) const {
186 auto result = MCPAccessLevel::NONE;
187 // 1. Exact match (most specific)
188 auto it = keys_.find(tool_name);
189 if (it != keys_.end()) {
190 result = it->second;
191 } else if (auto wc = server_wildcard(tool_name);
192 !wc.empty() &&
193 (it = keys_.find(wc)) != keys_.end()) {
194 // 2. Server wildcard (e.g., "filesystem.*")
195 result = it->second;
196 } else if ((it = keys_.find("*")) != keys_.end()) {
197 // 3. Full wildcard
198 result = it->second;
199 }
200 return result;
201}
202
203} // 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