Skip to main content
Glama
CamiR24

academic-remote-mcp

by CamiR24
README.md
# Academic Remote MCP Server

A minimal MCP (Model Context Protocol) server, deployed remotely on
**Google Cloud Run**, providing a single tool: random study tips.

Built for **CC3067 Redes, Project 1** (Universidad del Valle de Guatemala) —
functional requirement #7 (remote MCP server). Per the assignment
instructions, this server's functionality is intentionally trivial; what
matters is that it runs remotely and is reachable over the network.

## Tool exposed

| Tool | Parameters | Returns |
|---|---|---|
| `get_random_study_tip` | none | A random study tip (string) |

### Example

Request:
```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_random_study_tip","arguments":{}}}
```

Response:
```json
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"Prioriza entender antes de memorizar: lo que comprendes se te olvida menos."}]}}
```

## Architecture

```
Chatbot (local)
      │
      │ HTTPS (Streamable HTTP, stateless)
      ▼
   Internet
      │
      ▼
Google Cloud Run
      │
      ▼
FastMCP server (get_random_study_tip)
```

The server runs in **stateless HTTP mode** (`stateless_http=True`). This
is a deliberate design choice: Cloud Run can scale to multiple container
instances, and each instance keeps MCP sessions in its own memory. In
stateful mode, a follow-up request routed to a different instance than
the one that opened the session would fail with a "session not found"
error. Since this server's tool needs no session state at all, running
stateless avoids that failure mode entirely.

## Requirements

- Python 3.12+
- Docker (for local testing and for building the Cloud Run image)
- A Google Cloud project with the Cloud Run and Cloud Build APIs enabled

## Installation (local)

```bash
git clone <this-repository-url>
cd academic-remote-mcp

python3 -m venv venv
source venv/bin/activate      # on Windows: venv\Scripts\activate

pip install -r requirements.txt
```

## Running locally

```bash
export PORT=8080
python src/server.py
```

Or with Docker (recommended, matches the production environment exactly):

```bash
docker build -t academic-remote-mcp .
docker run -p 8080:8080 -e PORT=8080 academic-remote-mcp
```

Test the handshake:

```bash
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
```

## Deployment (Google Cloud Run)

```bash
gcloud run deploy academic-remote-mcp \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --port 8080
```

Cloud Run automatically injects the `PORT` environment variable; the
server reads it at startup rather than hardcoding a port.

**Deployed endpoint:**
`https://academic-remote-mcp-842046673187.us-central1.run.app/mcp`

## Connecting from an MCP host

Using the official `mcp` Python SDK's Streamable HTTP client:

```python
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client(
    "https://academic-remote-mcp-842046673187.us-central1.run.app/mcp"
) as (read, write, _):
    async with ClientSession(read, write) as session:
        await session.initialize()
        result = await session.call_tool("get_random_study_tip", {})
```

## Project Structure

```
academic-remote-mcp/
├── src/
│   └── server.py
├── Dockerfile
├── requirements.txt
└── README.md
```

## A note on the `mcp` SDK version

This server uses `mcp.server.fastmcp.FastMCP` (the `mcp` 1.x API),
pinned via `requirements.txt` (`mcp==1.29.1`) to stay consistent with the
other repositories in this project. The SDK's 2.x release renamed
`FastMCP` to `MCPServer` and moved `host`/`port` from the constructor to
`.run()`; if upgrading, adjust `src/server.py` accordingly.

## License

MIT.