@critical-path/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,162 @@
1
+ import type { CriticalPathClient } from '@critical-path/client';
2
+ import { ALL_TOOLS, TOOL_MAP, type ToolDefinition } from '../tools/definitions.js';
3
+
4
+ export interface WebMcpToolRegistration {
5
+ name: string;
6
+ title?: string;
7
+ description: string;
8
+ inputSchema: Record<string, unknown>;
9
+ annotations?: {
10
+ readOnlyHint?: boolean;
11
+ };
12
+ execute: (input: any) => Promise<any>;
13
+ }
14
+
15
+ export interface ModelContextInterface {
16
+ registerTool: (tool: WebMcpToolRegistration, options?: { signal?: AbortSignal }) => Promise<void> | void;
17
+ unregisterTool?: (toolName: string) => void;
18
+ getTools?: () => Promise<WebMcpToolRegistration[]> | WebMcpToolRegistration[];
19
+ executeTool?: (name: string, input?: any) => Promise<any>;
20
+ }
21
+
22
+ export interface RegisterWebMcpOptions {
23
+ client: CriticalPathClient;
24
+ projectId?: string;
25
+ tools?: string[];
26
+ signal?: AbortSignal;
27
+ document?: any;
28
+ navigator?: any;
29
+ window?: any;
30
+ onToolExecuted?: (toolName: string, input: any, result: any) => void;
31
+ }
32
+
33
+ export interface WebMcpRegistryHandle {
34
+ unregister: () => void;
35
+ getRegisteredTools: () => WebMcpToolRegistration[];
36
+ }
37
+
38
+ /**
39
+ * Polyfill/shim a minimal ModelContextInterface onto the document/window if not natively present.
40
+ */
41
+ export function ensureModelContextShim(doc: any = typeof document !== 'undefined' ? document : null): ModelContextInterface | null {
42
+ if (!doc) return null;
43
+
44
+ if (!doc.modelContext) {
45
+ const registeredTools = new Map<string, WebMcpToolRegistration>();
46
+
47
+ const shim: ModelContextInterface = {
48
+ registerTool(tool, options) {
49
+ registeredTools.set(tool.name, tool);
50
+ if (options?.signal) {
51
+ options.signal.addEventListener('abort', () => {
52
+ registeredTools.delete(tool.name);
53
+ }, { once: true });
54
+ }
55
+ },
56
+ unregisterTool(toolName) {
57
+ registeredTools.delete(toolName);
58
+ },
59
+ async getTools() {
60
+ return Array.from(registeredTools.values());
61
+ },
62
+ async executeTool(name, input) {
63
+ const tool = registeredTools.get(name);
64
+ if (!tool) {
65
+ throw new Error(`Tool "${name}" is not registered on modelContext.`);
66
+ }
67
+ return tool.execute(input || {});
68
+ }
69
+ };
70
+
71
+ doc.modelContext = shim;
72
+ }
73
+
74
+ return doc.modelContext;
75
+ }
76
+
77
+ /**
78
+ * Registers Critical Path tools with the browser's WebMCP modelContext.
79
+ */
80
+ export function registerWebMcpTools(options: RegisterWebMcpOptions): WebMcpRegistryHandle {
81
+ const doc = options.document ?? (typeof document !== 'undefined' ? document : null);
82
+ const nav = options.navigator ?? (typeof navigator !== 'undefined' ? navigator : null);
83
+ const win = options.window ?? (typeof window !== 'undefined' ? window : null);
84
+
85
+ // Target modelContext: document.modelContext (W3C standard draft) -> navigator.modelContext -> document shim
86
+ let modelContext: ModelContextInterface | undefined;
87
+ if (doc?.modelContext) {
88
+ modelContext = doc.modelContext;
89
+ } else if (nav?.modelContext) {
90
+ modelContext = nav.modelContext;
91
+ } else if (doc) {
92
+ modelContext = ensureModelContextShim(doc) ?? undefined;
93
+ }
94
+
95
+ const selectedTools: ToolDefinition[] = options.tools
96
+ ? ALL_TOOLS.filter((t) => options.tools!.includes(t.name))
97
+ : ALL_TOOLS;
98
+
99
+ const registeredTools: WebMcpToolRegistration[] = [];
100
+ const abortController = new AbortController();
101
+
102
+ // Combine caller signal with our internal abort controller
103
+ if (options.signal) {
104
+ options.signal.addEventListener('abort', () => abortController.abort(), { once: true });
105
+ }
106
+
107
+ for (const toolDef of selectedTools) {
108
+ const webTool: WebMcpToolRegistration = {
109
+ name: toolDef.name,
110
+ title: toolDef.title,
111
+ description: toolDef.description,
112
+ inputSchema: toolDef.inputSchema,
113
+ annotations: toolDef.annotations,
114
+ execute: async (input: any) => {
115
+ const ambientContext = options.projectId ? { projectId: options.projectId } : undefined;
116
+ const result = await toolDef.execute(input, options.client, ambientContext);
117
+ options.onToolExecuted?.(toolDef.name, input, result);
118
+ return result;
119
+ }
120
+ };
121
+
122
+ registeredTools.push(webTool);
123
+
124
+ if (modelContext?.registerTool) {
125
+ try {
126
+ modelContext.registerTool(webTool, { signal: abortController.signal });
127
+ } catch (err) {
128
+ console.warn(`[Critical Path WebMCP] Failed to register tool "${webTool.name}":`, err);
129
+ }
130
+ }
131
+ }
132
+
133
+ // Also publish to window fallback registry for browser extensions & DevTools
134
+ if (win) {
135
+ win.__CRITICAL_PATH_WEBMCP__ = {
136
+ projectId: options.projectId,
137
+ tools: registeredTools,
138
+ execute: async (name: string, input: any) => {
139
+ const tool = registeredTools.find((t) => t.name === name);
140
+ if (!tool) throw new Error(`WebMCP tool "${name}" not found in Critical Path registry.`);
141
+ return tool.execute(input);
142
+ }
143
+ };
144
+ }
145
+
146
+ const unregister = () => {
147
+ abortController.abort();
148
+ if (modelContext?.unregisterTool) {
149
+ for (const t of registeredTools) {
150
+ modelContext.unregisterTool(t.name);
151
+ }
152
+ }
153
+ if (win && win.__CRITICAL_PATH_WEBMCP__?.tools === registeredTools) {
154
+ delete win.__CRITICAL_PATH_WEBMCP__;
155
+ }
156
+ };
157
+
158
+ return {
159
+ unregister,
160
+ getRegisteredTools: () => registeredTools
161
+ };
162
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src"
6
+ },
7
+ "include": ["src/**/*"]
8
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.test.ts","./src/index.ts","./src/bin/cli.ts","./src/server/index.ts","./src/tools/definitions.ts","./src/web/index.ts"],"version":"5.9.3"}