NORA Data MCP Server
by allanhale
README.md
# NORA Data MCP Server
Read-only MCP server that exposes NORA Dashboard data from Upstash Redis.
## Prerequisites
- Python 3.10+ (the `mcp` package requires it)
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
## Setup
1. Copy `.env.example` to `.env` and fill in the Upstash Redis credentials:
```
cp .env.example .env
```
2. Install dependencies:
```bash
# With uv (recommended — handles Python version automatically):
uv sync
# Or with pip:
pip install -e .
```
## Running Locally (stdio transport)
```bash
# With uv:
uv run python server.py
# Or directly:
python server.py
```
### Claude Desktop Configuration
Add to your Claude Desktop MCP config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"nora-data": {
"command": "uv",
"args": ["run", "--directory", "/Users/ahale/nora-mcp-server", "python", "server.py"],
"env": {
"KV_REST_API_URL": "https://your-redis-instance.upstash.io",
"KV_REST_API_READ_ONLY_TOKEN": "your-read-only-token"
}
}
}
}
```
### Claude Code Configuration
Add to your Claude Code MCP settings:
```json
{
"mcpServers": {
"nora-data": {
"command": "uv",
"args": ["run", "--directory", "/Users/ahale/nora-mcp-server", "python", "server.py"],
"env": {
"KV_REST_API_URL": "https://your-redis-instance.upstash.io",
"KV_REST_API_READ_ONLY_TOKEN": "your-read-only-token"
}
}
}
}
```
## Remote Deployment (Hosted Mode)
The server supports `streamable-http` transport for remote access. When deployed, team members can connect to it without running anything locally.
### Deploy to Railway
1. Push this repo to GitHub
2. Create a new project on [Railway](https://railway.app)
3. Connect the GitHub repo
4. Add environment variables in Railway dashboard:
- `KV_REST_API_URL` — your Upstash Redis URL
- `KV_REST_API_READ_ONLY_TOKEN` — your read-only token
- `MCP_TRANSPORT` — `streamable-http` (set automatically via Dockerfile)
- `PORT` — Railway sets this automatically
5. Deploy — Railway will build from the Dockerfile
### Docker Build & Run
```bash
docker build -t nora-mcp-server .
docker run -p 8000:8000 \
-e KV_REST_API_URL="https://your-redis-instance.upstash.io" \
-e KV_REST_API_READ_ONLY_TOKEN="your-read-only-token" \
nora-mcp-server
```
### Connecting via Cowork / Claude Code (Remote)
Once deployed, team members add the remote MCP server in their project settings:
```json
{
"mcpServers": {
"nora-data": {
"type": "url",
"url": "https://your-deployed-url.up.railway.app/mcp/"
}
}
}
```
The streamable-http transport serves the MCP endpoint at `/mcp/` by default.
### Security Note
The server is read-only (it only reads from Upstash Redis with a read-only token). Authentication is not currently implemented — access control relies on URL obscurity and hosting platform network settings. Add bearer token auth if the server is exposed to the public internet.
## Available Tools
| Tool | Description |
|------|-------------|
| `get_data_status` | Health check — record counts for all tables |
| `get_okrs` | Full OKR tree (objectives + key results + linked initiatives) |
| `get_key_results` | Key results (optional filter: `objective_id`) |
| `get_initiatives` | Initiatives (optional filters: `key_result_id`, `bu_id`) |
| `get_okr_initiative_links` | OKR-to-initiative link records |
| `get_flags` | WBR flags/risks (optional filter: `status`) |
| `get_bu_portfolio` | Business unit portfolio overview |
| `get_kpis` | KPI metrics (optional filter: `initiative_id`) |
| `get_financial_summary` | Financial summary (optional filter: `bu_id`) |
| `get_northstar_metrics` | North Star metrics (optional filter: `bu_id`) |
| `get_business_units` | All business units |
## Architecture
- **Transport**: stdio (local) or streamable-http (hosted)
- **Data source**: Upstash Redis REST API (read-only token)
- **Redis key pattern**: `prod:table:{name}.json`
- **Caching**: Per-request cache (tables fetched once per tool call, not persisted)
- **Error handling**: All tools return JSON; errors are returned as `{"error": "..."}`, never thrown