mcp4openapi 0.1.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/LICENSE.md +7 -0
- package/README.md +489 -0
- package/dist/composite-executor.d.ts +65 -0
- package/dist/composite-executor.d.ts.map +1 -0
- package/dist/composite-executor.js +147 -0
- package/dist/composite-executor.js.map +1 -0
- package/dist/constants.d.ts +36 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +36 -0
- package/dist/constants.js.map +1 -0
- package/dist/http-transport.d.ts +195 -0
- package/dist/http-transport.d.ts.map +1 -0
- package/dist/http-transport.js +760 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/interceptors.d.ts +74 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +220 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/logger.d.ts +81 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +264 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-server.d.ts +110 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +568 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/metrics.d.ts +86 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +229 -0
- package/dist/metrics.js.map +1 -0
- package/dist/openapi-parser.d.ts +35 -0
- package/dist/openapi-parser.d.ts.map +1 -0
- package/dist/openapi-parser.js +160 -0
- package/dist/openapi-parser.js.map +1 -0
- package/dist/profile-loader.d.ts +25 -0
- package/dist/profile-loader.d.ts.map +1 -0
- package/dist/profile-loader.js +134 -0
- package/dist/profile-loader.js.map +1 -0
- package/dist/schema-validator.d.ts +32 -0
- package/dist/schema-validator.d.ts.map +1 -0
- package/dist/schema-validator.js +126 -0
- package/dist/schema-validator.js.map +1 -0
- package/dist/scripts/validate-profile.d.ts +9 -0
- package/dist/scripts/validate-profile.d.ts.map +1 -0
- package/dist/scripts/validate-profile.js +289 -0
- package/dist/scripts/validate-profile.js.map +1 -0
- package/dist/scripts/validate-schema.d.ts +9 -0
- package/dist/scripts/validate-schema.d.ts.map +1 -0
- package/dist/scripts/validate-schema.js +84 -0
- package/dist/scripts/validate-schema.js.map +1 -0
- package/dist/src/composite-executor.d.ts +75 -0
- package/dist/src/composite-executor.d.ts.map +1 -0
- package/dist/src/composite-executor.js +175 -0
- package/dist/src/composite-executor.js.map +1 -0
- package/dist/src/constants.d.ts +36 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +36 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/dag-executor.d.ts +49 -0
- package/dist/src/dag-executor.d.ts.map +1 -0
- package/dist/src/dag-executor.js +138 -0
- package/dist/src/dag-executor.js.map +1 -0
- package/dist/src/errors.d.ts +47 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +99 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/generated-schemas.d.ts +661 -0
- package/dist/src/generated-schemas.d.ts.map +1 -0
- package/dist/src/generated-schemas.js +66 -0
- package/dist/src/generated-schemas.js.map +1 -0
- package/dist/src/http-client-factory.d.ts +62 -0
- package/dist/src/http-client-factory.d.ts.map +1 -0
- package/dist/src/http-client-factory.js +121 -0
- package/dist/src/http-client-factory.js.map +1 -0
- package/dist/src/http-transport.d.ts +194 -0
- package/dist/src/http-transport.d.ts.map +1 -0
- package/dist/src/http-transport.js +851 -0
- package/dist/src/http-transport.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +59 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interceptors.d.ts +78 -0
- package/dist/src/interceptors.d.ts.map +1 -0
- package/dist/src/interceptors.js +252 -0
- package/dist/src/interceptors.js.map +1 -0
- package/dist/src/jsonrpc-validator.d.ts +27 -0
- package/dist/src/jsonrpc-validator.d.ts.map +1 -0
- package/dist/src/jsonrpc-validator.js +58 -0
- package/dist/src/jsonrpc-validator.js.map +1 -0
- package/dist/src/lib.d.ts +8 -0
- package/dist/src/lib.d.ts.map +1 -0
- package/dist/src/lib.js +7 -0
- package/dist/src/lib.js.map +1 -0
- package/dist/src/logger.d.ts +81 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +264 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/mcp-server.d.ts +117 -0
- package/dist/src/mcp-server.d.ts.map +1 -0
- package/dist/src/mcp-server.js +621 -0
- package/dist/src/mcp-server.js.map +1 -0
- package/dist/src/metrics.d.ts +86 -0
- package/dist/src/metrics.d.ts.map +1 -0
- package/dist/src/metrics.js +229 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/naming-warnings.d.ts +23 -0
- package/dist/src/naming-warnings.d.ts.map +1 -0
- package/dist/src/naming-warnings.js +83 -0
- package/dist/src/naming-warnings.js.map +1 -0
- package/dist/src/naming.d.ts +58 -0
- package/dist/src/naming.d.ts.map +1 -0
- package/dist/src/naming.js +510 -0
- package/dist/src/naming.js.map +1 -0
- package/dist/src/openapi-parser.d.ts +49 -0
- package/dist/src/openapi-parser.d.ts.map +1 -0
- package/dist/src/openapi-parser.js +216 -0
- package/dist/src/openapi-parser.js.map +1 -0
- package/dist/src/profile-loader.d.ts +77 -0
- package/dist/src/profile-loader.d.ts.map +1 -0
- package/dist/src/profile-loader.js +443 -0
- package/dist/src/profile-loader.js.map +1 -0
- package/dist/src/schema-validator.d.ts +30 -0
- package/dist/src/schema-validator.d.ts.map +1 -0
- package/dist/src/schema-validator.js +115 -0
- package/dist/src/schema-validator.js.map +1 -0
- package/dist/src/testing/fixtures.d.ts +268 -0
- package/dist/src/testing/fixtures.d.ts.map +1 -0
- package/dist/src/testing/fixtures.js +210 -0
- package/dist/src/testing/fixtures.js.map +1 -0
- package/dist/src/testing/mock-gitlab-server.d.ts +34 -0
- package/dist/src/testing/mock-gitlab-server.d.ts.map +1 -0
- package/dist/src/testing/mock-gitlab-server.js +351 -0
- package/dist/src/testing/mock-gitlab-server.js.map +1 -0
- package/dist/src/testing/mock-utils.d.ts +41 -0
- package/dist/src/testing/mock-utils.d.ts.map +1 -0
- package/dist/src/testing/mock-utils.js +59 -0
- package/dist/src/testing/mock-utils.js.map +1 -0
- package/dist/src/testing/test-http-utils.d.ts +52 -0
- package/dist/src/testing/test-http-utils.d.ts.map +1 -0
- package/dist/src/testing/test-http-utils.js +109 -0
- package/dist/src/testing/test-http-utils.js.map +1 -0
- package/dist/src/testing/test-types.d.ts +76 -0
- package/dist/src/testing/test-types.d.ts.map +1 -0
- package/dist/src/testing/test-types.js +7 -0
- package/dist/src/testing/test-types.js.map +1 -0
- package/dist/src/tool-generator.d.ts +43 -0
- package/dist/src/tool-generator.d.ts.map +1 -0
- package/dist/src/tool-generator.js +123 -0
- package/dist/src/tool-generator.js.map +1 -0
- package/dist/src/types/http-transport.d.ts +45 -0
- package/dist/src/types/http-transport.d.ts.map +1 -0
- package/dist/src/types/http-transport.js +8 -0
- package/dist/src/types/http-transport.js.map +1 -0
- package/dist/src/types/openapi.d.ts +50 -0
- package/dist/src/types/openapi.d.ts.map +1 -0
- package/dist/src/types/openapi.js +9 -0
- package/dist/src/types/openapi.js.map +1 -0
- package/dist/src/types/profile.d.ts +80 -0
- package/dist/src/types/profile.d.ts.map +1 -0
- package/dist/src/types/profile.js +9 -0
- package/dist/src/types/profile.js.map +1 -0
- package/dist/src/validation-utils.d.ts +15 -0
- package/dist/src/validation-utils.d.ts.map +1 -0
- package/dist/src/validation-utils.js +25 -0
- package/dist/src/validation-utils.js.map +1 -0
- package/dist/testing/fixtures.d.ts +186 -0
- package/dist/testing/fixtures.d.ts.map +1 -0
- package/dist/testing/fixtures.js +135 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/http-integration.test.d.ts +7 -0
- package/dist/testing/http-integration.test.d.ts.map +1 -0
- package/dist/testing/http-integration.test.js +383 -0
- package/dist/testing/http-integration.test.js.map +1 -0
- package/dist/testing/http-multiuser.test.d.ts +10 -0
- package/dist/testing/http-multiuser.test.d.ts.map +1 -0
- package/dist/testing/http-multiuser.test.js +255 -0
- package/dist/testing/http-multiuser.test.js.map +1 -0
- package/dist/testing/integration.test.d.ts +8 -0
- package/dist/testing/integration.test.d.ts.map +1 -0
- package/dist/testing/integration.test.js +247 -0
- package/dist/testing/integration.test.js.map +1 -0
- package/dist/testing/mock-gitlab-server.d.ts +34 -0
- package/dist/testing/mock-gitlab-server.d.ts.map +1 -0
- package/dist/testing/mock-gitlab-server.js +224 -0
- package/dist/testing/mock-gitlab-server.js.map +1 -0
- package/dist/testing/test-types.d.ts +59 -0
- package/dist/testing/test-types.d.ts.map +1 -0
- package/dist/testing/test-types.js +7 -0
- package/dist/testing/test-types.js.map +1 -0
- package/dist/tool-generator.d.ts +43 -0
- package/dist/tool-generator.d.ts.map +1 -0
- package/dist/tool-generator.js +123 -0
- package/dist/tool-generator.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/http-transport.d.ts +39 -0
- package/dist/types/http-transport.d.ts.map +1 -0
- package/dist/types/http-transport.js +8 -0
- package/dist/types/http-transport.js.map +1 -0
- package/dist/types/openapi.d.ts +50 -0
- package/dist/types/openapi.d.ts.map +1 -0
- package/dist/types/openapi.js +9 -0
- package/dist/types/openapi.js.map +1 -0
- package/dist/types/profile.d.ts +76 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +9 -0
- package/dist/types/profile.js.map +1 -0
- package/package.json +84 -0
- package/profile-schema.json +369 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite action executor for chaining API calls
|
|
3
|
+
*
|
|
4
|
+
* Why: Reduces roundtrips by fetching related data in sequence (e.g., MR + comments).
|
|
5
|
+
* Aggregates results into single JSON structure as defined by store_as paths.
|
|
6
|
+
*/
|
|
7
|
+
export class CompositeExecutor {
|
|
8
|
+
parser;
|
|
9
|
+
httpClient;
|
|
10
|
+
constructor(parser, httpClient) {
|
|
11
|
+
this.parser = parser;
|
|
12
|
+
this.httpClient = httpClient;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Execute a series of API calls and merge results
|
|
16
|
+
*
|
|
17
|
+
* Why sequential: Steps may depend on previous results (e.g., get MR ID, then fetch comments).
|
|
18
|
+
* Could parallelize independent steps in future optimization.
|
|
19
|
+
*
|
|
20
|
+
* Supports partial results: If allowPartial=true, continues after errors and returns
|
|
21
|
+
* what was completed. Useful for composite actions where some data is better than none.
|
|
22
|
+
*/
|
|
23
|
+
async execute(steps, args, allowPartial = false, httpClient) {
|
|
24
|
+
const result = {};
|
|
25
|
+
const errors = [];
|
|
26
|
+
let completedSteps = 0;
|
|
27
|
+
for (let i = 0; i < steps.length; i++) {
|
|
28
|
+
const step = steps[i];
|
|
29
|
+
try {
|
|
30
|
+
const { method, path, operation } = this.parseCall(step.call);
|
|
31
|
+
if (!operation) {
|
|
32
|
+
throw new Error(`Operation not found for call: ${step.call}`);
|
|
33
|
+
}
|
|
34
|
+
// Substitute path parameters from args
|
|
35
|
+
const resolvedPath = this.resolvePath(path, args);
|
|
36
|
+
// Execute request
|
|
37
|
+
const client = httpClient || this.httpClient;
|
|
38
|
+
if (!client) {
|
|
39
|
+
throw new Error('HTTP client not provided');
|
|
40
|
+
}
|
|
41
|
+
const response = await client.request(method, resolvedPath, {
|
|
42
|
+
params: this.extractQueryParams(operation, args),
|
|
43
|
+
});
|
|
44
|
+
// Store result at specified path
|
|
45
|
+
this.storeResult(result, step.store_as, response.body);
|
|
46
|
+
completedSteps++;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const stepError = {
|
|
50
|
+
step_index: i,
|
|
51
|
+
step_call: step.call,
|
|
52
|
+
error: error instanceof Error ? error.message : String(error),
|
|
53
|
+
timestamp: new Date().toISOString(),
|
|
54
|
+
};
|
|
55
|
+
errors.push(stepError);
|
|
56
|
+
// Store error in result for debugging
|
|
57
|
+
this.storeResult(result, `${step.store_as}_error`, stepError);
|
|
58
|
+
if (!allowPartial) {
|
|
59
|
+
throw new Error(`Composite step ${i + 1}/${steps.length} failed: ${stepError.error}\n` +
|
|
60
|
+
`Completed steps: ${completedSteps}\n` +
|
|
61
|
+
`Failed step: ${step.call}`);
|
|
62
|
+
}
|
|
63
|
+
// Continue with next step if partial results allowed
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
data: result,
|
|
68
|
+
completed_steps: completedSteps,
|
|
69
|
+
total_steps: steps.length,
|
|
70
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse composite step call syntax
|
|
75
|
+
*
|
|
76
|
+
* Format: "GET /projects/{id}/merge_requests/{iid}"
|
|
77
|
+
*/
|
|
78
|
+
parseCall(call) {
|
|
79
|
+
const [method, path] = call.split(' ');
|
|
80
|
+
const pathInfo = this.parser.getPath(path);
|
|
81
|
+
const operation = pathInfo?.operations[method.toLowerCase()];
|
|
82
|
+
return { method, path, operation };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve path template with actual values
|
|
86
|
+
*
|
|
87
|
+
* Example: "/projects/{id}" + {id: "123"} => "/projects/123"
|
|
88
|
+
*/
|
|
89
|
+
resolvePath(template, args) {
|
|
90
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
91
|
+
const value = args[key];
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
throw new Error(`Missing path parameter: ${key}`);
|
|
94
|
+
}
|
|
95
|
+
return String(value);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Extract query parameters from args based on operation definition
|
|
100
|
+
*/
|
|
101
|
+
extractQueryParams(operation, args) {
|
|
102
|
+
const params = {};
|
|
103
|
+
for (const param of operation.parameters) {
|
|
104
|
+
if (param.in === 'query' && args[param.name] !== undefined) {
|
|
105
|
+
const value = args[param.name];
|
|
106
|
+
// Pass arrays as-is for HttpClient serialization
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
params[param.name] = value.map(String);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
params[param.name] = String(value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return params;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Store value at JSONPath-like location
|
|
119
|
+
*
|
|
120
|
+
* Why nested: Allows semantic structure (comments belong under merge_request object).
|
|
121
|
+
*
|
|
122
|
+
* Examples:
|
|
123
|
+
* - "merge_request" => { merge_request: value }
|
|
124
|
+
* - "merge_request.comments" => { merge_request: { comments: value } }
|
|
125
|
+
*
|
|
126
|
+
* Validates path navigation to prevent overwriting non-object values.
|
|
127
|
+
*/
|
|
128
|
+
storeResult(target, path, value) {
|
|
129
|
+
const parts = path.split('.');
|
|
130
|
+
let current = target;
|
|
131
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
132
|
+
const part = parts[i];
|
|
133
|
+
const existing = current[part];
|
|
134
|
+
// Validate we can navigate through this path
|
|
135
|
+
if (existing !== undefined && (typeof existing !== 'object' || existing === null)) {
|
|
136
|
+
throw new Error(`Cannot store at path '${path}': ` +
|
|
137
|
+
`'${parts.slice(0, i + 1).join('.')}' is ${typeof existing}, not an object`);
|
|
138
|
+
}
|
|
139
|
+
if (!current[part]) {
|
|
140
|
+
current[part] = {};
|
|
141
|
+
}
|
|
142
|
+
current = current[part];
|
|
143
|
+
}
|
|
144
|
+
current[parts[parts.length - 1]] = value;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=composite-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composite-executor.js","sourceRoot":"","sources":["../src/composite-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,MAAM,OAAO,iBAAiB;IAElB;IACA;IAFV,YACU,MAAqB,EACrB,UAAuB;QADvB,WAAM,GAAN,MAAM,CAAe;QACrB,eAAU,GAAV,UAAU,CAAa;IAC9B,CAAC;IAEJ;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CACX,KAAsB,EACtB,IAA6B,EAC7B,eAAwB,KAAK,EAC7B,UAAuB;QAEvB,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,MAAM,MAAM,GAAgB,EAAE,CAAC;QAC/B,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAEtB,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAE9D,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChE,CAAC;gBAED,uCAAuC;gBACvC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAElD,kBAAkB;gBAClB,MAAM,MAAM,GAAG,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC;gBAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;gBAC9C,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,EAAE;oBAC1D,MAAM,EAAE,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC;iBACjD,CAAC,CAAC;gBAEH,iCAAiC;gBACjC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACvD,cAAc,EAAE,CAAC;YAEnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,SAAS,GAAc;oBAC3B,UAAU,EAAE,CAAC;oBACb,SAAS,EAAE,IAAI,CAAC,IAAI;oBACpB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC7D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC;gBAEF,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAEvB,sCAAsC;gBACtC,IAAI,CAAC,WAAW,CACd,MAAM,EACN,GAAG,IAAI,CAAC,QAAQ,QAAQ,EACxB,SAAS,CACV,CAAC;gBAEF,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CACb,kBAAkB,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,YAAY,SAAS,CAAC,KAAK,IAAI;wBACtE,oBAAoB,cAAc,IAAI;wBACtC,gBAAgB,IAAI,CAAC,IAAI,EAAE,CAC5B,CAAC;gBACJ,CAAC;gBAED,qDAAqD;YACvD,CAAC;QACH,CAAC;QAED,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,eAAe,EAAE,cAAc;YAC/B,WAAW,EAAE,KAAK,CAAC,MAAM;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SAC/C,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,SAAS,CAAC,IAAY;QAC5B,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,SAAS,GAAG,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAE7D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,QAAgB,EAAE,IAA6B;QACjE,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,SAAwB,EAAE,IAA6B;QAChF,MAAM,MAAM,GAAsC,EAAE,CAAC;QAErD,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YACzC,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,iDAAiD;gBACjD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACzC,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;OAUG;IACK,WAAW,CAAC,MAA+B,EAAE,IAAY,EAAE,KAAc;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,OAAO,GAAG,MAAiC,CAAC;QAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAE/B,6CAA6C;YAC7C,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,CAAC,EAAE,CAAC;gBAClF,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,KAAK;oBAClC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,OAAO,QAAQ,iBAAiB,CAC5E,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACrB,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,IAAI,CAA4B,CAAC;QACrD,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application constants
|
|
3
|
+
*
|
|
4
|
+
* Why: Centralized constants improve readability and maintainability.
|
|
5
|
+
* Magic numbers scattered through code are harder to understand and change.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Time conversion constants
|
|
9
|
+
*/
|
|
10
|
+
export declare const TIME: {
|
|
11
|
+
readonly MS_PER_SECOND: 1000;
|
|
12
|
+
readonly MS_PER_MINUTE: 60000;
|
|
13
|
+
readonly MS_PER_HOUR: 3600000;
|
|
14
|
+
readonly SECONDS_PER_MINUTE: 60;
|
|
15
|
+
readonly MINUTES_PER_HOUR: 60;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* HTTP status codes
|
|
19
|
+
*
|
|
20
|
+
* Why: Named constants more readable than numeric literals.
|
|
21
|
+
* Makes intent clear (STATUS_TOO_MANY_REQUESTS vs 429).
|
|
22
|
+
*/
|
|
23
|
+
export declare const HTTP_STATUS: {
|
|
24
|
+
readonly OK: 200;
|
|
25
|
+
readonly MULTIPLE_CHOICES: 300;
|
|
26
|
+
readonly BAD_REQUEST: 400;
|
|
27
|
+
readonly UNAUTHORIZED: 401;
|
|
28
|
+
readonly FORBIDDEN: 403;
|
|
29
|
+
readonly NOT_FOUND: 404;
|
|
30
|
+
readonly TOO_MANY_REQUESTS: 429;
|
|
31
|
+
readonly INTERNAL_SERVER_ERROR: 500;
|
|
32
|
+
readonly BAD_GATEWAY: 502;
|
|
33
|
+
readonly SERVICE_UNAVAILABLE: 503;
|
|
34
|
+
readonly GATEWAY_TIMEOUT: 504;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,IAAI;;;;;;CAMP,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;CAYd,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application constants
|
|
3
|
+
*
|
|
4
|
+
* Why: Centralized constants improve readability and maintainability.
|
|
5
|
+
* Magic numbers scattered through code are harder to understand and change.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Time conversion constants
|
|
9
|
+
*/
|
|
10
|
+
export const TIME = {
|
|
11
|
+
MS_PER_SECOND: 1000,
|
|
12
|
+
MS_PER_MINUTE: 60000,
|
|
13
|
+
MS_PER_HOUR: 3600000,
|
|
14
|
+
SECONDS_PER_MINUTE: 60,
|
|
15
|
+
MINUTES_PER_HOUR: 60,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* HTTP status codes
|
|
19
|
+
*
|
|
20
|
+
* Why: Named constants more readable than numeric literals.
|
|
21
|
+
* Makes intent clear (STATUS_TOO_MANY_REQUESTS vs 429).
|
|
22
|
+
*/
|
|
23
|
+
export const HTTP_STATUS = {
|
|
24
|
+
OK: 200,
|
|
25
|
+
MULTIPLE_CHOICES: 300,
|
|
26
|
+
BAD_REQUEST: 400,
|
|
27
|
+
UNAUTHORIZED: 401,
|
|
28
|
+
FORBIDDEN: 403,
|
|
29
|
+
NOT_FOUND: 404,
|
|
30
|
+
TOO_MANY_REQUESTS: 429,
|
|
31
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
32
|
+
BAD_GATEWAY: 502,
|
|
33
|
+
SERVICE_UNAVAILABLE: 503,
|
|
34
|
+
GATEWAY_TIMEOUT: 504,
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,OAAO;IACpB,kBAAkB,EAAE,EAAE;IACtB,gBAAgB,EAAE,EAAE;CACZ,CAAC;AAEX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,GAAG;IACP,gBAAgB,EAAE,GAAG;IACrB,WAAW,EAAE,GAAG;IAChB,YAAY,EAAE,GAAG;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,iBAAiB,EAAE,GAAG;IACtB,qBAAqB,EAAE,GAAG;IAC1B,WAAW,EAAE,GAAG;IAChB,mBAAmB,EAAE,GAAG;IACxB,eAAe,EAAE,GAAG;CACZ,CAAC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Streamable Transport for MCP
|
|
3
|
+
*
|
|
4
|
+
* Implements MCP Specification 2025-03-26
|
|
5
|
+
* https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
|
|
6
|
+
*
|
|
7
|
+
* Why: Enables remote MCP server access with SSE streaming, session management,
|
|
8
|
+
* and resumability for reliable communication over HTTP.
|
|
9
|
+
*/
|
|
10
|
+
import type { Logger } from './logger.js';
|
|
11
|
+
import type { HttpTransportConfig } from './types/http-transport.js';
|
|
12
|
+
export declare class HttpTransport {
|
|
13
|
+
private app;
|
|
14
|
+
private server;
|
|
15
|
+
private sessions;
|
|
16
|
+
private config;
|
|
17
|
+
private logger;
|
|
18
|
+
private metrics;
|
|
19
|
+
private cleanupInterval;
|
|
20
|
+
private messageHandler;
|
|
21
|
+
constructor(config: HttpTransportConfig, logger: Logger);
|
|
22
|
+
/**
|
|
23
|
+
* Setup Express middleware
|
|
24
|
+
*
|
|
25
|
+
* Why: Security (Origin validation), JSON parsing, session extraction, metrics
|
|
26
|
+
*/
|
|
27
|
+
private setupMiddleware;
|
|
28
|
+
private hasWarnedAboutBinding;
|
|
29
|
+
/**
|
|
30
|
+
* Check if origin is allowed
|
|
31
|
+
*
|
|
32
|
+
* Why: Prevent DNS rebinding attacks
|
|
33
|
+
*
|
|
34
|
+
* Supports:
|
|
35
|
+
* - Exact hostname: 'example.com', 'api.example.com'
|
|
36
|
+
* - Wildcard subdomain: '*.example.com'
|
|
37
|
+
* - IPv4 CIDR: '192.168.1.0/24', '10.0.0.0/8'
|
|
38
|
+
* - IPv4 exact: '192.168.1.100'
|
|
39
|
+
*/
|
|
40
|
+
private isAllowedOrigin;
|
|
41
|
+
/**
|
|
42
|
+
* Match hostname against allowed origin pattern
|
|
43
|
+
*
|
|
44
|
+
* Supports:
|
|
45
|
+
* - Exact match: 'example.com' === 'example.com'
|
|
46
|
+
* - Wildcard: '*.example.com' matches 'api.example.com', 'web.example.com'
|
|
47
|
+
* - CIDR: '192.168.1.0/24' matches '192.168.1.1' through '192.168.1.254'
|
|
48
|
+
*/
|
|
49
|
+
private matchOrigin;
|
|
50
|
+
/**
|
|
51
|
+
* Check if IP address is within CIDR range
|
|
52
|
+
*
|
|
53
|
+
* Example: '192.168.1.50' matches '192.168.1.0/24'
|
|
54
|
+
*/
|
|
55
|
+
private matchCIDR;
|
|
56
|
+
/**
|
|
57
|
+
* Convert IPv4 address to 32-bit integer
|
|
58
|
+
*
|
|
59
|
+
* Example: '192.168.1.1' -> 3232235777
|
|
60
|
+
*/
|
|
61
|
+
private ipToInt;
|
|
62
|
+
/**
|
|
63
|
+
* Setup MCP endpoint routes
|
|
64
|
+
*
|
|
65
|
+
* Why: Single endpoint for POST (client→server) and GET (SSE stream)
|
|
66
|
+
*/
|
|
67
|
+
private setupRoutes;
|
|
68
|
+
/**
|
|
69
|
+
* Handle metrics endpoint
|
|
70
|
+
*
|
|
71
|
+
* Why: Prometheus scraping endpoint
|
|
72
|
+
*/
|
|
73
|
+
private handleMetrics;
|
|
74
|
+
/**
|
|
75
|
+
* Validate token format and length
|
|
76
|
+
*
|
|
77
|
+
* Why centralized: Single source of truth for token validation rules
|
|
78
|
+
*/
|
|
79
|
+
private validateToken;
|
|
80
|
+
/**
|
|
81
|
+
* Extract and validate auth token from request headers
|
|
82
|
+
*
|
|
83
|
+
* Supports:
|
|
84
|
+
* - Authorization: Bearer <token>
|
|
85
|
+
* - X-API-Token: <token>
|
|
86
|
+
*
|
|
87
|
+
* Why strict validation: Prevents header injection attacks
|
|
88
|
+
*/
|
|
89
|
+
private extractAuthToken;
|
|
90
|
+
/**
|
|
91
|
+
* Handle POST requests - Client sending messages to server
|
|
92
|
+
*
|
|
93
|
+
* MCP Spec: POST can contain requests, notifications, or responses
|
|
94
|
+
*/
|
|
95
|
+
private handlePost;
|
|
96
|
+
/**
|
|
97
|
+
* Handle GET requests - Client opening SSE stream for server messages
|
|
98
|
+
*
|
|
99
|
+
* MCP Spec: GET opens SSE stream for server-initiated requests/notifications
|
|
100
|
+
*/
|
|
101
|
+
private handleGet;
|
|
102
|
+
/**
|
|
103
|
+
* Handle DELETE requests - Client terminating session
|
|
104
|
+
*
|
|
105
|
+
* MCP Spec: DELETE explicitly terminates session
|
|
106
|
+
*/
|
|
107
|
+
private handleDelete;
|
|
108
|
+
/**
|
|
109
|
+
* Start SSE response for a POST request
|
|
110
|
+
*
|
|
111
|
+
* Why: Returns response via SSE stream, allows server-initiated messages
|
|
112
|
+
*/
|
|
113
|
+
private startSSEResponse;
|
|
114
|
+
/**
|
|
115
|
+
* Start SSE stream for GET request
|
|
116
|
+
*
|
|
117
|
+
* Why: Allows server to send requests/notifications to client
|
|
118
|
+
*/
|
|
119
|
+
private startSSEStream;
|
|
120
|
+
/**
|
|
121
|
+
* Replay messages after Last-Event-ID
|
|
122
|
+
*
|
|
123
|
+
* Why: Resumability - client can reconnect and receive missed messages
|
|
124
|
+
*/
|
|
125
|
+
private replayMessages;
|
|
126
|
+
/**
|
|
127
|
+
* Send message to client via SSE
|
|
128
|
+
*
|
|
129
|
+
* Why: Server-initiated requests/notifications
|
|
130
|
+
*/
|
|
131
|
+
sendToClient(sessionId: string, message: unknown): void;
|
|
132
|
+
/**
|
|
133
|
+
* Check if request is initialization
|
|
134
|
+
*/
|
|
135
|
+
private isInitializeRequest;
|
|
136
|
+
/**
|
|
137
|
+
* Determine message type (request, notification, response)
|
|
138
|
+
*/
|
|
139
|
+
private getMessageType;
|
|
140
|
+
/**
|
|
141
|
+
* Create new session
|
|
142
|
+
*
|
|
143
|
+
* Why: Stateful sessions for MCP protocol
|
|
144
|
+
*/
|
|
145
|
+
private createSession;
|
|
146
|
+
/**
|
|
147
|
+
* Update session activity timestamp
|
|
148
|
+
*/
|
|
149
|
+
private updateSessionActivity;
|
|
150
|
+
/**
|
|
151
|
+
* Destroy session and cleanup resources
|
|
152
|
+
*
|
|
153
|
+
* Why: Free memory, close streams
|
|
154
|
+
*/
|
|
155
|
+
private destroySession;
|
|
156
|
+
/**
|
|
157
|
+
* Session destruction listeners for cleanup in other components
|
|
158
|
+
*/
|
|
159
|
+
private sessionDestroyedListeners;
|
|
160
|
+
/**
|
|
161
|
+
* Register listener for session destruction events
|
|
162
|
+
*
|
|
163
|
+
* Why: Allows MCPServer to cleanup per-session HTTP clients
|
|
164
|
+
*/
|
|
165
|
+
onSessionDestroyed(listener: (sessionId: string) => void): void;
|
|
166
|
+
/**
|
|
167
|
+
* Notify all listeners about session destruction
|
|
168
|
+
*/
|
|
169
|
+
private notifySessionDestroyed;
|
|
170
|
+
/**
|
|
171
|
+
* Cleanup expired sessions
|
|
172
|
+
*
|
|
173
|
+
* Why: Prevent memory leaks, enforce session timeout
|
|
174
|
+
*/
|
|
175
|
+
private cleanupExpiredSessions;
|
|
176
|
+
/**
|
|
177
|
+
* Get auth token from session
|
|
178
|
+
*
|
|
179
|
+
* Why public: Allows MCPServer to securely access session tokens without breaking encapsulation
|
|
180
|
+
*/
|
|
181
|
+
getSessionToken(sessionId: string): string | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* Set message handler for processing incoming JSON-RPC messages
|
|
184
|
+
*/
|
|
185
|
+
setMessageHandler(handler: (message: unknown, sessionId?: string) => Promise<unknown>): void;
|
|
186
|
+
/**
|
|
187
|
+
* Start HTTP server
|
|
188
|
+
*/
|
|
189
|
+
start(): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Stop HTTP server
|
|
192
|
+
*/
|
|
193
|
+
stop(): Promise<void>;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=http-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAIV,mBAAmB,EAEpB,MAAM,2BAA2B,CAAC;AAGnC,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,cAAc,CAA6E;gBAEvF,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM;IAiBvD;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,qBAAqB,CAAS;IAEtC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,eAAe;IA8BvB;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAoBnB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IAyBjB;;;;OAIG;IACH,OAAO,CAAC,OAAO;IAmBf;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA2BnB;;;;OAIG;YACW,aAAa;IAoB3B;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAUrB;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB;IAyBxB;;;;OAIG;YACW,UAAU;IA4FxB;;;;OAIG;YACW,SAAS;IAkDvB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAmCpB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IA4CtB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAatB;;;;OAIG;IACI,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IA4B9D;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAyBrB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAO7B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAsBtB;;OAEG;IACH,OAAO,CAAC,yBAAyB,CAA0C;IAE3E;;;;OAIG;IACI,kBAAkB,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAItE;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAqB9B;;;;OAIG;IACI,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7D;;OAEG;IACI,iBAAiB,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAInG;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BnC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBnC"}
|