rosetta-mcp
Allows searching, reading, and drafting emails (no send/delete) with attachment transcription.
Integrates with Google services for Gmail (search, read, draft) and Google Calendar (list, create, update) via server-side credential storage.
Provides access to Google Maps services including Routes, Places, and Weather data.
Provides access to SNCF (French national railway) transit information.
Click on "Install 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., "@rosetta-mcpfind the next train from Paris to Lyon"
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.
rosetta-mcp
Rosetta is a modular MCP hub: one HTTP service hosting many thin, read-only MCP servers (addons), each mounted under its own path, behind a single OIDC bearer-token authentication layer.
Like the stone: one endpoint, and every agent reads it in its own tongue.
agent ──Bearer JWT──► https://rosetta.example.com/maps/ (Google Maps, Places, Weather)
https://rosetta.example.com/meteo/ (Open-Meteo, wind for sailing)
https://rosetta.example.com/transit/ (SNCF + IDFM/Navitia)
https://rosetta.example.com/<addon>/ (drop a module in, it mounts)
https://rosetta.example.com/health (unauthenticated, per-addon state)Why a hub: provider API keys stay server-side (one deployment, one place to rotate), agents only ever hold an access token, and adding MCP #12 is a new module + nothing else - no new pod, no new image elsewhere, no key sprayed into agent environments.
Addons
An addon is a module in src/rosetta/addons/ exposing:
from ._common import new_server
mcp = new_server("name") # FastMCP: stateless streamable HTTP at "/"
required_env = ["SOME_API_KEY"] # optionalThe loader mounts each addon under /<module-name> and isolates failures:
Addon state | Meaning |
| mounted, fully operational |
| mounted, but some |
| import/startup failed - addon skipped, hub and other addons stay up |
| excluded by |
Per-addon state is reported on GET /health. Modules starting with _ are
shared helpers, never mounted. Each addon also runs standalone over stdio for
local debugging (python -m rosetta.addons.maps).
User-data addons (identity = "user")
An addon may declare identity = "user": the hub then refuses machine tokens
on its path (403) - the bearer token must carry a human subject. Tools read
the caller's claims via a context variable, so a user-data addon keys its
server-side credential store on sub: agents never hold the downstream
credentials, only their own identity token. Such addons may also register plain
HTTP routes (extra_routes / open_paths) for browser-facing enrolment flows,
guarded by the ingress SSO (forwardAuth) instead of the hub JWT.
Bundled addons: maps (Google Routes / Places New / Weather - needs
GOOGLE_MAPS_API_KEY; the three weather tools - current, daily and
hour-by-hour - all report wind with its gust and a bearing in degrees plus
a French 16-point cardinal derived from them, never Google's cardinal enum.
weather_hourly stops at 24 h because the upstream pageSize caps there, and
one page is enough to answer when the rain starts), transit (SNCF + IDFM Navitia - needs SNCF_API_KEY,
IDFM_API_KEY), google (user-data class: Gmail search / read / attachment +
drafts only - list, read, create (standalone or as a reply, where the server derives
thread, recipient and subject from the parent - Reply-To beating From) and amend,
each answering with a stable link
straight to the draft in the Gmail web UI (ROSETTA_GMAIL_ACCOUNT overrides the account
index when the mailbox is not the browser's first) - plus
Calendar list/create/update - deliberately no send, no delete, no labels:
the guard is the tool surface itself. Attachments come back transcribed to text
(PDF via pypdf) for reading, or as raw base64 (raw=True) for native storage. One-time per-user enrolment at
/google/enroll stores the Google refresh token server-side under
ROSETTA_GOOGLE_DATA), withings (user-data class, read-only: body
measures, daily activity, sleep summaries, workouts and the devices themselves,
enrolled once at /withings/enroll), and github (user-data class, for the
coding agent: nine read tools — repo listing, file, tree, commits, code search,
tags, Actions runs, plus pull requests (list, and one in detail with its merge
state, changed files and, on request, the patch) — and exactly three write
tools, repo_commit (create / modify / delete in one atomic commit through
the Git Data API; a null content deletes, so deletion is never a separate
capability to unlock), repo_tag, and pull_request_merge. Deliberately
absent, and that absence is the guarantee rather than a hook: repository
creation or deletion, forks, branch deletion, force-push, issues, opening /
closing / commenting / reviewing a pull request, Actions secrets, settings,
collaborators.
Two upstream behaviours shape the pull request tools. GitHub computes
mergeability asynchronously: the first read of a dormant PR answers
mergeable: null and starts a background job, so the addon re-reads rather than
handing an agent a null it would read as "not mergeable" — a silent false
negative. And a merge carries the head SHA that was just read, so a branch that
moved in between earns a 409 instead of merging something nobody looked at.
The branch is never deleted afterwards: that tool does not exist here.
Needs a GitHub App with Expire user authorization tokens enabled — without
it GitHub issues no refresh token — declaring contents: write,
metadata: read, actions: read, pull requests: read (merging itself
goes through contents: write) and, easily forgotten, workflows: write
for any commit touching .github/workflows/. Credentials via
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET, per-user tokens under
ROSETTA_GITHUB_DATA, enrolled once at /github/enroll), and food
(Open Food Facts: barcode(s) — a whole shopping basket in one call — to name,
brand, ingredients, allergens, additives, nutriments per 100 g, Nutri-Score,
NOVA and Eco-Score, plus a free-text search as a fallback. No key, no
account, no enrolment: read access is anonymous, so this addon carries no
secret and stays machine class. Open Food Facts is community-editable and no
writing tool exists here — that absence is what stops an agent publishing into
a public database on the user's behalf. Calls are rate-limited in-process
because the upstream quota, 15 product reads and 10 searches per minute, is
counted per IP — i.e. per deployment, shared with every other service
behind the same egress — and exceeding it earns a ban for all of them).
Finally meteo (Open-Meteo: hour-by-hour wind in knots - mean, gust and
gust ratio, bearing - for planning a sail. Like food it needs no key, no
account and no enrolment, so it holds no secret and stays machine class.
Two tools: wind_forecast, bounded to the spot's daylight hours and able to
run the same slot past several models, and wind_spots over a registry given
in ROSETTA_WIND_SPOTS.
Three upstream behaviours drive the design, all measured against the live API rather than read off the docs:
A model asked outside its domain vanishes from a batched response - no error, no null column, HTTP 200 - while the same model asked on its own answers an honest
400 / "No data is available for this location".The response key is suffixed by how many models survived, not by how many were asked: two requested and one returned yields the bare
wind_speed_10m, so a naive parser files one model's numbers under another's name.Past its horizon a model does the opposite and returns
nullrows.
Hence: one HTTP request per model, never a batched one, which makes the
first two impossible rather than merely handled, and nulls are dropped instead
of being read as a flat calm. Wind is requested in knots natively
(wind_speed_unit=kn) and in the spot's own zone (timezone=auto - pinning
the house zone onto a spot elsewhere pushes sunset onto the next calendar day
and collapses the daylight window). Bearings are averaged as a circular
mean, because 350° and 10° average to north, not to south. The data is
CC-BY 4.0, so every answer names its source).
Tool descriptions are intentionally in French: they are runtime UX for the French-speaking agents this hub serves, not documentation.
withings and github are the hub's single-writer components: both
rotate the refresh token on every refresh, invalidating the previous one, so
the stored credential must have exactly one writer. Refreshes are serialized
per user and the access token is cached for its full three hours - but running
two replicas would have them burn each other's token. Keep it at one.
Withings also answers HTTP 200 for its failures: the real outcome is the
status field inside the JSON body, and a measure arrives as a (value, unit)
pair where unit is a power of ten (78192, -3 = 78.192 kg).
Related MCP server: google-maps-mcp-server
Authentication
Rosetta is an OAuth 2.1 resource server. It stores no credentials and no
users: it validates JWT access tokens (RFC 9068)
issued by an external OIDC provider (tested with
Authelia >= 4.39, clients configured with
access_token_signed_response_alg != none), against the provider's JWKS.
Machine agents use the
client_credentialsgrant - no human in the loop.User-delegated access (future data-holding addons) uses
authorization_coderefresh, or the device code flow for headless bodies.
RFC 9728 protected-resource metadata is served at
/.well-known/oauth-protected-resource(and per addon), and every 401 carries theWWW-Authenticatepointer, so OAuth-aware MCP clients can discover the authorization server on their own.
Note the trailing slash: the MCP endpoint of an addon is /<name>/ - /<name>
answers with a 307 redirect.
Configuration
Env | Default | Purpose |
|
|
|
|
| OIDC issuer (token |
| external URL | required token |
|
| public URL (RFC 9728 metadata) |
|
| JWKS endpoint override |
| all discovered | comma-separated allowlist |
| - |
|
| - |
|
|
|
|
|
|
|
| - |
|
|
|
|
|
|
|
| (empty) |
|
|
| local zone used to resolve bare |
Development
python3 -m venv .venv
.venv/bin/pip install -e .[dev]
.venv/bin/pytest
ROSETTA_AUTH=off .venv/bin/uvicorn rosetta.main:app --port 8200Deployment
Published as ghcr.io/antorfr/rosetta-mcp (SemVer tags, docker-publish
workflow). Runs as a plain container: port 8200, no volume, configuration by
environment only.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
Alicense-qualityDmaintenanceA unified MCP server that provides OAuth-enabled integrations for multiple services through a single deployment. Currently supports Slack with 47 tools, with plans to expand to Gmail, Google Calendar, Notion, and 100+ other integrations.Last updated6MIT- AlicenseAqualityDmaintenanceProduction-ready MCP server for Google Maps Platform APIs, providing 11 tools for directions, places, geocoding, traffic, and road data to empower AI agents with location intelligence.Last updated114Apache 2.0
- Flicense-qualityDmaintenanceContainerized MCP server with 15 geospatial data tools exposed via HTTP API for Intercom integration.Last updated
- Flicense-qualityCmaintenanceA governed MCP server for integrating AI agents with customer data, featuring role-based access control, field redaction, and human-in-the-loop approval for secure support operations.Last updated1
Related MCP Connectors
MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration
Self-hosted federated MCP gateway: one OAuth 2.1 MCP server in front of N apps, user-level scopes.
Operator-as-agent MCP hub. 6 tools. First $5 free, then $0.001/call.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/AntorFr/rosetta-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server