---
title: "Deploying remote MCP servers and publishing to registries"
description: "From local to remote Remote servers let many users and clients share one governed integration. A production remote server needs: HTTPS, OAuth (lesson…"
url: https://optimizeall.com/learn/model-context-protocol-mcp/remote-deployment-and-registries
updated: 2026-10-05
---

Model Context Protocol (MCP): Connect AI to Your Tools and Data · MCP in production · lesson 14 of 18 · 15 min

# Deploying remote MCP servers and publishing to registries

## From local to remote

Remote servers let many users and clients share one governed integration. A production remote server needs: HTTPS, OAuth (lesson 11), a stateless deployment that scales horizontally, observability, rate limiting, versioning and a documented support model.

## Deployment targets

| Target | Why it fits MCP | Notes |
|---|---|---|
| Container platforms (Cloud Run, AWS ECS/Fargate, Azure Container Apps, Kubernetes) | Long-lived HTTP services, easy scaling | Standard choice for most teams |
| Serverless functions | Stateless 2026-07-28 servers fit well | Watch cold starts and timeouts for long tools; use tasks for long work |
| Edge runtimes (e.g., Cloudflare Workers, Deno, Bun) | TypeScript v2 handler is web-standard `fetch` | Check library compatibility |
| API gateways / MCP gateways | Central auth, rate limits, logging across many servers | Increasingly common in enterprises |

## Production checklist for a remote server

- **TLS everywhere**; HSTS on custom domains.
- **Auth**: Protected Resource Metadata, audience validation, scopes per tool.
- **Statelessness**: no in-memory session state; explicit handles for multi-step flows; shared state in a database or cache.
- **Idempotent writes** with client-supplied keys (broken streams are re-issued, not resumed).
- **Timeouts and limits**: per-tool timeouts, payload limits, result size caps, pagination.
- **Rate limiting** per user and per tool, using `Mcp-Method` / `Mcp-Name` headers at the gateway.
- **Caching hints**: `ttlMs` and `cacheScope` on list results; deterministic tool order.
- **Observability**: OpenTelemetry traces (the spec documents propagating `traceparent` via `_meta`), structured logs without tokens or personal data, metrics per tool.
- **Versioning**: semantic versions for your server; a changelog for tool changes; deprecate tools gracefully.
- **Backwards compatibility**: serve 2025-era clients during the transition (official v2 SDKs can serve both from the same code).

## Serving both protocol eras

The TypeScript v2 `createMcpHandler` serves 2025-era clients statelessly from the same factory by default; the Python v2 SDK similarly supports every protocol revision. Test with at least one older client (for example an older IDE build) and one current host before announcing an upgrade.

## Registries and discovery

The official **MCP Registry** (currently in preview) is a metadata catalog for **publicly accessible** servers: it stores a `server.json` describing where to get or reach your server (npm, PyPI, Docker packages, or remote URLs), how to run it, and descriptive metadata. It supports namespace verification (for example `io.github.username/…` via GitHub login, or your own domain via DNS). It is intended mainly for downstream aggregators and marketplaces rather than direct consumption by hosts, and it does not host private servers. For internal servers, run a **private registry** or catalog (the registry defines an OpenAPI spec other registries can implement) or use your host platform's admin-managed connector list.

A remote entry looks like:

```json
{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "com.example/acme-analytics",
  "title": "ACME Analytics",
  "description": "Read-only marketing analytics for ACME clients",
  "version": "2.0.0",
  "remotes": [{"type": "streamable-http", "url": "https://mcp.acme.example/mcp"}]
}
```

Publishing uses the `mcp-publisher` CLI (`mcp-publisher init`, `mcp-publisher login github` or DNS-based login, `mcp-publisher publish`). Check the registry docs for the current schema version and namespace rules.

## Worked example: a SaaS vendor in Dubai launches an MCP integration

A Dubai-based social-media scheduling SaaS wants customers to use it from Claude, ChatGPT and IDE agents.

1. Builds a TypeScript v2 server with 8 workflow-oriented tools (draft post, schedule post, list calendar, best-time suggestions, analytics summary, and so on).
2. Deploys on a container platform behind an API gateway, with OAuth via its existing identity service, CIMD support and scopes `posts:read`, `posts:write`, `analytics:read`.
3. Tools that publish content require `posts:write` via step-up and carry `destructiveHint`.
4. Publishes `server.json` with its domain namespace and a `streamable-http` remote.
5. Writes a public "Connect to Claude/ChatGPT/VS Code" guide, a changelog and a security page (data retention, scopes, contact).
6. Monitors adoption per client type and errors per tool.

