@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.
- package/README.md +75 -0
- package/index.mjs +168 -0
- 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
|
+
}
|