Create a private MCP server and expose it through Smithery Uplink (TLS tunnel from a local or LAN process)...
Build an MCP that stays on a private machine (or LAN), then expose it to agents via Smithery Uplink — a CLI-held TLS tunnel, similar in spirit to cloudflared but MCP-scoped.
Official Uplink docs: https://smithery.ai/docs/use/uplink.md
| Goal | Approach |
|---|---|
| Private tools; machine must stay reachable | Uplink (this skill) |
| Always-on public/remote agents without a home tunnel | Host HTTPS MCP + OAuth/API key; smithery mcp add https://... |
| Cursor-only on one laptop | Local stdio / ~/.cursor/mcp.json (no Smithery needed) |
Use Uplink when the MCP needs local resources (DB, browser, Home Assistant on LAN, SSH keys) or must not be publicly hosted.
npm install -g @smithery/cli
smithery auth login
smithery namespace show # prefer homelab for private/LAN MCPs; create/use if needed
Human must complete browser login if auth_required.
Progress:
- [ ] 1. Scaffold private MCP (HTTP preferred, or stdio)
- [ ] 2. Run it on the host that can reach private resources
- [ ] 3. Uplink with smithery mcp add (localhost URL or command)
- [ ] 4. Verify tools via smithery tool list / call
- [ ] 5. Point agents at the namespace connection (or --client cursor)
- [ ] 6. Keep CLI online; document --force takeover rules
Two supported shapes:
smithery mcp add --id ... -- <command>).127.0.0.1 only; uplink http://127.0.0.1:<port>/mcp.Use the current @modelcontextprotocol/sdk server + transport APIs (they change). Canonical pattern:
mkdir private-mcp && cd private-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
Implement an McpServer with the tools you need (start with a ping tool). For HTTP, follow the SDK’s Streamable HTTP server sample and listen on 127.0.0.1 only — do not publish the port.
// Sketch — verify imports/transport against installed SDK docs
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "private-mcp", version: "1.0.0" });
server.tool("ping", "Health check", { message: z.string().optional() }, async ({ message }) => ({
content: [{ type: "text", text: message ?? "pong" }],
}));
// connect StdioServerTransport OR Streamable HTTP on 127.0.0.1:<port>/mcp
LAN services (e.g. Home Assistant on tower):
http://127.0.0.1:... (MCP on that host or a local reverse proxy to the LAN URL).Uplink auto-triggers for localhost / 127.0.0.1 or a trailing stdio command. Smithery cloud cannot dial raw LAN hostnames without your tunnel.
smithery mcp add http://localhost:9090/mcp --id private-mcp --name "Private MCP"
smithery mcp add --id private-mcp --name "Private MCP" -- \
node /absolute/path/to/server-stdio.mjs
smithery mcp add http://localhost:9090/mcp --id private-mcp --force
--force disconnects the previous CLI immediately.
Expected status line:
Uplink connected → <namespace>/private-mcp (status: connected)
Keep this process running. Exiting the CLI → connection disconnected; tool lists are cleared.
smithery tool list private-mcp
smithery tool call private-mcp ping '{"message":"hello"}'
Optional: install into Cursor config:
smithery mcp add http://localhost:9090/mcp --id private-mcp --client cursor
Or consume via the namespace gateway once the uplink connection is healthy (https://mcp.smithery.run/<namespace>). Agents still depend on the uplink host being online.
~/.cursor/mcp.json secrets into the skill, repo, or Smithery listing.Publish a public (or privately authenticated) HTTPS MCP when you need uptime without a home CLI:
smithery mcp publish "https://your-server.example/mcp" -n @<namespace>/your-server
# or
smithery mcp add https://your-server.example/mcp --id your-server --client cursor
See also: https://smithery.ai/docs/build/publish.md
| Symptom | Fix |
|---|---|
disconnected |
Restart smithery mcp add ... on the host |
| Conflict / second machine | Use --force deliberately, or pick a new --id |
| Tools missing after CLI exit | Expected — reattach uplink |
Cloud can't reach tower / LAN IP |
Uplink from a machine on that network; target localhost or a local proxy |
auth_required on smithery |
Human opens the printed URL; retry |
| Cursor doesn't see tools | Restart Cursor / reload MCP; ensure uplink still connected |