Skip to main content
Glama

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.


Related MCP server: NASA-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

  1. Go to https://api.nasa.gov/ and fill in the short form (name + email).

  2. 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_KEY environment variable. Locally that's an export; 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 and server.py reads 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:

  1. Require a bearer token — add a check in the server for a shared secret in the Authorization header, and supply that header from the client.

  2. Keep the service private (drop --allow-unauthenticated) and require Google IAM auth, putting an authenticating proxy in front for Claude.

  3. 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=True and json_response=True are 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_get helper, 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.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rudylimxl/nasa_test_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server