nasa
MCP server that wraps three NASA public APIs (Astronomy Picture of the Day, Mars rover photos, and near-Earth objects) as tools for AI assistants.
README
NASA MCP Server
A small but complete Model Context Protocol (MCP) server you can deploy to Google Cloud Run. It wraps three of NASA's free public APIs as tools an AI assistant can call.
This is built as a learning project, so the code and these notes explain the why, not just the how.
What is an MCP server, briefly
MCP is a standard way to expose tools (callable functions), resources (readable data), and prompts (templates) to an AI model. Think of it as a web API designed specifically for LLMs. This project uses tools only.
There are two transports:
- stdio — the server runs as a local subprocess. Used by desktop apps (Claude Desktop, Cursor, IDE plugins). Not what we want here.
- streamable HTTP — the server runs as a normal web service reachable over
a URL. This is the one you use to host on Cloud Run. All MCP traffic flows
through a single endpoint at
/mcp.
Project structure
nasa-mcp-server/
├── server.py # the MCP server + 3 NASA tools
├── requirements.txt # mcp + httpx
├── Dockerfile # container image for Cloud Run
└── .dockerignore
The three tools:
| Tool | What it does |
|---|---|
get_astronomy_picture |
NASA's Astronomy Picture of the Day (optionally for a past date) |
get_mars_photos |
Photos from a Mars rover on a given Earth date |
get_near_earth_objects |
Asteroids passing near Earth in a date range |
Step 1 — Get a NASA API key
- Go to https://api.nasa.gov/ and fill in the short form (name + email).
- The key is emailed to you within a few minutes. No credit card. Registered keys allow ~1,000 requests/hour.
You can skip this at first: the code falls back to NASA's shared DEMO_KEY,
which works instantly but is heavily rate-limited (you'll see 429 errors fast).
Do not paste your key into source code or share it in chat. The server reads it from the
NASA_API_KEYenvironment variable. Locally that's anexport; on Cloud Run it's a Secret Manager secret (Step 4).
Step 2 — Run it locally
cd nasa-mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export NASA_API_KEY=your_key_here # omit to use DEMO_KEY
python server.py
The server starts on http://localhost:8080/mcp.
Step 3 — Test with the MCP Inspector
The Inspector is the official tool for poking at an MCP server by hand. With the server running, in another terminal:
npx @modelcontextprotocol/inspector
In the Inspector UI: set transport to Streamable HTTP, URL to
http://localhost:8080/mcp, connect, then open the Tools tab and run
get_astronomy_picture with no arguments. You should get back today's picture.
Step 4 — Deploy to Google Cloud Run
Prerequisites: a GCP project with billing enabled and the gcloud CLI
installed and authenticated (gcloud auth login).
# Set your project and a region close to you
gcloud config set project YOUR_PROJECT_ID
gcloud config set run/region australia-southeast1 # Sydney; pick your own
# Enable the services we need
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
secretmanager.googleapis.com
4a. Store your NASA key in Secret Manager
Never bake the key into the image. Create a secret instead:
printf '%s' 'YOUR_NASA_KEY' | gcloud secrets create nasa-api-key --data-file=-
4b. Deploy from source
gcloud builds the container from the Dockerfile and deploys it in one step:
gcloud run deploy nasa-mcp \
--source . \
--allow-unauthenticated \
--set-secrets=NASA_API_KEY=nasa-api-key:latest
When prompted to grant the runtime service account access to the secret, say
yes (or run gcloud secrets add-iam-policy-binding nasa-api-key --member="serviceAccount:$(gcloud run services describe nasa-mcp --format='value(spec.template.spec.serviceAccountName)')" --role="roles/secretmanager.secretAccessor").
Notes:
- You do not set
PORT— Cloud Run injects it andserver.pyreads it. - On success you get a URL like
https://nasa-mcp-xxxxxxxx.run.app. Your MCP endpoint is that URL plus/mcp.
Quick check it's alive:
curl -X POST https://nasa-mcp-xxxxxxxx.run.app/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
A JSON response with "serverInfo":{"name":"nasa",...} means you're live.
Step 5 — Connect it to Claude
Point the MCP Inspector at your live https://.../mcp URL first to confirm the
tools work remotely. To use it in Claude, add it as a custom connector in
Claude's settings (Settings → Connectors), pasting your /mcp URL. The exact
menu wording changes over time — see the current connector docs at
https://support.claude.com. Then ask Claude something like "what's NASA's
astronomy picture of the day?" and it will call your tool.
⚠️ About --allow-unauthenticated
The deploy command above makes your server publicly reachable by anyone with the URL. For a learning project that's fine, but be aware: strangers could call it and burn through your NASA rate limit. Before relying on it, lock it down. Reasonable next steps, easiest first:
- Require a bearer token — add a check in the server for a shared secret in
the
Authorizationheader, and supply that header from the client. - Keep the service private (drop
--allow-unauthenticated) and require Google IAM auth, putting an authenticating proxy in front for Claude. - Full OAuth 2.1, which the MCP spec defines for remote servers. FastMCP has helpers for this — it's the "proper" answer but the most work.
How the code maps to MCP concepts
FastMCP(name="nasa", ...)creates the server.stateless_http=Trueandjson_response=Trueare the recommended settings for a scalable HTTP deployment — Cloud Run may run several container instances, and stateless mode means none of them rely on in-memory session state.- Each
@mcp.tool()function becomes a callable tool. The docstring is the description the model sees, and the type hints become the input schema — so writing clear docstrings and precise types is the single highest-leverage thing you can do for tool quality. mcp.run(transport="streamable-http")serves everything at/mcp.
Ideas to extend it
- Add a tool for NASA's EPIC (full-disc Earth imagery) or EONET (natural-event
tracking) endpoints — same
_nasa_gethelper, new path. - Swap NASA for a different free API (weather, exchange rates, etc.) — only the tool bodies change; the server scaffolding and deployment stay identical.
- Add an MCP resource (read-only data) alongside the tools.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.