@honeyfield/rent2b-mcp 1.1.0 → 1.2.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 +14 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +24 -4
- package/dist/config.js.map +1 -1
- package/dist/index.js +87 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,6 +58,20 @@ npx @honeyfield/rent2b-mcp --http --port=8080
|
|
|
58
58
|
|
|
59
59
|
This exposes a single `/mcp` endpoint supporting POST (JSON-RPC messages), GET (SSE notifications), and DELETE (session termination). Sessions are tracked server-side via the `Mcp-Session-Id` header.
|
|
60
60
|
|
|
61
|
+
**Authentication:** In HTTP and SSE mode, each client sends their own API key per request via header:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Authorization: Bearer r2b_your-api-key
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
or:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
X-API-Key: r2b_your-api-key
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The API key is validated on session creation. The `RENT2B_API_KEY` environment variable is **not required** in HTTP/SSE mode.
|
|
74
|
+
|
|
61
75
|
### SSE Mode (Legacy)
|
|
62
76
|
|
|
63
77
|
For SSE transport (e.g. for older web-based MCP clients):
|
package/dist/config.d.ts
CHANGED
|
@@ -3,3 +3,8 @@ export interface Config {
|
|
|
3
3
|
apiUrl: string;
|
|
4
4
|
}
|
|
5
5
|
export declare function loadConfig(): Config;
|
|
6
|
+
export declare function loadHttpConfig(): {
|
|
7
|
+
apiUrl: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function validateApiKey(apiKey: string): void;
|
|
10
|
+
export declare function extractApiKey(headers: Record<string, string | string[] | undefined>): string;
|
package/dist/config.js
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
|
+
const DEFAULT_API_URL = 'https://rent2b-api.azurewebsites.net/api/v1';
|
|
1
2
|
export function loadConfig() {
|
|
2
3
|
const apiKey = process.env.RENT2B_API_KEY;
|
|
3
4
|
if (!apiKey) {
|
|
4
5
|
throw new Error('RENT2B_API_KEY environment variable is required');
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
-
throw new Error('RENT2B_API_KEY must start with "r2b_"');
|
|
8
|
-
}
|
|
7
|
+
validateApiKey(apiKey);
|
|
9
8
|
return {
|
|
10
9
|
apiKey,
|
|
11
|
-
apiUrl: process.env.RENT2B_API_URL ||
|
|
10
|
+
apiUrl: process.env.RENT2B_API_URL || DEFAULT_API_URL,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function loadHttpConfig() {
|
|
14
|
+
return {
|
|
15
|
+
apiUrl: process.env.RENT2B_API_URL || DEFAULT_API_URL,
|
|
12
16
|
};
|
|
13
17
|
}
|
|
18
|
+
export function validateApiKey(apiKey) {
|
|
19
|
+
if (!apiKey.startsWith('r2b_')) {
|
|
20
|
+
throw new Error('API key must start with "r2b_"');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function extractApiKey(headers) {
|
|
24
|
+
const authHeader = headers['authorization'];
|
|
25
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
26
|
+
return authHeader.slice(7);
|
|
27
|
+
}
|
|
28
|
+
const xApiKey = headers['x-api-key'];
|
|
29
|
+
if (xApiKey) {
|
|
30
|
+
return xApiKey;
|
|
31
|
+
}
|
|
32
|
+
throw new Error('Missing API key. Provide via Authorization: Bearer <key> or X-API-Key header.');
|
|
33
|
+
}
|
|
14
34
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,eAAe,GAAG,6CAA6C,CAAC;AAEtE,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO;QACL,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe;KACtD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe;KACtD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAsD;IAClF,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,CAAuB,CAAC;IAClE,IAAI,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAuB,CAAC;IAC3D,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;AACnG,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import { loadConfig } from './config.js';
|
|
4
|
+
import { loadConfig, loadHttpConfig, extractApiKey, validateApiKey } from './config.js';
|
|
5
5
|
import { Rent2bApiClient } from './api-client.js';
|
|
6
6
|
import { createServer } from './server.js';
|
|
7
7
|
async function main() {
|
|
@@ -9,36 +9,44 @@ async function main() {
|
|
|
9
9
|
const useSSE = args.includes('--sse');
|
|
10
10
|
const useHTTP = args.includes('--http');
|
|
11
11
|
const port = parseInt(args.find((a) => a.startsWith('--port='))?.split('=')[1] || '8080', 10);
|
|
12
|
-
const config = loadConfig();
|
|
13
|
-
const apiClient = new Rent2bApiClient(config);
|
|
14
|
-
console.error('Resolving organization from API key...');
|
|
15
|
-
try {
|
|
16
|
-
const orgId = await apiClient.resolveOrganization();
|
|
17
|
-
console.error(`Organization resolved: ${orgId}`);
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
const message = err instanceof Error
|
|
21
|
-
? err.message
|
|
22
|
-
: typeof err === 'object' && err !== null && 'message' in err
|
|
23
|
-
? String(err.message)
|
|
24
|
-
: String(err);
|
|
25
|
-
console.error(`Failed to resolve organization: ${message}`);
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
12
|
if (useHTTP) {
|
|
13
|
+
const httpConfig = loadHttpConfig();
|
|
29
14
|
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
30
15
|
const express = (await import('express')).default;
|
|
31
16
|
const app = express();
|
|
32
17
|
app.use(express.json());
|
|
33
|
-
const
|
|
18
|
+
const sessions = new Map();
|
|
34
19
|
app.post('/mcp', async (req, res) => {
|
|
35
20
|
const sessionId = req.headers['mcp-session-id'];
|
|
36
|
-
if (sessionId &&
|
|
37
|
-
const
|
|
38
|
-
await transport.handleRequest(req, res);
|
|
21
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
22
|
+
const session = sessions.get(sessionId);
|
|
23
|
+
await session.transport.handleRequest(req, res);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// New session — extract API key from request headers
|
|
27
|
+
let apiKey;
|
|
28
|
+
try {
|
|
29
|
+
apiKey = extractApiKey(req.headers);
|
|
30
|
+
validateApiKey(apiKey);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
34
|
+
res.status(401).json({ error: message });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const apiClient = new Rent2bApiClient({ apiKey, apiUrl: httpConfig.apiUrl });
|
|
38
|
+
try {
|
|
39
|
+
await apiClient.resolveOrganization();
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const message = err instanceof Error
|
|
43
|
+
? err.message
|
|
44
|
+
: typeof err === 'object' && err !== null && 'message' in err
|
|
45
|
+
? String(err.message)
|
|
46
|
+
: String(err);
|
|
47
|
+
res.status(401).json({ error: `Invalid API key: ${message}` });
|
|
39
48
|
return;
|
|
40
49
|
}
|
|
41
|
-
// New session — create transport + server
|
|
42
50
|
const transport = new StreamableHTTPServerTransport({
|
|
43
51
|
sessionIdGenerator: () => randomUUID(),
|
|
44
52
|
});
|
|
@@ -46,56 +54,81 @@ async function main() {
|
|
|
46
54
|
transport.onclose = () => {
|
|
47
55
|
const sid = transport.sessionId;
|
|
48
56
|
if (sid)
|
|
49
|
-
|
|
57
|
+
sessions.delete(sid);
|
|
50
58
|
server.close();
|
|
51
59
|
};
|
|
52
60
|
await server.connect(transport);
|
|
53
61
|
if (transport.sessionId) {
|
|
54
|
-
|
|
62
|
+
sessions.set(transport.sessionId, { transport, apiClient });
|
|
55
63
|
}
|
|
56
64
|
await transport.handleRequest(req, res);
|
|
57
65
|
});
|
|
58
66
|
app.get('/mcp', async (req, res) => {
|
|
59
67
|
const sessionId = req.headers['mcp-session-id'];
|
|
60
|
-
if (!sessionId || !
|
|
68
|
+
if (!sessionId || !sessions.has(sessionId)) {
|
|
61
69
|
res.status(400).json({ error: 'Invalid or missing session ID' });
|
|
62
70
|
return;
|
|
63
71
|
}
|
|
64
|
-
const
|
|
65
|
-
await transport.handleRequest(req, res);
|
|
72
|
+
const session = sessions.get(sessionId);
|
|
73
|
+
await session.transport.handleRequest(req, res);
|
|
66
74
|
});
|
|
67
75
|
app.delete('/mcp', async (req, res) => {
|
|
68
76
|
const sessionId = req.headers['mcp-session-id'];
|
|
69
|
-
if (!sessionId || !
|
|
77
|
+
if (!sessionId || !sessions.has(sessionId)) {
|
|
70
78
|
res.status(400).json({ error: 'Invalid or missing session ID' });
|
|
71
79
|
return;
|
|
72
80
|
}
|
|
73
|
-
const
|
|
74
|
-
await transport.handleRequest(req, res);
|
|
81
|
+
const session = sessions.get(sessionId);
|
|
82
|
+
await session.transport.handleRequest(req, res);
|
|
75
83
|
});
|
|
76
84
|
app.listen(port, () => {
|
|
77
85
|
console.error(`rent2b MCP server (Streamable HTTP) listening on port ${port}`);
|
|
86
|
+
console.error('API key required per request via Authorization or X-API-Key header');
|
|
78
87
|
});
|
|
79
88
|
}
|
|
80
89
|
else if (useSSE) {
|
|
90
|
+
const httpConfig = loadHttpConfig();
|
|
81
91
|
const { SSEServerTransport } = await import('@modelcontextprotocol/sdk/server/sse.js');
|
|
82
92
|
const express = (await import('express')).default;
|
|
83
93
|
const app = express();
|
|
84
|
-
const
|
|
94
|
+
const sessions = new Map();
|
|
85
95
|
app.get('/sse', async (req, res) => {
|
|
96
|
+
let apiKey;
|
|
97
|
+
try {
|
|
98
|
+
apiKey = extractApiKey(req.headers);
|
|
99
|
+
validateApiKey(apiKey);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
103
|
+
res.status(401).json({ error: message });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const apiClient = new Rent2bApiClient({ apiKey, apiUrl: httpConfig.apiUrl });
|
|
107
|
+
try {
|
|
108
|
+
await apiClient.resolveOrganization();
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
const message = err instanceof Error
|
|
112
|
+
? err.message
|
|
113
|
+
: typeof err === 'object' && err !== null && 'message' in err
|
|
114
|
+
? String(err.message)
|
|
115
|
+
: String(err);
|
|
116
|
+
res.status(401).json({ error: `Invalid API key: ${message}` });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
86
119
|
const server = createServer(apiClient);
|
|
87
120
|
const transport = new SSEServerTransport('/messages', res);
|
|
88
|
-
|
|
121
|
+
sessions.set(transport.sessionId, { transport, apiClient });
|
|
89
122
|
res.on('close', () => {
|
|
90
|
-
|
|
123
|
+
sessions.delete(transport.sessionId);
|
|
91
124
|
});
|
|
92
125
|
await server.connect(transport);
|
|
93
126
|
});
|
|
94
127
|
app.post('/messages', async (req, res) => {
|
|
95
128
|
const sessionId = req.query.sessionId;
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
await transport.handlePostMessage(req, res);
|
|
129
|
+
const session = sessions.get(sessionId);
|
|
130
|
+
if (session) {
|
|
131
|
+
await session.transport.handlePostMessage(req, res);
|
|
99
132
|
}
|
|
100
133
|
else {
|
|
101
134
|
res.status(400).json({ error: 'Unknown or expired session' });
|
|
@@ -103,9 +136,27 @@ async function main() {
|
|
|
103
136
|
});
|
|
104
137
|
app.listen(port, () => {
|
|
105
138
|
console.error(`rent2b MCP server (SSE) listening on port ${port}`);
|
|
139
|
+
console.error('API key required per request via Authorization or X-API-Key header');
|
|
106
140
|
});
|
|
107
141
|
}
|
|
108
142
|
else {
|
|
143
|
+
// stdio mode — use env variable as before
|
|
144
|
+
const config = loadConfig();
|
|
145
|
+
const apiClient = new Rent2bApiClient(config);
|
|
146
|
+
console.error('Resolving organization from API key...');
|
|
147
|
+
try {
|
|
148
|
+
const orgId = await apiClient.resolveOrganization();
|
|
149
|
+
console.error(`Organization resolved: ${orgId}`);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const message = err instanceof Error
|
|
153
|
+
? err.message
|
|
154
|
+
: typeof err === 'object' && err !== null && 'message' in err
|
|
155
|
+
? String(err.message)
|
|
156
|
+
: String(err);
|
|
157
|
+
console.error(`Failed to resolve organization: ${message}`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
109
160
|
const server = createServer(apiClient);
|
|
110
161
|
const transport = new StdioServerTransport();
|
|
111
162
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|