@honeyfield/rent2b-mcp 1.0.1 → 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 +30 -2
- package/dist/config.d.ts +5 -0
- package/dist/config.js +24 -4
- package/dist/config.js.map +1 -1
- package/dist/index.js +128 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,9 +48,33 @@ Add to your MCP configuration:
|
|
|
48
48
|
}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### Streamable HTTP Mode (Recommended)
|
|
52
52
|
|
|
53
|
-
For
|
|
53
|
+
For HTTP-based MCP clients (stateless-friendly, works well with load balancers):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx @honeyfield/rent2b-mcp --http --port=8080
|
|
57
|
+
```
|
|
58
|
+
|
|
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
|
+
|
|
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
|
+
|
|
75
|
+
### SSE Mode (Legacy)
|
|
76
|
+
|
|
77
|
+
For SSE transport (e.g. for older web-based MCP clients):
|
|
54
78
|
|
|
55
79
|
```bash
|
|
56
80
|
npx @honeyfield/rent2b-mcp --sse --port=8080
|
|
@@ -222,7 +246,11 @@ npm run dev
|
|
|
222
246
|
## Testing with MCP Inspector
|
|
223
247
|
|
|
224
248
|
```bash
|
|
249
|
+
# stdio (default)
|
|
225
250
|
npx @anthropic-ai/mcp-inspector dist/index.js
|
|
251
|
+
|
|
252
|
+
# Streamable HTTP
|
|
253
|
+
npx @anthropic-ai/mcp-inspector --transport http --url http://localhost:8080/mcp
|
|
226
254
|
```
|
|
227
255
|
|
|
228
256
|
## License
|
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,47 +1,134 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
2
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { loadConfig } from './config.js';
|
|
4
|
+
import { loadConfig, loadHttpConfig, extractApiKey, validateApiKey } from './config.js';
|
|
4
5
|
import { Rent2bApiClient } from './api-client.js';
|
|
5
6
|
import { createServer } from './server.js';
|
|
6
7
|
async function main() {
|
|
7
8
|
const args = process.argv.slice(2);
|
|
8
9
|
const useSSE = args.includes('--sse');
|
|
10
|
+
const useHTTP = args.includes('--http');
|
|
9
11
|
const port = parseInt(args.find((a) => a.startsWith('--port='))?.split('=')[1] || '8080', 10);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
if (useHTTP) {
|
|
13
|
+
const httpConfig = loadHttpConfig();
|
|
14
|
+
const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
15
|
+
const express = (await import('express')).default;
|
|
16
|
+
const app = express();
|
|
17
|
+
app.use(express.json());
|
|
18
|
+
const sessions = new Map();
|
|
19
|
+
app.post('/mcp', async (req, res) => {
|
|
20
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
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}` });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const transport = new StreamableHTTPServerTransport({
|
|
51
|
+
sessionIdGenerator: () => randomUUID(),
|
|
52
|
+
});
|
|
53
|
+
const server = createServer(apiClient);
|
|
54
|
+
transport.onclose = () => {
|
|
55
|
+
const sid = transport.sessionId;
|
|
56
|
+
if (sid)
|
|
57
|
+
sessions.delete(sid);
|
|
58
|
+
server.close();
|
|
59
|
+
};
|
|
60
|
+
await server.connect(transport);
|
|
61
|
+
if (transport.sessionId) {
|
|
62
|
+
sessions.set(transport.sessionId, { transport, apiClient });
|
|
63
|
+
}
|
|
64
|
+
await transport.handleRequest(req, res);
|
|
65
|
+
});
|
|
66
|
+
app.get('/mcp', async (req, res) => {
|
|
67
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
68
|
+
if (!sessionId || !sessions.has(sessionId)) {
|
|
69
|
+
res.status(400).json({ error: 'Invalid or missing session ID' });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const session = sessions.get(sessionId);
|
|
73
|
+
await session.transport.handleRequest(req, res);
|
|
74
|
+
});
|
|
75
|
+
app.delete('/mcp', async (req, res) => {
|
|
76
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
77
|
+
if (!sessionId || !sessions.has(sessionId)) {
|
|
78
|
+
res.status(400).json({ error: 'Invalid or missing session ID' });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const session = sessions.get(sessionId);
|
|
82
|
+
await session.transport.handleRequest(req, res);
|
|
83
|
+
});
|
|
84
|
+
app.listen(port, () => {
|
|
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');
|
|
87
|
+
});
|
|
25
88
|
}
|
|
26
|
-
if (useSSE) {
|
|
89
|
+
else if (useSSE) {
|
|
90
|
+
const httpConfig = loadHttpConfig();
|
|
27
91
|
const { SSEServerTransport } = await import('@modelcontextprotocol/sdk/server/sse.js');
|
|
28
92
|
const express = (await import('express')).default;
|
|
29
93
|
const app = express();
|
|
30
|
-
const
|
|
94
|
+
const sessions = new Map();
|
|
31
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
|
+
}
|
|
32
119
|
const server = createServer(apiClient);
|
|
33
120
|
const transport = new SSEServerTransport('/messages', res);
|
|
34
|
-
|
|
121
|
+
sessions.set(transport.sessionId, { transport, apiClient });
|
|
35
122
|
res.on('close', () => {
|
|
36
|
-
|
|
123
|
+
sessions.delete(transport.sessionId);
|
|
37
124
|
});
|
|
38
125
|
await server.connect(transport);
|
|
39
126
|
});
|
|
40
127
|
app.post('/messages', async (req, res) => {
|
|
41
128
|
const sessionId = req.query.sessionId;
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
await transport.handlePostMessage(req, res);
|
|
129
|
+
const session = sessions.get(sessionId);
|
|
130
|
+
if (session) {
|
|
131
|
+
await session.transport.handlePostMessage(req, res);
|
|
45
132
|
}
|
|
46
133
|
else {
|
|
47
134
|
res.status(400).json({ error: 'Unknown or expired session' });
|
|
@@ -49,9 +136,27 @@ async function main() {
|
|
|
49
136
|
});
|
|
50
137
|
app.listen(port, () => {
|
|
51
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');
|
|
52
140
|
});
|
|
53
141
|
}
|
|
54
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
|
+
}
|
|
55
160
|
const server = createServer(apiClient);
|
|
56
161
|
const transport = new StdioServerTransport();
|
|
57
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,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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"}
|