## Hands-on: containerize a Python server

```dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install --no-cache-dir uv && uv sync --frozen --no-dev
COPY server.py ./
ENV PORT=8080
# Bind to all interfaces inside the container; the platform's load balancer terminates TLS.
CMD ["uv", "run", "python", "-c", "import server, os; server.mcp.run(transport='streamable-http', host='0.0.0.0', port=int(os.environ['PORT']))"]
```

Binding to `0.0.0.0` is appropriate inside a container behind a load balancer; for local development keep `127.0.0.1`. Put authentication in front (SDK auth settings or gateway), never expose an unauthenticated write-capable server publicly. For TypeScript, mount `createMcpHandler` with `createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['mcp.example.com'] })` so Host validation still applies.

## Pitfalls

- In-memory state that breaks with more than one replica.
- Publishing a server to a public registry without auth, rate limits or a security page.
- Breaking tool changes without versioning or notice.
- Forgetting older clients during the protocol transition.

## Measuring success

Availability and p95 latency per tool, error rates by client type and protocol version, adoption (active users per host), and time to roll back a bad release.

## Video lecture: Deploying remote MCP servers and publishing to registries

Lecture coming soon · 15 chapters · about 9 minutes. Read the full transcript below.

1. Remote deployment and registries
2. Why remote changes things
3. Deployment targets
4. Production checklist
5. Serve both protocol eras
6. Simple example: the vanishing draft
7. The MCP Registry
8. Example: Dubai SaaS integration
9. Hands-on: containerize
10. Pitfalls and metrics
11. Public listing and security
12. Deeper: the SaaS launch (illustrative)
13. Watch me do it: container + server.json
14. Try this now
15. Recap

## Lecture transcript

### Remote deployment and registries

A server on your laptop helps you. A remote server helps your whole company, or your customers. In this lesson you'll learn how to deploy remote MCP servers properly, serve both old and new protocol clients, and publish to registries so people can find you.

### Why remote changes things

Why does remote deployment change everything? Because the moment your server has a URL, it stops being your tool and becomes a service. Other people depend on it, attackers can find it, and it needs to stay up while you sleep. Think of the difference between cooking dinner at home and running a food stall at a festival. Same recipes, but now you need hygiene certificates, a queue, enough stock, and a plan for when it rains. That's the production checklist in this lesson.

### Deployment targets

Where should it run? Container platforms like Cloud Run, AWS Fargate, Azure Container Apps or Kubernetes are the standard choice. Serverless functions suit stateless servers well, but watch cold starts and timeouts, and use the tasks extension for long work. Edge runtimes work nicely with the TypeScript handler, which is a standard fetch function. And many enterprises put an MCP gateway in front of all their servers for central auth, rate limits and logging.

### Production checklist

Here's the production checklist. TLS everywhere. OAuth with metadata, audience checks and scopes per tool. No in memory session state, with explicit handles for multi step flows and shared state in a database. Idempotent writes, because broken streams get re issued, not resumed. Timeouts, payload limits, result caps and pagination. Rate limiting per user and per tool at the gateway, using the method and name headers. Cache hints and deterministic tool order. Tracing with OpenTelemetry and clean logs. And versioning with a changelog.

### Serve both protocol eras

During the protocol transition, serve both eras. The TypeScript version two handler serves older clients statelessly from the same factory by default, and the Python version two SDK supports every revision. Before announcing an upgrade, test with at least one older client and one current host. Your users won't all upgrade on the same day.

### Simple example: the vanishing draft

A simple example of why statelessness matters. You deploy one copy of your server, and a multi step flow stores a draft in memory between two tool calls. It works perfectly. Then traffic grows and you scale to three copies. Now the second call often lands on a different copy that has never seen the draft, and users get, draft not found. The fix: store the draft in a database and return a draft id that the model passes to the next tool. Any copy can then continue the flow.

### The MCP Registry

Now discovery. The official MCP Registry, currently in preview, is a metadata catalog for publicly accessible servers. You publish a server dot json file describing where to get or reach your server, like an npm or PyPI package or a remote URL, how to run it, and a description. Namespaces are verified through GitHub or your own domain. The registry is mainly consumed by marketplaces and aggregators, not directly by hosts, and it doesn't list private servers. For internal servers, run a private catalog or use your platform's admin managed connector list.

