@diegoaltoworks/localize-remote-mcp-server 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,40 +1,60 @@
1
1
  # @diegoaltoworks/localize-remote-mcp-server
2
2
 
3
- Proxy a remote HTTP MCP server to localhost.
3
+ Bridge any remote HTTP MCP server into Claude Desktop.
4
4
 
5
5
  ## Why
6
6
 
7
- Claude Desktop currently only supports connecting to local MCP servers. If your MCP server is hosted remotely over HTTP, Claude Desktop can't reach it directly. This project bridges that gap — it runs a lightweight local proxy that forwards all MCP traffic to your remote server, letting Claude Desktop (and any other client with the same limitation) work with remote MCP servers as if they were local.
7
+ Claude Desktop only supports MCP servers that run locally as commands (stdio transport). It cannot connect to remote MCP servers over HTTP. This package bridges that gap — you configure it in Claude Desktop's config file, Claude launches it automatically, and it translates between stdio and your remote server's HTTP endpoint. You never run this yourself.
8
8
 
9
- ## Usage
9
+ ## Setup
10
10
 
11
- ```bash
12
- npx @diegoaltoworks/localize-remote-mcp-server --port 6969 https://example.com/mcp
11
+ 1. Open your Claude Desktop config file `claude_desktop_config.json`:
12
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
13
+ - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
14
+
15
+ 2. Add your remote MCP server to the `mcpServers` section. Replace the URL with your remote server's MCP endpoint:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "my-remote-server": {
21
+ "command": "npx",
22
+ "args": [
23
+ "@diegoaltoworks/localize-remote-mcp-server",
24
+ "https://my-remote-server.example.com/mcp"
25
+ ]
26
+ }
27
+ }
28
+ }
13
29
  ```
14
30
 
15
- This starts a local server at `http://localhost:6969/mcp` that proxies all MCP requests to the remote server.
31
+ 3. Restart Claude Desktop.
16
32
 
17
- ## Options
33
+ That's it. Claude Desktop will launch the bridge process in the background and your remote server's tools will appear in Claude.
18
34
 
19
- | Flag | Description | Default |
20
- |------|-------------|---------|
21
- | `-p, --port` | Local port to listen on | `3000` |
22
- | `-h, --help` | Show help message | |
35
+ ## How it works
23
36
 
24
- ## Example
37
+ When Claude Desktop starts, it runs the `npx` command from your config. The bridge process:
25
38
 
26
- ```bash
27
- # Proxy a remote MCP server to localhost:6969
28
- npx @diegoaltoworks/localize-remote-mcp-server --port 6969 https://london-toll-checker.diegoalto.app/mcp
39
+ 1. Receives JSON-RPC messages from Claude Desktop over stdin
40
+ 2. Forwards them as HTTP POST requests to your remote MCP server
41
+ 3. Parses the response (JSON or SSE) and writes it back to stdout
29
42
 
30
- # Proxying https://london-toll-checker.diegoalto.app/mcp -> http://localhost:6969/mcp
43
+ Claude Desktop sees it as a normal local MCP server. Your remote server receives normal HTTP MCP requests. Neither side knows about the bridge.
44
+
45
+ ## HTTP proxy mode
46
+
47
+ If you need a local HTTP proxy instead of stdio (for other MCP clients), you can run it directly with `--port`:
48
+
49
+ ```bash
50
+ npx @diegoaltoworks/localize-remote-mcp-server --port 6969 https://my-remote-server.example.com/mcp
31
51
  ```
32
52
 
33
- Then point your MCP client at `http://localhost:6969/mcp` instead of the remote URL.
53
+ This is not needed for Claude Desktop.
34
54
 
35
55
  ## What it does
36
56
 
37
- - Proxies POST and GET requests to the remote MCP server
38
- - Streams SSE responses back to the client
57
+ - Bridges stdio and HTTP MCP transports
58
+ - Parses SSE responses from remote servers
39
59
  - Forwards authorization headers and MCP session IDs
40
60
  - Zero dependencies — just Node.js
package/bin/cli.js CHANGED
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { parseArgs } from "node:util";
4
- import { createProxy } from "../src/proxy.js";
5
4
 
