Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,19 @@ RUN m3 init mimic-iv-demo

# Lite: SQLite only
FROM base AS lite
ENV MCP_TRANSPORT=http \
MCP_HOST=0.0.0.0 \
MCP_PORT=3000 \
MCP_PATH=/sse
EXPOSE 3000
CMD ["python", "-m", "m3.mcp_server"]

# BigQuery: add GCP client
FROM base AS bigquery
RUN pip install --no-cache-dir google-cloud-bigquery
ENV MCP_TRANSPORT=http \
MCP_HOST=0.0.0.0 \
MCP_PORT=3000 \
MCP_PATH=/sse
EXPOSE 3000
CMD ["python", "-m", "m3.mcp_server"]
58 changes: 58 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Makefile for M3 Docker Image Build and Push
DOCKER ?= docker
IMAGE_NAME := m3-mimic-demo
IMAGE_TAG ?= 0.4.0

# Prompt for registry only if not set
ifndef DOCKER_REGISTRY
DOCKER_REGISTRY := $(shell bash -c 'read -p "Enter Docker registry/username: " registry; echo $${registry}')
endif

DOCKER_IMAGE := $(DOCKER_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)

DB_FILE := m3_data/databases/mimic_iv_demo.db

.PHONY: help
help: ## Show help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'

.PHONY: all
all: download-db build push ## Complete workflow: download DB, build and push

.PHONY: login
login: ## Login to Docker Hub
@$(DOCKER) login docker.io

.PHONY: download-db
download-db: ## Download MIMIC-IV demo database
@uv sync
@uv run m3 init mimic-iv-demo

.PHONY: build
build: ## Build Docker image (lite version)
@test -f $(DB_FILE) || { echo "Run 'make download-db' first"; exit 1; }
@$(DOCKER) build --target lite -t $(DOCKER_IMAGE) -t $(DOCKER_REGISTRY)/$(IMAGE_NAME):lite .

.PHONY: build-bigquery
build-bigquery: ## Build BigQuery version
@test -f $(DB_FILE) || { echo "Run 'make download-db' first"; exit 1; }
@$(DOCKER) build --target bigquery -t $(DOCKER_REGISTRY)/$(IMAGE_NAME):bigquery .

.PHONY: push
push: ## Push Docker image to registry (run 'make login' first)
@$(DOCKER) push $(DOCKER_IMAGE)
@$(DOCKER) push $(DOCKER_REGISTRY)/$(IMAGE_NAME):lite

.PHONY: push-bigquery
push-bigquery: ## Push BigQuery image (run 'make login' first)
@$(DOCKER) push $(DOCKER_REGISTRY)/$(IMAGE_NAME):bigquery

.PHONY: test-image
test-image: ## Test the built Docker image
@$(DOCKER) run --rm $(DOCKER_IMAGE) python -c "import m3; print(f'M3 version: {m3.__version__}')"

.PHONY: clean
clean: ## Remove database and raw files
@rm -rf m3_data

.DEFAULT_GOAL := help
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,23 @@ m3-mcp-server
- 🔐 **Enhanced Security**: Role-based access control, audit logging
- 🌐 **Multi-tenant Support**: Organization-level data isolation

## Contributing
## 🐳 Kubernetes Deployment

Deploy M3 on Kubernetes using Docker images with pre-loaded MIMIC-IV demo database:

```bash
# Build and push Docker image
make all # Will prompt for Docker registry/username

# Or specify registry directly
make all DOCKER_REGISTRY=your-username DOCKER=podman
```

The container uses StreamableHTTP transport on port 3000 with path `/sse`. Configure your MCP client to connect to the service endpoint (e.g., `http://m3.kagent.svc.cluster.local:3000/sse` for intra-cluster access).

Helm charts for deploying M3 are available in a separate repository.

## 🤝 Contributing

We welcome contributions! Please:

Expand Down
27 changes: 24 additions & 3 deletions src/m3/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,9 +682,30 @@ def get_race_distribution(limit: int = 10) -> str:


def main():
"""Main entry point for MCP server."""
# Run the FastMCP server
mcp.run()
"""Main entry point for MCP server.

Runs FastMCP server in either STDIO mode (desktop clients) or HTTP mode
(Kubernetes/web clients). Transport mode configured via environment variables.

Environment Variables:
MCP_TRANSPORT: "stdio" (default), "sse", or "http"
MCP_HOST: Host binding for HTTP mode (default: "0.0.0.0")
MCP_PORT: Port for HTTP mode (default: 3000)
MCP_PATH: SSE endpoint path for HTTP mode (default: "/sse")

Notes:
HTTP/SSE mode uses streamable-http transport for containerized deployments
where STDIO is unavailable. Binds to 0.0.0.0 for Kubernetes service mesh access.
"""
transport = os.getenv("MCP_TRANSPORT", "stdio").lower()

if transport in ("sse", "http"):
host = os.getenv("MCP_HOST", "0.0.0.0")
port = int(os.getenv("MCP_PORT", "3000"))
path = os.getenv("MCP_PATH", "/sse")
mcp.run(transport="streamable-http", host=host, port=port, path=path)
else:
mcp.run()


if __name__ == "__main__":
Expand Down