### Example: Dubai SaaS integration

A worked example. A social media scheduling company in Dubai wants customers to use it from Claude, ChatGPT and IDE agents. It builds a TypeScript server with eight workflow tools, deploys it behind an API gateway with OAuth through its existing identity service and three scopes, requires step up for publishing posts, publishes a server dot json under its own domain, and writes a public connection guide, a changelog and a security page. Then it monitors adoption by client and errors by tool.

### Hands-on: containerize

The hands on section containerizes a Python server. Inside a container behind a load balancer, binding to all interfaces is appropriate. For local development, keep it on the loopback address. Put authentication in front, either the SDK's auth settings or your gateway, and never expose an unauthenticated server that can write data. For TypeScript, the Express helper still validates host headers when you bind publicly, as long as you list your allowed hosts.

### Pitfalls and metrics

Avoid four pitfalls: in memory state that breaks with more than one replica, publishing to a public registry without auth, rate limits or a security page, breaking tool changes without versioning or notice, and forgetting older clients during the transition. Measure availability and latency per tool, error rates by client type and protocol version, active users per host, and how fast you can roll back.

### Public listing and security

A common worry: will publishing to the public registry expose my server to attackers? The registry lists metadata, but a public server is discoverable anyway once people use it. What protects you is the same as for any public API: strong authentication, least privilege scopes, rate limits, input validation, monitoring and a security contact. Publishing responsibly means having those in place first, plus clear documentation of what data your server touches.

### Deeper: the SaaS launch (illustrative)

Let's deepen the Dubai SaaS vendor's launch. In the first quarter after listing its server, illustrative figures, a large share of new connections came from Claude and ChatGPT users, with a smaller share from IDE agents. Errors clustered on one tool, best time suggestions, which timed out for customers with years of history; the team added pagination and a task based path for large accounts. Their security page answered the most common procurement questions, so enterprise deals stopped stalling on questionnaires. And because the server was stateless, a traffic spike after a product announcement just meant the platform added replicas automatically.

### Watch me do it: container + server.json

Watch me do it. Let's walk through the Dockerfile and a server dot json. The image starts from Python three twelve slim, copies the project and lock file, installs uv and syncs dependencies without dev packages, then copies the server. The command imports the server module and runs Streamable HTTP on all interfaces inside the container, using the port from the environment. I build it, run two containers behind a local load balancer, and send the same multi step flow twice: it succeeds regardless of which container answers, because state lives in the database. Now the registry metadata: server dot json has the schema link, a reverse domain name, a title, a description, a version and a remotes entry of type streamable http with the public URL. With mcp publisher, I log in with GitHub or my domain and publish. For an internal server, I'd put the same metadata in our private catalog instead.

### Try this now

Try this now. Containerize your server with the Dockerfile pattern from the lesson and deploy it to a staging environment with authentication in front. Run two replicas. Test with a current host and, if you can, an older client that speaks an earlier protocol version. Then draft a server dot json file with your server's name, description, version and remote URL, and decide whether it belongs in the public registry or your organization's private catalog.

### Recap

To recap: deploy remote servers statelessly with TLS, OAuth, limits and observability; serve both protocol eras; version your tools; and publish to the right catalog, public or private. Your next step: containerize your server, deploy it to staging with auth in front, test with an older and a current client, and draft its server dot json.

## Key takeaways

- Remote servers need TLS, OAuth, statelessness, idempotent writes, limits, rate limiting and observability.
- 2026-07-28 servers scale horizontally; route and meter with Mcp-Method and Mcp-Name headers at gateways.
- Serve both protocol eras during the transition; official v2 SDKs support older clients.
- The official MCP Registry (preview) catalogs publicly accessible servers via server.json; use private catalogs for internal ones.
- Version tools, publish changelogs and never expose unauthenticated write-capable servers.

## Try it

Containerize your server, deploy it to a staging environment with auth in front, test it with an older and a current client, and draft a server.json (public or private catalog).

- [Previous: Testing and debugging MCP servers with the Inspector and automated tests](https://optimizeall.com/learn/model-context-protocol-mcp/testing-and-debugging-mcp-servers)
- [Next: Rolling out MCP across an organization](https://optimizeall.com/learn/model-context-protocol-mcp/enterprise-mcp-rollout)
- [All lessons of Model Context Protocol (MCP): Connect AI to Your Tools and Data](https://optimizeall.com/learn/model-context-protocol-mcp)
