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 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.16",
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 transport = new SSEClientTransport(url, { authProvider });
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
- return { serverUrl, callbackPort, clean };
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-NCBLL6DH.js";
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-NCBLL6DH.js";
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.16",
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": {