@contextual-io/cli 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -1
- package/dist/base.js +7 -1
- package/dist/commands/mcp/index.d.ts +9 -0
- package/dist/commands/mcp/index.js +16 -0
- package/dist/commands/mcp/serve.d.ts +17 -0
- package/dist/commands/mcp/serve.js +124 -0
- package/dist/hooks/init/index.d.ts +3 -0
- package/dist/hooks/init/index.js +38 -0
- package/dist/mcp/bridge-manager.d.ts +29 -0
- package/dist/mcp/bridge-manager.js +260 -0
- package/dist/mcp/contracts.d.ts +43 -0
- package/dist/mcp/contracts.js +27 -0
- package/dist/mcp/http-server.d.ts +45 -0
- package/dist/mcp/http-server.js +242 -0
- package/dist/mcp/logger.d.ts +4 -0
- package/dist/mcp/logger.js +9 -0
- package/dist/mcp/runtime.d.ts +24 -0
- package/dist/mcp/runtime.js +297 -0
- package/dist/mcp/server.d.ts +90 -0
- package/dist/mcp/server.js +308 -0
- package/dist/mcp/session.d.ts +42 -0
- package/dist/mcp/session.js +75 -0
- package/dist/mcp/socket-bridge.d.ts +67 -0
- package/dist/mcp/socket-bridge.js +357 -0
- package/dist/models/mcp.d.ts +288 -0
- package/dist/models/mcp.js +137 -0
- package/dist/utils/endpoints.d.ts +1 -0
- package/dist/utils/endpoints.js +1 -0
- package/dist/utils/message.d.ts +14 -0
- package/dist/utils/message.js +31 -0
- package/dist/utils/update-check.d.ts +23 -0
- package/dist/utils/update-check.js +101 -0
- package/oclif.manifest.json +109 -1
- package/package.json +10 -3
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WARNING: This is a shared, external API contract.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
export const McpSessionId = z.string();
|
|
6
|
+
export const McpDetachReason = z.enum([
|
|
7
|
+
"target-disconnected",
|
|
8
|
+
"mcp-disconnected",
|
|
9
|
+
"manual-detach",
|
|
10
|
+
]);
|
|
11
|
+
export const McpBindFailureCode = z.enum([
|
|
12
|
+
"MCP_DISABLED",
|
|
13
|
+
"NO_ACTIVE_BROWSER",
|
|
14
|
+
"BIND_DENIED",
|
|
15
|
+
"INTERNAL_ERROR",
|
|
16
|
+
]);
|
|
17
|
+
export const McpToolErrorCode = z.enum([
|
|
18
|
+
"NOT_ATTACHED",
|
|
19
|
+
"UNKNOWN_TOOL",
|
|
20
|
+
"COMMAND_IN_FLIGHT",
|
|
21
|
+
"TIMEOUT",
|
|
22
|
+
"UNAUTHORIZED",
|
|
23
|
+
"INTERNAL_ERROR",
|
|
24
|
+
]);
|
|
25
|
+
export const JsonSchema = z.record(z.string(), z.unknown());
|
|
26
|
+
export const McpToolDefinition = z.object({
|
|
27
|
+
annotations: z.record(z.string(), z.unknown()).optional(),
|
|
28
|
+
description: z.string(),
|
|
29
|
+
inputSchema: JsonSchema,
|
|
30
|
+
name: z.string(),
|
|
31
|
+
outputSchema: JsonSchema.optional(),
|
|
32
|
+
title: z.string().optional(),
|
|
33
|
+
});
|
|
34
|
+
export const McpClientPackageInfo = z.object({
|
|
35
|
+
name: z.string().optional(),
|
|
36
|
+
version: z.string().optional(),
|
|
37
|
+
});
|
|
38
|
+
export const McpManifestRequest = z.object({
|
|
39
|
+
interfaceType: z.string(),
|
|
40
|
+
});
|
|
41
|
+
export const McpManifestResponse = z.object({
|
|
42
|
+
definitions: z.array(McpToolDefinition),
|
|
43
|
+
interfaceType: z.string(),
|
|
44
|
+
resolvedAt: z.number().int(),
|
|
45
|
+
tools: z.array(z.string()),
|
|
46
|
+
});
|
|
47
|
+
export const McpFlowSession = z.object({
|
|
48
|
+
flowId: z.string(),
|
|
49
|
+
flowName: z.string(),
|
|
50
|
+
});
|
|
51
|
+
export const McpListSessionsRequest = z.object({
|
|
52
|
+
flowId: z.string().optional(),
|
|
53
|
+
interfaceType: z.string(),
|
|
54
|
+
});
|
|
55
|
+
export const McpListSessionsResponse = z.object({
|
|
56
|
+
sessions: z.array(McpFlowSession),
|
|
57
|
+
});
|
|
58
|
+
export const McpBindSessionRequest = z.object({
|
|
59
|
+
flowId: z.string(),
|
|
60
|
+
});
|
|
61
|
+
export const McpBindSessionResponse = z.object({
|
|
62
|
+
boundAt: z.number().int(),
|
|
63
|
+
flowId: z.string(),
|
|
64
|
+
flowName: z.string(),
|
|
65
|
+
});
|
|
66
|
+
export const McpBindSessionFailure = z.object({
|
|
67
|
+
code: McpBindFailureCode,
|
|
68
|
+
message: z.string(),
|
|
69
|
+
sessions: z.array(McpFlowSession).optional(),
|
|
70
|
+
});
|
|
71
|
+
export const McpSessionControlRequest = z.object({
|
|
72
|
+
mcpSessionId: McpSessionId,
|
|
73
|
+
});
|
|
74
|
+
export const McpSessionDisconnectAck = z.object({
|
|
75
|
+
detachedAt: z.number().int().optional(),
|
|
76
|
+
});
|
|
77
|
+
export const McpToolRegistrySync = z.object({
|
|
78
|
+
action: z.enum(["register", "clear"]),
|
|
79
|
+
clientPackage: McpClientPackageInfo.optional(),
|
|
80
|
+
definitions: z.array(McpToolDefinition),
|
|
81
|
+
expertId: z.string().optional(),
|
|
82
|
+
expertName: z.string().optional(),
|
|
83
|
+
mcpSessionId: McpSessionId,
|
|
84
|
+
replace: z.boolean().optional(),
|
|
85
|
+
tools: z.array(z.string()),
|
|
86
|
+
updatedAt: z.number().int(),
|
|
87
|
+
});
|
|
88
|
+
export const McpToolCall = z.object({
|
|
89
|
+
args: z.record(z.string(), z.unknown()),
|
|
90
|
+
name: z.string(),
|
|
91
|
+
timeoutMs: z.number().int().optional(),
|
|
92
|
+
type: z.literal("mcp-tool"),
|
|
93
|
+
});
|
|
94
|
+
export const McpToolProgress = z.object({
|
|
95
|
+
data: z.unknown().optional(),
|
|
96
|
+
message: z.string().optional(),
|
|
97
|
+
percent: z.number().optional(),
|
|
98
|
+
});
|
|
99
|
+
export const McpToolResult = z.object({
|
|
100
|
+
commandId: z.string(),
|
|
101
|
+
result: z.unknown(),
|
|
102
|
+
});
|
|
103
|
+
export const McpToolError = z.object({
|
|
104
|
+
code: McpToolErrorCode.optional(),
|
|
105
|
+
data: z.unknown().optional(),
|
|
106
|
+
message: z.string(),
|
|
107
|
+
});
|
|
108
|
+
export const McpCommandStatusType = z.enum([
|
|
109
|
+
"accepted",
|
|
110
|
+
"dispatched",
|
|
111
|
+
"progress",
|
|
112
|
+
"completed",
|
|
113
|
+
"failed",
|
|
114
|
+
"timeout",
|
|
115
|
+
]);
|
|
116
|
+
export const McpCommandStatus = z.object({
|
|
117
|
+
commandId: z.string(),
|
|
118
|
+
error: McpToolError.optional(),
|
|
119
|
+
mcpSessionId: McpSessionId,
|
|
120
|
+
progress: McpToolProgress.optional(),
|
|
121
|
+
status: McpCommandStatusType,
|
|
122
|
+
timestamp: z.number().int(),
|
|
123
|
+
toolName: z.string(),
|
|
124
|
+
});
|
|
125
|
+
export const McpCommandHistoryEntry = z.object({
|
|
126
|
+
commandId: z.string(),
|
|
127
|
+
completedAt: z.number().int().optional(),
|
|
128
|
+
createdAt: z.number().int(),
|
|
129
|
+
error: McpToolError.optional(),
|
|
130
|
+
mcpSessionId: McpSessionId,
|
|
131
|
+
progress: McpToolProgress.optional(),
|
|
132
|
+
result: z.unknown().optional(),
|
|
133
|
+
status: McpCommandStatusType,
|
|
134
|
+
toolCall: McpToolCall.optional(),
|
|
135
|
+
toolName: z.string(),
|
|
136
|
+
updatedAt: z.number().int(),
|
|
137
|
+
});
|
|
@@ -2,3 +2,4 @@ import { Silo } from "../models/silo.js";
|
|
|
2
2
|
export declare const getNativeObjectApiEndpoint: (tenantId: string, silo: Silo) => string;
|
|
3
3
|
export declare const getRegistryApiEndpoint: (tenantId: string, silo: Silo) => string;
|
|
4
4
|
export declare const getAuthApiEndpoint: (tenantId: string, silo: Silo) => string;
|
|
5
|
+
export declare const getSolutionAiApiEndpoint: (tenantId: string, silo: Silo) => string;
|
package/dist/utils/endpoints.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export const getNativeObjectApiEndpoint = (tenantId, silo) => `https://native-object.${tenantId}.my${silo === "prod" ? "" : `.${silo}`}.contextual.io`;
|
|
2
2
|
export const getRegistryApiEndpoint = (tenantId, silo) => `https://native-object-registry.${tenantId}.my${silo === "prod" ? "" : `.${silo}`}.contextual.io`;
|
|
3
3
|
export const getAuthApiEndpoint = (tenantId, silo) => `https://auth.${tenantId}.my${silo === "prod" ? "" : `.${silo}`}.contextual.io`;
|
|
4
|
+
export const getSolutionAiApiEndpoint = (tenantId, silo) => `https://solution-ai.${tenantId}.my${silo === "prod" ? "" : `.${silo}`}.contextual.io`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type BoxOptions = {
|
|
2
|
+
borderColorFn?: (text: string) => string;
|
|
3
|
+
bottomLeftBorderChar?: string;
|
|
4
|
+
bottomRightBorderChar?: string;
|
|
5
|
+
textColorFn?: (text: string) => string;
|
|
6
|
+
topLeftBorderChar?: string;
|
|
7
|
+
topRightBorderChar?: string;
|
|
8
|
+
xBorderChar?: string;
|
|
9
|
+
xPadding?: number;
|
|
10
|
+
yBorderChar?: string;
|
|
11
|
+
yPadding?: number;
|
|
12
|
+
};
|
|
13
|
+
export declare const boxMessage: (message: string, { borderColorFn, textColorFn, xPadding, yPadding, }?: BoxOptions) => string;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { stripVTControlCharacters } from "node:util";
|
|
3
|
+
const BoxTL = "╭";
|
|
4
|
+
const BoxTR = "╮";
|
|
5
|
+
const BoxBL = "╰";
|
|
6
|
+
const BoxBR = "╯";
|
|
7
|
+
const BoxX = "─";
|
|
8
|
+
const BoxY = "│";
|
|
9
|
+
const getVisibleLength = (value) => stripVTControlCharacters(value).length;
|
|
10
|
+
export const boxMessage = (message, { borderColorFn = (text) => chalk.yellow(text), textColorFn = (text) => chalk.white(text), xPadding = 2, yPadding = 0, } = {}) => {
|
|
11
|
+
xPadding = Math.max(0, xPadding);
|
|
12
|
+
yPadding = Math.max(0, yPadding);
|
|
13
|
+
const lines = message.split("\n");
|
|
14
|
+
const maxLength = Math.max(...lines.map(line => getVisibleLength(line)));
|
|
15
|
+
const totalInnerWidth = maxLength + xPadding * 2;
|
|
16
|
+
const leftPadding = " ".repeat(xPadding);
|
|
17
|
+
const topBorder = borderColorFn(`${BoxTL}${BoxX.repeat(totalInnerWidth)}${BoxTR}`);
|
|
18
|
+
const bottomBorder = borderColorFn(`${BoxBL}${BoxX.repeat(totalInnerWidth)}${BoxBR}`);
|
|
19
|
+
const yPaddingLines = Array.from({ length: yPadding }, () => `${textColorFn(BoxY)}${" ".repeat(totalInnerWidth)}${textColorFn(BoxY)}`);
|
|
20
|
+
const contentLines = lines.map(line => {
|
|
21
|
+
const rightPadding = " ".repeat(maxLength - getVisibleLength(line) + xPadding);
|
|
22
|
+
return `${borderColorFn(BoxY)}${leftPadding}${textColorFn(line)}${rightPadding}${borderColorFn(BoxY)}`;
|
|
23
|
+
});
|
|
24
|
+
return [
|
|
25
|
+
topBorder,
|
|
26
|
+
...yPaddingLines,
|
|
27
|
+
...contentLines,
|
|
28
|
+
...yPaddingLines,
|
|
29
|
+
bottomBorder,
|
|
30
|
+
].join("\n");
|
|
31
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type UpdateCheckResult = {
|
|
2
|
+
currentVersion: string;
|
|
3
|
+
latestVersion: string;
|
|
4
|
+
updateAvailable: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare const compareVersions: (left: string, right: string) => -1 | 0 | 1;
|
|
7
|
+
export declare const checkForUpdate: ({ currentVersion, packageName, timeoutMs, }: {
|
|
8
|
+
currentVersion: string;
|
|
9
|
+
packageName: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}) => Promise<undefined | UpdateCheckResult>;
|
|
12
|
+
export declare const shouldRunPeriodicCheck: ({ cacheDir, frequencyMs, }: {
|
|
13
|
+
cacheDir: string;
|
|
14
|
+
frequencyMs: number;
|
|
15
|
+
}) => boolean;
|
|
16
|
+
export declare const markChecked: ({ cacheDir, notifiedVersion, }: {
|
|
17
|
+
cacheDir: string;
|
|
18
|
+
notifiedVersion?: string;
|
|
19
|
+
}) => void;
|
|
20
|
+
export declare const hasNotifiedVersion: ({ cacheDir, latestVersion, }: {
|
|
21
|
+
cacheDir: string;
|
|
22
|
+
latestVersion: string;
|
|
23
|
+
}) => boolean;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fetch from "cross-fetch";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const NpmLatestVersionResponse = z.object({
|
|
6
|
+
version: z.string(),
|
|
7
|
+
});
|
|
8
|
+
const updateCheckFileName = "update-check.json";
|
|
9
|
+
const parseVersionPart = (value) => {
|
|
10
|
+
const parsed = Number.parseInt(value, 10);
|
|
11
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
12
|
+
};
|
|
13
|
+
const splitVersion = (version) => {
|
|
14
|
+
const trimmed = version.startsWith("v") ? version.slice(1) : version;
|
|
15
|
+
const [corePart, prerelease] = trimmed.split("-", 2);
|
|
16
|
+
const core = corePart.split(".").map((part) => parseVersionPart(part));
|
|
17
|
+
return { core, prerelease };
|
|
18
|
+
};
|
|
19
|
+
export const compareVersions = (left, right) => {
|
|
20
|
+
const leftVersion = splitVersion(left);
|
|
21
|
+
const rightVersion = splitVersion(right);
|
|
22
|
+
const maxLength = Math.max(leftVersion.core.length, rightVersion.core.length);
|
|
23
|
+
for (let i = 0; i < maxLength; i += 1) {
|
|
24
|
+
const leftPart = leftVersion.core[i] ?? 0;
|
|
25
|
+
const rightPart = rightVersion.core[i] ?? 0;
|
|
26
|
+
if (leftPart > rightPart)
|
|
27
|
+
return 1;
|
|
28
|
+
if (leftPart < rightPart)
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
if (!leftVersion.prerelease && rightVersion.prerelease)
|
|
32
|
+
return 1;
|
|
33
|
+
if (leftVersion.prerelease && !rightVersion.prerelease)
|
|
34
|
+
return -1;
|
|
35
|
+
return 0;
|
|
36
|
+
};
|
|
37
|
+
const readState = (cacheDir) => {
|
|
38
|
+
const statePath = path.join(cacheDir, updateCheckFileName);
|
|
39
|
+
if (!fs.existsSync(statePath))
|
|
40
|
+
return {};
|
|
41
|
+
try {
|
|
42
|
+
const rawState = fs.readFileSync(statePath, "utf8");
|
|
43
|
+
return JSON.parse(rawState);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const writeState = (cacheDir, state) => {
|
|
50
|
+
if (!fs.existsSync(cacheDir)) {
|
|
51
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
const statePath = path.join(cacheDir, updateCheckFileName);
|
|
54
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf8");
|
|
55
|
+
};
|
|
56
|
+
const fetchLatestVersion = async (packageName, timeoutMs) => {
|
|
57
|
+
try {
|
|
58
|
+
const encodedPackageName = encodeURIComponent(packageName);
|
|
59
|
+
const response = await fetch(`https://registry.npmjs.org/${encodedPackageName}/latest`, {
|
|
60
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok)
|
|
63
|
+
return undefined;
|
|
64
|
+
const { version } = NpmLatestVersionResponse.parse(await response.json());
|
|
65
|
+
return version;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
export const checkForUpdate = async ({ currentVersion, packageName, timeoutMs = 1500, }) => {
|
|
72
|
+
const latestVersion = await fetchLatestVersion(packageName, timeoutMs);
|
|
73
|
+
if (!latestVersion)
|
|
74
|
+
return undefined;
|
|
75
|
+
return {
|
|
76
|
+
currentVersion,
|
|
77
|
+
latestVersion,
|
|
78
|
+
updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export const shouldRunPeriodicCheck = ({ cacheDir, frequencyMs, }) => {
|
|
82
|
+
const state = readState(cacheDir);
|
|
83
|
+
if (!state.lastCheckedAt)
|
|
84
|
+
return true;
|
|
85
|
+
const lastCheckedAt = new Date(state.lastCheckedAt).getTime();
|
|
86
|
+
if (Number.isNaN(lastCheckedAt))
|
|
87
|
+
return true;
|
|
88
|
+
return Date.now() - lastCheckedAt >= frequencyMs;
|
|
89
|
+
};
|
|
90
|
+
export const markChecked = ({ cacheDir, notifiedVersion, }) => {
|
|
91
|
+
const state = readState(cacheDir);
|
|
92
|
+
writeState(cacheDir, {
|
|
93
|
+
...state,
|
|
94
|
+
lastCheckedAt: new Date().toISOString(),
|
|
95
|
+
lastNotifiedVersion: notifiedVersion ?? state.lastNotifiedVersion,
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
export const hasNotifiedVersion = ({ cacheDir, latestVersion, }) => {
|
|
99
|
+
const state = readState(cacheDir);
|
|
100
|
+
return state.lastNotifiedVersion === latestVersion;
|
|
101
|
+
};
|
package/oclif.manifest.json
CHANGED
|
@@ -265,6 +265,114 @@
|
|
|
265
265
|
"use.js"
|
|
266
266
|
]
|
|
267
267
|
},
|
|
268
|
+
"mcp": {
|
|
269
|
+
"aliases": [],
|
|
270
|
+
"args": {},
|
|
271
|
+
"description": "Manage local MCP server commands. Start with 'ctxl mcp serve' to run the local MCP bridge.",
|
|
272
|
+
"examples": [
|
|
273
|
+
"<%= config.bin %> <%= command.id %>",
|
|
274
|
+
"<%= config.bin %> <%= command.id %> flow-editor --flow my-flow-id"
|
|
275
|
+
],
|
|
276
|
+
"flags": {},
|
|
277
|
+
"hasDynamicHelp": false,
|
|
278
|
+
"hiddenAliases": [],
|
|
279
|
+
"id": "mcp",
|
|
280
|
+
"pluginAlias": "@contextual-io/cli",
|
|
281
|
+
"pluginName": "@contextual-io/cli",
|
|
282
|
+
"pluginType": "core",
|
|
283
|
+
"strict": true,
|
|
284
|
+
"usage": [
|
|
285
|
+
"<%= command.id %> <COMMAND>"
|
|
286
|
+
],
|
|
287
|
+
"enableJsonFlag": false,
|
|
288
|
+
"isESM": true,
|
|
289
|
+
"relativePath": [
|
|
290
|
+
"dist",
|
|
291
|
+
"commands",
|
|
292
|
+
"mcp",
|
|
293
|
+
"index.js"
|
|
294
|
+
]
|
|
295
|
+
},
|
|
296
|
+
"mcp:serve": {
|
|
297
|
+
"aliases": [],
|
|
298
|
+
"args": {
|
|
299
|
+
"interface": {
|
|
300
|
+
"default": "flow-editor",
|
|
301
|
+
"description": "Interface type to scope tools for. Available interfaces depend on your platform version.",
|
|
302
|
+
"name": "interface",
|
|
303
|
+
"required": false
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"description": "Start a local MCP HTTP server that connects to SolutionAI for a given interface type. By default it binds to http://localhost:5051/. The server fetches the full tool manifest from SolutionAI and serves all tools immediately. Pass a flowId with each tool call to target a specific flow, or use list_sessions to discover available flows.",
|
|
307
|
+
"examples": [
|
|
308
|
+
"<%= config.bin %> <%= command.id %>",
|
|
309
|
+
"<%= config.bin %> <%= command.id %> flow-editor --flow my-flow-id"
|
|
310
|
+
],
|
|
311
|
+
"flags": {
|
|
312
|
+
"config-id": {
|
|
313
|
+
"char": "C",
|
|
314
|
+
"helpGroup": "GLOBAL",
|
|
315
|
+
"name": "config-id",
|
|
316
|
+
"summary": "Specify config id to use for call.",
|
|
317
|
+
"hasDynamicHelp": false,
|
|
318
|
+
"multiple": false,
|
|
319
|
+
"type": "option"
|
|
320
|
+
},
|
|
321
|
+
"flow": {
|
|
322
|
+
"char": "f",
|
|
323
|
+
"description": "pre-filter session listing to a specific flow ID",
|
|
324
|
+
"name": "flow",
|
|
325
|
+
"hasDynamicHelp": false,
|
|
326
|
+
"multiple": false,
|
|
327
|
+
"type": "option"
|
|
328
|
+
},
|
|
329
|
+
"port": {
|
|
330
|
+
"char": "p",
|
|
331
|
+
"description": "local HTTP port (default: 5051)",
|
|
332
|
+
"name": "port",
|
|
333
|
+
"hasDynamicHelp": false,
|
|
334
|
+
"multiple": false,
|
|
335
|
+
"type": "option"
|
|
336
|
+
},
|
|
337
|
+
"tool-prefix": {
|
|
338
|
+
"char": "t",
|
|
339
|
+
"description": "prefix all MCP tool names with ctxl_",
|
|
340
|
+
"name": "tool-prefix",
|
|
341
|
+
"allowNo": true,
|
|
342
|
+
"type": "boolean"
|
|
343
|
+
},
|
|
344
|
+
"url": {
|
|
345
|
+
"description": "override MCP route URL (http/https)",
|
|
346
|
+
"hidden": true,
|
|
347
|
+
"name": "url",
|
|
348
|
+
"hasDynamicHelp": false,
|
|
349
|
+
"multiple": false,
|
|
350
|
+
"type": "option"
|
|
351
|
+
},
|
|
352
|
+
"verbose": {
|
|
353
|
+
"char": "V",
|
|
354
|
+
"description": "emit verbose MCP runtime diagnostics",
|
|
355
|
+
"name": "verbose",
|
|
356
|
+
"allowNo": false,
|
|
357
|
+
"type": "boolean"
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
"hasDynamicHelp": false,
|
|
361
|
+
"hiddenAliases": [],
|
|
362
|
+
"id": "mcp:serve",
|
|
363
|
+
"pluginAlias": "@contextual-io/cli",
|
|
364
|
+
"pluginName": "@contextual-io/cli",
|
|
365
|
+
"pluginType": "core",
|
|
366
|
+
"strict": true,
|
|
367
|
+
"enableJsonFlag": false,
|
|
368
|
+
"isESM": true,
|
|
369
|
+
"relativePath": [
|
|
370
|
+
"dist",
|
|
371
|
+
"commands",
|
|
372
|
+
"mcp",
|
|
373
|
+
"serve.js"
|
|
374
|
+
]
|
|
375
|
+
},
|
|
268
376
|
"records:add": {
|
|
269
377
|
"aliases": [
|
|
270
378
|
"records:create",
|
|
@@ -1259,5 +1367,5 @@
|
|
|
1259
1367
|
]
|
|
1260
1368
|
}
|
|
1261
1369
|
},
|
|
1262
|
-
"version": "0.
|
|
1370
|
+
"version": "0.8.0"
|
|
1263
1371
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contextual-io/cli",
|
|
3
3
|
"description": "Contextual CLI",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"author": "Nasser Oloumi",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ctxl": "./bin/run.js"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
10
11
|
"@oclif/core": "^4",
|
|
11
12
|
"@oclif/plugin-autocomplete": "^3.2.39",
|
|
12
13
|
"@oclif/plugin-help": "^6",
|
|
13
14
|
"@oclif/plugin-not-found": "^3.2.73",
|
|
14
|
-
"@oclif/table": "^0.5.
|
|
15
|
+
"@oclif/table": "^0.5.2",
|
|
15
16
|
"chalk": "^5.6.2",
|
|
16
17
|
"cross-fetch": "^4.1.0",
|
|
18
|
+
"express": "^5.2.1",
|
|
17
19
|
"open": "^11.0.0",
|
|
20
|
+
"socket.io-client": "^4.8.3",
|
|
18
21
|
"stream-json": "^1.9.1",
|
|
19
22
|
"zod": "4.1.12"
|
|
20
23
|
},
|
|
@@ -24,6 +27,7 @@
|
|
|
24
27
|
"@oclif/test": "^4",
|
|
25
28
|
"@stylistic/eslint-plugin": "^5.6.1",
|
|
26
29
|
"@types/chai": "^4",
|
|
30
|
+
"@types/express": "^5.0.5",
|
|
27
31
|
"@types/mocha": "^10",
|
|
28
32
|
"@types/node": "^18",
|
|
29
33
|
"@types/stream-json": "^1.7.8",
|
|
@@ -33,7 +37,7 @@
|
|
|
33
37
|
"eslint-config-prettier": "^10",
|
|
34
38
|
"eslint-plugin-unused-imports": "^4.3.0",
|
|
35
39
|
"mocha": "^10",
|
|
36
|
-
"oclif": "^4",
|
|
40
|
+
"oclif": "^4.22.81",
|
|
37
41
|
"shx": "^0.3.3",
|
|
38
42
|
"ts-node": "^10",
|
|
39
43
|
"typescript": "^5"
|
|
@@ -57,6 +61,9 @@
|
|
|
57
61
|
"bin": "ctxl",
|
|
58
62
|
"dirname": "ctxl",
|
|
59
63
|
"commands": "./dist/commands",
|
|
64
|
+
"hooks": {
|
|
65
|
+
"init": "./dist/hooks/init/index.js"
|
|
66
|
+
},
|
|
60
67
|
"plugins": [
|
|
61
68
|
"@oclif/plugin-help",
|
|
62
69
|
"@oclif/plugin-not-found",
|