Skip to content

Commit 47443ef

Browse files
committed
feat(clients): local-mode model selector + git-tag version in About
- local_server.rs: parse ?model= and inject into coordinate-tool args (provider-tuned default size in local mode) - local_mode_window.rs: Model dropdown (Default/Claude/Gemini/ChatGPT) appends ?model= to the copyable MCP URL - build.rs: SCREENMCP_VERSION from git tag (GITHUB_REF_NAME -> git describe -> Cargo); About shows it - bump Cargo.toml fallbacks to 0.3.8
1 parent 24b6349 commit 47443ef

18 files changed

Lines changed: 288 additions & 18 deletions

linux/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

linux/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "screenmcp-linux"
3-
version = "0.3.7"
3+
version = "0.3.8"
44
edition = "2021"
55
description = "ScreenMCP Linux client - desktop control via system tray"
66

linux/build.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// Expose SCREENMCP_VERSION derived from the git tag.
2+
/// Priority: CI tag (GITHUB_REF_NAME) -> `git describe --tags` -> Cargo version.
3+
fn main() {
4+
let version = std::env::var("GITHUB_REF_NAME")
5+
.ok()
6+
.filter(|s| s.starts_with('v'))
7+
.or_else(git_describe)
8+
.unwrap_or_else(|| format!("v{}", std::env::var("CARGO_PKG_VERSION").unwrap_or_default()));
9+
10+
println!("cargo:rustc-env=SCREENMCP_VERSION={version}");
11+
println!("cargo:rerun-if-changed=../.git/HEAD");
12+
println!("cargo:rerun-if-changed=../.git/refs/tags");
13+
println!("cargo:rerun-if-env-changed=GITHUB_REF_NAME");
14+
}
15+
16+
fn git_describe() -> Option<String> {
17+
let out = std::process::Command::new("git")
18+
.args(["describe", "--tags", "--always", "--dirty"])
19+
.output()
20+
.ok()?;
21+
if !out.status.success() {
22+
return None;
23+
}
24+
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
25+
if s.is_empty() {
26+
None
27+
} else {
28+
Some(s)
29+
}
30+
}

linux/src/local_mode_window.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub struct LocalModeState {
88
pub show_key: bool,
99
pub status: String,
1010
pub saved: bool,
11+
/// Default model for the copyable MCP URL: "default" | "claude" | "gemini" | "chatgpt".
12+
pub model: String,
1113
}
1214

1315
impl LocalModeState {
@@ -19,6 +21,7 @@ impl LocalModeState {
1921
show_key: false,
2022
status: String::new(),
2123
saved: false,
24+
model: "default".to_string(),
2225
}
2326
}
2427

@@ -82,6 +85,27 @@ impl LocalModeState {
8285
);
8386
});
8487

88+
ui.add_space(8.0);
89+
90+
// Model: sets a provider-tuned default screenshot size via ?model= in the URL
91+
ui.horizontal(|ui| {
92+
ui.label("Model: ");
93+
let label = match self.model.as_str() {
94+
"claude" => "Claude",
95+
"gemini" => "Gemini",
96+
"chatgpt" => "ChatGPT",
97+
_ => "Default",
98+
};
99+
egui::ComboBox::from_id_salt("local_mode_model")
100+
.selected_text(label)
101+
.show_ui(ui, |ui| {
102+
ui.selectable_value(&mut self.model, "default".to_string(), "Default");
103+
ui.selectable_value(&mut self.model, "claude".to_string(), "Claude");
104+
ui.selectable_value(&mut self.model, "gemini".to_string(), "Gemini");
105+
ui.selectable_value(&mut self.model, "chatgpt".to_string(), "ChatGPT");
106+
});
107+
});
108+
85109
ui.add_space(20.0);
86110

