@portel/photon-core 1.5.0 → 2.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.
- package/dist/auto-ui.js +1 -1
- package/dist/auto-ui.js.map +1 -1
- package/dist/base.d.ts +1 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +2 -2
- package/dist/base.js.map +1 -1
- package/dist/cli-ui-renderer.js +1 -1
- package/dist/cli-ui-renderer.js.map +1 -1
- package/dist/design-system/index.d.ts +21 -0
- package/dist/design-system/index.d.ts.map +1 -0
- package/dist/design-system/index.js +27 -0
- package/dist/design-system/index.js.map +1 -0
- package/dist/design-system/tokens.d.ts +149 -0
- package/dist/design-system/tokens.d.ts.map +1 -0
- package/dist/design-system/tokens.js +413 -0
- package/dist/design-system/tokens.js.map +1 -0
- package/dist/design-system/transaction-ui.d.ts +70 -0
- package/dist/design-system/transaction-ui.d.ts.map +1 -0
- package/dist/design-system/transaction-ui.js +982 -0
- package/dist/design-system/transaction-ui.js.map +1 -0
- package/dist/generator.d.ts +56 -6
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js.map +1 -1
- package/dist/index.d.ts +6 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -56
- package/dist/index.js.map +1 -1
- package/dist/io.d.ts +103 -2
- package/dist/io.d.ts.map +1 -1
- package/dist/io.js +37 -1
- package/dist/io.js.map +1 -1
- package/dist/rendering/components.d.ts +29 -0
- package/dist/rendering/components.d.ts.map +1 -0
- package/dist/rendering/components.js +773 -0
- package/dist/rendering/components.js.map +1 -0
- package/dist/rendering/field-analyzer.d.ts +48 -0
- package/dist/rendering/field-analyzer.d.ts.map +1 -0
- package/dist/rendering/field-analyzer.js +270 -0
- package/dist/rendering/field-analyzer.js.map +1 -0
- package/dist/rendering/field-renderers.d.ts +64 -0
- package/dist/rendering/field-renderers.d.ts.map +1 -0
- package/dist/rendering/field-renderers.js +317 -0
- package/dist/rendering/field-renderers.js.map +1 -0
- package/dist/rendering/index.d.ts +28 -0
- package/dist/rendering/index.d.ts.map +1 -0
- package/dist/rendering/index.js +60 -0
- package/dist/rendering/index.js.map +1 -0
- package/dist/rendering/layout-selector.d.ts +48 -0
- package/dist/rendering/layout-selector.d.ts.map +1 -0
- package/dist/rendering/layout-selector.js +347 -0
- package/dist/rendering/layout-selector.js.map +1 -0
- package/dist/rendering/template-engine.d.ts +41 -0
- package/dist/rendering/template-engine.d.ts.map +1 -0
- package/dist/rendering/template-engine.js +236 -0
- package/dist/rendering/template-engine.js.map +1 -0
- package/dist/schema-extractor.d.ts +30 -0
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +205 -12
- package/dist/schema-extractor.js.map +1 -1
- package/dist/stateful.js +1 -1
- package/dist/stateful.js.map +1 -1
- package/dist/types.d.ts +9 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ucp/ap2/handlers.d.ts +242 -0
- package/dist/ucp/ap2/handlers.d.ts.map +1 -0
- package/dist/ucp/ap2/handlers.js +482 -0
- package/dist/ucp/ap2/handlers.js.map +1 -0
- package/dist/ucp/ap2/mandates.d.ts +95 -0
- package/dist/ucp/ap2/mandates.d.ts.map +1 -0
- package/dist/ucp/ap2/mandates.js +234 -0
- package/dist/ucp/ap2/mandates.js.map +1 -0
- package/dist/ucp/ap2/types.d.ts +305 -0
- package/dist/ucp/ap2/types.d.ts.map +1 -0
- package/dist/ucp/ap2/types.js +8 -0
- package/dist/ucp/ap2/types.js.map +1 -0
- package/dist/ucp/capabilities/checkout.d.ts +118 -0
- package/dist/ucp/capabilities/checkout.d.ts.map +1 -0
- package/dist/ucp/capabilities/checkout.js +344 -0
- package/dist/ucp/capabilities/checkout.js.map +1 -0
- package/dist/ucp/capabilities/identity.d.ts +130 -0
- package/dist/ucp/capabilities/identity.d.ts.map +1 -0
- package/dist/ucp/capabilities/identity.js +290 -0
- package/dist/ucp/capabilities/identity.js.map +1 -0
- package/dist/ucp/capabilities/order.d.ts +142 -0
- package/dist/ucp/capabilities/order.d.ts.map +1 -0
- package/dist/ucp/capabilities/order.js +383 -0
- package/dist/ucp/capabilities/order.js.map +1 -0
- package/dist/ucp/index.d.ts +18 -0
- package/dist/ucp/index.d.ts.map +1 -0
- package/dist/ucp/index.js +19 -0
- package/dist/ucp/index.js.map +1 -0
- package/dist/ucp/manifest.d.ts +62 -0
- package/dist/ucp/manifest.d.ts.map +1 -0
- package/dist/ucp/manifest.js +180 -0
- package/dist/ucp/manifest.js.map +1 -0
- package/dist/ucp/types.d.ts +327 -0
- package/dist/ucp/types.d.ts.map +1 -0
- package/dist/ucp/types.js +8 -0
- package/dist/ucp/types.js.map +1 -0
- package/package.json +3 -4
- package/src/auto-ui.ts +1 -1
- package/src/base.ts +2 -2
- package/src/cli-ui-renderer.ts +1 -1
- package/src/design-system/index.ts +30 -0
- package/src/design-system/tokens.ts +451 -0
- package/src/design-system/transaction-ui.ts +1038 -0
- package/src/generator.ts +58 -2
- package/src/index.ts +135 -124
- package/src/io.ts +108 -3
- package/src/rendering/components.ts +785 -0
- package/src/rendering/field-analyzer.ts +299 -0
- package/src/rendering/field-renderers.ts +356 -0
- package/src/rendering/index.ts +63 -0
- package/src/rendering/layout-selector.ts +390 -0
- package/src/rendering/template-engine.ts +254 -0
- package/src/schema-extractor.ts +225 -12
- package/src/stateful.ts +1 -1
- package/src/types.ts +10 -1
- package/src/ucp/ap2/handlers.ts +779 -0
- package/src/ucp/ap2/mandates.ts +354 -0
- package/src/ucp/ap2/types.ts +441 -0
- package/src/ucp/capabilities/checkout.ts +497 -0
- package/src/ucp/capabilities/identity.ts +425 -0
- package/src/ucp/capabilities/order.ts +549 -0
- package/src/ucp/index.ts +27 -0
- package/src/ucp/manifest.ts +257 -0
- package/src/ucp/types.ts +454 -0
- package/dist/cli-formatter.d.ts +0 -92
- package/dist/cli-formatter.d.ts.map +0 -1
- package/dist/cli-formatter.js +0 -486
- package/dist/cli-formatter.js.map +0 -1
- package/dist/context.d.ts +0 -6
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -3
- package/dist/context.js.map +0 -1
- package/dist/elicit.d.ts +0 -93
- package/dist/elicit.d.ts.map +0 -1
- package/dist/elicit.js +0 -373
- package/dist/elicit.js.map +0 -1
- package/dist/mcp-client.d.ts +0 -218
- package/dist/mcp-client.d.ts.map +0 -1
- package/dist/mcp-client.js +0 -424
- package/dist/mcp-client.js.map +0 -1
- package/dist/mcp-sdk-transport.d.ts +0 -88
- package/dist/mcp-sdk-transport.d.ts.map +0 -1
- package/dist/mcp-sdk-transport.js +0 -360
- package/dist/mcp-sdk-transport.js.map +0 -1
- package/dist/photon-config.d.ts +0 -86
- package/dist/photon-config.d.ts.map +0 -1
- package/dist/photon-config.js +0 -156
- package/dist/photon-config.js.map +0 -1
- package/dist/progress.d.ts +0 -93
- package/dist/progress.d.ts.map +0 -1
- package/dist/progress.js +0 -195
- package/dist/progress.js.map +0 -1
- package/src/cli-formatter.ts +0 -579
- package/src/context.ts +0 -7
- package/src/elicit.ts +0 -438
- package/src/mcp-client.ts +0 -561
- package/src/mcp-sdk-transport.ts +0 -449
- package/src/photon-config.ts +0 -201
- package/src/progress.ts +0 -224
package/src/mcp-sdk-transport.ts
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP SDK Transport for Photon Core
|
|
3
|
-
*
|
|
4
|
-
* Uses the official @modelcontextprotocol/sdk for connecting to MCP servers.
|
|
5
|
-
* Supports multiple transports:
|
|
6
|
-
* - stdio: Local processes (command + args)
|
|
7
|
-
* - sse: Server-Sent Events over HTTP
|
|
8
|
-
* - streamable-http: HTTP streaming
|
|
9
|
-
* - websocket: WebSocket connections
|
|
10
|
-
*
|
|
11
|
-
* Configuration formats:
|
|
12
|
-
* 1. stdio (local process):
|
|
13
|
-
* { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"] }
|
|
14
|
-
*
|
|
15
|
-
* 2. sse (HTTP SSE):
|
|
16
|
-
* { "url": "http://localhost:3000/mcp", "transport": "sse" }
|
|
17
|
-
*
|
|
18
|
-
* 3. streamable-http:
|
|
19
|
-
* { "url": "http://localhost:3000/mcp", "transport": "streamable-http" }
|
|
20
|
-
*
|
|
21
|
-
* 4. websocket:
|
|
22
|
-
* { "url": "ws://localhost:3000/mcp", "transport": "websocket" }
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
26
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
27
|
-
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
28
|
-
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
29
|
-
import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js';
|
|
30
|
-
import * as fs from 'fs/promises';
|
|
31
|
-
import * as path from 'path';
|
|
32
|
-
import * as os from 'os';
|
|
33
|
-
import {
|
|
34
|
-
MCPClient,
|
|
35
|
-
MCPTransport,
|
|
36
|
-
MCPClientFactory,
|
|
37
|
-
MCPToolInfo,
|
|
38
|
-
MCPToolResult,
|
|
39
|
-
MCPNotConnectedError,
|
|
40
|
-
MCPToolError,
|
|
41
|
-
createMCPProxy,
|
|
42
|
-
} from './mcp-client.js';
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* MCP Server configuration
|
|
46
|
-
* Supports multiple transport types
|
|
47
|
-
*/
|
|
48
|
-
export interface MCPServerConfig {
|
|
49
|
-
// For stdio transport (local process)
|
|
50
|
-
command?: string;
|
|
51
|
-
args?: string[];
|
|
52
|
-
cwd?: string;
|
|
53
|
-
env?: Record<string, string>;
|
|
54
|
-
|
|
55
|
-
// For HTTP/WS transports
|
|
56
|
-
url?: string;
|
|
57
|
-
transport?: 'stdio' | 'sse' | 'streamable-http' | 'websocket';
|
|
58
|
-
|
|
59
|
-
// Authentication (for HTTP transports)
|
|
60
|
-
headers?: Record<string, string>;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Full MCP configuration file format
|
|
65
|
-
*/
|
|
66
|
-
export interface MCPConfig {
|
|
67
|
-
mcpServers: Record<string, MCPServerConfig>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Manages a single MCP server connection using official SDK
|
|
72
|
-
*/
|
|
73
|
-
class SDKMCPConnection {
|
|
74
|
-
private client: Client | null = null;
|
|
75
|
-
private transport: any = null;
|
|
76
|
-
private tools: MCPToolInfo[] = [];
|
|
77
|
-
private initialized = false;
|
|
78
|
-
|
|
79
|
-
constructor(
|
|
80
|
-
private name: string,
|
|
81
|
-
private config: MCPServerConfig,
|
|
82
|
-
private verbose: boolean = false
|
|
83
|
-
) {}
|
|
84
|
-
|
|
85
|
-
private log(message: string): void {
|
|
86
|
-
if (this.verbose) {
|
|
87
|
-
console.error(`[MCP:${this.name}] ${message}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Create appropriate transport based on config
|
|
93
|
-
*/
|
|
94
|
-
private createTransport(): any {
|
|
95
|
-
const transportType = this.config.transport || (this.config.command ? 'stdio' : 'sse');
|
|
96
|
-
|
|
97
|
-
switch (transportType) {
|
|
98
|
-
case 'stdio': {
|
|
99
|
-
if (!this.config.command) {
|
|
100
|
-
throw new Error(`stdio transport requires 'command' in config for ${this.name}`);
|
|
101
|
-
}
|
|
102
|
-
this.log(`Creating stdio transport: ${this.config.command} ${(this.config.args || []).join(' ')}`);
|
|
103
|
-
return new StdioClientTransport({
|
|
104
|
-
command: this.config.command,
|
|
105
|
-
args: this.config.args,
|
|
106
|
-
cwd: this.config.cwd,
|
|
107
|
-
env: this.config.env,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
case 'sse': {
|
|
112
|
-
if (!this.config.url) {
|
|
113
|
-
throw new Error(`sse transport requires 'url' in config for ${this.name}`);
|
|
114
|
-
}
|
|
115
|
-
this.log(`Creating SSE transport: ${this.config.url}`);
|
|
116
|
-
return new SSEClientTransport(new URL(this.config.url), {
|
|
117
|
-
requestInit: this.config.headers ? { headers: this.config.headers } : undefined,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
case 'streamable-http': {
|
|
122
|
-
if (!this.config.url) {
|
|
123
|
-
throw new Error(`streamable-http transport requires 'url' in config for ${this.name}`);
|
|
124
|
-
}
|
|
125
|
-
this.log(`Creating streamable HTTP transport: ${this.config.url}`);
|
|
126
|
-
return new StreamableHTTPClientTransport(new URL(this.config.url), {
|
|
127
|
-
requestInit: this.config.headers ? { headers: this.config.headers } : undefined,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
case 'websocket': {
|
|
132
|
-
if (!this.config.url) {
|
|
133
|
-
throw new Error(`websocket transport requires 'url' in config for ${this.name}`);
|
|
134
|
-
}
|
|
135
|
-
this.log(`Creating WebSocket transport: ${this.config.url}`);
|
|
136
|
-
return new WebSocketClientTransport(new URL(this.config.url));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
default:
|
|
140
|
-
throw new Error(`Unknown transport type: ${transportType}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Connect to the MCP server
|
|
146
|
-
*/
|
|
147
|
-
async connect(): Promise<void> {
|
|
148
|
-
if (this.client) {
|
|
149
|
-
return; // Already connected
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
this.transport = this.createTransport();
|
|
153
|
-
this.client = new Client(
|
|
154
|
-
{
|
|
155
|
-
name: 'photon-core',
|
|
156
|
-
version: '1.0.0',
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
capabilities: {
|
|
160
|
-
roots: { listChanged: false },
|
|
161
|
-
},
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
this.log('Connecting...');
|
|
166
|
-
await this.client.connect(this.transport);
|
|
167
|
-
this.log('Connected');
|
|
168
|
-
|
|
169
|
-
// List available tools
|
|
170
|
-
const toolsResult = await this.client.listTools();
|
|
171
|
-
this.tools = (toolsResult.tools || []).map((t: any) => ({
|
|
172
|
-
name: t.name,
|
|
173
|
-
description: t.description,
|
|
174
|
-
inputSchema: t.inputSchema,
|
|
175
|
-
}));
|
|
176
|
-
|
|
177
|
-
this.log(`Loaded ${this.tools.length} tools`);
|
|
178
|
-
this.initialized = true;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Call a tool
|
|
183
|
-
*/
|
|
184
|
-
async callTool(toolName: string, parameters: Record<string, any>): Promise<MCPToolResult> {
|
|
185
|
-
if (!this.client || !this.initialized) {
|
|
186
|
-
throw new MCPNotConnectedError(this.name);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
const result = await this.client.callTool({
|
|
191
|
-
name: toolName,
|
|
192
|
-
arguments: parameters,
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Convert to MCPToolResult format
|
|
196
|
-
if (result?.content && Array.isArray(result.content)) {
|
|
197
|
-
return {
|
|
198
|
-
content: result.content.map((c: any) => ({
|
|
199
|
-
type: c.type || 'text',
|
|
200
|
-
text: c.text,
|
|
201
|
-
data: c.data,
|
|
202
|
-
mimeType: c.mimeType,
|
|
203
|
-
})),
|
|
204
|
-
isError: result.isError as boolean | undefined,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
content: [{
|
|
210
|
-
type: 'text',
|
|
211
|
-
text: typeof result === 'string' ? result : JSON.stringify(result),
|
|
212
|
-
}],
|
|
213
|
-
isError: false,
|
|
214
|
-
};
|
|
215
|
-
} catch (error: any) {
|
|
216
|
-
throw new MCPToolError(this.name, toolName, error.message);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* List available tools
|
|
222
|
-
*/
|
|
223
|
-
listTools(): MCPToolInfo[] {
|
|
224
|
-
return this.tools;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Check if connected
|
|
229
|
-
*/
|
|
230
|
-
isConnected(): boolean {
|
|
231
|
-
return this.initialized && this.client !== null;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Disconnect
|
|
236
|
-
*/
|
|
237
|
-
async disconnect(): Promise<void> {
|
|
238
|
-
if (this.client) {
|
|
239
|
-
this.log('Disconnecting...');
|
|
240
|
-
await this.client.close();
|
|
241
|
-
this.client = null;
|
|
242
|
-
this.transport = null;
|
|
243
|
-
this.initialized = false;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* SDK-based MCP Transport using official @modelcontextprotocol/sdk
|
|
250
|
-
*/
|
|
251
|
-
export class SDKMCPTransport implements MCPTransport {
|
|
252
|
-
private connections: Map<string, SDKMCPConnection> = new Map();
|
|
253
|
-
|
|
254
|
-
constructor(
|
|
255
|
-
private config: MCPConfig,
|
|
256
|
-
private verbose: boolean = false
|
|
257
|
-
) {}
|
|
258
|
-
|
|
259
|
-
private log(message: string): void {
|
|
260
|
-
if (this.verbose) {
|
|
261
|
-
console.error(`[MCPTransport] ${message}`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Get or create connection to an MCP server
|
|
267
|
-
*/
|
|
268
|
-
private async getConnection(mcpName: string): Promise<SDKMCPConnection> {
|
|
269
|
-
let connection = this.connections.get(mcpName);
|
|
270
|
-
|
|
271
|
-
if (connection?.isConnected()) {
|
|
272
|
-
return connection;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const serverConfig = this.config.mcpServers[mcpName];
|
|
276
|
-
if (!serverConfig) {
|
|
277
|
-
throw new MCPNotConnectedError(mcpName);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
connection = new SDKMCPConnection(mcpName, serverConfig, this.verbose);
|
|
281
|
-
await connection.connect();
|
|
282
|
-
this.connections.set(mcpName, connection);
|
|
283
|
-
|
|
284
|
-
return connection;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async callTool(mcpName: string, toolName: string, parameters: Record<string, any>): Promise<MCPToolResult> {
|
|
288
|
-
const connection = await this.getConnection(mcpName);
|
|
289
|
-
return connection.callTool(toolName, parameters);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
async listTools(mcpName: string): Promise<MCPToolInfo[]> {
|
|
293
|
-
const connection = await this.getConnection(mcpName);
|
|
294
|
-
return connection.listTools();
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
async isConnected(mcpName: string): Promise<boolean> {
|
|
298
|
-
if (!this.config.mcpServers[mcpName]) {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
const connection = this.connections.get(mcpName);
|
|
302
|
-
return connection?.isConnected() ?? false;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
listServers(): string[] {
|
|
306
|
-
return Object.keys(this.config.mcpServers);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
async disconnectAll(): Promise<void> {
|
|
310
|
-
for (const connection of this.connections.values()) {
|
|
311
|
-
await connection.disconnect();
|
|
312
|
-
}
|
|
313
|
-
this.connections.clear();
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* SDK-based MCP Client Factory
|
|
319
|
-
*/
|
|
320
|
-
export class SDKMCPClientFactory implements MCPClientFactory {
|
|
321
|
-
private transport: SDKMCPTransport;
|
|
322
|
-
|
|
323
|
-
constructor(config: MCPConfig, verbose: boolean = false) {
|
|
324
|
-
this.transport = new SDKMCPTransport(config, verbose);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
create(mcpName: string): MCPClient {
|
|
328
|
-
return new MCPClient(mcpName, this.transport);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async listServers(): Promise<string[]> {
|
|
332
|
-
return this.transport.listServers();
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async disconnect(): Promise<void> {
|
|
336
|
-
await this.transport.disconnectAll();
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
getTransport(): SDKMCPTransport {
|
|
340
|
-
return this.transport;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Resolve an MCP source to a runnable configuration
|
|
346
|
-
* Handles: GitHub shorthand, npm packages, URLs, local paths
|
|
347
|
-
*/
|
|
348
|
-
export function resolveMCPSource(
|
|
349
|
-
name: string,
|
|
350
|
-
source: string,
|
|
351
|
-
sourceType: 'github' | 'npm' | 'url' | 'local'
|
|
352
|
-
): MCPServerConfig {
|
|
353
|
-
switch (sourceType) {
|
|
354
|
-
case 'npm': {
|
|
355
|
-
// npm:@scope/package or npm:package
|
|
356
|
-
const packageName = source.replace(/^npm:/, '');
|
|
357
|
-
return {
|
|
358
|
-
command: 'npx',
|
|
359
|
-
args: ['-y', packageName],
|
|
360
|
-
transport: 'stdio',
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
case 'github': {
|
|
365
|
-
// GitHub shorthand: owner/repo
|
|
366
|
-
// Try to run via npx assuming it's published to npm
|
|
367
|
-
return {
|
|
368
|
-
command: 'npx',
|
|
369
|
-
args: ['-y', `@${source}`],
|
|
370
|
-
transport: 'stdio',
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
case 'url': {
|
|
375
|
-
// Full URL - determine transport from protocol
|
|
376
|
-
if (source.startsWith('ws://') || source.startsWith('wss://')) {
|
|
377
|
-
return {
|
|
378
|
-
url: source,
|
|
379
|
-
transport: 'websocket',
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
// Default to SSE for HTTP URLs
|
|
383
|
-
return {
|
|
384
|
-
url: source,
|
|
385
|
-
transport: 'sse',
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
case 'local': {
|
|
390
|
-
// Local path - run directly with node
|
|
391
|
-
const resolvedPath = source.replace(/^~/, process.env.HOME || '');
|
|
392
|
-
return {
|
|
393
|
-
command: 'node',
|
|
394
|
-
args: [resolvedPath],
|
|
395
|
-
transport: 'stdio',
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
default:
|
|
400
|
-
throw new Error(`Unknown MCP source type: ${sourceType}`);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Load MCP configuration from standard locations
|
|
406
|
-
*/
|
|
407
|
-
export async function loadMCPConfig(verbose: boolean = false): Promise<MCPConfig> {
|
|
408
|
-
const log = verbose ? (msg: string) => console.error(`[MCPConfig] ${msg}`) : () => {};
|
|
409
|
-
|
|
410
|
-
const configPaths = [
|
|
411
|
-
process.env.PHOTON_MCP_CONFIG,
|
|
412
|
-
path.join(process.cwd(), 'photon.mcp.json'),
|
|
413
|
-
path.join(os.homedir(), '.config', 'photon', 'mcp.json'),
|
|
414
|
-
path.join(os.homedir(), '.photon', 'mcp.json'),
|
|
415
|
-
].filter(Boolean) as string[];
|
|
416
|
-
|
|
417
|
-
for (const configPath of configPaths) {
|
|
418
|
-
try {
|
|
419
|
-
const content = await fs.readFile(configPath, 'utf-8');
|
|
420
|
-
const config = JSON.parse(content) as MCPConfig;
|
|
421
|
-
|
|
422
|
-
if (config.mcpServers && typeof config.mcpServers === 'object') {
|
|
423
|
-
log(`Loaded MCP config from ${configPath}`);
|
|
424
|
-
log(`Found ${Object.keys(config.mcpServers).length} MCP servers`);
|
|
425
|
-
return config;
|
|
426
|
-
}
|
|
427
|
-
} catch (error: any) {
|
|
428
|
-
if (error.code !== 'ENOENT') {
|
|
429
|
-
log(`Failed to load ${configPath}: ${error.message}`);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
log('No MCP config found, MCP access will be unavailable');
|
|
435
|
-
return { mcpServers: {} };
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Create an SDK-based MCP client factory from default config
|
|
440
|
-
*/
|
|
441
|
-
export async function createSDKMCPClientFactory(
|
|
442
|
-
verbose: boolean = false
|
|
443
|
-
): Promise<SDKMCPClientFactory> {
|
|
444
|
-
const config = await loadMCPConfig(verbose);
|
|
445
|
-
return new SDKMCPClientFactory(config, verbose);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Re-export for convenience
|
|
449
|
-
export { MCPClient, createMCPProxy };
|
package/src/photon-config.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Photon Runtime Configuration
|
|
3
|
-
*
|
|
4
|
-
* Manages ~/.photon/mcp-servers.json for MCP server configuration.
|
|
5
|
-
* Compatible with Claude Desktop's mcpServers format.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as fs from 'fs/promises';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
import * as os from 'os';
|
|
11
|
-
import type { MCPConfig, MCPServerConfig } from './mcp-sdk-transport.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Default config directory
|
|
15
|
-
*/
|
|
16
|
-
export const PHOTON_CONFIG_DIR = path.join(os.homedir(), '.photon');
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Default MCP servers config file
|
|
20
|
-
*/
|
|
21
|
-
export const MCP_SERVERS_CONFIG_FILE = path.join(PHOTON_CONFIG_DIR, 'mcp-servers.json');
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Photon MCP servers configuration file format
|
|
25
|
-
* Compatible with Claude Desktop's mcpServers format
|
|
26
|
-
*/
|
|
27
|
-
export interface PhotonMCPConfig {
|
|
28
|
-
mcpServers: Record<string, MCPServerConfig>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Load MCP servers configuration from ~/.photon/mcp-servers.json
|
|
33
|
-
*
|
|
34
|
-
* @param configPath Optional custom config path (defaults to ~/.photon/mcp-servers.json)
|
|
35
|
-
* @returns The MCP configuration, or empty config if file doesn't exist
|
|
36
|
-
*/
|
|
37
|
-
export async function loadPhotonMCPConfig(configPath?: string): Promise<PhotonMCPConfig> {
|
|
38
|
-
const filePath = configPath || MCP_SERVERS_CONFIG_FILE;
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
42
|
-
const config = JSON.parse(content) as PhotonMCPConfig;
|
|
43
|
-
|
|
44
|
-
// Validate structure
|
|
45
|
-
if (!config.mcpServers || typeof config.mcpServers !== 'object') {
|
|
46
|
-
console.error(`Invalid config format in ${filePath}: missing mcpServers`);
|
|
47
|
-
return { mcpServers: {} };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return config;
|
|
51
|
-
} catch (error: any) {
|
|
52
|
-
if (error.code === 'ENOENT') {
|
|
53
|
-
// File doesn't exist - return empty config
|
|
54
|
-
return { mcpServers: {} };
|
|
55
|
-
}
|
|
56
|
-
console.error(`Failed to load config from ${filePath}: ${error.message}`);
|
|
57
|
-
return { mcpServers: {} };
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Save MCP servers configuration to ~/.photon/mcp-servers.json
|
|
63
|
-
*
|
|
64
|
-
* @param config The configuration to save
|
|
65
|
-
* @param configPath Optional custom config path
|
|
66
|
-
*/
|
|
67
|
-
export async function savePhotonMCPConfig(
|
|
68
|
-
config: PhotonMCPConfig,
|
|
69
|
-
configPath?: string
|
|
70
|
-
): Promise<void> {
|
|
71
|
-
const filePath = configPath || MCP_SERVERS_CONFIG_FILE;
|
|
72
|
-
const dir = path.dirname(filePath);
|
|
73
|
-
|
|
74
|
-
// Ensure directory exists
|
|
75
|
-
await fs.mkdir(dir, { recursive: true });
|
|
76
|
-
|
|
77
|
-
// Write config with pretty formatting
|
|
78
|
-
await fs.writeFile(filePath, JSON.stringify(config, null, 2), 'utf-8');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Check if an MCP server is configured
|
|
83
|
-
*
|
|
84
|
-
* @param mcpName The MCP server name to check
|
|
85
|
-
* @param config Optional pre-loaded config (loads from file if not provided)
|
|
86
|
-
*/
|
|
87
|
-
export async function isMCPConfigured(
|
|
88
|
-
mcpName: string,
|
|
89
|
-
config?: PhotonMCPConfig
|
|
90
|
-
): Promise<boolean> {
|
|
91
|
-
const cfg = config || await loadPhotonMCPConfig();
|
|
92
|
-
return mcpName in cfg.mcpServers;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get configuration for a specific MCP server
|
|
97
|
-
*
|
|
98
|
-
* @param mcpName The MCP server name
|
|
99
|
-
* @param config Optional pre-loaded config
|
|
100
|
-
* @returns The server config or undefined if not found
|
|
101
|
-
*/
|
|
102
|
-
export async function getMCPServerConfig(
|
|
103
|
-
mcpName: string,
|
|
104
|
-
config?: PhotonMCPConfig
|
|
105
|
-
): Promise<MCPServerConfig | undefined> {
|
|
106
|
-
const cfg = config || await loadPhotonMCPConfig();
|
|
107
|
-
return cfg.mcpServers[mcpName];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Add or update an MCP server configuration
|
|
112
|
-
*
|
|
113
|
-
* @param mcpName The MCP server name
|
|
114
|
-
* @param serverConfig The server configuration
|
|
115
|
-
* @param configPath Optional custom config path
|
|
116
|
-
*/
|
|
117
|
-
export async function setMCPServerConfig(
|
|
118
|
-
mcpName: string,
|
|
119
|
-
serverConfig: MCPServerConfig,
|
|
120
|
-
configPath?: string
|
|
121
|
-
): Promise<void> {
|
|
122
|
-
const config = await loadPhotonMCPConfig(configPath);
|
|
123
|
-
config.mcpServers[mcpName] = serverConfig;
|
|
124
|
-
await savePhotonMCPConfig(config, configPath);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Remove an MCP server configuration
|
|
129
|
-
*
|
|
130
|
-
* @param mcpName The MCP server name to remove
|
|
131
|
-
* @param configPath Optional custom config path
|
|
132
|
-
*/
|
|
133
|
-
export async function removeMCPServerConfig(
|
|
134
|
-
mcpName: string,
|
|
135
|
-
configPath?: string
|
|
136
|
-
): Promise<void> {
|
|
137
|
-
const config = await loadPhotonMCPConfig(configPath);
|
|
138
|
-
delete config.mcpServers[mcpName];
|
|
139
|
-
await savePhotonMCPConfig(config, configPath);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* List all configured MCP servers
|
|
144
|
-
*
|
|
145
|
-
* @param configPath Optional custom config path
|
|
146
|
-
* @returns Array of MCP server names
|
|
147
|
-
*/
|
|
148
|
-
export async function listMCPServers(configPath?: string): Promise<string[]> {
|
|
149
|
-
const config = await loadPhotonMCPConfig(configPath);
|
|
150
|
-
return Object.keys(config.mcpServers);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Convert PhotonMCPConfig to MCPConfig (for SDK transport)
|
|
155
|
-
*/
|
|
156
|
-
export function toMCPConfig(config: PhotonMCPConfig): MCPConfig {
|
|
157
|
-
return {
|
|
158
|
-
mcpServers: config.mcpServers,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Merge environment variables into MCP server config
|
|
164
|
-
* Supports ${VAR_NAME} syntax for env var references
|
|
165
|
-
*
|
|
166
|
-
* @param serverConfig The server config to process
|
|
167
|
-
* @returns Config with env vars resolved
|
|
168
|
-
*/
|
|
169
|
-
export function resolveEnvVars(serverConfig: MCPServerConfig): MCPServerConfig {
|
|
170
|
-
const resolved = { ...serverConfig };
|
|
171
|
-
|
|
172
|
-
// Process env object if present
|
|
173
|
-
if (resolved.env) {
|
|
174
|
-
const processedEnv: Record<string, string> = {};
|
|
175
|
-
for (const [key, value] of Object.entries(resolved.env)) {
|
|
176
|
-
processedEnv[key] = resolveEnvValue(value);
|
|
177
|
-
}
|
|
178
|
-
resolved.env = processedEnv;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Process args if present
|
|
182
|
-
if (resolved.args) {
|
|
183
|
-
resolved.args = resolved.args.map(resolveEnvValue);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Process url if present
|
|
187
|
-
if (resolved.url) {
|
|
188
|
-
resolved.url = resolveEnvValue(resolved.url);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return resolved;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Resolve ${VAR_NAME} references in a string value
|
|
196
|
-
*/
|
|
197
|
-
function resolveEnvValue(value: string): string {
|
|
198
|
-
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
199
|
-
return process.env[varName] || '';
|
|
200
|
-
});
|
|
201
|
-
}
|