mcpbox 0.2.0 → 0.2.1

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
@@ -7,12 +7,15 @@
7
7
 
8
8
  **MCPBox** is a lightweight gateway that exposes local stdio-based MCP (Model Context Protocol) servers via Streamable HTTP, enabling Claude and other AI agents to connect from anywhere.
9
9
 
10
- - Aggregate multiple local stdio servers behind a single HTTP endpoint
10
+ - Runs multiple MCP stdio servers behind a single HTTP endpoint
11
11
  - Exposes Tools, Resources & Prompts
12
- - Namespaces with `servername__` prefix to avoid collisions (e.g., `github__create_issue`)
12
+ - Namespaces with `servername__` prefix to avoid collisions
13
13
  - OAuth or API key authentication
14
14
 
15
- ![mcpbox diagram](assets/diagram.excalidraw.png)
15
+ <picture>
16
+ <source media="(prefers-color-scheme: dark)" srcset="assets/diagram-dark.excalidraw.png">
17
+ <img src="assets/diagram.excalidraw.png" alt="mcpbox diagram">
18
+ </picture>
16
19
 
17
20
  ## Quick Start
18
21
 
@@ -70,10 +73,10 @@ See [`mcpbox.example.jsonc`](mcpbox.example.jsonc) for all options. All string v
70
73
 
71
74
  To expose MCPBox remotely, put it behind a TLS-terminating reverse proxy.
72
75
 
73
- Before deploying:
74
- - [ ] Use `storage.type: "sqlite"` for persistence across restarts
75
- - [ ] Set `auth.issuer` to your public URL when using OAuth
76
- - [ ] Use bcrypt hashes for passwords
76
+ Before deploying with OAuth:
77
+ - [ ] Use sqlite storage for persistence across restarts
78
+ - [ ] Set issuer to your public URL
79
+ - [ ] Use bcrypt hashes for local passwords
77
80
 
78
81
  > [!NOTE]
79
82
  > MCPBox is single-instance only — don't run multiple instances behind a load balancer.
@@ -93,7 +96,9 @@ Then update your config with the generated public URL:
93
96
  "auth": {
94
97
  "type": "oauth",
95
98
  "issuer": "https://<tunnel-id>.trycloudflare.com",
96
- "users": [{ "username": "admin", "password": "${MCPBOX_PASSWORD}" }],
99
+ "identityProviders": [
100
+ { "type": "local", "users": [{ "username": "admin", "password": "${MCPBOX_PASSWORD}" }] }
101
+ ],
97
102
  "dynamicRegistration": true
98
103
  },
99
104
  "storage": {
@@ -126,12 +131,28 @@ claude mcp add --transport http mcpbox https://your-mcpbox-url.com
126
131
 
127
132
  Requires `dynamicRegistration: true` in your config.
128
133
 
129
- ### MCP clients with JSON config
134
+ ### Other MCP clients
135
+
136
+ **With dynamic registration (OAuth)** — just provide the URL:
130
137
 
131
138
  ```json
132
139
  {
133
140
  "mcpServers": {
134
141
  "mcpbox": {
142
+ "type": "http",
143
+ "url": "https://your-mcpbox-url.com"
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ **With API key:**
150
+
151
+ ```json
152
+ {
153
+ "mcpServers": {
154
+ "mcpbox": {
155
+ "type": "http",
135
156
  "url": "https://your-mcpbox-url.com",
136
157
  "headers": {
137
158
  "Authorization": "Bearer YOUR_API_KEY"
@@ -63,7 +63,7 @@ export class OAuthServer {
63
63
  return {
64
64
  resource: this.config.issuer,
65
65
  authorization_servers: [this.config.issuer],
66
- scopes_supported: ["mcp:tools"],
66
+ scopes_supported: ["mcp"],
67
67
  bearer_methods_supported: ["header"],
68
68
  // Non-standard: logo for client display
69
69
  logo_uri: `${this.config.issuer}/logo.png`,
@@ -87,7 +87,7 @@ export class OAuthServer {
87
87
  token_endpoint: `${this.config.issuer}/token`,
88
88
  grant_types_supported: grantTypes,
89
89
  token_endpoint_auth_methods_supported: ["none", "client_secret_post"],
90
- scopes_supported: ["mcp:tools"],
90
+ scopes_supported: ["mcp"],
91
91
  };
92
92
  // Only advertise authorization endpoint if identity providers are configured
93
93
  if (hasProviders) {
@@ -656,7 +656,7 @@ export class OAuthServer {
656
656
  this.store.saveAccessToken({
657
657
  token: hashSecret(accessToken),
658
658
  clientId,
659
- scope: "mcp:tools",
659
+ scope: "mcp",
660
660
  expiresAt: Date.now() + expiresIn * 1000,
661
661
  userId: `client:${clientId}`, // Mark as client-authenticated
662
662
  });
@@ -666,7 +666,7 @@ export class OAuthServer {
666
666
  access_token: accessToken, // Return unhashed token to client
667
667
  token_type: "Bearer",
668
668
  expires_in: expiresIn,
669
- scope: "mcp:tools",
669
+ scope: "mcp",
670
670
  });
671
671
  }
672
672
  // RFC 6749 Section 4.1: Authorization Code Grant
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
2
3
  import { loadConfig, resolveConfigPath, } from "./config/loader.js";
3
4
  import { configureLogger, logger } from "./logger.js";
4
5
  import { createServer } from "./server.js";
@@ -33,10 +34,6 @@ function parseArgs(args) {
33
34
  else if (arg === "-c" || arg === "--config") {
34
35
  result.config = args[++i];
35
36
  }
36
- else if (!arg.startsWith("-")) {
37
- // Positional arg = config path (backwards compat)
38
- result.config = arg;
39
- }
40
37
  }
41
38
  return result;
42
39
  }
@@ -50,6 +47,10 @@ if (args.version) {
50
47
  process.exit(0);
51
48
  }
52
49
  const configPath = resolveConfigPath(args.config);
50
+ if (args.config && !existsSync(configPath)) {
51
+ console.error(`Config file not found: ${configPath}`);
52
+ process.exit(1);
53
+ }
53
54
  let config;
54
55
  let warnings;
55
56
  try {
@@ -57,7 +58,6 @@ try {
57
58
  }
58
59
  catch (error) {
59
60
  const message = error instanceof Error ? error.message : String(error);
60
- // Log to stderr directly since logger config isn't loaded yet
61
61
  console.error(`Failed to load config from ${configPath}:\n${message}`);
62
62
  process.exit(1);
63
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpbox",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "A lightweight gateway that exposes local stdio-based MCP servers via Streamable HTTP",
5
5
  "main": "dist/index.js",
6
6
  "bin": {