@nexrall/code-core 1.0.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 +21 -0
- package/README.md +155 -0
- package/dist/agent/agentTypes.d.ts +17 -0
- package/dist/agent/agentTypes.d.ts.map +1 -0
- package/dist/agent/agentTypes.js +156 -0
- package/dist/agent/loop.d.ts +3 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +775 -0
- package/dist/api/client.d.ts +27 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +414 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +95 -0
- package/dist/checkpoint/manager.d.ts +86 -0
- package/dist/checkpoint/manager.d.ts.map +1 -0
- package/dist/checkpoint/manager.js +409 -0
- package/dist/commands/loader.d.ts +18 -0
- package/dist/commands/loader.d.ts.map +1 -0
- package/dist/commands/loader.js +183 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/mcp/client.d.ts +46 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +128 -0
- package/dist/mcp/httpClient.d.ts +25 -0
- package/dist/mcp/httpClient.d.ts.map +1 -0
- package/dist/mcp/httpClient.js +143 -0
- package/dist/mcp/manager.d.ts +56 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +234 -0
- package/dist/mcp/sseClient.d.ts +30 -0
- package/dist/mcp/sseClient.d.ts.map +1 -0
- package/dist/mcp/sseClient.js +224 -0
- package/dist/permissions/rules.d.ts +20 -0
- package/dist/permissions/rules.d.ts.map +1 -0
- package/dist/permissions/rules.js +218 -0
- package/dist/plugins/index.d.ts +18 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +139 -0
- package/dist/tools/executor.d.ts +6 -0
- package/dist/tools/executor.d.ts.map +1 -0
- package/dist/tools/executor.js +1458 -0
- package/dist/tools/sandbox.d.ts +13 -0
- package/dist/tools/sandbox.d.ts.map +1 -0
- package/dist/tools/sandbox.js +140 -0
- package/dist/tools/symbols.d.ts +13 -0
- package/dist/tools/symbols.d.ts.map +1 -0
- package/dist/tools/symbols.js +279 -0
- package/dist/types.d.ts +186 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/package.json +92 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface McpToolDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object';
|
|
6
|
+
properties?: Record<string, unknown>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface McpServerConfig {
|
|
11
|
+
/** Transport. Defaults to 'stdio' when a command is set, else inferred from url. */
|
|
12
|
+
type?: 'stdio' | 'http' | 'sse';
|
|
13
|
+
command?: string;
|
|
14
|
+
args?: string[];
|
|
15
|
+
env?: Record<string, string>;
|
|
16
|
+
url?: string;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/** Shared surface implemented by every MCP transport (stdio + HTTP/SSE). */
|
|
20
|
+
export interface McpTransport {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly tools: McpToolDefinition[];
|
|
23
|
+
connect(): Promise<void>;
|
|
24
|
+
callTool(name: string, args: Record<string, unknown>): Promise<string>;
|
|
25
|
+
disconnect(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare class McpClient implements McpTransport {
|
|
28
|
+
private readonly config;
|
|
29
|
+
private _proc;
|
|
30
|
+
private _nextId;
|
|
31
|
+
private _pending;
|
|
32
|
+
private _buf;
|
|
33
|
+
private _tools;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
constructor(name: string, config: McpServerConfig);
|
|
36
|
+
get tools(): McpToolDefinition[];
|
|
37
|
+
connect(): Promise<void>;
|
|
38
|
+
callTool(name: string, args: Record<string, unknown>): Promise<string>;
|
|
39
|
+
disconnect(): void;
|
|
40
|
+
private _request;
|
|
41
|
+
private _notify;
|
|
42
|
+
private _send;
|
|
43
|
+
private _handleLine;
|
|
44
|
+
private _rejectAll;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,oFAAoF;IACpF,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAEhC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,UAAU,IAAI,IAAI,CAAC;CACpB;AAkBD,qBAAa,SAAU,YAAW,YAAY;IAQlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPjD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAoF;IACpG,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAA2B;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAmB,MAAM,EAAE,eAAe;IAIlE,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAAwB;IAElD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2CxB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB5E,UAAU,IAAI,IAAI;IAWlB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;CAInB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpClient = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
// ─── McpClient ────────────────────────────────────────────────────────────────
|
|
6
|
+
class McpClient {
|
|
7
|
+
constructor(name, config) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
this._proc = null;
|
|
10
|
+
this._nextId = 1;
|
|
11
|
+
this._pending = new Map();
|
|
12
|
+
this._buf = '';
|
|
13
|
+
this._tools = [];
|
|
14
|
+
this.name = name;
|
|
15
|
+
}
|
|
16
|
+
get tools() { return this._tools; }
|
|
17
|
+
async connect() {
|
|
18
|
+
if (!this.config.command)
|
|
19
|
+
throw new Error(`MCP server "${this.name}" has no command (stdio transport requires one).`);
|
|
20
|
+
const env = { ...process.env, ...(this.config.env ?? {}) };
|
|
21
|
+
this._proc = (0, child_process_1.spawn)(this.config.command, this.config.args ?? [], {
|
|
22
|
+
env,
|
|
23
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
24
|
+
shell: false,
|
|
25
|
+
});
|
|
26
|
+
this._proc.stdout.on('data', (chunk) => {
|
|
27
|
+
this._buf += chunk.toString('utf-8');
|
|
28
|
+
let nl;
|
|
29
|
+
while ((nl = this._buf.indexOf('\n')) !== -1) {
|
|
30
|
+
const line = this._buf.slice(0, nl).trim();
|
|
31
|
+
this._buf = this._buf.slice(nl + 1);
|
|
32
|
+
if (line)
|
|
33
|
+
this._handleLine(line);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
this._proc.on('error', (err) => {
|
|
37
|
+
this._rejectAll(err);
|
|
38
|
+
});
|
|
39
|
+
this._proc.on('exit', () => {
|
|
40
|
+
this._rejectAll(new Error(`MCP server "${this.name}" exited unexpectedly`));
|
|
41
|
+
});
|
|
42
|
+
// Handshake: initialize
|
|
43
|
+
await this._request('initialize', {
|
|
44
|
+
protocolVersion: '2024-11-05',
|
|
45
|
+
capabilities: {},
|
|
46
|
+
clientInfo: { name: 'nexrall-code', version: '1.0' },
|
|
47
|
+
});
|
|
48
|
+
// Send initialized notification (no response expected)
|
|
49
|
+
this._notify('notifications/initialized');
|
|
50
|
+
// Fetch tools
|
|
51
|
+
const result = await this._request('tools/list', {});
|
|
52
|
+
this._tools = result?.tools ?? [];
|
|
53
|
+
}
|
|
54
|
+
async callTool(name, args) {
|
|
55
|
+
const result = await this._request('tools/call', { name, arguments: args });
|
|
56
|
+
if (!result)
|
|
57
|
+
return '';
|
|
58
|
+
const text = (result.content ?? [])
|
|
59
|
+
.filter((c) => c.type === 'text')
|
|
60
|
+
.map((c) => c.text ?? '')
|
|
61
|
+
.join('\n');
|
|
62
|
+
if (result.isError)
|
|
63
|
+
throw new Error(text || 'MCP tool returned an error');
|
|
64
|
+
return text;
|
|
65
|
+
}
|
|
66
|
+
disconnect() {
|
|
67
|
+
if (this._proc) {
|
|
68
|
+
try {
|
|
69
|
+
this._proc.kill('SIGTERM');
|
|
70
|
+
}
|
|
71
|
+
catch { /* ignore */ }
|
|
72
|
+
this._proc = null;
|
|
73
|
+
}
|
|
74
|
+
this._rejectAll(new Error(`MCP server "${this.name}" disconnected`));
|
|
75
|
+
this._pending.clear();
|
|
76
|
+
}
|
|
77
|
+
// ─── Private ────────────────────────────────────────────────────────────────
|
|
78
|
+
_request(method, params) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const id = this._nextId++;
|
|
81
|
+
this._pending.set(id, { resolve, reject });
|
|
82
|
+
this._send({ jsonrpc: '2.0', id, method, params });
|
|
83
|
+
// Timeout after 30s
|
|
84
|
+
setTimeout(() => {
|
|
85
|
+
if (this._pending.has(id)) {
|
|
86
|
+
this._pending.delete(id);
|
|
87
|
+
reject(new Error(`MCP request "${method}" timed out`));
|
|
88
|
+
}
|
|
89
|
+
}, 30000);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
_notify(method, params) {
|
|
93
|
+
this._send({ jsonrpc: '2.0', method, params });
|
|
94
|
+
}
|
|
95
|
+
_send(msg) {
|
|
96
|
+
if (!this._proc?.stdin?.writable)
|
|
97
|
+
return;
|
|
98
|
+
this._proc.stdin.write(JSON.stringify(msg) + '\n');
|
|
99
|
+
}
|
|
100
|
+
_handleLine(line) {
|
|
101
|
+
let msg;
|
|
102
|
+
try {
|
|
103
|
+
msg = JSON.parse(line);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (msg.id == null)
|
|
109
|
+
return; // notification, ignore
|
|
110
|
+
const pending = this._pending.get(msg.id);
|
|
111
|
+
if (!pending)
|
|
112
|
+
return;
|
|
113
|
+
this._pending.delete(msg.id);
|
|
114
|
+
if (msg.error) {
|
|
115
|
+
pending.reject(new Error(`MCP error ${msg.error.code}: ${msg.error.message}`));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
pending.resolve(msg.result);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
_rejectAll(err) {
|
|
122
|
+
for (const { reject } of this._pending.values())
|
|
123
|
+
reject(err);
|
|
124
|
+
this._pending.clear();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.McpClient = McpClient;
|
|
128
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { McpServerConfig, McpToolDefinition, McpTransport } from './client';
|
|
2
|
+
/** Thrown when a remote MCP server replies 401 — the caller should run the OAuth flow. */
|
|
3
|
+
export declare class McpOAuthRequiredError extends Error {
|
|
4
|
+
readonly serverName: string;
|
|
5
|
+
readonly serverUrl: string;
|
|
6
|
+
readonly wwwAuthenticate: string;
|
|
7
|
+
constructor(serverName: string, serverUrl: string, wwwAuthenticate: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class McpHttpClient implements McpTransport {
|
|
10
|
+
private readonly config;
|
|
11
|
+
private _nextId;
|
|
12
|
+
private _tools;
|
|
13
|
+
private _sessionId;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
constructor(name: string, config: McpServerConfig);
|
|
16
|
+
get tools(): McpToolDefinition[];
|
|
17
|
+
connect(): Promise<void>;
|
|
18
|
+
callTool(name: string, args: Record<string, unknown>): Promise<string>;
|
|
19
|
+
disconnect(): void;
|
|
20
|
+
private _rpc;
|
|
21
|
+
private _notify;
|
|
22
|
+
private _post;
|
|
23
|
+
private _extractResult;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=httpClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpClient.d.ts","sourceRoot":"","sources":["../../src/mcp/httpClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAqBjF,0FAA0F;AAC1F,qBAAa,qBAAsB,SAAQ,KAAK;aAE5B,UAAU,EAAE,MAAM;aAClB,SAAS,EAAE,MAAM;aACjB,eAAe,EAAE,MAAM;gBAFvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM;CAK1C;AAED,qBAAa,aAAc,YAAW,YAAY;IAMtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALjD,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAuB;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAmB,MAAM,EAAE,eAAe;IAIlE,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAE/B;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAc5E,UAAU,IAAI,IAAI;YAaJ,IAAI;YAMJ,OAAO;YAKP,KAAK;YA2BL,cAAc;CAqC7B"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.McpHttpClient = exports.McpOAuthRequiredError = void 0;
|
|
7
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
8
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
9
|
+
/** Thrown when a remote MCP server replies 401 — the caller should run the OAuth flow. */
|
|
10
|
+
class McpOAuthRequiredError extends Error {
|
|
11
|
+
constructor(serverName, serverUrl, wwwAuthenticate) {
|
|
12
|
+
super(`MCP server "${serverName}" requires authentication`);
|
|
13
|
+
this.serverName = serverName;
|
|
14
|
+
this.serverUrl = serverUrl;
|
|
15
|
+
this.wwwAuthenticate = wwwAuthenticate;
|
|
16
|
+
this.name = 'McpOAuthRequiredError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.McpOAuthRequiredError = McpOAuthRequiredError;
|
|
20
|
+
class McpHttpClient {
|
|
21
|
+
constructor(name, config) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
this._nextId = 1;
|
|
24
|
+
this._tools = [];
|
|
25
|
+
this._sessionId = null;
|
|
26
|
+
this.name = name;
|
|
27
|
+
}
|
|
28
|
+
get tools() {
|
|
29
|
+
return this._tools;
|
|
30
|
+
}
|
|
31
|
+
async connect() {
|
|
32
|
+
if (!this.config.url)
|
|
33
|
+
throw new Error(`MCP server "${this.name}" has no url (http/sse transport requires one).`);
|
|
34
|
+
await this._rpc('initialize', {
|
|
35
|
+
protocolVersion: '2024-11-05',
|
|
36
|
+
capabilities: {},
|
|
37
|
+
clientInfo: { name: 'nexrall-code', version: '1.0' },
|
|
38
|
+
});
|
|
39
|
+
await this._notify('notifications/initialized');
|
|
40
|
+
const res = (await this._rpc('tools/list', {}));
|
|
41
|
+
this._tools = res?.tools ?? [];
|
|
42
|
+
}
|
|
43
|
+
async callTool(name, args) {
|
|
44
|
+
const result = (await this._rpc('tools/call', { name, arguments: args }));
|
|
45
|
+
if (!result)
|
|
46
|
+
return '';
|
|
47
|
+
const text = (result.content ?? [])
|
|
48
|
+
.filter((c) => c.type === 'text')
|
|
49
|
+
.map((c) => c.text ?? '')
|
|
50
|
+
.join('\n');
|
|
51
|
+
if (result.isError)
|
|
52
|
+
throw new Error(text || 'MCP tool returned an error');
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
disconnect() {
|
|
56
|
+
// Best-effort session teardown; ignore failures (server may be stateless).
|
|
57
|
+
if (this._sessionId && this.config.url) {
|
|
58
|
+
(0, node_fetch_1.default)(this.config.url, {
|
|
59
|
+
method: 'DELETE',
|
|
60
|
+
headers: { 'Mcp-Session-Id': this._sessionId, ...(this.config.headers ?? {}) },
|
|
61
|
+
}).catch(() => { });
|
|
62
|
+
}
|
|
63
|
+
this._sessionId = null;
|
|
64
|
+
}
|
|
65
|
+
// ─── Private ──────────────────────────────────────────────────────────────
|
|
66
|
+
async _rpc(method, params) {
|
|
67
|
+
const id = this._nextId++;
|
|
68
|
+
const resp = await this._post({ jsonrpc: '2.0', id, method, params });
|
|
69
|
+
return this._extractResult(resp, id);
|
|
70
|
+
}
|
|
71
|
+
async _notify(method, params) {
|
|
72
|
+
// Notifications have no id; servers typically reply 202 with no body.
|
|
73
|
+
await this._post({ jsonrpc: '2.0', method, params });
|
|
74
|
+
}
|
|
75
|
+
async _post(body) {
|
|
76
|
+
const headers = {
|
|
77
|
+
'Content-Type': 'application/json',
|
|
78
|
+
Accept: 'application/json, text/event-stream',
|
|
79
|
+
...(this.config.headers ?? {}),
|
|
80
|
+
};
|
|
81
|
+
if (this._sessionId)
|
|
82
|
+
headers['Mcp-Session-Id'] = this._sessionId;
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
85
|
+
let resp;
|
|
86
|
+
try {
|
|
87
|
+
resp = await (0, node_fetch_1.default)(this.config.url, {
|
|
88
|
+
method: 'POST',
|
|
89
|
+
headers,
|
|
90
|
+
body: JSON.stringify(body),
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
}
|
|
97
|
+
const sid = resp.headers.get('mcp-session-id');
|
|
98
|
+
if (sid)
|
|
99
|
+
this._sessionId = sid;
|
|
100
|
+
return resp;
|
|
101
|
+
}
|
|
102
|
+
async _extractResult(resp, id) {
|
|
103
|
+
if (!resp.ok) {
|
|
104
|
+
if (resp.status === 401) {
|
|
105
|
+
throw new McpOAuthRequiredError(this.name, this.config.url, resp.headers.get('www-authenticate') ?? '');
|
|
106
|
+
}
|
|
107
|
+
const body = await resp.text().catch(() => '');
|
|
108
|
+
throw new Error(`MCP HTTP ${resp.status} ${resp.statusText}${body ? `: ${body.slice(0, 200)}` : ''}`);
|
|
109
|
+
}
|
|
110
|
+
const contentType = resp.headers.get('content-type') ?? '';
|
|
111
|
+
const text = await resp.text();
|
|
112
|
+
if (!text.trim())
|
|
113
|
+
return null; // e.g. 202 ack for a notification
|
|
114
|
+
const consume = (msg) => {
|
|
115
|
+
if (msg.error)
|
|
116
|
+
throw new Error(`MCP error ${msg.error.code}: ${msg.error.message}`);
|
|
117
|
+
return msg.result ?? null;
|
|
118
|
+
};
|
|
119
|
+
if (contentType.includes('text/event-stream')) {
|
|
120
|
+
// Walk SSE frames; return the JSON-RPC message matching our request id.
|
|
121
|
+
for (const frame of text.split(/\r?\n\r?\n/)) {
|
|
122
|
+
const dataLines = frame
|
|
123
|
+
.split(/\r?\n/)
|
|
124
|
+
.filter((l) => l.startsWith('data:'))
|
|
125
|
+
.map((l) => l.slice(5).trim());
|
|
126
|
+
if (!dataLines.length)
|
|
127
|
+
continue;
|
|
128
|
+
try {
|
|
129
|
+
const msg = JSON.parse(dataLines.join('\n'));
|
|
130
|
+
if (msg.id === id)
|
|
131
|
+
return consume(msg);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
/* skip non-JSON frames (comments, pings) */
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw new Error('No matching JSON-RPC response found in SSE stream');
|
|
138
|
+
}
|
|
139
|
+
return consume(JSON.parse(text));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.McpHttpClient = McpHttpClient;
|
|
143
|
+
//# sourceMappingURL=httpClient.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { McpServerConfig, McpToolDefinition } from './client';
|
|
2
|
+
export interface McpConfig {
|
|
3
|
+
mcpServers: Record<string, McpServerConfig>;
|
|
4
|
+
}
|
|
5
|
+
export interface AnthropicTool {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
input_schema: {
|
|
9
|
+
type: 'object';
|
|
10
|
+
properties?: Record<string, unknown>;
|
|
11
|
+
required?: string[];
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare class McpManager {
|
|
15
|
+
private _clients;
|
|
16
|
+
private _toolMap;
|
|
17
|
+
private _configs;
|
|
18
|
+
private _errors;
|
|
19
|
+
private _needsAuth;
|
|
20
|
+
/** Pick the transport for a server config: stdio (command), Streamable HTTP, or legacy SSE. */
|
|
21
|
+
private static makeClient;
|
|
22
|
+
/** Load config from ~/.nexrall/mcp.json, <workDir>/.nexrall/mcp.json, and plugin mcp.json files. */
|
|
23
|
+
static loadConfig(workDir: string): McpConfig;
|
|
24
|
+
/** Connect to all configured servers. Errors per-server are logged, not thrown. */
|
|
25
|
+
connectAll(config: McpConfig): Promise<void>;
|
|
26
|
+
/** Returns all MCP tools as Anthropic-compatible tool definitions. */
|
|
27
|
+
getAnthropicTools(): AnthropicTool[];
|
|
28
|
+
/** Execute an MCP tool call. Returns null if this tool is not an MCP tool. */
|
|
29
|
+
callTool(prefixedName: string, input: Record<string, unknown>): Promise<string | null>;
|
|
30
|
+
/** True if this tool name belongs to an MCP server. */
|
|
31
|
+
isMcpTool(name: string): boolean;
|
|
32
|
+
get serverNames(): string[];
|
|
33
|
+
get toolCount(): number;
|
|
34
|
+
private static transportOf;
|
|
35
|
+
/** Returns per-server status for UI display, including failed / auth-required connections. */
|
|
36
|
+
getStatus(): Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
transport: 'stdio' | 'http' | 'sse';
|
|
39
|
+
tools: McpToolDefinition[];
|
|
40
|
+
connected: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
needsAuth?: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
/** The WWW-Authenticate challenge a server returned on 401 (empty if none/unknown). */
|
|
45
|
+
authChallenge(name: string): string;
|
|
46
|
+
/** Path to an mcp.json for the given scope. */
|
|
47
|
+
static configPath(workDir: string, scope: 'project' | 'user'): string;
|
|
48
|
+
private static readConfigFile;
|
|
49
|
+
private static writeConfigFile;
|
|
50
|
+
/** Add (or overwrite) a server in the given scope's mcp.json. */
|
|
51
|
+
static addServer(workDir: string, name: string, server: McpServerConfig, scope?: 'project' | 'user'): void;
|
|
52
|
+
/** Remove a server from whichever scope(s) define it. Returns true if anything was removed. */
|
|
53
|
+
static removeServer(workDir: string, name: string): boolean;
|
|
54
|
+
disconnectAll(): void;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/mcp/manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAa,eAAe,EAAE,iBAAiB,EAAgB,MAAM,UAAU,CAAC;AAOvF,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC7C;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE;QACZ,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAID,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAmC;IAEnD,OAAO,CAAC,QAAQ,CAA6B;IAE7C,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,OAAO,CAA6B;IAE5C,OAAO,CAAC,UAAU,CAA6B;IAE/C,+FAA+F;IAC/F,OAAO,CAAC,MAAM,CAAC,UAAU;IAMzB,oGAAoG;IACpG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS;IA2B7C,mFAAmF;IAC7E,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BlD,sEAAsE;IACtE,iBAAiB,IAAI,aAAa,EAAE;IAkBpC,8EAA8E;IACxE,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAkB5F,uDAAuD;IACvD,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIhC,IAAI,WAAW,IAAI,MAAM,EAAE,CAE1B;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,OAAO,CAAC,MAAM,CAAC,WAAW;IAK1B,8FAA8F;IAC9F,SAAS,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;QAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAY9J,uFAAuF;IACvF,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAMnC,+CAA+C;IAC/C,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM;IAMrE,OAAO,CAAC,MAAM,CAAC,cAAc;IAS7B,OAAO,CAAC,MAAM,CAAC,eAAe;IAK9B,iEAAiE;IACjE,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,KAAK,GAAE,SAAS,GAAG,MAAkB,GAAG,IAAI;IAOrH,+FAA+F;IAC/F,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAc3D,aAAa,IAAI,IAAI;CAQtB"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.McpManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const client_1 = require("./client");
|
|
41
|
+
const httpClient_1 = require("./httpClient");
|
|
42
|
+
const sseClient_1 = require("./sseClient");
|
|
43
|
+
const index_1 = require("../plugins/index");
|
|
44
|
+
// ─── McpManager ───────────────────────────────────────────────────────────────
|
|
45
|
+
class McpManager {
|
|
46
|
+
constructor() {
|
|
47
|
+
this._clients = new Map();
|
|
48
|
+
// Map: prefixed tool name → server name
|
|
49
|
+
this._toolMap = new Map();
|
|
50
|
+
// Config + last connection error per server (for status UI, incl. failures)
|
|
51
|
+
this._configs = new Map();
|
|
52
|
+
this._errors = new Map();
|
|
53
|
+
// Servers that returned 401 → need OAuth. Value = WWW-Authenticate challenge header.
|
|
54
|
+
this._needsAuth = new Map();
|
|
55
|
+
}
|
|
56
|
+
/** Pick the transport for a server config: stdio (command), Streamable HTTP, or legacy SSE. */
|
|
57
|
+
static makeClient(name, cfg) {
|
|
58
|
+
if (cfg.type === 'sse')
|
|
59
|
+
return new sseClient_1.McpSseClient(name, cfg);
|
|
60
|
+
const isHttp = cfg.type === 'http' || (!cfg.command && !!cfg.url);
|
|
61
|
+
return isHttp ? new httpClient_1.McpHttpClient(name, cfg) : new client_1.McpClient(name, cfg);
|
|
62
|
+
}
|
|
63
|
+
/** Load config from ~/.nexrall/mcp.json, <workDir>/.nexrall/mcp.json, and plugin mcp.json files. */
|
|
64
|
+
static loadConfig(workDir) {
|
|
65
|
+
const merged = { mcpServers: {} };
|
|
66
|
+
// Plugins first, then user, then project — later assignments override, so
|
|
67
|
+
// a user/project server definition beats a plugin's same-name one.
|
|
68
|
+
try {
|
|
69
|
+
Object.assign(merged.mcpServers, (0, index_1.pluginMcpServers)(workDir));
|
|
70
|
+
}
|
|
71
|
+
catch { /* plugin scan is best-effort */ }
|
|
72
|
+
const locations = [
|
|
73
|
+
path.join(os.homedir(), '.nexrall', 'mcp.json'),
|
|
74
|
+
path.join(workDir, '.nexrall', 'mcp.json'),
|
|
75
|
+
];
|
|
76
|
+
for (const loc of locations) {
|
|
77
|
+
try {
|
|
78
|
+
const raw = fs.readFileSync(loc, 'utf-8');
|
|
79
|
+
const cfg = JSON.parse(raw);
|
|
80
|
+
Object.assign(merged.mcpServers, cfg.mcpServers ?? {});
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// File doesn't exist or invalid JSON — skip
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return merged;
|
|
87
|
+
}
|
|
88
|
+
/** Connect to all configured servers. Errors per-server are logged, not thrown. */
|
|
89
|
+
async connectAll(config) {
|
|
90
|
+
const entries = Object.entries(config.mcpServers);
|
|
91
|
+
await Promise.all(entries.map(async ([name, serverCfg]) => {
|
|
92
|
+
this._configs.set(name, serverCfg);
|
|
93
|
+
const client = McpManager.makeClient(name, serverCfg);
|
|
94
|
+
try {
|
|
95
|
+
await client.connect();
|
|
96
|
+
this._clients.set(name, client);
|
|
97
|
+
this._errors.delete(name);
|
|
98
|
+
this._needsAuth.delete(name);
|
|
99
|
+
// Register tools with prefixed names: serverName__toolName
|
|
100
|
+
for (const tool of client.tools) {
|
|
101
|
+
const prefixed = `${name}__${tool.name}`;
|
|
102
|
+
this._toolMap.set(prefixed, name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
if (err instanceof httpClient_1.McpOAuthRequiredError) {
|
|
107
|
+
this._needsAuth.set(name, err.wwwAuthenticate);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this._needsAuth.delete(name);
|
|
111
|
+
}
|
|
112
|
+
this._errors.set(name, err.message);
|
|
113
|
+
console.error(`[MCP] Failed to connect to server "${name}": ${err.message}`);
|
|
114
|
+
}
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
/** Returns all MCP tools as Anthropic-compatible tool definitions. */
|
|
118
|
+
getAnthropicTools() {
|
|
119
|
+
const tools = [];
|
|
120
|
+
for (const [serverName, client] of this._clients) {
|
|
121
|
+
for (const tool of client.tools) {
|
|
122
|
+
tools.push({
|
|
123
|
+
name: `${serverName}__${tool.name}`,
|
|
124
|
+
description: `[${serverName}] ${tool.description}`,
|
|
125
|
+
input_schema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: tool.inputSchema?.properties ?? {},
|
|
128
|
+
required: tool.inputSchema?.required,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return tools;
|
|
134
|
+
}
|
|
135
|
+
/** Execute an MCP tool call. Returns null if this tool is not an MCP tool. */
|
|
136
|
+
async callTool(prefixedName, input) {
|
|
137
|
+
const serverName = this._toolMap.get(prefixedName);
|
|
138
|
+
if (!serverName)
|
|
139
|
+
return null;
|
|
140
|
+
const client = this._clients.get(serverName);
|
|
141
|
+
if (!client)
|
|
142
|
+
return null;
|
|
143
|
+
// Strip the server prefix to get the real tool name
|
|
144
|
+
const toolName = prefixedName.slice(serverName.length + 2);
|
|
145
|
+
// Enforce a timeout — a hung MCP server would otherwise block the agent loop forever.
|
|
146
|
+
const MCP_TOOL_TIMEOUT_MS = 60000;
|
|
147
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(`MCP tool "${prefixedName}" timed out after ${MCP_TOOL_TIMEOUT_MS / 1000}s`)), MCP_TOOL_TIMEOUT_MS));
|
|
148
|
+
return Promise.race([client.callTool(toolName, input), timeoutPromise]);
|
|
149
|
+
}
|
|
150
|
+
/** True if this tool name belongs to an MCP server. */
|
|
151
|
+
isMcpTool(name) {
|
|
152
|
+
return this._toolMap.has(name);
|
|
153
|
+
}
|
|
154
|
+
get serverNames() {
|
|
155
|
+
return [...this._clients.keys()];
|
|
156
|
+
}
|
|
157
|
+
get toolCount() {
|
|
158
|
+
return this._toolMap.size;
|
|
159
|
+
}
|
|
160
|
+
static transportOf(cfg) {
|
|
161
|
+
if (cfg?.type)
|
|
162
|
+
return cfg.type;
|
|
163
|
+
return cfg?.url && !cfg?.command ? 'http' : 'stdio';
|
|
164
|
+
}
|
|
165
|
+
/** Returns per-server status for UI display, including failed / auth-required connections. */
|
|
166
|
+
getStatus() {
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const [name, client] of this._clients) {
|
|
169
|
+
out.push({ name, transport: McpManager.transportOf(this._configs.get(name)), tools: client.tools, connected: true });
|
|
170
|
+
}
|
|
171
|
+
for (const [name, error] of this._errors) {
|
|
172
|
+
if (this._clients.has(name))
|
|
173
|
+
continue;
|
|
174
|
+
out.push({ name, transport: McpManager.transportOf(this._configs.get(name)), tools: [], connected: false, error, needsAuth: this._needsAuth.has(name) });
|
|
175
|
+
}
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
/** The WWW-Authenticate challenge a server returned on 401 (empty if none/unknown). */
|
|
179
|
+
authChallenge(name) {
|
|
180
|
+
return this._needsAuth.get(name) ?? '';
|
|
181
|
+
}
|
|
182
|
+
// ─── Config file persistence (for the management UI) ──────────────────────────
|
|
183
|
+
/** Path to an mcp.json for the given scope. */
|
|
184
|
+
static configPath(workDir, scope) {
|
|
185
|
+
return scope === 'user'
|
|
186
|
+
? path.join(os.homedir(), '.nexrall', 'mcp.json')
|
|
187
|
+
: path.join(workDir, '.nexrall', 'mcp.json');
|
|
188
|
+
}
|
|
189
|
+
static readConfigFile(p) {
|
|
190
|
+
try {
|
|
191
|
+
const cfg = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
192
|
+
return { mcpServers: cfg.mcpServers ?? {} };
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return { mcpServers: {} };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
static writeConfigFile(p, cfg) {
|
|
199
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
200
|
+
fs.writeFileSync(p, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
|
|
201
|
+
}
|
|
202
|
+
/** Add (or overwrite) a server in the given scope's mcp.json. */
|
|
203
|
+
static addServer(workDir, name, server, scope = 'project') {
|
|
204
|
+
const p = McpManager.configPath(workDir, scope);
|
|
205
|
+
const cfg = McpManager.readConfigFile(p);
|
|
206
|
+
cfg.mcpServers[name] = server;
|
|
207
|
+
McpManager.writeConfigFile(p, cfg);
|
|
208
|
+
}
|
|
209
|
+
/** Remove a server from whichever scope(s) define it. Returns true if anything was removed. */
|
|
210
|
+
static removeServer(workDir, name) {
|
|
211
|
+
let removed = false;
|
|
212
|
+
for (const scope of ['project', 'user']) {
|
|
213
|
+
const p = McpManager.configPath(workDir, scope);
|
|
214
|
+
const cfg = McpManager.readConfigFile(p);
|
|
215
|
+
if (cfg.mcpServers[name]) {
|
|
216
|
+
delete cfg.mcpServers[name];
|
|
217
|
+
McpManager.writeConfigFile(p, cfg);
|
|
218
|
+
removed = true;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return removed;
|
|
222
|
+
}
|
|
223
|
+
disconnectAll() {
|
|
224
|
+
for (const client of this._clients.values())
|
|
225
|
+
client.disconnect();
|
|
226
|
+
this._clients.clear();
|
|
227
|
+
this._toolMap.clear();
|
|
228
|
+
this._configs.clear();
|
|
229
|
+
this._errors.clear();
|
|
230
|
+
this._needsAuth.clear();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
exports.McpManager = McpManager;
|
|
234
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { McpServerConfig, McpToolDefinition, McpTransport } from './client';
|
|
2
|
+
export declare class McpSseClient implements McpTransport {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private _nextId;
|
|
5
|
+
private _tools;
|
|
6
|
+
private _endpointUrl;
|
|
7
|
+
private _abort;
|
|
8
|
+
private _sseBuf;
|
|
9
|
+
private _closed;
|
|
10
|
+
private readonly _pending;
|
|
11
|
+
private _endpointWaiter;
|
|
12
|
+
readonly name: string;
|
|
13
|
+
constructor(name: string, config: McpServerConfig);
|
|
14
|
+
get tools(): McpToolDefinition[];
|
|
15
|
+
connect(): Promise<void>;
|
|
16
|
+
callTool(name: string, args: Record<string, unknown>): Promise<string>;
|
|
17
|
+
disconnect(): void;
|
|
18
|
+
/** Open the GET event stream and wait for the server's `endpoint` event. */
|
|
19
|
+
private _openStream;
|
|
20
|
+
private _onStreamClosed;
|
|
21
|
+
/** Accumulate raw bytes and dispatch complete SSE events (blank-line delimited). */
|
|
22
|
+
private _feed;
|
|
23
|
+
private _firstEventBoundary;
|
|
24
|
+
private _dispatchEvent;
|
|
25
|
+
private _rpc;
|
|
26
|
+
private _notify;
|
|
27
|
+
/** POST a JSON-RPC message to the endpoint discovered via the SSE stream. */
|
|
28
|
+
private _postMessage;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=sseClient.d.ts.map
|