spectro-kernel
A shared catalogue of astronomical spectroscopy algorithms — composable into reproducible pipelines, usable as a Python library, a CLI, or an MCP server.
spectro-kernel is the common foundation for every spectroscopy application: FITS
reading/writing, continuum normalisation, SNR, line detection and fitting, smoothing,
resampling, barycentric correction, periodograms, exports — implemented once, tested
once, and reused everywhere instead of being re-coded (subtly differently) in each project.
It is designed to be the substrate of any future spectroscopy app — a stellar reduction pipeline, a visualisation dashboard, a campaign-collection backend — and it works with or without an AI agent:
- Without an agent —
import spectro_kernelin any Python project, or use thespectrocommand-line tool. - With an agent — run the MCP server (
spectro_mcp); Claude and other agents see the same catalogue as discoverable tools. Functional parity between the two access paths is an invariant.
Install
pip install spectro-kernel # core library + CLI
pip install spectro-kernel[catalogs] # + SIMBAD / VizieR queries
pip install spectro-kernel[mcp] # + MCP server
pip install spectro-kernel[all] # everything
From source (recommended for development):
uv venv --python 3.12
uv pip install -e ".[dev,mcp]"
Quickstart — library
from spectro_kernel import WorkContext, run_algorithm
from spectro_kernel.io import read_fits
ctx = WorkContext(spectrum=read_fits("obs.fits"))
run_algorithm("normalize_polynomial", ctx, {"order": 3})
run_algorithm("snr_der", ctx)
print(ctx.metrics["snr_der"])
Or compose a pipeline:
from spectro_kernel import PipelineBuilder
pipeline = (
PipelineBuilder()
.add("normalize_polynomial", order=3)
.add("snr_der")
.add("fit_gaussian_line", line_center_angstrom=6562.8, window_angstrom=30)
.build()
)
result = pipeline.execute(ctx)
Quickstart — CLI (no AI agent needed)
spectro list # discover the catalogue
spectro describe fit_gaussian_line # see params, inputs, outputs
spectro run snr_der --input obs.fits # run one algorithm
spectro pipeline balmer_quick --input obs.fits # run a preset pipeline
Quickstart — MCP server (for AI agents)
Local-first. After pip install "spectro-kernel[mcp]", point Claude Desktop at
the binary — no server to run, no URL, no API key:
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
{
"mcpServers": {
"spectro": { "command": "spectro-mcp" }
}
}
Restart Claude Desktop — every catalogue algorithm appears as a tool, plus the
transverse ones (list_algorithms, describe_algorithm, get_algorithm_source,
run_preset, …).
Cloud option. For claude.ai (web), shared access, or non-Python users:
deploy the same spectro-mcp in HTTP mode on any container host (DigitalOcean
App Platform, Fly.io, etc.). Local-stdio remains the recommended default.
In --http mode the server refuses local filesystem paths, fetches URLs
through an SSRF guard (no private addresses, no redirects, size and time
caps), caps sessions and memory, and rate-limits clients. Two postures :
- Open (the public demo server) :
SPECTRO_MCP_ALLOW_ANONYMOUS=1. No accounts, no key ; anyone addshttps://<host>/mcpas a connector. - Closed :
SPECTRO_MCP_API_KEY=<secret>; clients send it in theX-API-Keyheader (or?api_key=withSPECTRO_MCP_ALLOW_KEY_IN_URL=1).
The server refuses to start in --http mode with neither. Configuration is
by environment variable (none of these affect stdio mode) :
| Variable | Default | Meaning |
|---|---|---|
SPECTRO_MCP_API_KEY |
unset | Closed posture : shared secret clients send in the X-API-Key header. |
SPECTRO_MCP_ALLOW_ANONYMOUS |
unset | Open posture : 1 to start without a key (explicit opt-in). |
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 request 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 for the client IP. |
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 |
Cap on live in-memory sessions; the least recently used one is evicted. |
SPECTRO_MCP_MAX_PIXELS |
32000000 |
Refuse downloaded FITS files with more data elements than this (256 MB as float64); 0 disables. |
SPECTRO_MCP_DOWNLOAD_BUDGET_S |
120 |
Wall-clock budget for one URL download (on top of the 256 MiB cap). |
SPECTRO_MCP_MAX_CONCURRENT_DOWNLOADS |
4 |
Downloads allowed in flight at once. |
SPECTRO_EMBED_ENDPOINT_ALLOW |
unset | Comma-separated hosts embed_remote may call with the server-side SPECTRO_EMBED_API_KEY (and bypass the SSRF guard for, e.g. an internal inference service). |
SPECTRO_MCP_REDIS_URL, SPECTRO_MCP_SESSION_SECRET |
unset | Redis-backed sessions for multi-instance deployments (payloads are HMAC-signed with the secret). |
SPECTRO_MCP_S3_BUCKET, SPECTRO_MCP_S3_ENDPOINT, … |
unset | Presigned-URL uploads (request_upload_url). |
SENTRY_DSN |
unset | Error reporting. |
Architecture
spectro_kernel/ importable Python package — the catalogue
types/ Spectrum1D, WorkContext, ProcessingStep, ...
registry.py @register_algorithm + discovery API
base.py BaseAlgorithm + AlgorithmOutput
pipeline.py Pipeline + PipelineBuilder
io/ FITS / ASCII readers and writers
algorithms/ the catalogue, one file per algorithm
presets/ YAML pipeline recipes
cli.py the `spectro` command
spectro_mcp/ MCP server wrapping the same catalogue
Add an algorithm = one Python file + one test. No change to the core. See CONTRIBUTING.md.
Documentation
The full documentation site (built with MkDocs Material) lives in docs/ and covers: Why spectro-kernel? (what it adds on top of astropy/specutils), the concepts with diagrams, a guide per access path, tutorials, and an algorithm catalogue generated from the registry. Build it locally with:
uv pip install -e ".[docs,all]"
python tools/docs/generate.py && zensical serve # live preview at http://127.0.0.1:8000
Every algorithm declares its provenance — a backend (the library it leans on) and
literature references — visible in spectro describe <name> and in the docs.
Repository layout
Two things in this repo are documentation-facing; do not confuse them:
| Path | What it is | Tracked? |
|---|---|---|
src/spectro_kernel/, src/spectro_mcp/ |
The Python packages — the actual product. | yes |
tests/ |
The test suite. | yes |
docs/ |
The documentation — MkDocs Material source (Markdown). The technical site: concepts, guides, tutorials, API reference. | yes |
website/ |
The public landing page — a standalone React + Vite app, deployable to Netlify. Separate from docs/; see website/README.md. |
yes |
site/, website/dist/, website/node_modules/ |
Generated build output / dependencies. Build cruft — git-ignored, never edited by hand. | no |
In short: edit docs/ for documentation, edit website/ for the landing page,
ignore site/.
Status
v0.1.0 — alpha. API unstable until v1.0.0. See CHANGELOG.md for
release notes.
License
MIT — see LICENSE.
Release files for spectro-kernel 0.6.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spectro_kernel-0.6.2.tar.gz | 2.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spectro_kernel-0.6.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:2.9 MB
Release files / spectro_kernel-0.6.2.tar.gz
| Download URL | spectro_kernel-0.6.2.tar.gz |
|---|---|
| Size | 2.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0b7597dcaebf966e419bcfe4790607f6bddb570eb680d53c54a67602df5ef7e
|
|
BLAKE2b-256 checksum How to use checksums |
f499b754f471ae0dc63bbf8e462c164c8fda31d2cf3dd75dcf4840d4f4768427
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency logRelease files / spectro_kernel-0.6.2-py3-none-any.whl
| Download URL | spectro_kernel-0.6.2-py3-none-any.whl |
|---|---|
| Size | 400.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bdd0e920ed427b862112f99f42741ed8a0e1ac1a7c9606e62d41f87b27b19dd5
|
|
BLAKE2b-256 checksum How to use checksums |
0057ee9bd6de07b0897118aa26ed4135f640cdb582a62ec4c2214790f1e1b12d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log