@elsium-ai/mcp 0.9.1 → 0.10.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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +170 -0
- package/dist/trust.d.ts +42 -0
- package/dist/trust.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,6 @@ export type { MCPClient, MCPClientConfig, MCPClientStdioConfig, MCPClientHttpCon
|
|
|
3
3
|
export { createMCPServer, createMCPHttpHandler } from './server';
|
|
4
4
|
export type { MCPServer, MCPServerConfig, MCPHttpHandlerConfig, MCPHttpHandler, MCPResourceHandler, MCPPromptHandler, } from './server';
|
|
5
5
|
export type { JsonRpcRequest, JsonRpcResponse, MCPTransport, MCPResource, MCPResourceContent, MCPPrompt, MCPPromptArgument, MCPPromptMessage, } from './types';
|
|
6
|
+
export { createTrustedMCPClient } from './trust';
|
|
7
|
+
export type { MCPTrustConfig, AllowedServer, MCPAuditLogger, MCPAuditEvent, MCPToolManifest, MCPToolManifestEntry, TrustedMCPClient, } from './trust';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,YAAY,EACX,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,GACX,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAChE,YAAY,EACX,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GAChB,MAAM,UAAU,CAAA;AAGjB,YAAY,EACX,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,YAAY,EACX,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,GACX,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAChE,YAAY,EACX,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GAChB,MAAM,UAAU,CAAA;AAGjB,YAAY,EACX,cAAc,EACd,eAAe,EACf,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAChD,YAAY,EACX,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,gBAAgB,GAChB,MAAM,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1012,7 +1012,177 @@ function createMCPHttpHandler(config) {
|
|
|
1012
1012
|
});
|
|
1013
1013
|
};
|
|
1014
1014
|
}
|
|
1015
|
+
// src/trust.ts
|
|
1016
|
+
import { createHash } from "node:crypto";
|
|
1017
|
+
function computeSchemaHash(schema) {
|
|
1018
|
+
return createHash("sha256").update(JSON.stringify(schema)).digest("hex");
|
|
1019
|
+
}
|
|
1020
|
+
function computeManifestHash(tools) {
|
|
1021
|
+
const content = tools.map((t) => `${t.name}:${t.inputSchemaHash}`).join("|");
|
|
1022
|
+
return createHash("sha256").update(content).digest("hex");
|
|
1023
|
+
}
|
|
1024
|
+
function isServerAllowed(config, trust) {
|
|
1025
|
+
if (!trust.allowedServers?.length)
|
|
1026
|
+
return true;
|
|
1027
|
+
return trust.allowedServers.some((s) => {
|
|
1028
|
+
if (s.name !== config.name)
|
|
1029
|
+
return false;
|
|
1030
|
+
if (s.transport !== config.transport)
|
|
1031
|
+
return false;
|
|
1032
|
+
if (config.transport === "http" && s.urlPattern) {
|
|
1033
|
+
const pattern = new RegExp(s.urlPattern);
|
|
1034
|
+
if (!pattern.test(config.url))
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
if (config.transport === "stdio" && s.commandHash) {
|
|
1038
|
+
const cmdHash = createHash("sha256").update(`${config.command}:${(config.args ?? []).join(":")}`).digest("hex");
|
|
1039
|
+
if (cmdHash !== s.commandHash)
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
return true;
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
function isToolAllowed(toolName, serverName, trust) {
|
|
1046
|
+
if (!trust.allowedServers?.length)
|
|
1047
|
+
return true;
|
|
1048
|
+
const server = trust.allowedServers.find((s) => s.name === serverName);
|
|
1049
|
+
if (!server)
|
|
1050
|
+
return false;
|
|
1051
|
+
if (server.deniedTools?.includes(toolName))
|
|
1052
|
+
return false;
|
|
1053
|
+
if (server.allowedTools && !server.allowedTools.includes(toolName))
|
|
1054
|
+
return false;
|
|
1055
|
+
return true;
|
|
1056
|
+
}
|
|
1057
|
+
var MAX_TOOL_OUTPUT_SIZE = 1024 * 1024;
|
|
1058
|
+
function createTrustedMCPClient(config, trustConfig) {
|
|
1059
|
+
if (!isServerAllowed(config, trustConfig)) {
|
|
1060
|
+
throw new ElsiumError({
|
|
1061
|
+
code: "AUTH_ERROR",
|
|
1062
|
+
message: `MCP server "${config.name}" is not in the allowed servers list`,
|
|
1063
|
+
retryable: false
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
const inner = createMCPClient(config);
|
|
1067
|
+
let currentManifest = null;
|
|
1068
|
+
const maxOutputSize = trustConfig.maxToolOutputSize ?? MAX_TOOL_OUTPUT_SIZE;
|
|
1069
|
+
function audit(event) {
|
|
1070
|
+
trustConfig.auditLog?.log({ ...event, timestamp: Date.now() });
|
|
1071
|
+
}
|
|
1072
|
+
return {
|
|
1073
|
+
get connected() {
|
|
1074
|
+
return inner.connected;
|
|
1075
|
+
},
|
|
1076
|
+
get manifest() {
|
|
1077
|
+
return currentManifest;
|
|
1078
|
+
},
|
|
1079
|
+
async connect() {
|
|
1080
|
+
audit({ type: "connection", serverName: config.name, data: { action: "connect" } });
|
|
1081
|
+
await inner.connect();
|
|
1082
|
+
},
|
|
1083
|
+
async disconnect() {
|
|
1084
|
+
audit({ type: "connection", serverName: config.name, data: { action: "disconnect" } });
|
|
1085
|
+
await inner.disconnect();
|
|
1086
|
+
},
|
|
1087
|
+
async listTools() {
|
|
1088
|
+
const tools = await inner.listTools();
|
|
1089
|
+
const filteredTools = tools.filter((t) => isToolAllowed(t.name, config.name, trustConfig));
|
|
1090
|
+
audit({
|
|
1091
|
+
type: "tool_list",
|
|
1092
|
+
serverName: config.name,
|
|
1093
|
+
data: {
|
|
1094
|
+
totalTools: tools.length,
|
|
1095
|
+
allowedTools: filteredTools.length,
|
|
1096
|
+
toolNames: filteredTools.map((t) => t.name)
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
return filteredTools;
|
|
1100
|
+
},
|
|
1101
|
+
async callTool(name, args) {
|
|
1102
|
+
if (!isToolAllowed(name, config.name, trustConfig)) {
|
|
1103
|
+
audit({
|
|
1104
|
+
type: "security_violation",
|
|
1105
|
+
serverName: config.name,
|
|
1106
|
+
data: { tool: name, reason: "Tool not allowed" }
|
|
1107
|
+
});
|
|
1108
|
+
throw new ElsiumError({
|
|
1109
|
+
code: "AUTH_ERROR",
|
|
1110
|
+
message: `Tool "${name}" is not allowed on server "${config.name}"`,
|
|
1111
|
+
retryable: false
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
audit({
|
|
1115
|
+
type: "tool_call",
|
|
1116
|
+
serverName: config.name,
|
|
1117
|
+
data: { tool: name, argumentKeys: Object.keys(args) }
|
|
1118
|
+
});
|
|
1119
|
+
const result = await inner.callTool(name, args);
|
|
1120
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
1121
|
+
if (resultStr.length > maxOutputSize) {
|
|
1122
|
+
audit({
|
|
1123
|
+
type: "security_violation",
|
|
1124
|
+
serverName: config.name,
|
|
1125
|
+
data: { tool: name, reason: "Output exceeds size limit", size: resultStr.length }
|
|
1126
|
+
});
|
|
1127
|
+
throw new ElsiumError({
|
|
1128
|
+
code: "VALIDATION_ERROR",
|
|
1129
|
+
message: `Tool "${name}" output exceeds maximum size (${resultStr.length} > ${maxOutputSize})`,
|
|
1130
|
+
retryable: false
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
audit({
|
|
1134
|
+
type: "tool_result",
|
|
1135
|
+
serverName: config.name,
|
|
1136
|
+
data: { tool: name, outputSize: resultStr.length }
|
|
1137
|
+
});
|
|
1138
|
+
return result;
|
|
1139
|
+
},
|
|
1140
|
+
listResources: inner.listResources.bind(inner),
|
|
1141
|
+
readResource: inner.readResource.bind(inner),
|
|
1142
|
+
listPrompts: inner.listPrompts.bind(inner),
|
|
1143
|
+
getPrompt: inner.getPrompt.bind(inner),
|
|
1144
|
+
toElsiumTools: inner.toElsiumTools.bind(inner),
|
|
1145
|
+
async generateManifest() {
|
|
1146
|
+
const tools = await inner.listTools();
|
|
1147
|
+
const entries = tools.map((t) => ({
|
|
1148
|
+
name: t.name,
|
|
1149
|
+
description: t.description,
|
|
1150
|
+
inputSchemaHash: computeSchemaHash(t.inputSchema)
|
|
1151
|
+
}));
|
|
1152
|
+
currentManifest = {
|
|
1153
|
+
serverName: config.name,
|
|
1154
|
+
tools: entries,
|
|
1155
|
+
generatedAt: Date.now(),
|
|
1156
|
+
hash: computeManifestHash(entries)
|
|
1157
|
+
};
|
|
1158
|
+
return currentManifest;
|
|
1159
|
+
},
|
|
1160
|
+
async verifyManifest(manifest) {
|
|
1161
|
+
const tools = await inner.listTools();
|
|
1162
|
+
const currentEntries = tools.map((t) => ({
|
|
1163
|
+
name: t.name,
|
|
1164
|
+
description: t.description,
|
|
1165
|
+
inputSchemaHash: computeSchemaHash(t.inputSchema)
|
|
1166
|
+
}));
|
|
1167
|
+
const currentHash = computeManifestHash(currentEntries);
|
|
1168
|
+
if (currentHash !== manifest.hash) {
|
|
1169
|
+
audit({
|
|
1170
|
+
type: "security_violation",
|
|
1171
|
+
serverName: config.name,
|
|
1172
|
+
data: {
|
|
1173
|
+
reason: "Manifest mismatch",
|
|
1174
|
+
expectedHash: manifest.hash,
|
|
1175
|
+
actualHash: currentHash
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1015
1184
|
export {
|
|
1185
|
+
createTrustedMCPClient,
|
|
1016
1186
|
createMCPServer,
|
|
1017
1187
|
createMCPHttpHandler,
|
|
1018
1188
|
createMCPClient
|
package/dist/trust.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { MCPClient, MCPClientConfig } from './client';
|
|
2
|
+
export interface MCPTrustConfig {
|
|
3
|
+
allowedServers?: AllowedServer[];
|
|
4
|
+
validateToolOutputs?: boolean;
|
|
5
|
+
auditLog?: MCPAuditLogger;
|
|
6
|
+
maxToolOutputSize?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface AllowedServer {
|
|
9
|
+
name: string;
|
|
10
|
+
transport: 'stdio' | 'http';
|
|
11
|
+
commandHash?: string;
|
|
12
|
+
urlPattern?: string;
|
|
13
|
+
allowedTools?: string[];
|
|
14
|
+
deniedTools?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface MCPAuditLogger {
|
|
17
|
+
log(event: MCPAuditEvent): void;
|
|
18
|
+
}
|
|
19
|
+
export interface MCPAuditEvent {
|
|
20
|
+
type: 'connection' | 'tool_list' | 'tool_call' | 'tool_result' | 'security_violation';
|
|
21
|
+
serverName: string;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
data: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export interface MCPToolManifest {
|
|
26
|
+
serverName: string;
|
|
27
|
+
tools: MCPToolManifestEntry[];
|
|
28
|
+
generatedAt: number;
|
|
29
|
+
hash: string;
|
|
30
|
+
}
|
|
31
|
+
export interface MCPToolManifestEntry {
|
|
32
|
+
name: string;
|
|
33
|
+
description: string;
|
|
34
|
+
inputSchemaHash: string;
|
|
35
|
+
}
|
|
36
|
+
export interface TrustedMCPClient extends MCPClient {
|
|
37
|
+
readonly manifest: MCPToolManifest | null;
|
|
38
|
+
generateManifest(): Promise<MCPToolManifest>;
|
|
39
|
+
verifyManifest(manifest: MCPToolManifest): Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
export declare function createTrustedMCPClient(config: MCPClientConfig, trustConfig: MCPTrustConfig): TrustedMCPClient;
|
|
42
|
+
//# sourceMappingURL=trust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../src/trust.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAe,MAAM,UAAU,CAAA;AAGvE,MAAM,WAAW,cAAc;IAC9B,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,OAAO,GAAG,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,oBAAoB,CAAA;IACrF,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,oBAAoB,EAAE,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IAClD,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;IACzC,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAAA;IAC5C,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC3D;AA8CD,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,cAAc,GACzB,gBAAgB,CAoJlB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elsium-ai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Model Context Protocol (MCP) support for ElsiumAI — bidirectional bridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Utrera <ebutrera9103@gmail.com>",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"dev": "bun --watch src/index.ts"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@elsium-ai/core": "^0.
|
|
30
|
-
"@elsium-ai/tools": "^0.
|
|
29
|
+
"@elsium-ai/core": "^0.10.0",
|
|
30
|
+
"@elsium-ai/tools": "^0.10.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "^5.7.0"
|