Skip to main content

DeskLink

Turn your local computer into a remotely accessible MCP endpoint for cloud AI agents.

DeskLink is a thin authenticated bridge. It starts the local STDIO MCP servers you already use (or the official filesystem server), discovers their tools, and exposes everything through a single Streamable HTTP MCP URL. Optionally tunnels that URL with ngrok so Claude, ChatGPT, Cursor, Manus, or any remote MCP client can reach your machine securely.

Package name on PyPI: desklink
CLI commands: desklink and devlink (alias)


What it does

  1. Loads MCP servers from a standard mcp.json (or injects the official @modelcontextprotocol/server-filesystem if none are defined).
  2. Starts a local Streamable HTTP server (default http://127.0.0.1:8765/mcp).
  3. Proxies every discovered tool under a namespaced name (servername__toolname).
  4. Protects the endpoint with a device bearer token and/or OAuth 2.1 (Authorization Code + PKCE).
  5. Optionally opens an ngrok tunnel so the same endpoint is reachable from the public internet.
  6. Gives you a simple web dashboard + consent screen for OAuth apps.

You keep full control: tools stay on your machine, approvals can prompt you, and tokens never leave your machine unless you choose.


Quick start

pip install desklink

# Optional but recommended for public tunnels
export NGROK_AUTHTOKEN=your_ngrok_token

desklink start

On first run DeskLink will:

  • Create ~/.desklink/token (device bearer token)
  • Start the official filesystem MCP server scoped to your home directory (unless you provide an mcp.json)
  • Print the local and public MCP URLs plus the auth token

Copy the public URL + token into any MCP-compatible client.

Useful flags

desklink start \
  --mcp-config ./mcp.json \
  --config ./desklink.config.json \
  --dir ~/Documents --dir ~/projects \
  --port 8765 \
  --tunnel ngrok          # or "none" for local-only
  --token my-static-token # optional override
  -v                      # verbose logging

Configuration

DeskLink looks for two files (first match wins):

File Search order
DeskLink settings --config → ./desklink.config.json → ~/.desklink/config.json
MCP servers --mcp-config → ./mcp.json → ~/.desklink/mcp.json

Example mcp.json

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/Documents", "/Users/you/projects"]
    },
    "my-custom-server": {
      "command": "python",
      "args": ["-m", "my_mcp_server"],
      "env": { "API_KEY": "..." }
    }
  }
}

Any STDIO MCP server works. Tools appear as filesystem__read_file, my-custom-server__do_something, etc.

Example desklink.config.json

{
  "logging": { "level": "info" },
  "tracing": {
    "enabled": true,
    "level": "basic",
    "redact_sensitive": true
  },
  "auth": {
    "enabled": true
  },
  "approvals": {
    "default": "auto",
    "tools": {
      "filesystem__write_file": "prompt",
      "filesystem__create_directory": "prompt"
    }
  },
  "server": {
    "host": "127.0.0.1",
    "port": 8765,
    "mcp_path": "/mcp"
  },
  "tunnel": {
    "provider": "ngrok"
  }
}

Approvals

  • "auto" – run immediately
  • "prompt" – ask in the terminal before the tool executes

Tracing levels

  • none / basic / full (full logs args + truncated results; sensitive keys are redacted by default)

Environment variables use the prefix DESKLINK_ (e.g. DESKLINK_SERVER__PORT=9000). NGROK_AUTHTOKEN is also picked up automatically.


Authentication

1. Device bearer token (always available)

Stored at ~/.desklink/token. Sent as:

Authorization: Bearer <token>

Use this for simple scripts or clients that just need a static secret.

DeskLink acts as a full OAuth 2.1 authorization server so agents never see your device token.

Create an app (CLI)

desklink create oauth-app claude
desklink create oauth-app chatgpt
desklink create oauth-app manus
desklink create oauth-app cursor
desklink create oauth-app custom --name "My Agent" --public

Presets come with sensible default scopes. Confidential clients get a Client Secret; public clients rely on PKCE.

Endpoints (when desklink start is running)

Purpose URL
Metadata http://127.0.0.1:8765/.well-known/oauth-authorization-server
Authorize http://127.0.0.1:8765/oauth/authorize
Token http://127.0.0.1:8765/oauth/token
Revoke http://127.0.0.1:8765/oauth/revoke
Dynamic registration POST http://127.0.0.1:8765/oauth/register
Dashboard http://127.0.0.1:8765/dashboard
MCP http://127.0.0.1:8765/mcp

When using a tunnel the same paths work on the public URL.

Manage apps

desklink oauth list
desklink oauth revoke <client_id>

Or open /dashboard in a browser – create apps, view Client IDs, revoke access, and see recent activity.

Scopes

Scope Meaning
mcp:tools Call tools
mcp:resources Read resources
filesystem:read Read files
filesystem:write Write / create
admin Full control

All OAuth state lives as JSON under ~/.desklink/oauth/ (no database).


Customer usage flow

  1. Install & start DeskLink on the machine whose tools/files you want to expose.
  2. (Optional) Create an OAuth app for the agent you will connect.
  3. Give the agent the public MCP URL + either the device token or the OAuth Client ID (and secret if confidential).
  4. The agent discovers tools via normal MCP tools/list and calls them. DeskLink proxies the call to the local STDIO server, applies your approval policy, and returns the result.
  5. Stop with Ctrl+C. The tunnel and local servers shut down cleanly.

Extensibility

  • Any STDIO MCP server – just add it to mcp.json. No code changes required.
  • Approvals & tracing – configure per-tool policies and log levels without touching the bridge.
  • Tunnel providers – currently ngrok and none. The interface is abstract; additional providers (Cloudflare Tunnel, etc.) can be added later.
  • Auth – static bearer + full OAuth 2.1 (PKCE, refresh tokens, dynamic registration, consent screen). Device identity stays separate from OAuth application credentials.
  • Programmatic use – import desklink and drive DeskLinkServer / McpBridge from your own Python process if you need tighter integration.

Development

git clone https://github.com/sam-14uel/desklink-py.git
cd desklink-py
pip install -e ".[dev]"
pytest

License

MIT © Samuel Obinna Chimdi

Metadata

Release files for desklink 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for desklink 0.3.0
File Size Uploaded Provenance Actions
desklink-0.3.0.tar.gz 20.5 kB Without provenance Details for desklink-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for desklink 0.3.0
File Interpreter ABI Platform Actions
desklink-0.3.0-py3-none-any.whl Python 3 none any Details for desklink-0.3.0-py3-none-any.whl

Total release size: 43.7 kB

Security for desklink 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page