@loopstack/mcp-module 0.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 +213 -0
- package/dist/config/mcp-tool-config.schema.d.ts +11 -0
- package/dist/config/mcp-tool-config.schema.d.ts.map +1 -0
- package/dist/config/mcp-tool-config.schema.js +38 -0
- package/dist/config/mcp-tool-config.schema.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +17 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.module.d.ts +3 -0
- package/dist/mcp.module.d.ts.map +1 -0
- package/dist/mcp.module.js +31 -0
- package/dist/mcp.module.js.map +1 -0
- package/dist/services/env-reader.d.ts +8 -0
- package/dist/services/env-reader.d.ts.map +1 -0
- package/dist/services/env-reader.js +10 -0
- package/dist/services/env-reader.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +5 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/mcp-client.service.d.ts +39 -0
- package/dist/services/mcp-client.service.d.ts.map +1 -0
- package/dist/services/mcp-client.service.js +309 -0
- package/dist/services/mcp-client.service.js.map +1 -0
- package/dist/services/mcp-sdk.types.d.ts +14 -0
- package/dist/services/mcp-sdk.types.d.ts.map +1 -0
- package/dist/services/mcp-sdk.types.js +2 -0
- package/dist/services/mcp-sdk.types.js.map +1 -0
- package/dist/services/metrics-port.d.ts +26 -0
- package/dist/services/metrics-port.d.ts.map +1 -0
- package/dist/services/metrics-port.js +6 -0
- package/dist/services/metrics-port.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mcp-call.tool.d.ts +19 -0
- package/dist/tools/mcp-call.tool.d.ts.map +1 -0
- package/dist/tools/mcp-call.tool.js +36 -0
- package/dist/tools/mcp-call.tool.js.map +1 -0
- package/dist/tools/mcp-connection-args.schema.d.ts +11 -0
- package/dist/tools/mcp-connection-args.schema.d.ts.map +1 -0
- package/dist/tools/mcp-connection-args.schema.js +13 -0
- package/dist/tools/mcp-connection-args.schema.js.map +1 -0
- package/dist/tools/mcp-list-tools.tool.d.ts +17 -0
- package/dist/tools/mcp-list-tools.tool.d.ts.map +1 -0
- package/dist/tools/mcp-list-tools.tool.js +32 -0
- package/dist/tools/mcp-list-tools.tool.js.map +1 -0
- package/dist/tools/mcp-tool-base.d.ts +8 -0
- package/dist/tools/mcp-tool-base.d.ts.map +1 -0
- package/dist/tools/mcp-tool-base.js +26 -0
- package/dist/tools/mcp-tool-base.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/url-security.d.ts +8 -0
- package/dist/utils/url-security.d.ts.map +1 -0
- package/dist/utils/url-security.js +192 -0
- package/dist/utils/url-security.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function hostMatchesAllowlist(hostname: string, allowedHosts: string[]): boolean;
|
|
2
|
+
export declare function assertIpIsPublic(ip: string): void;
|
|
3
|
+
export declare function assertResolvableHostIsPublic(host: string): Promise<void>;
|
|
4
|
+
export declare function assertMcpUrlSafe(rawUrl: string, allowedHosts: string[], allowInsecureHttp: boolean, options?: {
|
|
5
|
+
skipDnsResolution?: boolean;
|
|
6
|
+
allowPrivateHosts?: boolean;
|
|
7
|
+
}): Promise<URL>;
|
|
8
|
+
//# sourceMappingURL=url-security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-security.d.ts","sourceRoot":"","sources":["../../src/utils/url-security.ts"],"names":[],"mappings":"AAiBA,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAgBtF;AA+GD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAWjD;AAKD,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB9E;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EAAE,EACtB,iBAAiB,EAAE,OAAO,EAC1B,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GACrE,OAAO,CAAC,GAAG,CAAC,CAkCd"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as dns from 'node:dns/promises';
|
|
2
|
+
import * as net from 'node:net';
|
|
3
|
+
import { domainToASCII } from 'node:url';
|
|
4
|
+
import { McpUrlSecurityError } from '../errors.js';
|
|
5
|
+
function toAscii(host) {
|
|
6
|
+
const ascii = domainToASCII(host);
|
|
7
|
+
return (ascii || host).toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
function normalizePattern(pattern) {
|
|
10
|
+
const p = pattern.toLowerCase();
|
|
11
|
+
if (p.startsWith('*.'))
|
|
12
|
+
return `*.${toAscii(p.slice(2))}`;
|
|
13
|
+
return toAscii(p);
|
|
14
|
+
}
|
|
15
|
+
export function hostMatchesAllowlist(hostname, allowedHosts) {
|
|
16
|
+
const host = toAscii(hostname);
|
|
17
|
+
for (const pattern of allowedHosts) {
|
|
18
|
+
const p = normalizePattern(pattern);
|
|
19
|
+
if (p.startsWith('*.')) {
|
|
20
|
+
const root = p.slice(2);
|
|
21
|
+
if (host === root)
|
|
22
|
+
return true;
|
|
23
|
+
const suffix = `.${root}`;
|
|
24
|
+
if (host.endsWith(suffix) && host.length > suffix.length)
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
else if (host === p) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
function isPrivateIpv4(ip) {
|
|
34
|
+
const parts = ip.split('.').map((x) => Number(x));
|
|
35
|
+
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
const [a, b] = parts;
|
|
39
|
+
if (a === 0)
|
|
40
|
+
return true;
|
|
41
|
+
if (a === 10)
|
|
42
|
+
return true;
|
|
43
|
+
if (a === 127)
|
|
44
|
+
return true;
|
|
45
|
+
if (a === 169 && b === 254)
|
|
46
|
+
return true;
|
|
47
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
48
|
+
return true;
|
|
49
|
+
if (a === 192 && b === 168)
|
|
50
|
+
return true;
|
|
51
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
52
|
+
return true;
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function expandIpv6ToGroups(ip) {
|
|
56
|
+
let s = ip.toLowerCase().split('%')[0] ?? '';
|
|
57
|
+
const dotted = s.match(/^(.*:)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
|
|
58
|
+
if (dotted) {
|
|
59
|
+
const v4 = dotted[2].split('.').map(Number);
|
|
60
|
+
if (v4.some((n) => Number.isNaN(n) || n < 0 || n > 255))
|
|
61
|
+
return undefined;
|
|
62
|
+
const hi = (v4[0] << 8) | v4[1];
|
|
63
|
+
const lo = (v4[2] << 8) | v4[3];
|
|
64
|
+
s = `${dotted[1]}${hi.toString(16)}:${lo.toString(16)}`;
|
|
65
|
+
}
|
|
66
|
+
const halves = s.split('::');
|
|
67
|
+
if (halves.length > 2)
|
|
68
|
+
return undefined;
|
|
69
|
+
const head = halves[0] ? halves[0].split(':') : [];
|
|
70
|
+
let parts;
|
|
71
|
+
if (halves.length === 2) {
|
|
72
|
+
const tail = halves[1] ? halves[1].split(':') : [];
|
|
73
|
+
const missing = 8 - head.length - tail.length;
|
|
74
|
+
if (missing < 0)
|
|
75
|
+
return undefined;
|
|
76
|
+
parts = [...head, ...Array(missing).fill('0'), ...tail];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
parts = head;
|
|
80
|
+
}
|
|
81
|
+
if (parts.length !== 8)
|
|
82
|
+
return undefined;
|
|
83
|
+
const groups = [];
|
|
84
|
+
for (const p of parts) {
|
|
85
|
+
if (!/^[0-9a-f]{1,4}$/.test(p))
|
|
86
|
+
return undefined;
|
|
87
|
+
groups.push(parseInt(p, 16));
|
|
88
|
+
}
|
|
89
|
+
return groups;
|
|
90
|
+
}
|
|
91
|
+
function groupsToIpv4(hi, lo) {
|
|
92
|
+
return `${(hi >> 8) & 0xff}.${hi & 0xff}.${(lo >> 8) & 0xff}.${lo & 0xff}`;
|
|
93
|
+
}
|
|
94
|
+
function embeddedIpv4(groups) {
|
|
95
|
+
if (groups[0] === 0x2002) {
|
|
96
|
+
return groupsToIpv4(groups[1], groups[2]);
|
|
97
|
+
}
|
|
98
|
+
if (groups[0] === 0 &&
|
|
99
|
+
groups[1] === 0 &&
|
|
100
|
+
groups[2] === 0 &&
|
|
101
|
+
groups[3] === 0 &&
|
|
102
|
+
groups[4] === 0 &&
|
|
103
|
+
groups[5] === 0xffff) {
|
|
104
|
+
return groupsToIpv4(groups[6], groups[7]);
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
function isPrivateIpv6(ip) {
|
|
109
|
+
const n = ip.toLowerCase();
|
|
110
|
+
if (n === '::1')
|
|
111
|
+
return true;
|
|
112
|
+
if (n === '::')
|
|
113
|
+
return true;
|
|
114
|
+
if (n.startsWith('fe80:'))
|
|
115
|
+
return true;
|
|
116
|
+
if (n.startsWith('64:ff9b:'))
|
|
117
|
+
return true;
|
|
118
|
+
const first = n.split(':')[0] ?? '';
|
|
119
|
+
if (first.startsWith('fc') || first.startsWith('fd'))
|
|
120
|
+
return true;
|
|
121
|
+
if (first.startsWith('ff'))
|
|
122
|
+
return true;
|
|
123
|
+
const groups = expandIpv6ToGroups(n);
|
|
124
|
+
if (groups) {
|
|
125
|
+
const v4 = embeddedIpv4(groups);
|
|
126
|
+
if (v4 !== undefined && isPrivateIpv4(v4))
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
export function assertIpIsPublic(ip) {
|
|
132
|
+
const family = net.isIP(ip);
|
|
133
|
+
if (family === 0) {
|
|
134
|
+
throw new McpUrlSecurityError('Invalid IP address from resolution.');
|
|
135
|
+
}
|
|
136
|
+
if (family === 4 && isPrivateIpv4(ip)) {
|
|
137
|
+
throw new McpUrlSecurityError('Refusing to connect to a non-public IPv4 address.');
|
|
138
|
+
}
|
|
139
|
+
if (family === 6 && isPrivateIpv6(ip)) {
|
|
140
|
+
throw new McpUrlSecurityError('Refusing to connect to a non-public IPv6 address.');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export async function assertResolvableHostIsPublic(host) {
|
|
144
|
+
if (net.isIP(host)) {
|
|
145
|
+
assertIpIsPublic(host);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let records;
|
|
149
|
+
try {
|
|
150
|
+
records = await dns.lookup(host, { all: true });
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
154
|
+
throw new McpUrlSecurityError(`DNS lookup failed for "${host}": ${msg}`);
|
|
155
|
+
}
|
|
156
|
+
if (records.length === 0) {
|
|
157
|
+
throw new McpUrlSecurityError(`No DNS records for "${host}".`);
|
|
158
|
+
}
|
|
159
|
+
for (const r of records) {
|
|
160
|
+
assertIpIsPublic(r.address);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export async function assertMcpUrlSafe(rawUrl, allowedHosts, allowInsecureHttp, options) {
|
|
164
|
+
let url;
|
|
165
|
+
try {
|
|
166
|
+
url = new URL(rawUrl);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
throw new McpUrlSecurityError('Invalid serverUrl.');
|
|
170
|
+
}
|
|
171
|
+
if (url.username || url.password) {
|
|
172
|
+
throw new McpUrlSecurityError('Userinfo in serverUrl is not allowed; use headers or headerEnv in tool config.');
|
|
173
|
+
}
|
|
174
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
175
|
+
throw new McpUrlSecurityError('Only http and https MCP URLs are supported.');
|
|
176
|
+
}
|
|
177
|
+
if (url.protocol === 'http:' && !allowInsecureHttp) {
|
|
178
|
+
throw new McpUrlSecurityError('HTTP is disabled; use https or set allowInsecureHttp on the tool injection config.');
|
|
179
|
+
}
|
|
180
|
+
const hostname = url.hostname;
|
|
181
|
+
if (!hostname) {
|
|
182
|
+
throw new McpUrlSecurityError('Missing hostname in serverUrl.');
|
|
183
|
+
}
|
|
184
|
+
if (!hostMatchesAllowlist(hostname, allowedHosts)) {
|
|
185
|
+
throw new McpUrlSecurityError(`Hostname "${hostname}" is not in allowedHosts.`);
|
|
186
|
+
}
|
|
187
|
+
if (!options?.skipDnsResolution && !options?.allowPrivateHosts) {
|
|
188
|
+
await assertResolvableHostIsPublic(hostname);
|
|
189
|
+
}
|
|
190
|
+
return url;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=url-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-security.js","sourceRoot":"","sources":["../../src/utils/url-security.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loopstack/mcp-module",
|
|
3
|
+
"displayName": "Loopstack MCP Module",
|
|
4
|
+
"description": "Workflow tools to list and call tools on remote MCP servers over Streamable HTTP, with host allowlisting and SSRF mitigations.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"loopstack",
|
|
9
|
+
"tool"
|
|
10
|
+
],
|
|
11
|
+
"version": "0.2.0",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "Jakob Klippel",
|
|
15
|
+
"url": "https://www.linkedin.com/in/jakob-klippel/"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"types": "dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "nest build",
|
|
28
|
+
"compile": "tsc --noEmit",
|
|
29
|
+
"format": "prettier --write .",
|
|
30
|
+
"lint": "eslint .",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"watch": "nest build --watch"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@loopstack/common": "^0.30.0",
|
|
36
|
+
"@loopstack/core": "^0.30.0",
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
38
|
+
"@nestjs/common": "^11.1.19",
|
|
39
|
+
"@nestjs/core": "^11.1.19",
|
|
40
|
+
"zod": "^4.3.6"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist"
|
|
44
|
+
],
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"vitest": "^4.1.6",
|
|
47
|
+
"@swc/core": "^1.15.33",
|
|
48
|
+
"unplugin-swc": "^1.5.9"
|
|
49
|
+
}
|
|
50
|
+
}
|