Levitate
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., "@Levitateexpose my local filesystem MCP server with bearer token auth"
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.
Levitate runs near local tools, launches one configured stdio MCP server, connects as an MCP client, then exposes a Streamable HTTP endpoint for Claude, ChatGPT, and other remote MCP hosts.
The project is Levitate. The package, CLI, Docker image, and binary artifact are levitate.
Initial target flow:
Claude.ai / ChatGPT
-> public HTTPS remote MCP endpoint
-> Levitate
-> local stdio MCP server
-> private tool or data systemLevitate is backend-agnostic. Any stdio MCP server can be exposed through its HTTP endpoint, subject to auth and policy.
Why Promotion Exists
Many useful MCP servers are local stdio servers. They work with Claude Desktop, Claude Code, Cursor, and other local MCP hosts, but cloud-hosted AI apps cannot connect to them directly. Levitate promotes those local capabilities into a remote MCP endpoint while keeping policy and auth at the gateway.
Related MCP server: MCP HTTP Proxy
Security
Do not expose private local tools without authentication.
Levitate requires authentication for the MCP endpoint.
Static bearer tokens are available for local/dev/simple deployments.
OIDC/JWT validation is available for Auth0 and other RS256 JWKS-backed issuers.
MCP servers can read or modify private data, and tunnel-published endpoints are public unless protected.
GET /health is unauthenticated for deployment checks; /mcp requires Authorization: Bearer <token>.
Quick Start
Install dependencies:
pnpm installSet a bearer token:
export LEVITATE_TOKEN="$(openssl rand -hex 32)"Start levitate with the fake stdio backend profile:
pnpm build
pnpm start -- --config config/fake-stdio.tomlMCP endpoint:
http://127.0.0.1:8790/mcpHealth check:
curl http://127.0.0.1:8787/healthAuthenticated MCP clients must send:
Authorization: Bearer <LEVITATE_TOKEN>Example Backend Profile
config/fake-stdio.toml shows one deterministic local profile for the fake stdio test backend:
[server]
name = "fake"
host = "127.0.0.1"
port = 8790
[stdio]
command = "node"
args = ["test/fixtures/fake-stdio-server.mjs"]
[auth]
mode = "bearer"
token_env = "LEVITATE_TOKEN"Real deployments can point [stdio] at any stdio MCP server and then use tool policy to filter or block exposed tools.
Auth Configuration
Static bearer tokens
Static bearer mode reads a token from config or an environment variable:
[auth]
mode = "bearer"
token_env = "LEVITATE_TOKEN"Authenticated clients must send:
Authorization: Bearer <LEVITATE_TOKEN>OIDC/JWT validation
OIDC mode validates incoming bearer JWTs against the configured issuer, audience, expiration, and JWKS signature:
[auth]
mode = "oidc"
issuer = "https://YOUR_TENANT.auth0.com/"
audience = "https://levitate.example.com"
jwks_uri = "https://YOUR_TENANT.auth0.com/.well-known/jwks.json"jwks_uri is optional when the issuer's standard /.well-known/jwks.json path is correct.
Auth0 setup:
Create an Auth0 Machine to Machine application for clients that need tokens.
Create an Auth0 API with identifier
https://levitate.example.com.Use RS256 signing.
Configure Levitate with issuer
https://YOUR_TENANT.auth0.com/and audiencehttps://levitate.example.com.
Levitate only needs issuer, audience, and optionally JWKS URI to validate incoming tokens. Auth0 client credentials are for clients or smoke scripts that obtain tokens; do not store client secrets in Levitate config.
Manual token acquisition for local smoke tests can use environment variables:
export AUTH0_DOMAIN=YOUR_TENANT.auth0.com
export AUTH0_AUDIENCE=https://levitate.example.com
export AUTH0_CLIENT_ID=...
export AUTH0_CLIENT_SECRET=...Then request a token from:
https://${AUTH0_DOMAIN}/oauth/tokenTool Policy
Levitate filters backend tools before advertising them to remote clients.
Rules:
If
tools.allowis configured, only listed tools are advertised and callable.tools.denyis always enforced as an extra guard.Direct calls to denied tools return an MCP tool error and are logged.
This lets a private backend expose read-only or append-only tools while hiding destructive tools.
Server Instructions
Instructions can be configured inline or loaded from a file:
[instructions]
file = "/path/to/SKILL.md"Levitate passes these instructions through the MCP server initialization result using the official TypeScript SDK Server instructions option.
Multi-backend Routing Model
Levitate is intended to host multiple MCP backends by assigning each backend its own HTTP MCP endpoint:
/notes/mcp/ingest/mcp/tools/mcp/example/mcp
Each endpoint should behave as an independent MCP server backed by one stdio MCP backend.
Levitate does not merge multiple backend tool namespaces into a single /mcp endpoint by default.
MCP already provides tool discovery through tools/list, so Levitate should preserve backend tool names and schemas unless an explicit policy filters or blocks them.
This keeps Levitate transport-transparent and avoids tool-name collisions, namespace rewriting, ambiguous routing, and policy mistakes. If an aggregate MCP endpoint is ever needed, it should be treated as a separate explicit feature, not the default multi-backend model.
Tunnel Deployment
Run levitate locally, then expose it with Cloudflare Tunnel, ngrok, or another HTTPS tunnel:
cloudflared tunnel --url http://127.0.0.1:8787or:
ngrok http 8787Configure the AI app connector to use the public HTTPS /mcp URL and bearer token.
Smoke Tests
Fake stdio backend
Use the fake stdio backend for deterministic local checks of Levitate's HTTP proxy and policy behavior:
export LEVITATE_TOKEN="dev-secret"
pnpm build
pnpm start -- --config config/fake-stdio.tomlIn another terminal, connect MCP Inspector over Streamable HTTP with bearer auth:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8790/mcp \
--method tools/listCall the allowed tool:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8790/mcp \
--method tools/call \
--tool-name fake_allowed \
--tool-arg message=helloCall the denied tool directly:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8790/mcp \
--method tools/call \
--tool-name fake_deniedExpected result:
initialize succeeds
tools/listadvertisesfake_allowedfake_deniedis not advertisedcalling
fake_allowedreturns fixture JSONdirectly calling
fake_deniedreturns an MCP tool error from Levitate
The automated version is covered by:
pnpm test test/mcp.test.tsOptional local real-backend smoke test
You can test Levitate against any real stdio MCP backend using a local config. This is not required for normal development or CI. Create a local config that points to your backend, then choose one safe allowed tool and one denied tool for policy testing.
export LEVITATE_TOKEN="$(openssl rand -hex 32)"
export LEVITATE_CONFIG="config/example.local.toml"
export LEVITATE_SAFE_TOOL="example_safe_tool"
export LEVITATE_DENIED_TOOL="example_denied_tool"
pnpm build
pnpm start -- --config "$LEVITATE_CONFIG"In another terminal, connect MCP Inspector:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8787/mcp \
--method tools/listCall a safe read-only tool:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8787/mcp \
--method tools/call \
--tool-name "$LEVITATE_SAFE_TOOL"Call a denied tool directly:
npx -y @modelcontextprotocol/inspector@0.22.0 \
--cli \
--transport http \
--header "Authorization: Bearer ${LEVITATE_TOKEN}" \
-- http://127.0.0.1:8787/mcp \
--method tools/call \
--tool-name "$LEVITATE_DENIED_TOOL"If a tool requires arguments, add --tool-arg key=value entries according to the backend's advertised input schema.
Verify in Inspector:
initialize succeeds
tools/listshows allowed backend toolsallowed tool calls work through Levitate
denied direct calls return an MCP tool error instead of an HTTP error or server crash
MCP Inspector 0.22.0 CLI supports HTTP headers with --header, so the smoke test keeps bearer-token auth enabled.
The browser UI path may require entering headers in the UI; use the CLI commands above as the reproducible smoke path.
Docker
Build:
docker build -t levitate .Run:
docker run --rm -p 8787:8787 \
-e LEVITATE_TOKEN="$LEVITATE_TOKEN" \
-v "$PWD/config:/app/config:ro" \
levitateFor local stdio servers that need host files, mount required vault/tool paths and adjust config paths for the container.
Auth Notes
OIDC/JWT validation runs behind the same Authenticator interface as static bearer tokens.
OIDC validation checks:
JWKS signature
issuer
audience
expiration
not-before when present
subject or email allowlists when configured
Only RS256 JWTs are accepted. Static bearer auth remains available for local/dev/simple deployments.
MCP Transport Choice
Levitate uses the official @modelcontextprotocol/sdk v1 Streamable HTTP implementation:
backend:
StdioClientTransportremote endpoint:
WebStandardStreamableHTTPServerTransportHTTP framework: Hono, following the SDK Hono example
The remote endpoint is /mcp and uses JSON responses from Streamable HTTP for straightforward request/response behavior.
Compatibility should be validated against each target remote MCP host because Claude, ChatGPT, and other hosts may differ in connector rollout details.
Non-Goals
No web UI
No Chrome extension
No WebRTC mode
No OAuth login UI
No approval UI
No multi-user management
No multi-profile routing
No persistent audit database
No backend-specific wrapper behavior
No Go or Rust rewrite plan
Validation
pnpm test
pnpm typecheck
pnpm buildThis 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.
Latest Blog Posts
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/iomz/levitate'
If you have feedback or need assistance with the MCP directory API, please join our Discord server