@invect/mcp 0.0.1
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/dist/backend/audit.d.ts +29 -0
- package/dist/backend/audit.d.ts.map +1 -0
- package/dist/backend/auth.d.ts +32 -0
- package/dist/backend/auth.d.ts.map +1 -0
- package/dist/backend/client/direct-client.d.ts +223 -0
- package/dist/backend/client/direct-client.d.ts.map +1 -0
- package/dist/backend/client/http-client.d.ts +74 -0
- package/dist/backend/client/http-client.d.ts.map +1 -0
- package/dist/backend/client/types.d.ts +83 -0
- package/dist/backend/client/types.d.ts.map +1 -0
- package/dist/backend/index.cjs +357 -0
- package/dist/backend/index.cjs.map +1 -0
- package/dist/backend/index.d.cts +29 -0
- package/dist/backend/index.d.cts.map +1 -0
- package/dist/backend/index.d.mts +29 -0
- package/dist/backend/index.d.mts.map +1 -0
- package/dist/backend/index.d.ts +32 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.mjs +356 -0
- package/dist/backend/index.mjs.map +1 -0
- package/dist/backend/mcp-server.d.ts +8 -0
- package/dist/backend/mcp-server.d.ts.map +1 -0
- package/dist/backend/prompts/index.d.ts +7 -0
- package/dist/backend/prompts/index.d.ts.map +1 -0
- package/dist/backend/resources/index.d.ts +7 -0
- package/dist/backend/resources/index.d.ts.map +1 -0
- package/dist/backend/response-mappers.d.ts +26 -0
- package/dist/backend/response-mappers.d.ts.map +1 -0
- package/dist/backend/session-manager.d.ts +30 -0
- package/dist/backend/session-manager.d.ts.map +1 -0
- package/dist/backend/tools/credential-tools.d.ts +8 -0
- package/dist/backend/tools/credential-tools.d.ts.map +1 -0
- package/dist/backend/tools/debug-tools.d.ts +7 -0
- package/dist/backend/tools/debug-tools.d.ts.map +1 -0
- package/dist/backend/tools/flow-tools.d.ts +7 -0
- package/dist/backend/tools/flow-tools.d.ts.map +1 -0
- package/dist/backend/tools/node-tools.d.ts +7 -0
- package/dist/backend/tools/node-tools.d.ts.map +1 -0
- package/dist/backend/tools/run-tools.d.ts +7 -0
- package/dist/backend/tools/run-tools.d.ts.map +1 -0
- package/dist/backend/tools/trigger-tools.d.ts +7 -0
- package/dist/backend/tools/trigger-tools.d.ts.map +1 -0
- package/dist/backend/tools/version-tools.d.ts +7 -0
- package/dist/backend/tools/version-tools.d.ts.map +1 -0
- package/dist/cli/index.cjs +213 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +151 -0
- package/dist/cli/index.d.cts.map +1 -0
- package/dist/cli/index.d.mts +151 -0
- package/dist/cli/index.d.mts.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.mjs +211 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/mcp-server-Brb4wc6I.mjs +671 -0
- package/dist/mcp-server-Brb4wc6I.mjs.map +1 -0
- package/dist/mcp-server-DzO5MpFJ.cjs +676 -0
- package/dist/mcp-server-DzO5MpFJ.cjs.map +1 -0
- package/dist/shared/types.cjs +39 -0
- package/dist/shared/types.cjs.map +1 -0
- package/dist/shared/types.d.cts +64 -0
- package/dist/shared/types.d.cts.map +1 -0
- package/dist/shared/types.d.mts +64 -0
- package/dist/shared/types.d.mts.map +1 -0
- package/dist/shared/types.d.ts +64 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.mjs +38 -0
- package/dist/shared/types.mjs.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_mcp_server = require("../mcp-server-DzO5MpFJ.cjs");
|
|
3
|
+
//#region src/backend/client/direct-client.ts
|
|
4
|
+
var DirectClient = class {
|
|
5
|
+
constructor(invect) {
|
|
6
|
+
this.invect = invect;
|
|
7
|
+
}
|
|
8
|
+
async listFlows(_identity) {
|
|
9
|
+
return await this.invect.flows.list();
|
|
10
|
+
}
|
|
11
|
+
async getFlow(_identity, flowId) {
|
|
12
|
+
return await this.invect.flows.get(flowId);
|
|
13
|
+
}
|
|
14
|
+
async getFlowDefinition(_identity, flowId) {
|
|
15
|
+
return await this.invect.versions.get(flowId, "latest");
|
|
16
|
+
}
|
|
17
|
+
async createFlow(_identity, data) {
|
|
18
|
+
return await this.invect.flows.create(data);
|
|
19
|
+
}
|
|
20
|
+
async updateFlow(_identity, flowId, data) {
|
|
21
|
+
return await this.invect.flows.update(flowId, data);
|
|
22
|
+
}
|
|
23
|
+
async deleteFlow(_identity, flowId) {
|
|
24
|
+
await this.invect.flows.delete(flowId);
|
|
25
|
+
}
|
|
26
|
+
async validateFlow(_identity, flowId, definition) {
|
|
27
|
+
const result = await this.invect.flows.validate(flowId, definition);
|
|
28
|
+
return {
|
|
29
|
+
valid: result.isValid,
|
|
30
|
+
errors: result.isValid ? void 0 : result.errors?.map((e) => e.message)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async listVersions(_identity, flowId) {
|
|
34
|
+
return await this.invect.versions.list(flowId);
|
|
35
|
+
}
|
|
36
|
+
async getVersion(_identity, flowId, version) {
|
|
37
|
+
return await this.invect.versions.get(flowId, version);
|
|
38
|
+
}
|
|
39
|
+
async publishVersion(_identity, flowId, data) {
|
|
40
|
+
return await this.invect.versions.create(flowId, data);
|
|
41
|
+
}
|
|
42
|
+
async startRun(_identity, flowId, inputs) {
|
|
43
|
+
return await this.invect.runs.start(flowId, inputs);
|
|
44
|
+
}
|
|
45
|
+
async runToNode(_identity, flowId, nodeId, inputs) {
|
|
46
|
+
return await this.invect.runs.executeToNode(flowId, nodeId, inputs);
|
|
47
|
+
}
|
|
48
|
+
async listRuns(_identity, flowId) {
|
|
49
|
+
return await this.invect.runs.listByFlowId(flowId);
|
|
50
|
+
}
|
|
51
|
+
async getRun(_identity, flowRunId) {
|
|
52
|
+
return await this.invect.runs.get(flowRunId);
|
|
53
|
+
}
|
|
54
|
+
async cancelRun(_identity, flowRunId) {
|
|
55
|
+
return await this.invect.runs.cancel(flowRunId);
|
|
56
|
+
}
|
|
57
|
+
async pauseRun(_identity, flowRunId) {
|
|
58
|
+
return await this.invect.runs.pause(flowRunId);
|
|
59
|
+
}
|
|
60
|
+
async resumeRun(_identity, flowRunId) {
|
|
61
|
+
return await this.invect.runs.resume(flowRunId);
|
|
62
|
+
}
|
|
63
|
+
async getNodeExecutions(_identity, flowRunId) {
|
|
64
|
+
return (await this.invect.runs.getNodeExecutions(flowRunId)).data;
|
|
65
|
+
}
|
|
66
|
+
async testNode(_identity, nodeType, params, inputData) {
|
|
67
|
+
return await this.invect.testing.testNode(nodeType, params, inputData);
|
|
68
|
+
}
|
|
69
|
+
async testJsExpression(_identity, expression, context) {
|
|
70
|
+
return await this.invect.testing.testJsExpression({
|
|
71
|
+
expression,
|
|
72
|
+
context
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async testMapper(_identity, expression, incomingData) {
|
|
76
|
+
return await this.invect.testing.testMapper({
|
|
77
|
+
expression,
|
|
78
|
+
incomingData
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async listCredentials(_identity) {
|
|
82
|
+
return (await this.invect.credentials.list()).map((c) => ({
|
|
83
|
+
id: c.id,
|
|
84
|
+
name: c.name,
|
|
85
|
+
type: String(c.type),
|
|
86
|
+
provider: "provider" in c ? String(c.provider ?? "") : void 0,
|
|
87
|
+
lastUsedAt: c.lastUsedAt ? String(c.lastUsedAt) : void 0,
|
|
88
|
+
createdAt: c.createdAt ? String(c.createdAt) : void 0
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
async testCredential(_identity, credentialId) {
|
|
92
|
+
return await this.invect.credentials.test(credentialId);
|
|
93
|
+
}
|
|
94
|
+
async listTriggers(_identity, flowId) {
|
|
95
|
+
return await this.invect.triggers.list(flowId);
|
|
96
|
+
}
|
|
97
|
+
async getTrigger(_identity, triggerId) {
|
|
98
|
+
return await this.invect.triggers.get(triggerId);
|
|
99
|
+
}
|
|
100
|
+
async createTrigger(_identity, input) {
|
|
101
|
+
return await this.invect.triggers.create(input);
|
|
102
|
+
}
|
|
103
|
+
async updateTrigger(_identity, triggerId, input) {
|
|
104
|
+
return await this.invect.triggers.update(triggerId, input);
|
|
105
|
+
}
|
|
106
|
+
async deleteTrigger(_identity, triggerId) {
|
|
107
|
+
await this.invect.triggers.delete(triggerId);
|
|
108
|
+
}
|
|
109
|
+
async listProviders(_identity) {
|
|
110
|
+
return this.invect.actions.getProviders();
|
|
111
|
+
}
|
|
112
|
+
async listAvailableNodes(_identity) {
|
|
113
|
+
return this.invect.actions.getAvailableNodes();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/backend/session-manager.ts
|
|
118
|
+
var SessionManager = class {
|
|
119
|
+
sessions = /* @__PURE__ */ new Map();
|
|
120
|
+
cleanupTimer = null;
|
|
121
|
+
constructor(ttlMs = 1800 * 1e3) {
|
|
122
|
+
this.ttlMs = ttlMs;
|
|
123
|
+
}
|
|
124
|
+
/** Start periodic cleanup of expired sessions */
|
|
125
|
+
startCleanup(intervalMs = 6e4) {
|
|
126
|
+
if (this.cleanupTimer) return;
|
|
127
|
+
this.cleanupTimer = setInterval(() => this.cleanupExpired(), intervalMs);
|
|
128
|
+
if (this.cleanupTimer && typeof this.cleanupTimer === "object" && "unref" in this.cleanupTimer) this.cleanupTimer.unref();
|
|
129
|
+
}
|
|
130
|
+
/** Stop periodic cleanup */
|
|
131
|
+
stopCleanup() {
|
|
132
|
+
if (this.cleanupTimer) {
|
|
133
|
+
clearInterval(this.cleanupTimer);
|
|
134
|
+
this.cleanupTimer = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Track a new session */
|
|
138
|
+
set(sessionId, transport) {
|
|
139
|
+
this.sessions.set(sessionId, {
|
|
140
|
+
transport,
|
|
141
|
+
createdAt: Date.now()
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/** Get a session's transport */
|
|
145
|
+
get(sessionId) {
|
|
146
|
+
return this.sessions.get(sessionId)?.transport;
|
|
147
|
+
}
|
|
148
|
+
/** Check if a session exists */
|
|
149
|
+
has(sessionId) {
|
|
150
|
+
return this.sessions.has(sessionId);
|
|
151
|
+
}
|
|
152
|
+
/** Remove a specific session */
|
|
153
|
+
delete(sessionId) {
|
|
154
|
+
return this.sessions.delete(sessionId);
|
|
155
|
+
}
|
|
156
|
+
/** Remove sessions that exceed the TTL */
|
|
157
|
+
cleanupExpired() {
|
|
158
|
+
const now = Date.now();
|
|
159
|
+
let cleaned = 0;
|
|
160
|
+
for (const [id, entry] of this.sessions) if (now - entry.createdAt > this.ttlMs) {
|
|
161
|
+
this.sessions.delete(id);
|
|
162
|
+
cleaned++;
|
|
163
|
+
}
|
|
164
|
+
return cleaned;
|
|
165
|
+
}
|
|
166
|
+
/** Number of active sessions */
|
|
167
|
+
get size() {
|
|
168
|
+
return this.sessions.size;
|
|
169
|
+
}
|
|
170
|
+
/** Close all sessions and stop cleanup */
|
|
171
|
+
async closeAll() {
|
|
172
|
+
this.stopCleanup();
|
|
173
|
+
for (const [_id, entry] of this.sessions) try {
|
|
174
|
+
const transport = entry.transport;
|
|
175
|
+
if (transport.close) await transport.close();
|
|
176
|
+
} catch {}
|
|
177
|
+
this.sessions.clear();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/backend/audit.ts
|
|
182
|
+
var AuditLogger = class {
|
|
183
|
+
enabled;
|
|
184
|
+
logLevel;
|
|
185
|
+
constructor(logger, options) {
|
|
186
|
+
this.logger = logger;
|
|
187
|
+
this.enabled = options?.enabled ?? true;
|
|
188
|
+
this.logLevel = options?.logLevel ?? "info";
|
|
189
|
+
}
|
|
190
|
+
log(entry) {
|
|
191
|
+
if (!this.enabled) return;
|
|
192
|
+
const msg = `[MCP Audit] ${entry.tool} ${entry.status} (${entry.durationMs}ms) user=${entry.userId ?? "unknown"}`;
|
|
193
|
+
const meta = {
|
|
194
|
+
sessionId: entry.sessionId,
|
|
195
|
+
userId: entry.userId,
|
|
196
|
+
userRole: entry.userRole,
|
|
197
|
+
tool: entry.tool,
|
|
198
|
+
status: entry.status,
|
|
199
|
+
durationMs: entry.durationMs,
|
|
200
|
+
...entry.error ? { error: entry.error } : {}
|
|
201
|
+
};
|
|
202
|
+
switch (this.logLevel) {
|
|
203
|
+
case "debug":
|
|
204
|
+
this.logger.debug(msg, meta);
|
|
205
|
+
break;
|
|
206
|
+
case "warn":
|
|
207
|
+
this.logger.warn(msg, meta);
|
|
208
|
+
break;
|
|
209
|
+
default: this.logger.info(msg, meta);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Create an audit entry helper that tracks timing */
|
|
213
|
+
startTimer(tool, options) {
|
|
214
|
+
const start = Date.now();
|
|
215
|
+
return { finish: (result) => {
|
|
216
|
+
this.log({
|
|
217
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
218
|
+
tool,
|
|
219
|
+
params: {},
|
|
220
|
+
durationMs: Date.now() - start,
|
|
221
|
+
sessionId: options?.sessionId,
|
|
222
|
+
userId: options?.userId,
|
|
223
|
+
userRole: options?.userRole,
|
|
224
|
+
...result
|
|
225
|
+
});
|
|
226
|
+
} };
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/backend/index.ts
|
|
231
|
+
/**
|
|
232
|
+
* Create the MCP plugin.
|
|
233
|
+
*
|
|
234
|
+
* When registered with Invect, this plugin mounts Streamable HTTP endpoints
|
|
235
|
+
* at `/plugins/mcp/` that implement the Model Context Protocol. MCP clients
|
|
236
|
+
* (Claude Desktop, VS Code Copilot, Cursor, etc.) connect to these endpoints.
|
|
237
|
+
*
|
|
238
|
+
* Authentication flows through the host app's existing auth middleware — the
|
|
239
|
+
* MCP SDK's Streamable HTTP transport receives the request identity resolved
|
|
240
|
+
* by the framework adapter.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* import { createInvect } from '@invect/core';
|
|
245
|
+
* import { mcpPlugin } from '@invect/mcp';
|
|
246
|
+
*
|
|
247
|
+
* const invect = await createInvect({
|
|
248
|
+
* plugins: [mcpPlugin()],
|
|
249
|
+
* });
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
function mcpPlugin(options = {}) {
|
|
253
|
+
const sessionTtlMs = options.sessionTtlMs ?? 1800 * 1e3;
|
|
254
|
+
const sessionManager = new SessionManager(sessionTtlMs);
|
|
255
|
+
let auditLogger;
|
|
256
|
+
return {
|
|
257
|
+
id: "mcp",
|
|
258
|
+
name: "Model Context Protocol",
|
|
259
|
+
init(ctx) {
|
|
260
|
+
auditLogger = new AuditLogger(ctx.logger, options.audit);
|
|
261
|
+
ctx.store.set("sessionManager", sessionManager);
|
|
262
|
+
ctx.store.set("auditLogger", auditLogger);
|
|
263
|
+
sessionManager.startCleanup();
|
|
264
|
+
ctx.logger.info(`MCP plugin initialized (session TTL: ${sessionTtlMs / 1e3}s, audit: ${options.audit?.enabled !== false ? "on" : "off"})`);
|
|
265
|
+
},
|
|
266
|
+
endpoints: [{
|
|
267
|
+
method: "POST",
|
|
268
|
+
path: "/mcp",
|
|
269
|
+
handler: async (ctx) => {
|
|
270
|
+
const mcpServer = require_mcp_server.createMcpServer(new DirectClient(ctx.getInvect()));
|
|
271
|
+
try {
|
|
272
|
+
return {
|
|
273
|
+
status: 200,
|
|
274
|
+
body: await handleMcpJsonRpc(mcpServer, ctx.body, ctx.identity)
|
|
275
|
+
};
|
|
276
|
+
} catch (error) {
|
|
277
|
+
return {
|
|
278
|
+
status: 500,
|
|
279
|
+
body: {
|
|
280
|
+
jsonrpc: "2.0",
|
|
281
|
+
error: {
|
|
282
|
+
code: -32603,
|
|
283
|
+
message: error instanceof Error ? error.message : "Internal error"
|
|
284
|
+
},
|
|
285
|
+
id: ctx.body.id ?? null
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}, {
|
|
291
|
+
method: "GET",
|
|
292
|
+
path: "/mcp/info",
|
|
293
|
+
handler: async () => {
|
|
294
|
+
return {
|
|
295
|
+
status: 200,
|
|
296
|
+
body: {
|
|
297
|
+
name: "invect-mcp",
|
|
298
|
+
version: "0.0.1",
|
|
299
|
+
protocolVersion: "2025-03-26",
|
|
300
|
+
capabilities: {
|
|
301
|
+
tools: true,
|
|
302
|
+
resources: true,
|
|
303
|
+
prompts: true
|
|
304
|
+
},
|
|
305
|
+
sessions: sessionManager.size
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
},
|
|
309
|
+
isPublic: true
|
|
310
|
+
}],
|
|
311
|
+
async shutdown() {
|
|
312
|
+
sessionManager.stopCleanup();
|
|
313
|
+
await sessionManager.closeAll();
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Lightweight JSON-RPC handler that delegates to the McpServer.
|
|
319
|
+
*
|
|
320
|
+
* The MCP SDK's McpServer handles tool/resource/prompt dispatch internally.
|
|
321
|
+
* We intercept the JSON-RPC request, add auth context, and call the server.
|
|
322
|
+
*/
|
|
323
|
+
async function handleMcpJsonRpc(_server, body, _identity) {
|
|
324
|
+
const method = body.method;
|
|
325
|
+
const id = body.id;
|
|
326
|
+
if (method === "initialize") return {
|
|
327
|
+
jsonrpc: "2.0",
|
|
328
|
+
result: {
|
|
329
|
+
protocolVersion: "2025-03-26",
|
|
330
|
+
capabilities: {
|
|
331
|
+
tools: { listChanged: false },
|
|
332
|
+
resources: {
|
|
333
|
+
subscribe: false,
|
|
334
|
+
listChanged: false
|
|
335
|
+
},
|
|
336
|
+
prompts: { listChanged: false }
|
|
337
|
+
},
|
|
338
|
+
serverInfo: {
|
|
339
|
+
name: "invect-mcp",
|
|
340
|
+
version: "0.0.1"
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
id
|
|
344
|
+
};
|
|
345
|
+
return {
|
|
346
|
+
jsonrpc: "2.0",
|
|
347
|
+
error: {
|
|
348
|
+
code: -32601,
|
|
349
|
+
message: `Method not yet implemented via plugin endpoint: ${method}. Use the stdio CLI transport for full MCP support.`
|
|
350
|
+
},
|
|
351
|
+
id
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
355
|
+
exports.mcpPlugin = mcpPlugin;
|
|
356
|
+
|
|
357
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["createMcpServer"],"sources":["../../src/backend/client/direct-client.ts","../../src/backend/session-manager.ts","../../src/backend/audit.ts","../../src/backend/index.ts"],"sourcesContent":["/**\n * DirectClient — wraps InvectInstance for plugin mode (zero HTTP overhead).\n */\n\nimport type { InvectInstance, InvectIdentity } from '@invect/core';\nimport type { InvectClient, CredentialSummary } from './types';\n\nexport class DirectClient implements InvectClient {\n constructor(private readonly invect: InvectInstance) {}\n\n // ===== Flows =====\n\n async listFlows(_identity: InvectIdentity | null) {\n return await this.invect.flows.list();\n }\n\n async getFlow(_identity: InvectIdentity | null, flowId: string) {\n return await this.invect.flows.get(flowId);\n }\n\n async getFlowDefinition(_identity: InvectIdentity | null, flowId: string) {\n return await this.invect.versions.get(flowId, 'latest');\n }\n\n async createFlow(_identity: InvectIdentity | null, data: { name: string; description?: string }) {\n return await this.invect.flows.create(data);\n }\n\n async updateFlow(\n _identity: InvectIdentity | null,\n flowId: string,\n data: { name?: string; description?: string },\n ) {\n return await this.invect.flows.update(flowId, data);\n }\n\n async deleteFlow(_identity: InvectIdentity | null, flowId: string) {\n await this.invect.flows.delete(flowId);\n }\n\n async validateFlow(_identity: InvectIdentity | null, flowId: string, definition: unknown) {\n const result = await this.invect.flows.validate(flowId, definition);\n return {\n valid: result.isValid,\n errors: result.isValid ? undefined : result.errors?.map((e) => e.message),\n };\n }\n\n // ===== Versions =====\n\n async listVersions(_identity: InvectIdentity | null, flowId: string) {\n return await this.invect.versions.list(flowId);\n }\n\n async getVersion(\n _identity: InvectIdentity | null,\n flowId: string,\n version: string | number | 'latest',\n ) {\n return await this.invect.versions.get(flowId, version);\n }\n\n async publishVersion(_identity: InvectIdentity | null, flowId: string, data: unknown) {\n return await this.invect.versions.create(\n flowId,\n data as Parameters<InvectInstance['versions']['create']>[1],\n );\n }\n\n // ===== Runs =====\n\n async startRun(\n _identity: InvectIdentity | null,\n flowId: string,\n inputs?: Record<string, unknown>,\n ) {\n return await this.invect.runs.start(flowId, inputs);\n }\n\n async runToNode(\n _identity: InvectIdentity | null,\n flowId: string,\n nodeId: string,\n inputs?: Record<string, unknown>,\n ) {\n return await this.invect.runs.executeToNode(flowId, nodeId, inputs);\n }\n\n async listRuns(_identity: InvectIdentity | null, flowId: string) {\n return await this.invect.runs.listByFlowId(flowId);\n }\n\n async getRun(_identity: InvectIdentity | null, flowRunId: string) {\n return await this.invect.runs.get(flowRunId);\n }\n\n async cancelRun(_identity: InvectIdentity | null, flowRunId: string) {\n return await this.invect.runs.cancel(flowRunId);\n }\n\n async pauseRun(_identity: InvectIdentity | null, flowRunId: string) {\n return await this.invect.runs.pause(flowRunId);\n }\n\n async resumeRun(_identity: InvectIdentity | null, flowRunId: string) {\n return await this.invect.runs.resume(flowRunId);\n }\n\n // ===== Debug =====\n\n async getNodeExecutions(_identity: InvectIdentity | null, flowRunId: string) {\n const result = await this.invect.runs.getNodeExecutions(flowRunId);\n return result.data;\n }\n\n async testNode(\n _identity: InvectIdentity | null,\n nodeType: string,\n params: Record<string, unknown>,\n inputData?: Record<string, unknown>,\n ) {\n return await this.invect.testing.testNode(nodeType, params, inputData);\n }\n\n async testJsExpression(\n _identity: InvectIdentity | null,\n expression: string,\n context: Record<string, unknown>,\n ) {\n return await this.invect.testing.testJsExpression({ expression, context });\n }\n\n async testMapper(\n _identity: InvectIdentity | null,\n expression: string,\n incomingData: Record<string, unknown>,\n ) {\n return await this.invect.testing.testMapper({ expression, incomingData });\n }\n\n // ===== Credentials =====\n\n async listCredentials(_identity: InvectIdentity | null): Promise<CredentialSummary[]> {\n const creds = await this.invect.credentials.list();\n return creds.map((c) => ({\n id: c.id,\n name: c.name,\n type: String(c.type),\n provider: 'provider' in c ? String((c as Record<string, unknown>).provider ?? '') : undefined,\n lastUsedAt: c.lastUsedAt ? String(c.lastUsedAt) : undefined,\n createdAt: c.createdAt ? String(c.createdAt) : undefined,\n }));\n }\n\n async testCredential(_identity: InvectIdentity | null, credentialId: string) {\n return await this.invect.credentials.test(credentialId);\n }\n\n // ===== Triggers =====\n\n async listTriggers(_identity: InvectIdentity | null, flowId: string) {\n return await this.invect.triggers.list(flowId);\n }\n\n async getTrigger(_identity: InvectIdentity | null, triggerId: string) {\n return await this.invect.triggers.get(triggerId);\n }\n\n async createTrigger(_identity: InvectIdentity | null, input: unknown) {\n return await this.invect.triggers.create(\n input as Parameters<InvectInstance['triggers']['create']>[0],\n );\n }\n\n async updateTrigger(_identity: InvectIdentity | null, triggerId: string, input: unknown) {\n return await this.invect.triggers.update(\n triggerId,\n input as Parameters<InvectInstance['triggers']['update']>[1],\n );\n }\n\n async deleteTrigger(_identity: InvectIdentity | null, triggerId: string) {\n await this.invect.triggers.delete(triggerId);\n }\n\n // ===== Node Reference =====\n\n async listProviders(_identity: InvectIdentity | null) {\n return this.invect.actions.getProviders();\n }\n\n async listAvailableNodes(_identity: InvectIdentity | null) {\n return this.invect.actions.getAvailableNodes();\n }\n}\n","/**\n * Session manager for MCP Streamable HTTP transport.\n *\n * Tracks active sessions, their transports, and handles TTL-based cleanup.\n */\n\ninterface SessionEntry {\n transport: unknown; // NodeStreamableHTTPServerTransport\n createdAt: number;\n}\n\nexport class SessionManager {\n private sessions = new Map<string, SessionEntry>();\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(private readonly ttlMs: number = 30 * 60 * 1000) {}\n\n /** Start periodic cleanup of expired sessions */\n startCleanup(intervalMs: number = 60_000): void {\n if (this.cleanupTimer) {\n return;\n }\n this.cleanupTimer = setInterval(() => this.cleanupExpired(), intervalMs);\n // Don't block process exit\n if (\n this.cleanupTimer &&\n typeof this.cleanupTimer === 'object' &&\n 'unref' in this.cleanupTimer\n ) {\n this.cleanupTimer.unref();\n }\n }\n\n /** Stop periodic cleanup */\n stopCleanup(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /** Track a new session */\n set(sessionId: string, transport: unknown): void {\n this.sessions.set(sessionId, {\n transport,\n createdAt: Date.now(),\n });\n }\n\n /** Get a session's transport */\n get(sessionId: string): unknown | undefined {\n return this.sessions.get(sessionId)?.transport;\n }\n\n /** Check if a session exists */\n has(sessionId: string): boolean {\n return this.sessions.has(sessionId);\n }\n\n /** Remove a specific session */\n delete(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\n }\n\n /** Remove sessions that exceed the TTL */\n cleanupExpired(): number {\n const now = Date.now();\n let cleaned = 0;\n for (const [id, entry] of this.sessions) {\n if (now - entry.createdAt > this.ttlMs) {\n this.sessions.delete(id);\n cleaned++;\n }\n }\n return cleaned;\n }\n\n /** Number of active sessions */\n get size(): number {\n return this.sessions.size;\n }\n\n /** Close all sessions and stop cleanup */\n async closeAll(): Promise<void> {\n this.stopCleanup();\n for (const [_id, entry] of this.sessions) {\n try {\n const transport = entry.transport as { close?: () => Promise<void> | void };\n if (transport.close) {\n await transport.close();\n }\n } catch {\n // Best-effort cleanup\n }\n }\n this.sessions.clear();\n }\n}\n","/**\n * Audit logger for MCP tool invocations.\n */\n\nimport type { AuditEntry, McpPluginOptions } from '../shared/types';\n\ntype Logger = {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n};\n\nexport class AuditLogger {\n private enabled: boolean;\n private logLevel: 'debug' | 'info' | 'warn';\n\n constructor(\n private readonly logger: Logger,\n options?: McpPluginOptions['audit'],\n ) {\n this.enabled = options?.enabled ?? true;\n this.logLevel = options?.logLevel ?? 'info';\n }\n\n log(entry: AuditEntry): void {\n if (!this.enabled) {\n return;\n }\n\n const msg = `[MCP Audit] ${entry.tool} ${entry.status} (${entry.durationMs}ms) user=${entry.userId ?? 'unknown'}`;\n const meta = {\n sessionId: entry.sessionId,\n userId: entry.userId,\n userRole: entry.userRole,\n tool: entry.tool,\n status: entry.status,\n durationMs: entry.durationMs,\n ...(entry.error ? { error: entry.error } : {}),\n };\n\n switch (this.logLevel) {\n case 'debug':\n this.logger.debug(msg, meta);\n break;\n case 'warn':\n this.logger.warn(msg, meta);\n break;\n default:\n this.logger.info(msg, meta);\n }\n }\n\n /** Create an audit entry helper that tracks timing */\n startTimer(\n tool: string,\n options?: { sessionId?: string; userId?: string; userRole?: string },\n ): { finish: (result: { status: 'success' | 'error'; error?: string }) => void } {\n const start = Date.now();\n return {\n finish: (result) => {\n this.log({\n timestamp: new Date().toISOString(),\n tool,\n params: {}, // Params are not logged by default for security\n durationMs: Date.now() - start,\n sessionId: options?.sessionId,\n userId: options?.userId,\n userRole: options?.userRole,\n ...result,\n });\n },\n };\n }\n}\n","/**\n * @invect/mcp — Plugin entry point\n *\n * Exports the `mcpPlugin()` factory that creates an InvectPlugin providing\n * MCP (Model Context Protocol) endpoints for AI coding agents.\n */\n\nimport type { InvectPlugin, InvectPluginContext } from '@invect/core';\nimport type { McpPluginOptions } from '../shared/types';\nimport { DirectClient } from './client/direct-client';\nimport { createMcpServer } from './mcp-server';\nimport { SessionManager } from './session-manager';\nimport { AuditLogger } from './audit';\n\n/**\n * Create the MCP plugin.\n *\n * When registered with Invect, this plugin mounts Streamable HTTP endpoints\n * at `/plugins/mcp/` that implement the Model Context Protocol. MCP clients\n * (Claude Desktop, VS Code Copilot, Cursor, etc.) connect to these endpoints.\n *\n * Authentication flows through the host app's existing auth middleware — the\n * MCP SDK's Streamable HTTP transport receives the request identity resolved\n * by the framework adapter.\n *\n * @example\n * ```typescript\n * import { createInvect } from '@invect/core';\n * import { mcpPlugin } from '@invect/mcp';\n *\n * const invect = await createInvect({\n * plugins: [mcpPlugin()],\n * });\n * ```\n */\nexport function mcpPlugin(options: McpPluginOptions = {}): InvectPlugin {\n const sessionTtlMs = options.sessionTtlMs ?? 30 * 60 * 1000;\n const sessionManager = new SessionManager(sessionTtlMs);\n let auditLogger: AuditLogger | undefined;\n\n return {\n id: 'mcp',\n name: 'Model Context Protocol',\n\n init(ctx: InvectPluginContext) {\n auditLogger = new AuditLogger(ctx.logger, options.audit);\n\n // Store references for endpoint handlers\n ctx.store.set('sessionManager', sessionManager);\n ctx.store.set('auditLogger', auditLogger);\n\n sessionManager.startCleanup();\n\n ctx.logger.info(\n `MCP plugin initialized (session TTL: ${sessionTtlMs / 1000}s, audit: ${options.audit?.enabled !== false ? 'on' : 'off'})`,\n );\n },\n\n endpoints: [\n // Streamable HTTP → MCP endpoint (POST for messages, GET for SSE, DELETE for close)\n {\n method: 'POST',\n path: '/mcp',\n handler: async (ctx) => {\n const invect = ctx.getInvect();\n const client = new DirectClient(invect);\n const mcpServer = createMcpServer(client);\n\n // The body contains an MCP JSON-RPC message.\n // For a full Streamable HTTP implementation, we'd use\n // StreamableHTTPServerTransport. For now, handle inline.\n try {\n // Delegate to a simple JSON-RPC handler\n const result = await handleMcpJsonRpc(mcpServer, ctx.body, ctx.identity);\n return { status: 200, body: result };\n } catch (error) {\n return {\n status: 500,\n body: {\n jsonrpc: '2.0',\n error: {\n code: -32603,\n message: error instanceof Error ? error.message : 'Internal error',\n },\n id: (ctx.body as { id?: unknown }).id ?? null,\n },\n };\n }\n },\n },\n\n // Health check / server info\n {\n method: 'GET',\n path: '/mcp/info',\n handler: async () => {\n return {\n status: 200,\n body: {\n name: 'invect-mcp',\n version: '0.0.1',\n protocolVersion: '2025-03-26',\n capabilities: {\n tools: true,\n resources: true,\n prompts: true,\n },\n sessions: sessionManager.size,\n },\n };\n },\n isPublic: true,\n },\n ],\n\n async shutdown() {\n sessionManager.stopCleanup();\n await sessionManager.closeAll();\n },\n };\n}\n\n/**\n * Lightweight JSON-RPC handler that delegates to the McpServer.\n *\n * The MCP SDK's McpServer handles tool/resource/prompt dispatch internally.\n * We intercept the JSON-RPC request, add auth context, and call the server.\n */\nasync function handleMcpJsonRpc(\n _server: ReturnType<typeof createMcpServer>,\n body: Record<string, unknown>,\n _identity: unknown,\n): Promise<unknown> {\n // The MCP SDK expects to handle transport-level protocol details.\n // For the plugin endpoint integration, we need to use the SDK's\n // Streamable HTTP transport properly. This is a placeholder that\n // returns the server capabilities for the \"initialize\" method.\n\n const method = body.method as string | undefined;\n const id = body.id;\n\n if (method === 'initialize') {\n return {\n jsonrpc: '2.0',\n result: {\n protocolVersion: '2025-03-26',\n capabilities: {\n tools: { listChanged: false },\n resources: { subscribe: false, listChanged: false },\n prompts: { listChanged: false },\n },\n serverInfo: {\n name: 'invect-mcp',\n version: '0.0.1',\n },\n },\n id,\n };\n }\n\n // For other methods, we need the full Streamable HTTP transport integration.\n // This will be completed when connecting the MCP SDK transport layer.\n return {\n jsonrpc: '2.0',\n error: {\n code: -32601,\n message: `Method not yet implemented via plugin endpoint: ${method}. Use the stdio CLI transport for full MCP support.`,\n },\n id,\n };\n}\n\nexport type { McpPluginOptions } from '../shared/types';\n"],"mappings":";;;AAOA,IAAa,eAAb,MAAkD;CAChD,YAAY,QAAyC;AAAxB,OAAA,SAAA;;CAI7B,MAAM,UAAU,WAAkC;AAChD,SAAO,MAAM,KAAK,OAAO,MAAM,MAAM;;CAGvC,MAAM,QAAQ,WAAkC,QAAgB;AAC9D,SAAO,MAAM,KAAK,OAAO,MAAM,IAAI,OAAO;;CAG5C,MAAM,kBAAkB,WAAkC,QAAgB;AACxE,SAAO,MAAM,KAAK,OAAO,SAAS,IAAI,QAAQ,SAAS;;CAGzD,MAAM,WAAW,WAAkC,MAA8C;AAC/F,SAAO,MAAM,KAAK,OAAO,MAAM,OAAO,KAAK;;CAG7C,MAAM,WACJ,WACA,QACA,MACA;AACA,SAAO,MAAM,KAAK,OAAO,MAAM,OAAO,QAAQ,KAAK;;CAGrD,MAAM,WAAW,WAAkC,QAAgB;AACjE,QAAM,KAAK,OAAO,MAAM,OAAO,OAAO;;CAGxC,MAAM,aAAa,WAAkC,QAAgB,YAAqB;EACxF,MAAM,SAAS,MAAM,KAAK,OAAO,MAAM,SAAS,QAAQ,WAAW;AACnE,SAAO;GACL,OAAO,OAAO;GACd,QAAQ,OAAO,UAAU,KAAA,IAAY,OAAO,QAAQ,KAAK,MAAM,EAAE,QAAQ;GAC1E;;CAKH,MAAM,aAAa,WAAkC,QAAgB;AACnE,SAAO,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO;;CAGhD,MAAM,WACJ,WACA,QACA,SACA;AACA,SAAO,MAAM,KAAK,OAAO,SAAS,IAAI,QAAQ,QAAQ;;CAGxD,MAAM,eAAe,WAAkC,QAAgB,MAAe;AACpF,SAAO,MAAM,KAAK,OAAO,SAAS,OAChC,QACA,KACD;;CAKH,MAAM,SACJ,WACA,QACA,QACA;AACA,SAAO,MAAM,KAAK,OAAO,KAAK,MAAM,QAAQ,OAAO;;CAGrD,MAAM,UACJ,WACA,QACA,QACA,QACA;AACA,SAAO,MAAM,KAAK,OAAO,KAAK,cAAc,QAAQ,QAAQ,OAAO;;CAGrE,MAAM,SAAS,WAAkC,QAAgB;AAC/D,SAAO,MAAM,KAAK,OAAO,KAAK,aAAa,OAAO;;CAGpD,MAAM,OAAO,WAAkC,WAAmB;AAChE,SAAO,MAAM,KAAK,OAAO,KAAK,IAAI,UAAU;;CAG9C,MAAM,UAAU,WAAkC,WAAmB;AACnE,SAAO,MAAM,KAAK,OAAO,KAAK,OAAO,UAAU;;CAGjD,MAAM,SAAS,WAAkC,WAAmB;AAClE,SAAO,MAAM,KAAK,OAAO,KAAK,MAAM,UAAU;;CAGhD,MAAM,UAAU,WAAkC,WAAmB;AACnE,SAAO,MAAM,KAAK,OAAO,KAAK,OAAO,UAAU;;CAKjD,MAAM,kBAAkB,WAAkC,WAAmB;AAE3E,UADe,MAAM,KAAK,OAAO,KAAK,kBAAkB,UAAU,EACpD;;CAGhB,MAAM,SACJ,WACA,UACA,QACA,WACA;AACA,SAAO,MAAM,KAAK,OAAO,QAAQ,SAAS,UAAU,QAAQ,UAAU;;CAGxE,MAAM,iBACJ,WACA,YACA,SACA;AACA,SAAO,MAAM,KAAK,OAAO,QAAQ,iBAAiB;GAAE;GAAY;GAAS,CAAC;;CAG5E,MAAM,WACJ,WACA,YACA,cACA;AACA,SAAO,MAAM,KAAK,OAAO,QAAQ,WAAW;GAAE;GAAY;GAAc,CAAC;;CAK3E,MAAM,gBAAgB,WAAgE;AAEpF,UADc,MAAM,KAAK,OAAO,YAAY,MAAM,EACrC,KAAK,OAAO;GACvB,IAAI,EAAE;GACN,MAAM,EAAE;GACR,MAAM,OAAO,EAAE,KAAK;GACpB,UAAU,cAAc,IAAI,OAAQ,EAA8B,YAAY,GAAG,GAAG,KAAA;GACpF,YAAY,EAAE,aAAa,OAAO,EAAE,WAAW,GAAG,KAAA;GAClD,WAAW,EAAE,YAAY,OAAO,EAAE,UAAU,GAAG,KAAA;GAChD,EAAE;;CAGL,MAAM,eAAe,WAAkC,cAAsB;AAC3E,SAAO,MAAM,KAAK,OAAO,YAAY,KAAK,aAAa;;CAKzD,MAAM,aAAa,WAAkC,QAAgB;AACnE,SAAO,MAAM,KAAK,OAAO,SAAS,KAAK,OAAO;;CAGhD,MAAM,WAAW,WAAkC,WAAmB;AACpE,SAAO,MAAM,KAAK,OAAO,SAAS,IAAI,UAAU;;CAGlD,MAAM,cAAc,WAAkC,OAAgB;AACpE,SAAO,MAAM,KAAK,OAAO,SAAS,OAChC,MACD;;CAGH,MAAM,cAAc,WAAkC,WAAmB,OAAgB;AACvF,SAAO,MAAM,KAAK,OAAO,SAAS,OAChC,WACA,MACD;;CAGH,MAAM,cAAc,WAAkC,WAAmB;AACvE,QAAM,KAAK,OAAO,SAAS,OAAO,UAAU;;CAK9C,MAAM,cAAc,WAAkC;AACpD,SAAO,KAAK,OAAO,QAAQ,cAAc;;CAG3C,MAAM,mBAAmB,WAAkC;AACzD,SAAO,KAAK,OAAO,QAAQ,mBAAmB;;;;;ACrLlD,IAAa,iBAAb,MAA4B;CAC1B,2BAAmB,IAAI,KAA2B;CAClD,eAA8D;CAE9D,YAAY,QAAiC,OAAU,KAAM;AAAhC,OAAA,QAAA;;;CAG7B,aAAa,aAAqB,KAAc;AAC9C,MAAI,KAAK,aACP;AAEF,OAAK,eAAe,kBAAkB,KAAK,gBAAgB,EAAE,WAAW;AAExE,MACE,KAAK,gBACL,OAAO,KAAK,iBAAiB,YAC7B,WAAW,KAAK,aAEhB,MAAK,aAAa,OAAO;;;CAK7B,cAAoB;AAClB,MAAI,KAAK,cAAc;AACrB,iBAAc,KAAK,aAAa;AAChC,QAAK,eAAe;;;;CAKxB,IAAI,WAAmB,WAA0B;AAC/C,OAAK,SAAS,IAAI,WAAW;GAC3B;GACA,WAAW,KAAK,KAAK;GACtB,CAAC;;;CAIJ,IAAI,WAAwC;AAC1C,SAAO,KAAK,SAAS,IAAI,UAAU,EAAE;;;CAIvC,IAAI,WAA4B;AAC9B,SAAO,KAAK,SAAS,IAAI,UAAU;;;CAIrC,OAAO,WAA4B;AACjC,SAAO,KAAK,SAAS,OAAO,UAAU;;;CAIxC,iBAAyB;EACvB,MAAM,MAAM,KAAK,KAAK;EACtB,IAAI,UAAU;AACd,OAAK,MAAM,CAAC,IAAI,UAAU,KAAK,SAC7B,KAAI,MAAM,MAAM,YAAY,KAAK,OAAO;AACtC,QAAK,SAAS,OAAO,GAAG;AACxB;;AAGJ,SAAO;;;CAIT,IAAI,OAAe;AACjB,SAAO,KAAK,SAAS;;;CAIvB,MAAM,WAA0B;AAC9B,OAAK,aAAa;AAClB,OAAK,MAAM,CAAC,KAAK,UAAU,KAAK,SAC9B,KAAI;GACF,MAAM,YAAY,MAAM;AACxB,OAAI,UAAU,MACZ,OAAM,UAAU,OAAO;UAEnB;AAIV,OAAK,SAAS,OAAO;;;;;ACnFzB,IAAa,cAAb,MAAyB;CACvB;CACA;CAEA,YACE,QACA,SACA;AAFiB,OAAA,SAAA;AAGjB,OAAK,UAAU,SAAS,WAAW;AACnC,OAAK,WAAW,SAAS,YAAY;;CAGvC,IAAI,OAAyB;AAC3B,MAAI,CAAC,KAAK,QACR;EAGF,MAAM,MAAM,eAAe,MAAM,KAAK,GAAG,MAAM,OAAO,IAAI,MAAM,WAAW,WAAW,MAAM,UAAU;EACtG,MAAM,OAAO;GACX,WAAW,MAAM;GACjB,QAAQ,MAAM;GACd,UAAU,MAAM;GAChB,MAAM,MAAM;GACZ,QAAQ,MAAM;GACd,YAAY,MAAM;GAClB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,GAAG,EAAE;GAC9C;AAED,UAAQ,KAAK,UAAb;GACE,KAAK;AACH,SAAK,OAAO,MAAM,KAAK,KAAK;AAC5B;GACF,KAAK;AACH,SAAK,OAAO,KAAK,KAAK,KAAK;AAC3B;GACF,QACE,MAAK,OAAO,KAAK,KAAK,KAAK;;;;CAKjC,WACE,MACA,SAC+E;EAC/E,MAAM,QAAQ,KAAK,KAAK;AACxB,SAAO,EACL,SAAS,WAAW;AAClB,QAAK,IAAI;IACP,4BAAW,IAAI,MAAM,EAAC,aAAa;IACnC;IACA,QAAQ,EAAE;IACV,YAAY,KAAK,KAAK,GAAG;IACzB,WAAW,SAAS;IACpB,QAAQ,SAAS;IACjB,UAAU,SAAS;IACnB,GAAG;IACJ,CAAC;KAEL;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCL,SAAgB,UAAU,UAA4B,EAAE,EAAgB;CACtE,MAAM,eAAe,QAAQ,gBAAgB,OAAU;CACvD,MAAM,iBAAiB,IAAI,eAAe,aAAa;CACvD,IAAI;AAEJ,QAAO;EACL,IAAI;EACJ,MAAM;EAEN,KAAK,KAA0B;AAC7B,iBAAc,IAAI,YAAY,IAAI,QAAQ,QAAQ,MAAM;AAGxD,OAAI,MAAM,IAAI,kBAAkB,eAAe;AAC/C,OAAI,MAAM,IAAI,eAAe,YAAY;AAEzC,kBAAe,cAAc;AAE7B,OAAI,OAAO,KACT,wCAAwC,eAAe,IAAK,YAAY,QAAQ,OAAO,YAAY,QAAQ,OAAO,MAAM,GACzH;;EAGH,WAAW,CAET;GACE,QAAQ;GACR,MAAM;GACN,SAAS,OAAO,QAAQ;IAGtB,MAAM,YAAYA,mBAAAA,gBADH,IAAI,aADJ,IAAI,WAAW,CACS,CACE;AAKzC,QAAI;AAGF,YAAO;MAAE,QAAQ;MAAK,MADP,MAAM,iBAAiB,WAAW,IAAI,MAAM,IAAI,SAAS;MACpC;aAC7B,OAAO;AACd,YAAO;MACL,QAAQ;MACR,MAAM;OACJ,SAAS;OACT,OAAO;QACL,MAAM;QACN,SAAS,iBAAiB,QAAQ,MAAM,UAAU;QACnD;OACD,IAAK,IAAI,KAA0B,MAAM;OAC1C;MACF;;;GAGN,EAGD;GACE,QAAQ;GACR,MAAM;GACN,SAAS,YAAY;AACnB,WAAO;KACL,QAAQ;KACR,MAAM;MACJ,MAAM;MACN,SAAS;MACT,iBAAiB;MACjB,cAAc;OACZ,OAAO;OACP,WAAW;OACX,SAAS;OACV;MACD,UAAU,eAAe;MAC1B;KACF;;GAEH,UAAU;GACX,CACF;EAED,MAAM,WAAW;AACf,kBAAe,aAAa;AAC5B,SAAM,eAAe,UAAU;;EAElC;;;;;;;;AASH,eAAe,iBACb,SACA,MACA,WACkB;CAMlB,MAAM,SAAS,KAAK;CACpB,MAAM,KAAK,KAAK;AAEhB,KAAI,WAAW,aACb,QAAO;EACL,SAAS;EACT,QAAQ;GACN,iBAAiB;GACjB,cAAc;IACZ,OAAO,EAAE,aAAa,OAAO;IAC7B,WAAW;KAAE,WAAW;KAAO,aAAa;KAAO;IACnD,SAAS,EAAE,aAAa,OAAO;IAChC;GACD,YAAY;IACV,MAAM;IACN,SAAS;IACV;GACF;EACD;EACD;AAKH,QAAO;EACL,SAAS;EACT,OAAO;GACL,MAAM;GACN,SAAS,mDAAmD,OAAO;GACpE;EACD;EACD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { McpPluginOptions } from "../shared/types.cjs";
|
|
2
|
+
import { InvectPlugin } from "@invect/core";
|
|
3
|
+
|
|
4
|
+
//#region src/backend/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create the MCP plugin.
|
|
7
|
+
*
|
|
8
|
+
* When registered with Invect, this plugin mounts Streamable HTTP endpoints
|
|
9
|
+
* at `/plugins/mcp/` that implement the Model Context Protocol. MCP clients
|
|
10
|
+
* (Claude Desktop, VS Code Copilot, Cursor, etc.) connect to these endpoints.
|
|
11
|
+
*
|
|
12
|
+
* Authentication flows through the host app's existing auth middleware — the
|
|
13
|
+
* MCP SDK's Streamable HTTP transport receives the request identity resolved
|
|
14
|
+
* by the framework adapter.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { createInvect } from '@invect/core';
|
|
19
|
+
* import { mcpPlugin } from '@invect/mcp';
|
|
20
|
+
*
|
|
21
|
+
* const invect = await createInvect({
|
|
22
|
+
* plugins: [mcpPlugin()],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare function mcpPlugin(options?: McpPluginOptions): InvectPlugin;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { type McpPluginOptions, mcpPlugin };
|
|
29
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/backend/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;iBAmCgB,SAAA,CAAU,OAAA,GAAS,gBAAA,GAAwB,YAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { McpPluginOptions } from "../shared/types.mjs";
|
|
2
|
+
import { InvectPlugin } from "@invect/core";
|
|
3
|
+
|
|
4
|
+
//#region src/backend/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create the MCP plugin.
|
|
7
|
+
*
|
|
8
|
+
* When registered with Invect, this plugin mounts Streamable HTTP endpoints
|
|
9
|
+
* at `/plugins/mcp/` that implement the Model Context Protocol. MCP clients
|
|
10
|
+
* (Claude Desktop, VS Code Copilot, Cursor, etc.) connect to these endpoints.
|
|
11
|
+
*
|
|
12
|
+
* Authentication flows through the host app's existing auth middleware — the
|
|
13
|
+
* MCP SDK's Streamable HTTP transport receives the request identity resolved
|
|
14
|
+
* by the framework adapter.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { createInvect } from '@invect/core';
|
|
19
|
+
* import { mcpPlugin } from '@invect/mcp';
|
|
20
|
+
*
|
|
21
|
+
* const invect = await createInvect({
|
|
22
|
+
* plugins: [mcpPlugin()],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare function mcpPlugin(options?: McpPluginOptions): InvectPlugin;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { type McpPluginOptions, mcpPlugin };
|
|
29
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/backend/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;iBAmCgB,SAAA,CAAU,OAAA,GAAS,gBAAA,GAAwB,YAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @invect/mcp — Plugin entry point
|
|
3
|
+
*
|
|
4
|
+
* Exports the `mcpPlugin()` factory that creates an InvectPlugin providing
|
|
5
|
+
* MCP (Model Context Protocol) endpoints for AI coding agents.
|
|
6
|
+
*/
|
|
7
|
+
import type { InvectPlugin } from '@invect/core';
|
|
8
|
+
import type { McpPluginOptions } from '../shared/types';
|
|
9
|
+
/**
|
|
10
|
+
* Create the MCP plugin.
|
|
11
|
+
*
|
|
12
|
+
* When registered with Invect, this plugin mounts Streamable HTTP endpoints
|
|
13
|
+
* at `/plugins/mcp/` that implement the Model Context Protocol. MCP clients
|
|
14
|
+
* (Claude Desktop, VS Code Copilot, Cursor, etc.) connect to these endpoints.
|
|
15
|
+
*
|
|
16
|
+
* Authentication flows through the host app's existing auth middleware — the
|
|
17
|
+
* MCP SDK's Streamable HTTP transport receives the request identity resolved
|
|
18
|
+
* by the framework adapter.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { createInvect } from '@invect/core';
|
|
23
|
+
* import { mcpPlugin } from '@invect/mcp';
|
|
24
|
+
*
|
|
25
|
+
* const invect = await createInvect({
|
|
26
|
+
* plugins: [mcpPlugin()],
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function mcpPlugin(options?: McpPluginOptions): InvectPlugin;
|
|
31
|
+
export type { McpPluginOptions } from '../shared/types';
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,YAAY,CAqFtE;AAoDD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|