Skip to content

Commit c3fee4a

Browse files
Merge pull request #2 from LoamStudios/migrate-to-offical-package
Migrate MCP Server to use official GitHub server.
2 parents cc31c53 + 63a3eb9 commit c3fee4a

File tree

4 files changed

+91
-21
lines changed

4 files changed

+91
-21
lines changed

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.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcp_server_github"
3-
version = "0.0.1"
3+
version = "0.0.2"
44
edition = "2021"
55
publish = false
66
license = "Apache-2.0"

extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
id = "mcp-server-github"
22
name = "GitHub MCP Server"
33
description = "Model Context Protocol Server for GitHub"
4-
version = "0.0.1"
4+
version = "0.0.2"
55
schema_version = 1
66
authors = ["Jeffrey Guenther <[email protected]>"]
77
repository = "https://github.com/LoamStudios/zed-mcp-server-github"

src/mcp_server_github.rs

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,108 @@
11
use serde::Deserialize;
2-
use std::env;
2+
use std::fs;
33
use zed::settings::ContextServerSettings;
44
use zed_extension_api::{self as zed, serde_json, Command, ContextServerId, Project, Result};
55

6-
const PACKAGE_NAME: &str = "@modelcontextprotocol/server-github";
7-
const SERVER_PATH: &str = "node_modules/@modelcontextprotocol/server-github/dist/index.js";
6+
const REPO_NAME: &str = "github/github-mcp-server";
7+
const BINARY_NAME: &str = "github-mcp-server";
88

99
#[derive(Debug, Deserialize)]
1010
struct GitHubContextServerSettings {
1111
github_personal_access_token: String,
1212
}
1313

14-
struct GitHubModelContextExtension;
14+
struct GitHubModelContextExtension {
15+
cached_binary_path: Option<String>,
16+
}
17+
18+
impl GitHubModelContextExtension {
19+
fn context_server_binary_path(
20+
&mut self,
21+
_context_server_id: &ContextServerId,
22+
) -> Result<String> {
23+
if let Some(path) = &self.cached_binary_path {
24+
if fs::metadata(path).map_or(false, |stat| stat.is_file()) {
25+
return Ok(path.clone());
26+
}
27+
}
28+
29+
let release = zed::latest_github_release(
30+
REPO_NAME,
31+
zed::GithubReleaseOptions {
32+
require_assets: true,
33+
pre_release: false,
34+
},
35+
)?;
36+
37+
let (platform, arch) = zed::current_platform();
38+
let asset_name = format!(
39+
"{BINARY_NAME}_{os}_{arch}.{ext}",
40+
arch = match arch {
41+
zed::Architecture::Aarch64 => "arm64",
42+
zed::Architecture::X86 => "i386",
43+
zed::Architecture::X8664 => "x86_64",
44+
},
45+
os = match platform {
46+
zed::Os::Mac => "Darwin",
47+
zed::Os::Linux => "Linux",
48+
zed::Os::Windows => "Windows",
49+
},
50+
ext = match platform {
51+
zed::Os::Mac | zed::Os::Linux => "tar.gz",
52+
zed::Os::Windows => "zip",
53+
}
54+
);
55+
56+
let asset = release
57+
.assets
58+
.iter()
59+
.find(|asset| asset.name == asset_name)
60+
.ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
61+
62+
let version_dir = format!("{BINARY_NAME}-{}", release.version);
63+
fs::create_dir_all(&version_dir)
64+
.map_err(|err| format!("failed to create directory '{version_dir}': {err}"))?;
65+
let binary_path = format!("{version_dir}/{BINARY_NAME}");
66+
67+
if !fs::metadata(&binary_path).map_or(false, |stat| stat.is_file()) {
68+
let file_kind = match platform {
69+
zed::Os::Mac | zed::Os::Linux => zed::DownloadedFileType::GzipTar,
70+
zed::Os::Windows => zed::DownloadedFileType::Zip,
71+
};
72+
73+
zed::download_file(&asset.download_url, &version_dir, file_kind)
74+
.map_err(|e| format!("failed to download file: {e}"))?;
75+
76+
zed::make_file_executable(&binary_path)?;
77+
78+
// Removes old versions
79+
let entries =
80+
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
81+
for entry in entries {
82+
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
83+
if entry.file_name().to_str() != Some(&version_dir) {
84+
fs::remove_dir_all(entry.path()).ok();
85+
}
86+
}
87+
}
88+
89+
self.cached_binary_path = Some(binary_path.clone());
90+
Ok(binary_path)
91+
}
92+
}
1593

1694
impl zed::Extension for GitHubModelContextExtension {
1795
fn new() -> Self {
18-
Self
96+
Self {
97+
cached_binary_path: None,
98+
}
1999
}
20100

21101
fn context_server_command(
22102
&mut self,
23-
_context_server_id: &ContextServerId,
103+
context_server_id: &ContextServerId,
24104
project: &Project,
25105
) -> Result<Command> {
26-
let latest_version = zed::npm_package_latest_version(PACKAGE_NAME)?;
27-
let version = zed::npm_package_installed_version(PACKAGE_NAME)?;
28-
if version.as_deref() != Some(latest_version.as_ref()) {
29-
zed::npm_install_package(PACKAGE_NAME, &latest_version)?;
30-
}
31-
32106
let settings = ContextServerSettings::for_project("mcp-server-github", project)?;
33107
let Some(settings) = settings.settings else {
34108
return Err("missing `github_personal_access_token` setting".into());
@@ -37,12 +111,8 @@ impl zed::Extension for GitHubModelContextExtension {
37111
serde_json::from_value(settings).map_err(|e| e.to_string())?;
38112

39113
Ok(Command {
40-
command: zed::node_binary_path()?,
41-
args: vec![env::current_dir()
42-
.unwrap()
43-
.join(SERVER_PATH)
44-
.to_string_lossy()
45-
.to_string()],
114+
command: self.context_server_binary_path(context_server_id)?,
115+
args: vec!["stdio".to_string()],
46116
env: vec![(
47117
"GITHUB_PERSONAL_ACCESS_TOKEN".into(),
48118
settings.github_personal_access_token,

0 commit comments

Comments
 (0)