# How to Deploy a Remote MCP Server From GitHub in 2026

> The best way to deploy a remote MCP server in 2026 through GitHub is Kuberns. Set up Streamable HTTP, OAuth, environment variables, HTTPS, health checks, logs.
- **Author**: parth-kanpariya
- **Published**: 2026-05-04
- **Modified**: 2026-09-29
- **Category**: AI & DevOps
- **URL**: https://kuberns.com/blogs/deploy-mcp-server/

---

An MCP server that works locally is not automatically ready for production. Most local servers communicate through stdio, but a shared server needs a remote transport, a stable HTTPS endpoint, secure authorization, production environment variables, and logs that help you diagnose failed requests.

The practical deployment path is to expose the server through **Streamable HTTP**, verify it locally, push the project to GitHub, and run it on a platform that can keep the service available. Kuberns fits this workflow as an Agentic AI platform for deployment: it connects to the repository and manages the application deployment layer without requiring you to begin with a Dockerfile or manually configure a VPS.

This guide explains how to prepare Node.js and Python MCP servers, choose between stateless and stateful behavior, secure the remote endpoint, deploy it from GitHub with Kuberns, and verify it before connecting Claude, ChatGPT, Cursor, or another MCP client.

> **TL;DR**
>
> - Replace a local stdio-only entry point with Streamable HTTP for remote access.
> - Decide whether the server is stateless or needs session-aware routing.
> - Read the runtime port from `PORT` and bind the application to the public interface.
> - Configure the production Host and Origin allowlists.
> - Protect sensitive tools with appropriate authorization and least-privilege scopes.
> - Push the project to GitHub, deploy it on Kuberns, and verify the live endpoint before connecting a client.

## What Changes When You Deploy an MCP Server?

An MCP server exposes tools, resources, or prompts to an MCP client. A local server commonly uses **stdio**, where the client launches the server as a subprocess and exchanges messages through standard input and output.

A remotely hosted MCP server is different. It runs as an independent web service and normally uses **Streamable HTTP** through an endpoint such as `https://mcp.example.com/mcp`.

| Deployment | Transport | Who can reach it | Main operational need |
|---|---|---|---|
| Local development | stdio | A client on the same machine | Correct command and local dependencies |
| Remote production | Streamable HTTP | Authorized clients over the network | HTTPS, auth, runtime configuration, logs, and availability |

Deploying the process is only part of the job. A production server also needs a predictable MCP endpoint, a health check, secure secret storage, Host and Origin validation, and an authorization model that matches the clients and tools it serves.

