@agentmailbox/mcp-auth 1.0.0

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.
Files changed (3) hide show
  1. package/README.md +75 -0
  2. package/index.mjs +168 -0
  3. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @agentmailbox/mcp-auth
2
+
3
+ OAuth2 Client Credentials wrapper for MCP servers. Enables M2M (machine-to-machine) authentication with [AgentMailbox](https://agentmailbox.to).
4
+
5
+ ## Installation
6
+
7
+ No installation required! Use `npx` to run directly:
8
+
9
+ ```bash
10
+ npx @agentmailbox/mcp-auth <mcp-url> <token-endpoint> [scope]
11
+ ```
12
+
13
+ ## Usage with Claude Desktop
14
+
15
+ Add to your `claude_desktop_config.json`:
16
+
17
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
18
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
19
+
20
+ ```json
21
+ {
22
+ "mcpServers": {
23
+ "agentmail": {
24
+ "command": "npx",
25
+ "args": [
26
+ "-y",
27
+ "@agentmailbox/mcp-auth",
28
+ "https://mcp.agentmailbox.to/tenant/YOUR_TENANT/mailbox/YOUR_MAILBOX",
29
+ "https://auth.agentmailbox.to/oauth2/token",
30
+ "mcp-api/email.full"
31
+ ],
32
+ "env": {
33
+ "MCP_OAUTH_CLIENT_ID": "your-client-id",
34
+ "MCP_OAUTH_CLIENT_SECRET": "your-client-secret"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Replace:
42
+ - `YOUR_TENANT` - Your AgentMailbox tenant codename (e.g., `peach`)
43
+ - `YOUR_MAILBOX` - The mailbox username (e.g., `admin`)
44
+ - `your-client-id` - Your OAuth2 Client ID from the credentials page
45
+ - `your-client-secret` - Your OAuth2 Client Secret
46
+
47
+ ## Arguments
48
+
49
+ | Argument | Required | Description |
50
+ |----------|----------|-------------|
51
+ | `mcp-url` | Yes | The MCP server URL |
52
+ | `token-endpoint` | Yes | The OAuth2 token endpoint |
53
+ | `scope` | No | OAuth2 scope (default: `mcp-api/email.full`) |
54
+
55
+ ## Environment Variables
56
+
57
+ | Variable | Required | Description |
58
+ |----------|----------|-------------|
59
+ | `MCP_OAUTH_CLIENT_ID` | Yes | Your OAuth2 client ID |
60
+ | `MCP_OAUTH_CLIENT_SECRET` | Yes | Your OAuth2 client secret |
61
+
62
+ ## How It Works
63
+
64
+ 1. Fetches an OAuth2 access token using the Client Credentials flow
65
+ 2. Passes the token to `@anthropic/mcp-remote` via environment variable
66
+ 3. Forwards all MCP communication to the AgentMailbox server
67
+
68
+ ## Requirements
69
+
70
+ - Node.js 18 or later
71
+ - `@anthropic/mcp-remote` (installed automatically via npx)
72
+
73
+ ## License
74
+
75
+ MIT
package/index.mjs ADDED
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @agentmailbox/mcp-auth
4
+ *
5
+ * OAuth2 Client Credentials wrapper for MCP servers.
6
+ * Handles M2M (machine-to-machine) authentication for AgentMailbox MCP endpoints.
7
+ *
8
+ * Usage with npx in claude_desktop_config.json:
9
+ * {
10
+ * "mcpServers": {
11
+ * "agentmail": {
12
+ * "command": "npx",
13
+ * "args": [
14
+ * "-y",
15
+ * "@agentmailbox/mcp-auth",
16
+ * "https://mcp.agentmailbox.to/tenant/mytenant/mailbox/admin",
17
+ * "https://auth.agentmailbox.to/oauth2/token",
18
+ * "mcp-api/email.full"
19
+ * ],
20
+ * "env": {
21
+ * "MCP_OAUTH_CLIENT_ID": "your-client-id",
22
+ * "MCP_OAUTH_CLIENT_SECRET": "your-client-secret"
23
+ * }
24
+ * }
25
+ * }
26
+ * }
27
+ */
28
+
29
+ import { spawn } from 'child_process';
30
+
31
+ // Default timeout for token requests (30 seconds)
32
+ const TOKEN_TIMEOUT_MS = 30000;
33
+
34
+ const [mcpUrl, tokenEndpoint, scope] = process.argv.slice(2);
35
+ const clientId = process.env.MCP_OAUTH_CLIENT_ID;
36
+ const clientSecret = process.env.MCP_OAUTH_CLIENT_SECRET;
37
+
38
+ if (!mcpUrl || !tokenEndpoint || !clientId || !clientSecret) {
39
+ console.error('Usage: npx @agentmailbox/mcp-auth <mcp-url> <token-endpoint> [scope]');
40
+ console.error('');
41
+ console.error('Arguments:');
42
+ console.error(' mcp-url The MCP server URL (e.g., https://mcp.agentmailbox.to/tenant/mytenant/mailbox/admin)');
43
+ console.error(' token-endpoint The OAuth2 token endpoint (e.g., https://auth.agentmailbox.to/oauth2/token)');
44
+ console.error(' scope Optional OAuth2 scope (default: mcp-api/email.full)');
45
+ console.error('');
46
+ console.error('Environment variables required:');
47
+ console.error(' MCP_OAUTH_CLIENT_ID Your OAuth2 client ID');
48
+ console.error(' MCP_OAUTH_CLIENT_SECRET Your OAuth2 client secret');
49
+ process.exit(1);
50
+ }
51
+
52
+ /**
53
+ * Build a minimal environment for the child process.
54
+ * Only passes through essential variables to avoid leaking secrets.
55
+ */
56
+ function buildChildEnv(env) {
57
+ const allowList = [
58
+ // Essential for process execution
59
+ 'PATH', 'HOME', 'USERPROFILE',
60
+ // Temp directories
61
+ 'TMP', 'TEMP', 'TMPDIR',
62
+ // Windows-specific
63
+ 'SystemRoot', 'ComSpec', 'WINDIR', 'PATHEXT',
64
+ // Proxy settings (important for corporate environments)
65
+ 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY',
66
+ 'http_proxy', 'https_proxy', 'no_proxy',
67
+ // Node.js configuration
68
+ 'NODE_EXTRA_CA_CERTS', 'NODE_OPTIONS',
69
+ // MCP-specific
70
+ 'MCP_REMOTE_CONFIG_DIR',
71
+ ];
72
+
73
+ return Object.fromEntries(
74
+ allowList.flatMap((key) => (env[key] ? [[key, env[key]]] : []))
75
+ );
76
+ }
77
+
78
+ async function getAccessToken() {
79
+ const params = new URLSearchParams({
80
+ grant_type: 'client_credentials',
81
+ client_id: clientId,
82
+ client_secret: clientSecret,
83
+ scope: scope || 'mcp-api/email.full',
84
+ });
85
+
86
+ // Use AbortController for timeout
87
+ const controller = new AbortController();
88
+ const timeoutId = setTimeout(() => controller.abort(), TOKEN_TIMEOUT_MS);
89
+
90
+ let response;
91
+ try {
92
+ response = await fetch(tokenEndpoint, {
93
+ method: 'POST',
94
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
95
+ body: params.toString(),
96
+ signal: controller.signal,
97
+ });
98
+ } catch (err) {
99
+ clearTimeout(timeoutId);
100
+ if (err.name === 'AbortError') {
101
+ throw new Error(`Token request timed out after ${TOKEN_TIMEOUT_MS}ms`);
102
+ }
103
+ throw err;
104
+ } finally {
105
+ clearTimeout(timeoutId);
106
+ }
107
+
108
+ if (!response.ok) {
109
+ const error = await response.text();
110
+ throw new Error(`Token request failed: ${response.status} ${error}`);
111
+ }
112
+
113
+ const data = await response.json();
114
+ if (!data || typeof data.access_token !== 'string' || data.access_token.trim() === '') {
115
+ throw new Error('Missing or invalid access_token in token response');
116
+ }
117
+ return data.access_token;
118
+ }
119
+
120
+ async function main() {
121
+ try {
122
+ const token = await getAccessToken();
123
+
124
+ // Build minimal environment with only necessary variables, plus the token
125
+ const childEnv = buildChildEnv(process.env);
126
+ childEnv.AUTH_TOKEN = token;
127
+
128
+ // Launch @anthropic/mcp-remote with token passed via environment variable
129
+ const child = spawn('npx', [
130
+ '-y',
131
+ '@anthropic/mcp-remote',
132
+ mcpUrl,
133
+ ], {
134
+ stdio: 'inherit',
135
+ env: childEnv,
136
+ });
137
+
138
+ child.on('error', (err) => {
139
+ console.error('Failed to start @anthropic/mcp-remote:', err);
140
+ process.exit(1);
141
+ });
142
+
143
+ child.on('exit', (code, signal) => {
144
+ if (code !== null) {
145
+ process.exit(code);
146
+ } else if (signal !== null) {
147
+ // Child was terminated by signal - exit with non-zero
148
+ process.exit(128);
149
+ } else {
150
+ process.exit(0);
151
+ }
152
+ });
153
+
154
+ // Forward signals to child process for graceful shutdown
155
+ const forwardSignal = (sig) => {
156
+ if (child.pid) {
157
+ child.kill(sig);
158
+ }
159
+ };
160
+ process.on('SIGINT', () => forwardSignal('SIGINT'));
161
+ process.on('SIGTERM', () => forwardSignal('SIGTERM'));
162
+ } catch (err) {
163
+ console.error('Error:', err.message);
164
+ process.exit(1);
165
+ }
166
+ }
167
+
168
+ main();
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@agentmailbox/mcp-auth",
3
+ "version": "1.0.0",
4
+ "description": "OAuth2 Client Credentials wrapper for MCP servers - enables M2M authentication with AgentMailbox",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-auth": "index.mjs"
8
+ },
9
+ "files": [
10
+ "index.mjs",
11
+ "README.md"
12
+ ],
13
+ "keywords": [
14
+ "mcp",
15
+ "oauth2",
16
+ "client-credentials",
17
+ "agentmailbox",
18
+ "claude",
19
+ "anthropic",
20
+ "m2m",
21
+ "machine-to-machine"
22
+ ],
23
+ "author": "AgentMailbox",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/compostableai/SES-deployment-in-AWS.git",
28
+ "directory": "mcp/mcp-auth"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/compostableai/SES-deployment-in-AWS/issues"
32
+ },
33
+ "homepage": "https://github.com/compostableai/SES-deployment-in-AWS/tree/main/mcp/mcp-auth#readme",
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "dependencies": {},
38
+ "peerDependencies": {
39
+ "@anthropic/mcp-remote": ">=0.1.0"
40
+ }
41
+ }