Skip to content

Commit a313ffd

Browse files
committed
fix(meta-tools): scope to caller's resolved Space + drop stale pin/active wording
Two bugs the user surfaced after exercising the live tools: 1. **Wrong space.** All four meta tools (`list_all_tools`, `list_feature_sets`, `create_feature_set`, `bind_current_workspace`) went through `caller_space_id`, which always returned the *default* Space — meaning a client routed via WorkspaceBinding into a non-default Space could still read/write FSes in the default Space. The tools must stay inside the Space the resolver actually picked for that caller, so `caller_space_id` now consults `FeatureSetResolverService::resolve` and uses the resolved `space_id`. Falls back to the default Space when the resolver returns no binding match. 2. **Stale tool descriptions.** Several descriptions still referenced long-gone concepts: * `list_feature_sets` claimed an `is_active` / `is_pinned` field on each entry — neither exists in the response, and both concepts have been removed from the model. Description now lists the actual fields (`id`, `name`, `description`, `type`, `is_builtin`). * `create_feature_set` told callers to follow up with `mcpmux_pin_this_session` or `mcpmux_set_space_active` — neither tool exists. New text points at `mcpmux_bind_current_workspace`, which is the one mechanism that actually makes a FeatureSet take effect. * `list_all_tools` mentioned "before deciding which tools to pin" — trimmed to "before composing a custom FeatureSet". * `bind_current_workspace` removed the "unless they have an explicit pin" carve-out. Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
1 parent 42bfbf9 commit a313ffd

1 file changed

Lines changed: 35 additions & 28 deletions

File tree

  • crates/mcpmux-gateway/src/services/meta_tools

crates/mcpmux-gateway/src/services/meta_tools/tools.rs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,25 @@ fn text_result(v: Value) -> CallToolResult {
3939
CallToolResult::success(vec![Content::text(v.to_string())])
4040
}
4141

42-
/// Resolve the caller's effective Space id — always the default/active space
43-
/// in the current (no-client-pinning) model. Returns an error only in the
44-
/// pathological "no default space" setup.
42+
/// Resolve the Space the caller is *actually* routed into — i.e. whichever
43+
/// Space the resolver picks via WorkspaceBinding for this session's reported
44+
/// roots, falling back to the default Space when no binding matches.
45+
///
46+
/// Every meta tool reads (and writes) inside this Space. That keeps the
47+
/// caller's tool/FS view aligned with the tools the gateway actually exposes
48+
/// to them, and prevents an LLM in workspace A from mutating FSes in
49+
/// workspace B just because both sit under the same default-Space-flagged
50+
/// row in the DB.
4551
async fn caller_space_id(call: &MetaToolCall<'_>) -> Result<Uuid, MetaToolError> {
46-
let default_space = call
47-
.ctx
48-
.space_repo
49-
.get_default()
50-
.await?
51-
.ok_or_else(|| MetaToolError::Internal("no default space".into()))?;
52-
Ok(default_space.id)
52+
let resolved = call.ctx.resolver.resolve(call.session_id).await?;
53+
if let Some(space_id) = resolved.space_id {
54+
return Ok(space_id);
55+
}
56+
// Resolver returned no space — should only happen in the pathological
57+
// "no default space configured" setup. Fail loudly so callers see why.
58+
Err(MetaToolError::Internal(
59+
"no Space resolved for this caller (no default Space configured?)".into(),
60+
))
5361
}
5462

5563
// ---------------------------------------------------------------------------
@@ -65,10 +73,10 @@ impl MetaTool for ListAllToolsTool {
6573
}
6674

6775
fn description(&self) -> &'static str {
68-
"List EVERY tool available on every connected MCP server, without the \
69-
current FeatureSet filter applied. Useful when you want to know what's \
70-
possible in this workspace before deciding which tools to pin. Returns \
71-
an array of {server_id, qualified_name, description, available}."
76+
"List every tool installed in the caller's resolved Space, without \
77+
the current FeatureSet filter applied. Use this to see what the \
78+
workspace could expose before composing a custom FeatureSet. \
79+
Returns an array of {server_id, qualified_name, description, available}."
7280
}
7381

7482
fn input_schema(&self) -> Value {
@@ -111,11 +119,10 @@ impl MetaTool for ListFeatureSetsTool {
111119
}
112120

113121
fn description(&self) -> &'static str {
114-
"List every FeatureSet in the caller's Space — built-ins and custom. \
115-
Each entry carries `id`, `name`, `type`, `is_active` (the one that \
116-
applies when no pin/binding matches), and `is_pinned` (this caller's \
117-
current pin). Use before proposing a pin so you don't recreate one \
118-
that already fits."
122+
"List every FeatureSet defined in the caller's resolved Space — \
123+
built-ins and custom. Each entry carries `id`, `name`, `description`, \
124+
`type`, and `is_builtin`. Use before composing a new FeatureSet so \
125+
you don't recreate one that already fits."
119126
}
120127

121128
fn input_schema(&self) -> Value {
@@ -211,11 +218,11 @@ impl MetaTool for CreateFeatureSetTool {
211218
}
212219

213220
fn description(&self) -> &'static str {
214-
"Create a new custom FeatureSet in the caller's Space from an explicit \
215-
list of qualified tool names (e.g. ['github_create_issue', \
216-
'firebase_deploy']). Returns the new FS id; does NOT activate it — \
217-
call mcpmux_pin_this_session or mcpmux_set_space_active separately \
218-
so the user sees the activation dialog distinct from creation."
221+
"Create a new custom FeatureSet in the caller's resolved Space from \
222+
an explicit list of qualified tool names (e.g. ['github_create_issue', \
223+
'firebase_deploy']). Returns the new FS id. To make a workspace \
224+
actually route through this FeatureSet, follow up with \
225+
`mcpmux_bind_current_workspace`."
219226
}
220227

221228
fn input_schema(&self) -> Value {
@@ -338,10 +345,10 @@ impl MetaTool for BindCurrentWorkspaceTool {
338345

339346
fn description(&self) -> &'static str {
340347
"Persistently bind the caller's first reported workspace root to the \
341-
given FeatureSet. Every future connection in this Space that reports \
342-
the same root (or a subdirectory) will resolve to this FeatureSet \
343-
unless they have an explicit pin. Requires user approval and the \
344-
calling client MUST have declared MCP roots."
348+
given FeatureSet inside the caller's resolved Space. Every future \
349+
connection that reports the same root (or a subdirectory) will \
350+
resolve to this FeatureSet. Requires user approval and the calling \
351+
client MUST have declared MCP roots."
345352
}
346353

347354
fn input_schema(&self) -> Value {

0 commit comments

Comments
 (0)