6
5
  const { values, positionals } = parseArgs({
7
6
  options: {
8
- port: { type: "string", short: "p", default: "3000" },
7
+ port: { type: "string", short: "p" },
9
8
  help: { type: "boolean", short: "h", default: false },
10
9
  },
11
10
  allowPositionals: true,
@@ -15,19 +14,33 @@ if (values.help || positionals.length === 0) {
15
14
  console.log(`
16
15
  Usage: localize-remote-mcp-server [options] <remote-url>
17
16
 
18
- Proxy a remote HTTP MCP server to localhost.
17
+ Proxy a remote HTTP MCP server for local use.
18
+
19
+ Modes:
20
+ Default (stdio) Bridges stdin/stdout to the remote server.
21
+ Use this with Claude Desktop.
22
+ --port <port> Runs a local HTTP proxy server instead.
19
23
 
20
24
  Options:
21
- -p, --port <port> Local port to listen on (default: 3000)
25
+ -p, --port <port> Local port for HTTP proxy mode
22
26
  -h, --help Show this help message
23
27
 
24
- Example:
25
- npx @diegoaltoworks/localize-remote-mcp-server --port 6969 https://example.com/mcp
28
+ Examples:
29
+ # stdio mode (for Claude Desktop)
30
+ npx @diegoaltoworks/localize-remote-mcp-server https://my-remote-server.example.com/mcp
31
+
32
+ # HTTP proxy mode
33
+ npx @diegoaltoworks/localize-remote-mcp-server --port 6969 https://my-remote-server.example.com/mcp
26
34
  `);
27
35
  process.exit(values.help ? 0 : 1);
28
36
  }
29
37
 
30
38
  const remoteUrl = positionals[0];
31
- const port = parseInt(values.port, 10);
32
39
 
33
- createProxy({ remoteUrl, port });
40
+ if (values.port) {
41
+ const { createProxy } = await import("../src/proxy.js");
42
+ createProxy({ remoteUrl, port: parseInt(values.port, 10) });
43
+ } else {
44
+ const { createStdioBridge } = await import("../src/stdio.js");
45
+ createStdioBridge({ remoteUrl });
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegoaltoworks/localize-remote-mcp-server",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Proxy a remote HTTP MCP server to localhost",
5
5
  "bin": {
6
6
  "localize-remote-mcp-server": "./bin/cli.js"
package/src/stdio.js ADDED
@@ -0,0 +1,85 @@
1
+ import { createInterface } from "node:readline";
2
+
3
+ export function createStdioBridge({ remoteUrl }) {
4
+ let sessionId = null;
5
+ let pending = 0;
6
+ let stdinClosed = false;
7
+
8
+ const rl = createInterface({ input: process.stdin });
9
+
10
+ function maybeExit() {
11
+ if (stdinClosed && pending === 0) process.exit(0);
12
+ }
13
+
14
+ rl.on("line", async (line) => {
15
+ if (!line.trim()) return;
16
+
17
+ let message;
18
+ try {
19
+ message = JSON.parse(line);
20
+ } catch {
21
+ return;
22
+ }
23
+
24
+ pending++;
25
+
26
+ const headers = {
27
+ "content-type": "application/json",
28
+ accept: "application/json, text/event-stream",
29
+ };
30
+ if (sessionId) {
31
+ headers["mcp-session-id"] = sessionId;
32
+ }
33
+
34
+ try {
35
+ const response = await fetch(remoteUrl, {
36
+ method: "POST",
37
+ headers,
38
+ body: line,
39
+ });
40
+
41
+ // Capture session ID from response
42
+ const newSessionId = response.headers.get("mcp-session-id");
43
+ if (newSessionId) {
44
+ sessionId = newSessionId;
45
+ }
46
+
47
+ const contentType = response.headers.get("content-type") || "";
48
+
49
+ if (contentType.includes("text/event-stream")) {
50
+ // Parse SSE and extract JSON-RPC messages
51
+ const text = await response.text();
52
+ for (const sseLine of text.split("\n")) {
53
+ if (sseLine.startsWith("data: ")) {
54
+ const data = sseLine.slice(6).trim();
55
+ if (data) {
56
+ process.stdout.write(data + "\n");
57
+ }
58
+ }
59
+ }
60
+ } else {
61
+ // Plain JSON response
62
+ const text = await response.text();
63
+ if (text.trim()) {
64
+ process.stdout.write(text.trim() + "\n");
65
+ }
66
+ }
67
+ } catch (err) {
68
+ // Write JSON-RPC error to stdout
69
+ const errorResponse = {
70
+ jsonrpc: "2.0",
71
+ error: { code: -32000, message: `Proxy error: ${err.message}` },
72
+ id: message.id ?? null,
73
+ };
74
+ process.stdout.write(JSON.stringify(errorResponse) + "\n");
75
+ } finally {
76
+ pending--;
77
+ maybeExit();
78
+ }
79
+ });
80
+
81
+ rl.on("close", () => {
82
+ stdinClosed = true;
83
+ maybeExit();
84
+ });
85
+ }