ReNile-MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ReNile-MCPshow me the latest sensor readings for my greenhouse devices"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Nojo-MCP
A remote MCP server for the Nojo platform, served over
Streamable HTTP at https://nojo.ai/mcp.
It is currently an OAuth bridge only. The sign-in chain is the thing being proved; platform tools come later, on top of it.
Tools
Tool | Arguments | Returns |
| none |
|
whoami makes no upstream call. It reports what the token exchange already established, so a
successful call is a green light for the whole chain: discovery → authorize → token → exchange.
Related MCP server: Smart Irrigation MCP Server
How authentication works
This server is an OAuth resource server, never an authorization server. It issues no tokens and stores no passwords.
A client (Claude, ChatGPT, Codex) hits
/mcpwith no token and gets401plus aWWW-Authenticateheader naming/.well-known/oauth-protected-resource/mcp.That document points the client at the Nojo backend as the authorization server. The client does login, consent and PKCE there and comes back with an OAuth access token.
On each request this server exchanges that token at the backend (RFC 8693), authenticating with its own client credentials, and gets a short-lived Nojo JWT plus the user's
sub.The exchange result is cached until 30s before expiry.
The Nojo JWT never leaves the server — it is excluded from the token's repr and serialization, so it cannot reach the model or the client.
Failure modes are kept distinct on purpose:
Backend rejects the token (
400/401) →401back to the client, which re-authenticates.Backend is down or broken (
5xx, unreachable, malformed body) →500. A client must not read an outage as "your login expired" and loop through sign-in.
/.well-known/oauth-authorization-server and /oauth/* are deliberately not served here —
they belong to the backend. See MCP_APIs_Contract.md for the endpoints the backend must provide.
Proxy routing (required)
The authorization server and this server share the host nojo.ai, so the reverse proxy must split
them:
Path on | Served by |
| Backend |
| Backend |
| This server |
| This server |
If a backend catch-all swallows /.well-known/oauth-protected-resource/mcp, discovery fails with
no visible error. Check this first when a connector will not connect.
Setup
uv sync
cp src/.env.example src/.env # then fill in MCP_OAUTH_CLIENT_SECRET
uv run uvicorn src.app:app --port 8000Variable | Required | Default | Purpose |
| yes | — | Authorization server issuer, exact string, no trailing slash |
| yes | — | Public URL of this server including |
| yes | — | Backend RFC 8693 endpoint |
| yes | — | This server's confidential client id |
| yes | — | Its secret; keep out of version control |
| no |
| Bind address |
| no | empty | Host allowlist; a request for an unlisted host gets |
| no | empty | Origin allowlist |
| no |
| Set true only for multiple replicas without sticky routing |
| no |
| Token-exchange timeout |
| no |
| Shared connection pool size |
| no |
|
ALLOWED_HOSTS accepts a bare hostname and matches it on any port.
Deployment
docker build -t nojo-mcp .
docker run -p 8000:8000 --env-file src/.env nojo-mcpRuns as a non-root user with a /healthz healthcheck. Terminate TLS at the proxy and pass
--proxy-headers (already in the image's CMD); set FORWARDED_ALLOW_IPS to the proxy's network
so the app sees the real scheme and host. NOJO_RESOURCE_SERVER_URL must be the public HTTPS URL,
not the internal one — clients compare it exactly.
Connecting a client
Add https://nojo.ai/mcp as a custom connector. The client discovers the authorization server on
its own, walks the sign-in flow, and then whoami should return the signed-in user's id.
Development
uv run pytestTests use httpx.MockTransport for the backend and an ASGI transport for the server, so nothing
touches the network.
src/
app.py ASGI app; Streamable HTTP at /mcp
server.py MCP server, lifespan, /healthz
tools.py AppState and the whoami tool
core/config.py Settings
core/logging.py Logging setup
services/auth.py Token exchange and the verifier cache
services/http.py Shared httpx client
services/errors.py Error typesThis server cannot be deployed
Maintenance
Related MCP Connectors
An authenticated remote MCP server for user-owned devices and one-shot capability invocation.
Query, browse, and automate OmegaAI workspaces from any MCP client. Streamable HTTP with OAuth 2.0.
Remote MCP server for training, nutrition, wellness, and performance data with OAuth 2.0.
NOAA and ECMWF weather forecast MCP for discovery, validation, and GribStream OAuth queries.
Related MCP Servers
AlicenseNot gradedqualityDmaintenanceEnables to retrieve device information, images, media, location, thumbnails, and events from the Safie API through MCP.7MIT- AlicenseNot gradedqualityDmaintenanceExposes real-time soil sensor metrics as MCP Resources and irrigation valve controls as MCP Tools, enabling AI-driven agronomic decisions with built-in safety guardrails.Apache 2.0
- AlicenseAqualityCmaintenanceMCP server for the Withings Health API with per-user OAuth2, enabling users to securely access their own health data (measures, activity, sleep, workouts, heart rate, devices, and goals) and optionally add measurements.12Apache 2.0
- FlicenseNot gradedqualityBmaintenanceEnables read-only access to Amazfit/Zepp fitness data via the unofficial Zepp cloud API, exposing normalized health and workout metrics to MCP clients.-