Using it as an MCP server¶
The MCP server is the AI-agent door. It exposes the whole catalogue to assistants like Claude through the Model Context Protocol, so an agent can analyse spectra by calling tools - the same operations you call from the library or the CLI.
It requires the mcp extra:
Running the server¶
Connecting Claude Desktop¶
Add the server to Claude Desktop's configuration file:
Restart Claude Desktop; the spectro-kernel tools appear in the conversation.
What the agent sees¶
The server exposes two kinds of tools:
One tool per algorithm. Every registered algorithm becomes a tool automatically - so the agent-facing catalogue can never drift from the code. Each tool's description includes the parameters, the backend and the literature references.
Transverse tools for session and discovery:
| Tool | Purpose |
|---|---|
create_session |
Start a working session; returns a session_id. |
load_spectrum |
Load a FITS/ASCII/VOTable spectrum into a session. |
get_session_state |
Inspect everything held in a session. |
get_spectrum_preview |
A downsampled preview of the session's spectrum. |
list_algorithms |
Discover the catalogue (optionally by category). |
describe_algorithm |
Full details of one algorithm. |
get_algorithm_source |
The wrapper's source code + GitHub permalink - for auditing what the algorithm actually does, especially when it delegates to an external library. |
list_presets |
List the bundled pipeline presets. |
run_preset |
Run a whole preset pipeline in one call. |
request_upload_url |
Pre-signed S3/Spaces PUT URL for large file uploads (needs SPECTRO_MCP_S3_BUCKET). |
load_spectrum_from_url |
Download a spectrum from any http(s) URL and load it into the session. |
end_session |
Discard a session. |
Why sessions?¶
MCP tool calls are stateless, but a real analysis is a sequence of calls sharing one
spectrum. A session keeps a WorkContext alive between calls, identified by an
opaque session_id.
sequenceDiagram
participant A as AI agent
participant S as spectro-mcp
A->>S: create_session()
S-->>A: session_id "s_ab12"
A->>S: load_spectrum("s_ab12", "obs.fits")
A->>S: normalize_polynomial("s_ab12", {order: 3})
A->>S: snr_der("s_ab12")
A->>S: fit_gaussian_line("s_ab12", {line_center_angstrom: 6562.8})
A->>S: get_session_state("s_ab12")
S-->>A: metrics, line fits, history
Every algorithm tool takes a session_id and an optional params object; it runs
against that session's context and returns the metrics, the context summary and any
artifacts.
Session storage
Sessions are kept in process memory with a sliding TTL and a cap on live
sessions (SPECTRO_MCP_MAX_SESSIONS, default 200, least-recently-used
eviction). A multi-instance deployment backs them with Redis (set
SPECTRO_MCP_REDIS_URL; payloads are HMAC-signed with
SPECTRO_MCP_SESSION_SECRET).
Hardened HTTP mode¶
spectro-mcp --http is the shared, network-facing variant. Since v0.6.1 it
applies the same guards to every tool, not only to load_spectrum:
- No local filesystem access. Any parameter that names a path
(
path,*_path,*_paths,*_dir,model_path,target_path,atlas_dir) is refused when it points at a local file, for theread_*bricks, theexport_*bricks, the EasySpec wrappers and the embedding bricks alike. Presets can only be called by bundled name. - URLs go through the SSRF guard. Private, loopback, link-local, CGNAT and NAT64-embedded-private addresses are refused, redirects are refused, the resolved address is pinned for the connection, and downloads are bounded in size (256 MiB), wall-clock time and concurrency. Downloaded FITS files are checked for their pixel count before conversion.
- An explicit posture is mandatory. The server refuses to start
unless you either set
SPECTRO_MCP_API_KEY(closed : clients send the key in theX-API-Keyheader, the rate limiter counts per key) orSPECTRO_MCP_ALLOW_ANONYMOUS=1(open : no accounts, no key, the rate limiter counts per client IP). The public demo server is open. - Error details are masked and non-finite metrics (
NaN,inf) are serialised asnull, so every response is strict JSON. get_spectrum_datareturns at mostmax_pointssamples (default 20 000, stride-downsampled; pass0for everything) and says so withdownsampled,npix_total,npix_returnedandstride.
None of this changes stdio mode, except that URLs handed to the read_*
bricks are now fetched through the same guard as load_spectrum.
| Variable | Default | Meaning |
|---|---|---|
SPECTRO_MCP_API_KEY |
unset | Closed posture : shared secret, X-API-Key header. |
SPECTRO_MCP_ALLOW_ANONYMOUS |
unset | Open posture : 1 to start --http without a key. |
SPECTRO_MCP_ALLOW_KEY_IN_URL |
unset | 1 also accepts the key as ?api_key=… in the URL (for claude.ai / Claude Desktop connectors, which cannot set headers); the parameter is scrubbed before access logging. Authorization: Bearer <key> is always accepted. |
SPECTRO_MCP_RATE_PER_MINUTE |
0 (off) |
Sliding-window limit per API key (per client IP when auth is off). |
SPECTRO_MCP_TRUSTED_PROXY |
unset | 1 behind a load balancer: trust X-Forwarded-For. |
SPECTRO_MCP_CORS_ORIGINS |
spectrokernel.io sites | Comma-separated browser origins allowed to call the server (* for any, none to disable). The Mcp-Session-Id header is exposed to browsers. |
SPECTRO_MCP_MAX_SESSIONS |
200 |
Live in-memory sessions before LRU eviction. |
SPECTRO_MCP_MAX_PIXELS |
32000000 |
Largest downloaded FITS accepted (data elements); 0 disables. |
SPECTRO_MCP_DOWNLOAD_BUDGET_S |
120 |
Wall-clock budget per URL download. |
SPECTRO_MCP_MAX_CONCURRENT_DOWNLOADS |
4 |
Downloads in flight at once. |
SPECTRO_EMBED_ENDPOINT_ALLOW |
unset | Hosts embed_remote may call with the server-side SPECTRO_EMBED_API_KEY. |
A typical agent conversation¶
You: Here is a FITS spectrum. Measure its SNR and fit H-alpha.
Claude (calling tools):
create_session()→s_qrpload_spectrum("s_qrp", "<path>")normalize_polynomial("s_qrp", {"order": 3})snr_der("s_qrp")→ SNR 142fit_gaussian_line("s_qrp", {"line_center_angstrom": 6562.8})Claude: SNR is 142 (excellent). H-alpha is in emission, FWHM 12.4 Å…
Because the MCP tools are generated from the same registry as the library and CLI, the agent is never working with a different or stale catalogue.