If the server is still being tested locally, complete the [Claude Code MCP setup](https://kuberns.com/blogs/set-up-mcp-server-in-claude-code/) before converting it into a shared remote service.

## What Does an MCP Server Need Before Production?

Confirm these requirements before connecting the repository to a deployment platform:

- A Streamable HTTP endpoint, commonly `/mcp`
- A production start command
- A server that reads the assigned `PORT` value
- A public network bind such as `0.0.0.0` at the application-server layer
- Explicit Host and Origin rules for the final hostname
- A lightweight health-check route such as `/health`
- Secrets loaded from environment variables
- Authentication and authorization for protected tools
- A decision about stateless versus stateful behavior

For new, request-response tool servers, a stateless design is usually easier to scale because requests do not depend on in-memory session state. Use stateful sessions only when the server genuinely needs features such as session continuity, resumability, or server-initiated communication. If sessions are stored in one process, scaling across replicas may require sticky routing or shared state.

## How Do You Prepare a Node.js MCP Server for Deployment?

The current TypeScript SDK provides an HTTP handler that can serve modern MCP requests and stateless legacy clients through the same endpoint. A minimal Express setup follows this shape:

```javascript
import { createMcpExpressApp } from "@modelcontextprotocol/express";
import { toNodeHandler } from "@modelcontextprotocol/node";
import { createMcpHandler, McpServer } from "@modelcontextprotocol/server";
import * as z from "zod/v4";

const buildServer = () => {
  const server = new McpServer({ name: "my-server", version: "1.0.0" });

  server.registerTool(
    "get-data",
    {
      description: "Return example data",
      inputSchema: z.object({ query: z.string() }),
    },
    async ({ query }) => ({
      content: [{ type: "text", text: `Result for ${query}` }],
    })
  );

  return server;
};

const app = createMcpExpressApp({
  host: "0.0.0.0",
  allowedHosts: [process.env.PUBLIC_HOST],
});

const mcpHandler = toNodeHandler(createMcpHandler(buildServer));
app.all("/mcp", (req, res) => void mcpHandler(req, res, req.body));
app.get("/health", (_req, res) => res.status(200).send("ok"));

const port = Number(process.env.PORT || 3000);
app.listen(port, "0.0.0.0", () => {
  console.log(`MCP server listening on port ${port}`);
});
```

Add a production start command to `package.json`:

```json
{
  "scripts": {
    "start": "node server.js"
  }
}
```

Use the versions and imports documented for the SDK version locked in your repository. Do not copy an example written for a different major version without checking its migration guide.

## How Do You Prepare a Python MCP Server for Deployment?

The Python SDK can expose a Streamable HTTP ASGI application that runs behind an ASGI server such as Uvicorn. A deployment should configure the final hostname explicitly because the secure default accepts only local hosts.

```python
from mcp.server import MCPServer
from mcp.server.transport_security import TransportSecuritySettings

mcp = MCPServer("my-server")

@mcp.tool()
def get_data(query: str) -> str:
    """Return example data for a query."""
    return f"Result for {query}"

security = TransportSecuritySettings(
    allowed_hosts=["mcp.example.com", "mcp.example.com:*"],
    allowed_origins=["https://trusted-client.example.com"],
)

app = mcp.streamable_http_app(transport_security=security)
```

Start the ASGI application with the port supplied by the platform:

```bash
uvicorn server:app --host 0.0.0.0 --port $PORT
```

Replace the example hostname and Origin with the real values used by your deployment. Do not disable DNS-rebinding protection simply to make a failed deployment respond.

The same repository and runtime rules apply when you [deploy a Python application](https://kuberns.com/blogs/how-to-deploy-python-app-with-ai/) alongside an MCP endpoint.

## How Should You Secure a Remote MCP Server?

Use several controls together rather than treating a single API key as complete production security:

1. **Serve the endpoint over HTTPS.** Never send access tokens to a production server over plain HTTP.
2. **Validate Host and Origin headers.** Allow only the production hostname and the browser origins that genuinely need access.
3. **Authorize protected tools.** Tools that read private data or change external systems should require an authenticated identity and appropriate scopes.
4. **Validate the token audience.** A server must not accept a token issued for another service.
5. **Use least privilege.** Separate read-only capabilities from actions that create, update, deploy, or delete resources.
6. **Keep secrets out of Git.** Store API keys, database credentials, and authorization configuration in environment variables.
7. **Avoid credential leakage.** Do not include tokens or secret values in logs, error messages, or tool results.

The MCP authorization specification is based on OAuth for interoperable protected remote servers. A static bearer token may be acceptable for a controlled private integration when both ends support custom headers, but it is not a substitute for a user-aware OAuth flow when multiple users or public MCP clients need access. The [ChatGPT remote MCP connection](https://kuberns.com/blogs/connect-remote-mcp-server-to-chatgpt/) guide shows where OAuth authorization fits after the endpoint has been deployed.

## How Do You Deploy an MCP Server From GitHub With Kuberns?

Once the server works locally through Streamable HTTP, the deployment flow is straightforward.

### Step 1: Push the Production-Ready Project to GitHub

Commit the server code, dependency lockfile, and start command. Keep `.env` files and secret values out of the repository.

After the first release, [automatic GitHub deployments](https://kuberns.com/blogs/how-to-auto-deploy-your-apps-from-github-in-one-click/) keep the live service aligned with the selected production branch.

### Step 2: Connect the Repository to Kuberns

Create a service in [Kuberns](https://kuberns.com/), connect GitHub, and select the repository and production branch. Review the detected runtime, build command, and start command before deploying.

![Connect a GitHub repository to Kuberns](https://kuberns-blogs-media.s3.ap-south-1.amazonaws.com/kuberns-registration.png)

### Step 3: Add Environment Variables

Add only the variables the server actually uses. Typical examples include:

- `PUBLIC_HOST` for the production Host allowlist
- Authorization issuer, audience, or client configuration
- Third-party API credentials used by tools
- `DATABASE_URL` when tools access a database
- `NODE_ENV=production` for a Node.js service

The platform supplies the runtime port. Your code should read `PORT`; do not set a conflicting hardcoded production value.

![Configure environment variables for an MCP server](https://kuberns-blogs-media.s3.ap-south-1.amazonaws.com/environment-variable-kuberns.png)

### Step 4: Deploy and Inspect the Logs

Start the deployment and watch the build and runtime logs. Kuberns provisions the application endpoint and HTTPS while the repository remains the source for subsequent deployments.

![Inspect an MCP server deployment on Kuberns](https://kuberns-blogs-media.s3.ap-south-1.amazonaws.com/kuberns-ai-deploying.png)

Kuberns plans start at $7. A Trial Option is available, and bundle packs provide additional savings.

## How Do You Verify the Live MCP Endpoint?

Do not treat a successful build as proof that the MCP server works. Verify each layer separately:

1. Open the health endpoint and confirm it returns HTTP 200.
2. Review runtime logs for missing variables, invalid Host errors, or startup crashes.
3. Use an MCP-compatible client or Inspector to initialize the endpoint and list its tools. For a real client test, follow the [Claude remote MCP setup](https://kuberns.com/blogs/connect-remote-mcp-server-to-claude/) after the server-side checks pass.
4. Call a read-only test tool with a valid identity.
5. Repeat the request without authorization and confirm the server rejects it.
6. Push a small safe change and confirm the connected production branch redeploys correctly.

The final MCP URL will normally include the endpoint path, for example:

```text
https://your-service.example.com/mcp
```

Be precise about trailing slashes. Some clients reject an HTTPS URL that redirects to a different HTTP or path variant, so configure the exact endpoint the server exposes.

## What Should You Check When Connecting an MCP Client?

Client setup should happen only after the production endpoint passes its deployment and authorization checks. Confirm that the client supports the server's transport and authorization method, then provide the exact HTTPS endpoint including the `/mcp` path.

For coding workflows, a [Cursor MCP connection](https://kuberns.com/blogs/connect-cursor-to-kuberns/) can combine repository context with deployment information after the remote server is available. Other clients may use a connector interface, an IDE configuration file, or an OAuth browser flow, so do not copy one client's configuration into another.

Keeping these stages separate makes failures easier to diagnose. If the health check succeeds but a client cannot discover tools, inspect the endpoint path, authorization metadata, scopes, protocol compatibility, and server logs. If the endpoint itself is unavailable, fix the deployment before changing the client configuration.

## What Are the Most Common MCP Deployment Failures?

| Symptom | Likely cause | What to check |
|---|---|---|
| Build succeeds but the service is unreachable | Wrong network bind or port | Listen on `0.0.0.0` and read `PORT` |
| `421 Misdirected Request` | Production hostname is not allowed | Add the exact Host value to the transport security settings |
| `403 Forbidden` from a browser client | Origin is missing from the allowlist | Allow only the trusted browser Origin |
| `404` or `405` at the MCP URL | Wrong endpoint path or unsupported method | Confirm the exact `/mcp` route and SDK handler |
| Client finds the server but not its tools | Protocol or initialization failure | Inspect server logs and test tool discovery with an Inspector |
| Requests fail after scaling | In-memory state is tied to one replica | Use a stateless design, sticky routing, or shared session state as appropriate |
| Unauthorized requests succeed | Missing or incomplete authorization | Protect the MCP route and validate audience and scopes |
| Credentials appear in logs | Unsafe logging or error handling | Redact headers, tokens, environment values, and downstream credentials |

## Production Checklist for an MCP Server

- [ ] The deployed server uses Streamable HTTP rather than a stdio-only entry point.
- [ ] The process reads `PORT` from the environment and binds correctly for the hosting runtime.
- [ ] The production Host and trusted Origins are explicitly allowed.
- [ ] The MCP endpoint uses HTTPS.
- [ ] Protected tools require appropriate authorization.
- [ ] Token audience and scopes are validated.
- [ ] Secrets are stored outside the repository.
- [ ] A lightweight health-check endpoint returns HTTP 200.
- [ ] Logs do not expose tokens, tool inputs containing secrets, or environment values.
- [ ] Stateful behavior has an explicit scaling strategy.
- [ ] Tool discovery and a safe tool call work through at least one intended client.
- [ ] A Git push triggers the expected deployment workflow.

## Why Use Kuberns to Deploy an MCP Server?

Kuberns is a practical fit when the MCP server already lives in GitHub and the team wants a managed production route without beginning with VPS administration or a custom deployment pipeline.

![Kuberns Agentic AI platform for deployment](https://kuberns-blogs-media.s3.ap-south-1.amazonaws.com/kuberns-home-page-new.png)

| Production requirement | Manual server workflow | Kuberns workflow |
|---|---|---|
| Build and start process | Configure the runtime and process manager | Review repository-based detection and deploy |
| HTTPS endpoint | Configure a proxy and certificate lifecycle | Managed with the deployed service |
| Environment variables | Maintain server-side files or a separate secret system | Configure variables outside the repository |
| Deployment updates | Build a CI/CD workflow | Deploy from the connected Git branch |
| Troubleshooting | Assemble log access and monitoring | Inspect build and runtime logs in the platform |

Kuberns handles the deployment layer, but the application owner still controls the MCP protocol behavior, tool permissions, Host and Origin allowlists, and authorization policy. That distinction keeps the deployment convenient without hiding important security decisions.

## Conclusion

To deploy an MCP server successfully, convert the local process into a production-ready Streamable HTTP service, configure the real hostname and runtime port, protect sensitive tools, and test the live endpoint before connecting users.

Kuberns provides the GitHub-to-production layer, including the managed application endpoint, environment configuration, logs, and deployment workflow. Your repository continues to define the MCP tools and security rules, while the platform removes the need to begin with manual server provisioning.

<a href="https://dashboard.kuberns.com" target="_blank" rel="noopener noreferrer">
  <img src="https://kuberns-blogs-media.s3.ap-south-1.amazonaws.com/deploy-on-kuberns-bannner6.png" alt="Deploy an MCP server from GitHub with Kuberns" style={{ width: "100%", height: "auto" }} />
</a>

## Frequently Asked Questions

### How do you deploy an MCP server?

Use Streamable HTTP, configure the server for its production hostname and runtime port, secure the endpoint, push the project to GitHub, deploy it to a platform that provides HTTPS and logs, and test the live MCP endpoint with a compatible client.

### Can you deploy an MCP server without Docker?

Yes. If the repository has a supported runtime and a valid production start command, Kuberns can build and deploy a Node.js or Python MCP server without requiring a Dockerfile.

### What port should an MCP server use in production?

The server should listen on the `PORT` environment variable supplied by the hosting platform. A local fallback such as `3000` or `8000` can be used for development.

### Does a remote MCP server need HTTPS?

Yes. A production remote MCP endpoint should use HTTPS so client requests and authorization credentials are encrypted in transit.

### How should you secure an MCP server in production?

Use HTTPS, validate Host and Origin headers, apply authorization to protected tools, validate token audience and scopes, store secrets as environment variables, limit permissions, and avoid logging credentials.

### What is the difference between stdio and Streamable HTTP in MCP?

Stdio is normally used when a local MCP client launches the server as a subprocess. Streamable HTTP runs the server as an independent HTTP service and is the appropriate transport for a remotely hosted endpoint.

---
- [More AI & DevOps articles](https://kuberns.com/blogs/category/ai-devops/1/)
- [All articles](https://kuberns.com/blogs/)