Skip to content

Commit 4749a3e

Browse files
Refactor configuration handling and update README for SPICE kernels path
1 parent c6e4d4a commit 4749a3e

File tree

6 files changed

+147
-126
lines changed

6 files changed

+147
-126
lines changed

.github/workflows/release.yml

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ jobs:
5555
dotnet publish "$PROJ" -c Release -r "$RID" \
5656
-p:PublishSingleFile=true \
5757
-p:SelfContained=true \
58-
-p:PublishTrimmed=false
58+
-p:PublishTrimmed=false \
59+
-p:IncludeNativeLibrariesForSelfExtract=true
5960
6061
TF=$(dotnet msbuild "$PROJ" -getproperty:TargetFramework -nologo -v:quiet)
6162
PUB_DIR="$(dirname "$PROJ")/bin/Release/${TF}/${RID}/publish"
@@ -65,18 +66,31 @@ jobs:
6566
if [[ "$RID" == win* ]]; then
6667
EXE=$(find "$PUB_DIR" -maxdepth 1 -type f -name "*.exe" | head -n1 || true)
6768
else
68-
EXE=$(find "$PUB_DIR" -maxdepth 1 -type f -perm -u+x | head -n1 || true)
69+
EXE=$(find "$PUB_DIR" -maxdepth 1 -type f -perm -u+x -printf '%f\n' -exec test -f "$PUB_DIR/{}" \; -print | head -n1 || true)
70+
# Fallback in case -printf isn't supported
71+
if [ -z "$EXE" ]; then EXE=$(find "$PUB_DIR" -maxdepth 1 -type f -perm -u+x | head -n1 || true); fi
6972
fi
7073
7174
if [ -z "$EXE" ]; then
7275
echo "No executable found in $PUB_DIR" >&2
7376
ls -la "$PUB_DIR" || true
7477
exit 1
7578
fi
79+
# Normalize to absolute path
80+
if [[ ! "$EXE" = /* ]]; then EXE="$PUB_DIR/$EXE"; fi
7681
echo "exe=$EXE" >> "$GITHUB_OUTPUT"
7782
echo "Executable: $EXE"
7883
79-
- name: Prepare asset for Release
84+
# Detect sidecar native libraries (needed on some RIDs like macOS)
85+
SIDECAR=""
86+
for pattern in "*.so" "*.dylib"; do
87+
CAND=$(find "$PUB_DIR" -maxdepth 1 -type f -name "$pattern" | head -n1 || true)
88+
if [ -n "$CAND" ]; then SIDECAR="$CAND"; break; fi
89+
done
90+
echo "sidecar=$SIDECAR" >> "$GITHUB_OUTPUT"
91+
if [ -n "$SIDECAR" ]; then echo "Detected sidecar: $SIDECAR"; else echo "No sidecar native lib detected"; fi
92+
93+
- name: Prepare native asset
8094
id: package
8195
shell: bash
8296
env:
@@ -88,21 +102,51 @@ jobs:
88102
if [[ "$RID" == win* ]]; then EXT=".exe"; fi
89103
BASENAME="mcp-server-stdio-${TAG}-${RID}${EXT}"
90104
SRC="${{ steps.publish.outputs.exe }}"
91-
DEST="${{ steps.publish.outputs.publish_dir }}/$BASENAME"
105+
DEST_DIR="$(mktemp -d)"
106+
DEST="$DEST_DIR/$BASENAME"
92107
cp "$SRC" "$DEST"
108+
chmod +x "$DEST" || true
93109
echo "asset=$DEST" >> "$GITHUB_OUTPUT"
94-
echo "Packaged asset: $DEST"
110+
echo "Prepared native asset: $DEST"
111+
112+
# If sidecar exists, prepare it with a deterministic name
113+
SIDECAR_SRC="${{ steps.publish.outputs.sidecar }}"
114+
if [ -n "$SIDECAR_SRC" ]; then
115+
SNAME="mcp-server-stdio-${TAG}-${RID}-$(basename "$SIDECAR_SRC")"
116+
SC_DEST="$DEST_DIR/$SNAME"
117+
cp "$SIDECAR_SRC" "$SC_DEST"
118+
echo "sidecar_asset=$SC_DEST" >> "$GITHUB_OUTPUT"
119+
echo "Prepared sidecar asset: $SC_DEST"
120+
else
121+
echo "sidecar_asset=" >> "$GITHUB_OUTPUT"
122+
fi
95123
96-
- name: Upload asset to GitHub Release
124+
- name: Upload executable to GitHub Release
97125
uses: softprops/action-gh-release@v2
98126
with:
99127
tag_name: ${{ github.ref_name }}
100128
files: ${{ steps.package.outputs.asset }}
101129
fail_on_unmatched_files: true
102130

103-
- name: Upload executable artifact
131+
- name: Upload sidecar (if any) to GitHub Release
132+
if: ${{ steps.package.outputs.sidecar_asset != '' }}
133+
uses: softprops/action-gh-release@v2
134+
with:
135+
tag_name: ${{ github.ref_name }}
136+
files: ${{ steps.package.outputs.sidecar_asset }}
137+
fail_on_unmatched_files: true
138+
139+
- name: Upload artifact (native executable)
104140
uses: actions/upload-artifact@v4
105141
with:
106142
name: io-aerosapce-mcp-${{ github.ref_name }}-${{ matrix.rid }}
107143
path: ${{ steps.package.outputs.asset }}
108144
if-no-files-found: error
145+
146+
- name: Upload artifact (sidecar if any)
147+
if: ${{ steps.package.outputs.sidecar_asset != '' }}
148+
uses: actions/upload-artifact@v4
149+
with:
150+
name: io-aerosapce-mcp-${{ github.ref_name }}-${{ matrix.rid }}-sidecar
151+
path: ${{ steps.package.outputs.sidecar_asset }}
152+
if-no-files-found: error

Data/Data.csproj

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -12,79 +12,4 @@
1212
<PackageReference Include="FuzzySharp" Version="2.0.2" />
1313
</ItemGroup>
1414

15-
<ItemGroup>
16-
<None Remove="SolarSystem\de440s.bsp" />
17-
<Content Include="SolarSystem\de440s.bsp">
18-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
19-
</Content>
20-
<None Remove="SolarSystem\earth_assoc_itrf93.tf" />
21-
<Content Include="SolarSystem\earth_assoc_itrf93.tf">
22-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
23-
</Content>
24-
<None Remove="SolarSystem\earth_fixed.tf" />
25-
<Content Include="SolarSystem\earth_fixed.tf">
26-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
27-
</Content>
28-
<None Remove="SolarSystem\earth_latest_high_prec.bpc" />
29-
<Content Include="SolarSystem\earth_latest_high_prec.bpc">
30-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
31-
</Content>
32-
<None Remove="SolarSystem\earth_topo_201023.tf" />
33-
<Content Include="SolarSystem\earth_topo_201023.tf">
34-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
35-
</Content>
36-
<None Remove="SolarSystem\earthstns_itrf93_201023.bsp" />
37-
<Content Include="SolarSystem\earthstns_itrf93_201023.bsp">
38-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
39-
</Content>
40-
<None Remove="SolarSystem\EGM2008_to70_TideFree" />
41-
<Content Include="SolarSystem\EGM2008_to70_TideFree">
42-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
43-
</Content>
44-
<None Remove="SolarSystem\geophysical.ker" />
45-
<Content Include="SolarSystem\geophysical.ker">
46-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
47-
</Content>
48-
<None Remove="SolarSystem\gm_de440.tpc" />
49-
<Content Include="SolarSystem\gm_de440.tpc">
50-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
51-
</Content>
52-
<None Remove="SolarSystem\L1_de431.bsp" />
53-
<Content Include="SolarSystem\L1_de431.bsp">
54-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
55-
</Content>
56-
<None Remove="SolarSystem\L2_de431.bsp" />
57-
<Content Include="SolarSystem\L2_de431.bsp">
58-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
59-
</Content>
60-
<None Remove="SolarSystem\L4_de431.bsp" />
61-
<Content Include="SolarSystem\L4_de431.bsp">
62-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
63-
</Content>
64-
<None Remove="SolarSystem\L5_de431.bsp" />
65-
<Content Include="SolarSystem\L5_de431.bsp">
66-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
67-
</Content>
68-
<None Remove="SolarSystem\latest_leapseconds.tls" />
69-
<Content Include="SolarSystem\latest_leapseconds.tls">
70-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
71-
</Content>
72-
<None Remove="SolarSystem\moon_080317.tf" />
73-
<Content Include="SolarSystem\moon_080317.tf">
74-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
75-
</Content>
76-
<None Remove="SolarSystem\moon_assoc_me.tf" />
77-
<Content Include="SolarSystem\moon_assoc_me.tf">
78-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
79-
</Content>
80-
<None Remove="SolarSystem\moon_pa_de421_1900-2050.bpc" />
81-
<Content Include="SolarSystem\moon_pa_de421_1900-2050.bpc">
82-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
83-
</Content>
84-
<None Remove="SolarSystem\pck00011.tpc" />
85-
<Content Include="SolarSystem\pck00011.tpc">
86-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
87-
</Content>
88-
</ItemGroup>
89-
9015
</Project>

Directory.Build.props

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project>
2+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
3+
<DebugType>none</DebugType>
4+
<DebugSymbols>false</DebugSymbols>
5+
<EmbedAllSources>false</EmbedAllSources>
6+
<IncludeSymbolsInSingleFile>false</IncludeSymbolsInSingleFile>
7+
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
8+
</PropertyGroup>
9+
</Project>
10+

README.md

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,19 +149,28 @@ dotnet build
149149

150150
#### 2. Solar System Data Setup
151151

152-
The server requires SPICE kernels for solar system calculations. You can configure the path in multiple ways (in order of priority):
152+
The server requires SPICE kernels for solar system calculations.
153153

154-
1. **Environment Variable** (Recommended):
154+
- STDIO server configuration (no appsettings):
155+
- Provide the kernels path via CLI or environment variable
156+
- Priority: CLI flag > IO_DATA_DIR environment variable
157+
- CLI flags: `-k <path>`, `--kernels <path>`, or `--kernels-path <path>`
158+
159+
Examples:
155160
```bash
156-
# Linux/macOS
161+
# Using CLI flag
162+
./Server.Stdio -k /path/to/your/spice/kernels
163+
164+
# Using environment variable (Linux/macOS)
157165
export IO_DATA_DIR="/path/to/your/spice/kernels"
166+
./Server.Stdio
158167

159-
# Windows
160-
set IO_DATA_DIR=C:\path\to\your\spice\kernels
168+
# Windows (PowerShell)
169+
$env:IO_DATA_DIR="C:\path\to\your\spice\kernels"
170+
./Server.Stdio.exe
161171
```
162172

163-
2. **Configuration File**: Edit `KernelsPath` in `appsettings.json`
164-
3. **Default Location**: Place files in `Data/SolarSystem/` directory
173+
- SSE server configuration: may use appsettings.json as before.
165174

166175
**Required Kernel Files:**
167176
```
@@ -173,14 +182,18 @@ kernels/
173182
└── ... # Additional kernel files
174183
```
175184

176-
- `IO_DATA_DIR`: Override kernels directory path (takes priority over appsettings.json)
177-
178185
#### 3. Choose Transport Method
179186

180187
##### STDIO Transport (For MCP Clients)
188+
- Release assets are native executables per OS/RID (no ZIP). Filenames:
189+
- mcp-server-stdio-<tag>-linux-x64
190+
- mcp-server-stdio-<tag>-win-x64.exe
191+
- mcp-server-stdio-<tag>-osx-arm64
192+
- On macOS, a sidecar native library may be provided (e.g., libIO.Astrodynamics.so). Place it in the same directory as the executable.
193+
181194
```bash
182-
cd Server.Stdio
183-
dotnet run
195+
# After publishing or downloading a release asset for your OS
196+
./Server.Stdio -k /path/to/kernels
184197
```
185198

186199
##### SSE Transport (For Web/HTTP)
@@ -211,6 +224,19 @@ Note: Many MCP clients use JSON-based configuration files, but schemas differ pe
211224
### Claude Desktop Configuration (STDIO)
212225
Add to your Claude Desktop configuration:
213226

227+
```json
228+
{
229+
"mcpServers": {
230+
"astrodynamics": {
231+
"command": "/path/to/Server.Stdio",
232+
"args": ["-k", "/path/to/kernels"]
233+
}
234+
}
235+
}
236+
```
237+
238+
Alternatively, set an environment variable if your client supports it:
239+
214240
```json
215241
{
216242
"mcpServers": {
@@ -286,9 +312,9 @@ Your support helps keep the hosted server online and the SPICE data current.
286312

287313
### Common Issues
288314

289-
1. **"Kernels directory does not exist"**: Verify the kernels path exists and contains SPICE files
290-
2. **"Failed to load kernel"**: Ensure all required kernel files are present and accessible
291-
3. **Connection errors**: Check firewall settings and port availability
315+
1. "Kernels directory does not exist": Verify the path passed with `-k` (or `IO_DATA_DIR`) exists and contains SPICE files
316+
2. "Failed to load kernel": Ensure all required kernel files are present and accessible
317+
3. Connection errors: Check firewall settings and port availability
292318

293319
### Log Monitoring
294320
```bash

Server.Stdio/Program.cs

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,49 +26,65 @@ public static async Task<int> Main(string[] args)
2626
Log.Information("Starting IO-Aerospace MCP server...");
2727

2828
var builder = Host.CreateApplicationBuilder(args);
29-
30-
// Obtenir le répertoire de l'exécutable
29+
30+
// Application base directory (next to the executable)
3131
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
3232
Log.Information("Application base directory: {BaseDirectory}", baseDirectory);
33-
34-
// Ajouter la configuration des fichiers appsettings.json avec chemins absolus
35-
builder.Configuration
36-
.AddJsonFile(Path.Combine(baseDirectory, "appsettings.json"), optional: false, reloadOnChange: true)
37-
.AddJsonFile(Path.Combine(baseDirectory, $"appsettings.{builder.Environment.EnvironmentName}.json"), optional: true, reloadOnChange: true)
38-
.AddEnvironmentVariables(); // Add environment variables to configuration
39-
33+
34+
// Only use environment variables for config (no appsettings)
35+
builder.Configuration.AddEnvironmentVariables();
36+
4037
builder.Services.AddSerilog();
4138
builder.Services.AddMcpServer()
4239
.WithStdioServerTransport().WithToolsFromAssembly(typeof(CelestialBodyTools).Assembly);
4340
var app = builder.Build();
4441

45-
Log.Information("IO-Aerospace MCP server started successfully");
46-
47-
// Check for environment variable override first, then fall back to configuration
48-
var kernelsPath = Environment.GetEnvironmentVariable("IO_DATA_DIR") ?? builder.Configuration["KernelsPath"];
49-
50-
if (string.IsNullOrEmpty(kernelsPath))
42+
// Parse CLI for kernels path: --kernels-path <path> | --kernels <path> | -k <path>
43+
string? kernelsPathArg = null;
44+
for (int i = 0; i < args.Length; i++)
45+
{
46+
var a = args[i];
47+
if (a == "-k" || a == "--kernels" || a == "--kernels-path")
48+
{
49+
if (i + 1 < args.Length)
50+
{
51+
kernelsPathArg = args[i + 1];
52+
i++;
53+
}
54+
else
55+
{
56+
Log.Error("Missing value for {Arg}. Usage: -k <path>", a);
57+
return 1;
58+
}
59+
}
60+
}
61+
62+
// Priority: CLI arg > IO_DATA_DIR env
63+
var kernelsPath = kernelsPathArg ?? Environment.GetEnvironmentVariable("IO_DATA_DIR");
64+
65+
if (string.IsNullOrWhiteSpace(kernelsPath))
5166
{
52-
Log.Error("KernelsPath is not set. Please set it in appsettings.json or use IO_DATA_DIR environment variable.");
67+
Log.Error("Kernels path not provided. Use -k|--kernels-path <path> or set IO_DATA_DIR environment variable.");
68+
Log.Information("Example: ./Server.Stdio -k /path/to/your/spice/kernels");
5369
return 1;
5470
}
55-
56-
// Construire le chemin absolu vers les kernels
57-
var absoluteKernelsPath = Path.IsPathRooted(kernelsPath)
58-
? kernelsPath
71+
72+
// Build absolute path; if relative, resolve next to the executable directory
73+
var absoluteKernelsPath = Path.IsPathRooted(kernelsPath)
74+
? kernelsPath
5975
: Path.Combine(baseDirectory, kernelsPath);
60-
76+
6177
Log.Information("Trying to load kernels from {KernelsPath} (absolute: {AbsoluteKernelsPath})", kernelsPath, absoluteKernelsPath);
62-
78+
6379
if (!Directory.Exists(absoluteKernelsPath))
6480
{
6581
Log.Error("Kernels directory does not exist: {AbsoluteKernelsPath}", absoluteKernelsPath);
6682
return 1;
6783
}
68-
84+
6985
API.Instance.LoadKernels(new DirectoryInfo(absoluteKernelsPath));
7086
Log.Information("Kernels loaded successfully from {AbsoluteKernelsPath}", absoluteKernelsPath);
71-
87+
7288
await app.RunAsync();
7389
return 0;
7490
}

Server.Stdio/Server.Stdio.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

10+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
11+
<DebugType>none</DebugType>
12+
<DebugSymbols>false</DebugSymbols>
13+
</PropertyGroup>
14+
1015
<ItemGroup>
1116
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
1217
<PackageReference Include="ModelContextProtocol" Version="0.3.0-preview.3" />
@@ -23,12 +28,7 @@
2328
</ItemGroup>
2429

2530
<ItemGroup>
26-
<None Update="appsettings.json">
27-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
28-
</None>
29-
<None Update="appsettings.Development.json">
30-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
31-
</None>
31+
<FileToPublish Remove="**/*.pdb" />
3232
</ItemGroup>
3333

3434
</Project>

0 commit comments

Comments
 (0)