mcp-remote 0.0.16 → 0.0.18
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 +23 -0
- package/dist/{chunk-NCBLL6DH.js → chunk-D7JDXBXO.js} +49 -6
- package/dist/client.js +5 -5
- package/dist/proxy.js +5 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -32,6 +32,29 @@ All the most popular MCP clients (Claude Desktop, Cursor & Windsurf) use the fol
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
### Custom Headers
|
|
36
|
+
|
|
37
|
+
To bypass authentication, or to emit custom headers on all requests to your remote server, pass `--header` CLI arguments:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"remote-example": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": [
|
|
45
|
+
"mcp-remote",
|
|
46
|
+
"https://remote.mcp.server/sse",
|
|
47
|
+
"--header",
|
|
48
|
+
"Authorization: Bearer ${AUTH_TOKEN}"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"env": {
|
|
52
|
+
"AUTH_TOKEN": "..."
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
35
58
|
### Flags
|
|
36
59
|
|
|
37
60
|
* If `npx` is producing errors, consider adding `-y` as the first argument to auto-accept the installation of the `mcp-remote` package.
|
|
@@ -14,7 +14,7 @@ var require_package = __commonJS({
|
|
|
14
14
|
"package.json"(exports, module) {
|
|
15
15
|
module.exports = {
|
|
16
16
|
name: "mcp-remote",
|
|
17
|
-
version: "0.0.
|
|
17
|
+
version: "0.0.18",
|
|
18
18
|
description: "Remote proxy for Model Context Protocol, allowing local-only clients to connect to remote servers using oAuth",
|
|
19
19
|
keywords: [
|
|
20
20
|
"mcp",
|
|
@@ -37,8 +37,8 @@ var require_package = __commonJS({
|
|
|
37
37
|
"mcp-remote-client": "dist/client.js"
|
|
38
38
|
},
|
|
39
39
|
scripts: {
|
|
40
|
-
dev: "tsup --watch",
|
|
41
40
|
build: "tsup",
|
|
41
|
+
"build:watch": "tsup --watch",
|
|
42
42
|
check: "prettier --check . && tsc"
|
|
43
43
|
},
|
|
44
44
|
dependencies: {
|
|
@@ -120,10 +120,25 @@ function mcpProxy({ transportToClient, transportToServer }) {
|
|
|
120
120
|
log("Error from remote server:", error);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
async function connectToRemoteServer(serverUrl, authProvider, waitForAuthCode, skipBrowserAuth = false) {
|
|
123
|
+
async function connectToRemoteServer(serverUrl, authProvider, headers, waitForAuthCode, skipBrowserAuth = false) {
|
|
124
124
|
log(`[${pid}] Connecting to remote server: ${serverUrl}`);
|
|
125
125
|
const url = new URL(serverUrl);
|
|
126
|
-
const
|
|
126
|
+
const eventSourceInit = {
|
|
127
|
+
fetch: (url2, init) => {
|
|
128
|
+
return fetch(url2, {
|
|
129
|
+
...init,
|
|
130
|
+
headers: {
|
|
131
|
+
...init?.headers,
|
|
132
|
+
...headers
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const transport = new SSEClientTransport(url, {
|
|
138
|
+
authProvider,
|
|
139
|
+
requestInit: { headers },
|
|
140
|
+
eventSourceInit
|
|
141
|
+
});
|
|
127
142
|
try {
|
|
128
143
|
await transport.start();
|
|
129
144
|
log("Connected to remote server");
|
|
@@ -139,7 +154,7 @@ async function connectToRemoteServer(serverUrl, authProvider, waitForAuthCode, s
|
|
|
139
154
|
try {
|
|
140
155
|
log("Completing authorization...");
|
|
141
156
|
await transport.finishAuth(code);
|
|
142
|
-
const newTransport = new SSEClientTransport(url, { authProvider });
|
|
157
|
+
const newTransport = new SSEClientTransport(url, { authProvider, requestInit: { headers } });
|
|
143
158
|
await newTransport.start();
|
|
144
159
|
log("Connected to remote server after authentication");
|
|
145
160
|
return newTransport;
|
|
@@ -242,6 +257,19 @@ async function parseCommandLineArgs(args, defaultPort, usage) {
|
|
|
242
257
|
if (clean) {
|
|
243
258
|
args.splice(cleanIndex, 1);
|
|
244
259
|
}
|
|
260
|
+
const headers = {};
|
|
261
|
+
args.forEach((arg, i) => {
|
|
262
|
+
if (arg === "--header" && i < args.length - 1) {
|
|
263
|
+
const value = args[i + 1];
|
|
264
|
+
const match = value.match(/^([A-Za-z0-9_-]+):(.*)$/);
|
|
265
|
+
if (match) {
|
|
266
|
+
headers[match[1]] = match[2];
|
|
267
|
+
} else {
|
|
268
|
+
log(`Warning: ignoring invalid header argument: ${value}`);
|
|
269
|
+
}
|
|
270
|
+
args.splice(i, 2);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
245
273
|
const serverUrl = args[0];
|
|
246
274
|
const specifiedPort = args[1] ? parseInt(args[1]) : void 0;
|
|
247
275
|
if (!serverUrl) {
|
|
@@ -263,7 +291,22 @@ async function parseCommandLineArgs(args, defaultPort, usage) {
|
|
|
263
291
|
if (clean) {
|
|
264
292
|
log("Clean mode enabled: config files will be reset before reading");
|
|
265
293
|
}
|
|
266
|
-
|
|
294
|
+
if (Object.keys(headers).length > 0) {
|
|
295
|
+
log(`Using custom headers: ${JSON.stringify(headers)}`);
|
|
296
|
+
}
|
|
297
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
298
|
+
headers[key] = value.replace(/\$\{([^}]+)}/g, (match, envVarName) => {
|
|
299
|
+
const envVarValue = process.env[envVarName];
|
|
300
|
+
if (envVarValue !== void 0) {
|
|
301
|
+
log(`Replacing ${match} with environment value in header '${key}'`);
|
|
302
|
+
return envVarValue;
|
|
303
|
+
} else {
|
|
304
|
+
log(`Warning: Environment variable '${envVarName}' not found for header '${key}'.`);
|
|
305
|
+
return "";
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return { serverUrl, callbackPort, clean, headers };
|
|
267
310
|
}
|
|
268
311
|
function setupSignalHandlers(cleanup) {
|
|
269
312
|
process.on("SIGINT", async () => {
|
package/dist/client.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
log,
|
|
8
8
|
parseCommandLineArgs,
|
|
9
9
|
setupSignalHandlers
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-D7JDXBXO.js";
|
|
11
11
|
|
|
12
12
|
// src/client.ts
|
|
13
13
|
import { EventEmitter } from "events";
|
|
@@ -15,7 +15,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
15
15
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
16
16
|
import { ListResourcesResultSchema, ListToolsResultSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
17
17
|
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
18
|
-
async function runClient(serverUrl, callbackPort, clean = false) {
|
|
18
|
+
async function runClient(serverUrl, callbackPort, headers, clean = false) {
|
|
19
19
|
const events = new EventEmitter();
|
|
20
20
|
const serverUrlHash = getServerUrlHash(serverUrl);
|
|
21
21
|
const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events);
|
|
@@ -40,7 +40,7 @@ async function runClient(serverUrl, callbackPort, clean = false) {
|
|
|
40
40
|
);
|
|
41
41
|
const url = new URL(serverUrl);
|
|
42
42
|
function initTransport() {
|
|
43
|
-
const transport2 = new SSEClientTransport(url, { authProvider });
|
|
43
|
+
const transport2 = new SSEClientTransport(url, { authProvider, requestInit: { headers } });
|
|
44
44
|
transport2.onmessage = (message) => {
|
|
45
45
|
log("Received message:", JSON.stringify(message, null, 2));
|
|
46
46
|
};
|
|
@@ -108,8 +108,8 @@ async function runClient(serverUrl, callbackPort, clean = false) {
|
|
|
108
108
|
}
|
|
109
109
|
log("Listening for messages. Press Ctrl+C to exit.");
|
|
110
110
|
}
|
|
111
|
-
parseCommandLineArgs(process.argv.slice(2), 3333, "Usage: npx tsx client.ts [--clean] <https://server-url> [callback-port]").then(({ serverUrl, callbackPort, clean }) => {
|
|
112
|
-
return runClient(serverUrl, callbackPort, clean);
|
|
111
|
+
parseCommandLineArgs(process.argv.slice(2), 3333, "Usage: npx tsx client.ts [--clean] <https://server-url> [callback-port]").then(({ serverUrl, callbackPort, clean, headers }) => {
|
|
112
|
+
return runClient(serverUrl, callbackPort, headers, clean);
|
|
113
113
|
}).catch((error) => {
|
|
114
114
|
console.error("Fatal error:", error);
|
|
115
115
|
process.exit(1);
|
package/dist/proxy.js
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
mcpProxy,
|
|
9
9
|
parseCommandLineArgs,
|
|
10
10
|
setupSignalHandlers
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-D7JDXBXO.js";
|
|
12
12
|
|
|
13
13
|
// src/proxy.ts
|
|
14
14
|
import { EventEmitter } from "events";
|
|
15
15
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
16
|
-
async function runProxy(serverUrl, callbackPort, clean = false) {
|
|
16
|
+
async function runProxy(serverUrl, callbackPort, headers, clean = false) {
|
|
17
17
|
const events = new EventEmitter();
|
|
18
18
|
const serverUrlHash = getServerUrlHash(serverUrl);
|
|
19
19
|
const { server, waitForAuthCode, skipBrowserAuth } = await coordinateAuth(serverUrlHash, callbackPort, events);
|
|
@@ -29,7 +29,7 @@ async function runProxy(serverUrl, callbackPort, clean = false) {
|
|
|
29
29
|
}
|
|
30
30
|
const localTransport = new StdioServerTransport();
|
|
31
31
|
try {
|
|
32
|
-
const remoteTransport = await connectToRemoteServer(serverUrl, authProvider, waitForAuthCode, skipBrowserAuth);
|
|
32
|
+
const remoteTransport = await connectToRemoteServer(serverUrl, authProvider, headers, waitForAuthCode, skipBrowserAuth);
|
|
33
33
|
mcpProxy({
|
|
34
34
|
transportToClient: localTransport,
|
|
35
35
|
transportToServer: remoteTransport
|
|
@@ -72,8 +72,8 @@ to the CA certificate file. If using claude_desktop_config.json, this might look
|
|
|
72
72
|
process.exit(1);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
parseCommandLineArgs(process.argv.slice(2), 3334, "Usage: npx tsx proxy.ts [--clean] <https://server-url> [callback-port]").then(({ serverUrl, callbackPort, clean }) => {
|
|
76
|
-
return runProxy(serverUrl, callbackPort, clean);
|
|
75
|
+
parseCommandLineArgs(process.argv.slice(2), 3334, "Usage: npx tsx proxy.ts [--clean] <https://server-url> [callback-port]").then(({ serverUrl, callbackPort, clean, headers }) => {
|
|
76
|
+
return runProxy(serverUrl, callbackPort, headers, clean);
|
|
77
77
|
}).catch((error) => {
|
|
78
78
|
log("Fatal error:", error);
|
|
79
79
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-remote",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Remote proxy for Model Context Protocol, allowing local-only clients to connect to remote servers using oAuth",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"mcp-remote-client": "dist/client.js"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"dev": "tsup --watch",
|
|
27
26
|
"build": "tsup",
|
|
27
|
+
"build:watch": "tsup --watch",
|
|
28
28
|
"check": "prettier --check . && tsc"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|