87111
ui.vertical_centered(|ui| {
@@ -142,12 +166,17 @@ impl LocalModeState {
142166
.strong(),
143167
);
144168
let port = self.port_str.trim();
169+
let model_q = if self.model != "default" {
170+
format!("?model={}", self.model)
171+
} else {
172+
String::new()
173+
};
145174
let snippet = format!(
146175
r#"{{
147176
"mcpServers": {{
148177
"screenmcp": {{
149178
"type": "url",
150-
"url": "http://127.0.0.1:{port}/mcp",
179+
"url": "http://127.0.0.1:{port}/mcp{model_q}",
151180
"headers": {{
152181
"Authorization": "Bearer {}"
153182
}}

linux/src/local_server.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
use axum::{
2-
extract::State,
2+
extract::{Query, State},
33
http::{header, HeaderMap, StatusCode},
44
response::IntoResponse,
55
routing::{get, post},
66
Json, Router,
77
};
88
use serde_json::{json, Value};
9+
use std::collections::HashMap;
10+
11+
/// Coordinate-bearing commands that take a provider-tuned default size when the
12+
/// connection set ?model= and the caller gave no max_width/max_height.
13+
const MODEL_COORD_TOOLS: &[&str] = &[
14+
"screenshot", "screenshot_region", "screenshot_window", "ui_tree",
15+
"get_screen_size", "click", "long_click", "drag", "scroll",
16+
"double_click", "right_click", "middle_click", "mouse_move", "mouse_scroll",
17+
];
918
use std::sync::Arc;
1019
use tokio::sync::RwLock;
1120
use tracing::{error, info};
@@ -502,6 +511,7 @@ fn mcp_tool_definitions() -> Vec<Value> {
502511

503512
async fn handle_mcp_post(
504513
State(state): State<AppState>,
514+
Query(query): Query<HashMap<String, String>>,
505515
headers: HeaderMap,
506516
Json(body): Json<Value>,
507517
) -> impl IntoResponse {
@@ -562,7 +572,23 @@ async fn handle_mcp_post(
562572
.and_then(|v| v.as_str())
563573
.unwrap_or("")
564574
.to_string();
565-
let tool_args = params.get("arguments").cloned().unwrap_or(json!({}));
575+
let mut tool_args = params.get("arguments").cloned().unwrap_or(json!({}));
576+
577+
// Inject the connection's model (from ?model=) so coordinate tools pick a
578+
// provider-tuned default size when the caller gave no max_width/max_height.
579+
if let Some(model) = query
580+
.get("model")
581+
.map(|s| s.as_str())
582+
.filter(|m| matches!(*m, "claude" | "gemini" | "chatgpt"))
583+
{
584+
if MODEL_COORD_TOOLS.contains(&tool_name.as_str()) {
585+
if let Some(obj) = tool_args.as_object_mut() {
586+
if !obj.contains_key("max_width") && !obj.contains_key("max_height") {
587+
obj.insert("model".to_string(), json!(model));
588+
}
589+
}
590+
}
591+
}
566592

567593
let config_clone = config.clone();
568594
drop(config);

linux/src/tray.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,11 @@ impl TrayApp {
216216
let config = Config::load();
217217

218218
// ── Build tray menu ──
219-
let about = MenuItem::new("About ScreenMCP.com", true, None);
219+
let about = MenuItem::new(
220+
concat!("About ScreenMCP.com ", env!("SCREENMCP_VERSION")),
221+
true,
222+
None,
223+
);
220224
let status = MenuItem::new("Status: Disconnected", false, None);
221225
let oss_ready = config.opensource_server_enabled
222226
&& !config.opensource_user_id.is_empty()

mac/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mac/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "screenmcp-mac"
3-
version = "0.3.3"
3+
version = "0.3.8"
44
edition = "2021"
55
description = "ScreenMCP Mac client - desktop control via menu bar icon"
66

mac/build.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/// Expose SCREENMCP_VERSION derived from the git tag.
2+
/// Priority: CI tag (GITHUB_REF_NAME) -> `git describe --tags` -> Cargo version.
3+
fn main() {
4+
let version = std::env::var("GITHUB_REF_NAME")
5+
.ok()
6+
.filter(|s| s.starts_with('v'))
7+
.or_else(git_describe)
8+
.unwrap_or_else(|| format!("v{}", std::env::var("CARGO_PKG_VERSION").unwrap_or_default()));
9+
10+
println!("cargo:rustc-env=SCREENMCP_VERSION={version}");
11+
println!("cargo:rerun-if-changed=../.git/HEAD");
12+
println!("cargo:rerun-if-changed=../.git/refs/tags");
13+
println!("cargo:rerun-if-env-changed=GITHUB_REF_NAME");
14+
}
15+
16+
fn git_describe() -> Option<String> {
17+
let out = std::process::Command::new("git")
18+
.args(["describe", "--tags", "--always", "--dirty"])
19+
.output()
20+
.ok()?;
21+
if !out.status.success() {
22+
return None;
23+
}
24+
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
25+
if s.is_empty() {
26+
None
27+
} else {
28+
Some(s)
29+
}
30+
}

mac/src/local_mode_window.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub struct LocalModeState {
88
pub show_key: bool,
99
pub status: String,
1010
pub saved: bool,
11+
/// Default model for the copyable MCP URL: "default" | "claude" | "gemini" | "chatgpt".
12+
pub model: String,
1113
}
1214

1315
impl LocalModeState {
@@ -19,6 +21,7 @@ impl LocalModeState {
1921
show_key: false,
2022
status: String::new(),
2123
saved: false,
24+
model: "default".to_string(),
2225
}
2326
}
2427

@@ -82,6 +85,27 @@ impl LocalModeState {
8285
);
8386
});
8487

88+
ui.add_space(8.0);
89+
90+
// Model: sets a provider-tuned default screenshot size via ?model= in the URL
91+
ui.horizontal(|ui| {
92+
ui.label("Model: ");
93+
let label = match self.model.as_str() {
94+
"claude" => "Claude",
95+
"gemini" => "Gemini",
96+
"chatgpt" => "ChatGPT",
97+
_ => "Default",
98+
};
99+
egui::ComboBox::from_id_salt("local_mode_model")
100+
.selected_text(label)
101+
.show_ui(ui, |ui| {
102+
ui.selectable_value(&mut self.model, "default".to_string(), "Default");
103+
ui.selectable_value(&mut self.model, "claude".to_string(), "Claude");
104+
ui.selectable_value(&mut self.model, "gemini".to_string(), "Gemini");
105+
ui.selectable_value(&mut self.model, "chatgpt".to_string(), "ChatGPT");
106+
});
107+
});
108+
85109
ui.add_space(20.0);
86110

87111
ui.vertical_centered(|ui| {
@@ -142,12 +166,17 @@ impl LocalModeState {
142166
.strong(),
143167
);
144168
let port = self.port_str.trim();
169+
let model_q = if self.model != "default" {
170+
format!("?model={}", self.model)
171+
} else {
172+
String::new()
173+
};
145174
let snippet = format!(
146175
r#"{{
147176
"mcpServers": {{
148177
"screenmcp": {{
149178
"type": "url",
150-
"url": "http://127.0.0.1:{port}/mcp",
179+
"url": "http://127.0.0.1:{port}/mcp{model_q}",
151180
"headers": {{
152181
"Authorization": "Bearer {}"
153182
}}

0 commit comments

Comments
 (0)