pdauth 1.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/PROXY-SPEC.md +159 -0
- package/README.md +142 -0
- package/bin/ga.mjs +329 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +88 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/apps.d.ts +8 -0
- package/dist/commands/apps.d.ts.map +1 -0
- package/dist/commands/apps.js +76 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +58 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/connect.d.ts +6 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +67 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/proxy.d.ts +12 -0
- package/dist/commands/proxy.d.ts.map +1 -0
- package/dist/commands/proxy.js +127 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +117 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tools.d.ts +10 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +123 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/pipedream.d.ts +52 -0
- package/dist/pipedream.d.ts.map +1 -0
- package/dist/pipedream.js +142 -0
- package/dist/pipedream.js.map +1 -0
- package/package.json +46 -0
- package/src/cli.ts +111 -0
- package/src/commands/apps.ts +88 -0
- package/src/commands/config.ts +68 -0
- package/src/commands/connect.ts +76 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/proxy.ts +155 -0
- package/src/commands/status.ts +143 -0
- package/src/commands/tools.ts +150 -0
- package/src/config.ts +78 -0
- package/src/index.ts +6 -0
- package/src/pipedream.ts +216 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { listMcpTools, invokeMcpTool, listAccounts } from '../pipedream.js';
|
|
4
|
+
import { isConfigured, getDefaultUser } from '../config.js';
|
|
5
|
+
|
|
6
|
+
export async function toolsCommand(
|
|
7
|
+
appSlug: string,
|
|
8
|
+
options: { user?: string; json?: boolean }
|
|
9
|
+
): Promise<void> {
|
|
10
|
+
if (!isConfigured()) {
|
|
11
|
+
console.error(chalk.red('Not configured. Run: pdauth config'));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const userId = options.user || getDefaultUser();
|
|
16
|
+
const spinner = ora(`Fetching tools for ${appSlug}...`).start();
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
// Check if app is connected
|
|
20
|
+
const accounts = await listAccounts(userId);
|
|
21
|
+
const connected = accounts.find(a => a.app.nameSlug === appSlug);
|
|
22
|
+
|
|
23
|
+
if (!connected) {
|
|
24
|
+
spinner.fail(`App not connected: ${appSlug}`);
|
|
25
|
+
console.log(chalk.gray(`\nRun: pdauth connect ${appSlug} --user ${userId}`));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const tools = await listMcpTools(userId, appSlug);
|
|
30
|
+
spinner.stop();
|
|
31
|
+
|
|
32
|
+
if (options.json) {
|
|
33
|
+
console.log(JSON.stringify(tools, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(chalk.bold(`\n🔧 Tools for ${chalk.cyan(appSlug)} (${tools.length} available)\n`));
|
|
38
|
+
|
|
39
|
+
if (tools.length === 0) {
|
|
40
|
+
console.log(chalk.yellow(' No tools available for this app.\n'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const tool of tools) {
|
|
45
|
+
console.log(` ${chalk.cyan(tool.name)}`);
|
|
46
|
+
if (tool.description) {
|
|
47
|
+
console.log(` ${chalk.gray(tool.description.slice(0, 80))}${tool.description.length > 80 ? '...' : ''}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const required = tool.inputSchema?.required || [];
|
|
51
|
+
const props = Object.keys(tool.inputSchema?.properties || {});
|
|
52
|
+
|
|
53
|
+
if (props.length > 0) {
|
|
54
|
+
const propDisplay = props.map(p => required.includes(p) ? chalk.yellow(p) : chalk.gray(p)).join(', ');
|
|
55
|
+
console.log(` ${chalk.dim('params:')} ${propDisplay}`);
|
|
56
|
+
}
|
|
57
|
+
console.log();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(chalk.gray(` Invoke: pdauth call ${appSlug}.<tool_name> key=value\n`));
|
|
61
|
+
} catch (error) {
|
|
62
|
+
spinner.fail('Failed to fetch tools');
|
|
63
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function callCommand(
|
|
69
|
+
toolSelector: string,
|
|
70
|
+
args: string[],
|
|
71
|
+
options: { user?: string; json?: boolean; args?: string }
|
|
72
|
+
): Promise<void> {
|
|
73
|
+
if (!isConfigured()) {
|
|
74
|
+
console.error(chalk.red('Not configured. Run: pdauth config'));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Parse tool selector: app.tool_name
|
|
79
|
+
const [appSlug, ...toolParts] = toolSelector.split('.');
|
|
80
|
+
const toolName = toolParts.join('.');
|
|
81
|
+
|
|
82
|
+
if (!appSlug || !toolName) {
|
|
83
|
+
console.error(chalk.red('Invalid tool selector. Use: app_slug.tool_name'));
|
|
84
|
+
console.error(chalk.gray('Example: pdauth call slack.send_message channel=general text="Hello"'));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const userId = options.user || getDefaultUser();
|
|
89
|
+
|
|
90
|
+
// Parse arguments
|
|
91
|
+
let toolArgs: Record<string, unknown> = {};
|
|
92
|
+
|
|
93
|
+
if (options.args) {
|
|
94
|
+
// JSON args from --args flag
|
|
95
|
+
try {
|
|
96
|
+
toolArgs = JSON.parse(options.args);
|
|
97
|
+
} catch {
|
|
98
|
+
console.error(chalk.red('Invalid JSON in --args'));
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
// Parse key=value args
|
|
103
|
+
for (const arg of args) {
|
|
104
|
+
const eqIndex = arg.indexOf('=');
|
|
105
|
+
if (eqIndex === -1) continue;
|
|
106
|
+
|
|
107
|
+
const key = arg.slice(0, eqIndex);
|
|
108
|
+
let value: unknown = arg.slice(eqIndex + 1);
|
|
109
|
+
|
|
110
|
+
// Try to parse as JSON for complex values
|
|
111
|
+
try {
|
|
112
|
+
value = JSON.parse(value as string);
|
|
113
|
+
} catch {
|
|
114
|
+
// Keep as string
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
toolArgs[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const spinner = ora(`Calling ${appSlug}.${toolName}...`).start();
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Check if app is connected
|
|
125
|
+
const accounts = await listAccounts(userId);
|
|
126
|
+
const connected = accounts.find(a => a.app.nameSlug === appSlug);
|
|
127
|
+
|
|
128
|
+
if (!connected) {
|
|
129
|
+
spinner.fail(`App not connected: ${appSlug}`);
|
|
130
|
+
console.log(chalk.gray(`\nRun: pdauth connect ${appSlug} --user ${userId}`));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const result = await invokeMcpTool(userId, appSlug, toolName, toolArgs);
|
|
135
|
+
spinner.stop();
|
|
136
|
+
|
|
137
|
+
if (options.json) {
|
|
138
|
+
console.log(JSON.stringify(result, null, 2));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log(chalk.bold(`\n✅ ${appSlug}.${toolName} completed\n`));
|
|
143
|
+
console.log(JSON.stringify(result, null, 2));
|
|
144
|
+
console.log();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
spinner.fail('Tool call failed');
|
|
147
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
export interface PdAuthConfig {
|
|
6
|
+
clientId: string;
|
|
7
|
+
clientSecret: string;
|
|
8
|
+
projectId: string;
|
|
9
|
+
environment: 'development' | 'production';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UserMapping {
|
|
13
|
+
[externalUserId: string]: {
|
|
14
|
+
label?: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const schema = {
|
|
20
|
+
clientId: { type: 'string' as const, default: '' },
|
|
21
|
+
clientSecret: { type: 'string' as const, default: '' },
|
|
22
|
+
projectId: { type: 'string' as const, default: '' },
|
|
23
|
+
environment: { type: 'string' as const, default: 'development' },
|
|
24
|
+
defaultUser: { type: 'string' as const, default: 'default' },
|
|
25
|
+
users: { type: 'object' as const, default: {} },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const config = new Conf({
|
|
29
|
+
projectName: 'pdauth',
|
|
30
|
+
cwd: join(homedir(), '.config', 'pdauth'),
|
|
31
|
+
schema,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export function getConfig(): PdAuthConfig {
|
|
35
|
+
return {
|
|
36
|
+
clientId: config.get('clientId') as string,
|
|
37
|
+
clientSecret: config.get('clientSecret') as string,
|
|
38
|
+
projectId: config.get('projectId') as string,
|
|
39
|
+
environment: config.get('environment') as 'development' | 'production',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function setConfig(values: Partial<PdAuthConfig>): void {
|
|
44
|
+
if (values.clientId !== undefined) config.set('clientId', values.clientId);
|
|
45
|
+
if (values.clientSecret !== undefined) config.set('clientSecret', values.clientSecret);
|
|
46
|
+
if (values.projectId !== undefined) config.set('projectId', values.projectId);
|
|
47
|
+
if (values.environment !== undefined) config.set('environment', values.environment);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function isConfigured(): boolean {
|
|
51
|
+
const cfg = getConfig();
|
|
52
|
+
return !!(cfg.clientId && cfg.clientSecret && cfg.projectId);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getDefaultUser(): string {
|
|
56
|
+
return config.get('defaultUser') as string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function setDefaultUser(userId: string): void {
|
|
60
|
+
config.set('defaultUser', userId);
|
|
61
|
+
addUser(userId);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getUsers(): UserMapping {
|
|
65
|
+
return config.get('users') as UserMapping;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function addUser(userId: string, label?: string): void {
|
|
69
|
+
const users = getUsers();
|
|
70
|
+
if (!users[userId]) {
|
|
71
|
+
users[userId] = { createdAt: new Date().toISOString(), label };
|
|
72
|
+
config.set('users', users);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getConfigPath(): string {
|
|
77
|
+
return config.path;
|
|
78
|
+
}
|
package/src/index.ts
ADDED
package/src/pipedream.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { PipedreamClient } from '@pipedream/sdk';
|
|
2
|
+
import { getConfig, isConfigured } from './config.js';
|
|
3
|
+
|
|
4
|
+
let _client: PipedreamClient | null = null;
|
|
5
|
+
|
|
6
|
+
export function getClient(): PipedreamClient {
|
|
7
|
+
if (!isConfigured()) {
|
|
8
|
+
throw new Error('Pipedream not configured. Run: pdauth config');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!_client) {
|
|
12
|
+
const config = getConfig();
|
|
13
|
+
_client = new PipedreamClient({
|
|
14
|
+
projectEnvironment: config.environment,
|
|
15
|
+
clientId: config.clientId,
|
|
16
|
+
clientSecret: config.clientSecret,
|
|
17
|
+
projectId: config.projectId,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return _client;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resetClient(): void {
|
|
24
|
+
_client = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ConnectLinkResult {
|
|
28
|
+
token: string;
|
|
29
|
+
expiresAt: string;
|
|
30
|
+
connectLinkUrl: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function createConnectLink(
|
|
34
|
+
externalUserId: string,
|
|
35
|
+
appSlug: string
|
|
36
|
+
): Promise<ConnectLinkResult> {
|
|
37
|
+
const client = getClient();
|
|
38
|
+
|
|
39
|
+
const response = await client.tokens.create({
|
|
40
|
+
externalUserId,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const expiresAt =
|
|
44
|
+
typeof response.expiresAt === 'string'
|
|
45
|
+
? response.expiresAt
|
|
46
|
+
: response.expiresAt
|
|
47
|
+
? new Date(response.expiresAt).toISOString()
|
|
48
|
+
: new Date(Date.now() + 3600000).toISOString();
|
|
49
|
+
|
|
50
|
+
// Build connect link URL with app parameter
|
|
51
|
+
const baseUrl = response.connectLinkUrl || 'https://connect.pipedream.com';
|
|
52
|
+
const separator = baseUrl.includes('?') ? '&' : '?';
|
|
53
|
+
const connectLinkUrl = `${baseUrl}${separator}app=${encodeURIComponent(appSlug)}&connectLink=true`;
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
token: response.token ?? '',
|
|
57
|
+
expiresAt,
|
|
58
|
+
connectLinkUrl,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface PipedreamAccount {
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
externalId?: string;
|
|
66
|
+
healthy: boolean;
|
|
67
|
+
dead: boolean;
|
|
68
|
+
app: {
|
|
69
|
+
id: string;
|
|
70
|
+
nameSlug: string;
|
|
71
|
+
name: string;
|
|
72
|
+
imgSrc?: string;
|
|
73
|
+
};
|
|
74
|
+
createdAt: string;
|
|
75
|
+
updatedAt: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function listAccounts(externalUserId: string): Promise<PipedreamAccount[]> {
|
|
79
|
+
const client = getClient();
|
|
80
|
+
const response = await client.accounts.list({ externalUserId });
|
|
81
|
+
return (response.data ?? []) as unknown as PipedreamAccount[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function deleteAccount(accountId: string): Promise<boolean> {
|
|
85
|
+
const client = getClient();
|
|
86
|
+
try {
|
|
87
|
+
await client.accounts.delete(accountId);
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface PipedreamApp {
|
|
95
|
+
id: string;
|
|
96
|
+
nameSlug: string;
|
|
97
|
+
name: string;
|
|
98
|
+
authType: string;
|
|
99
|
+
description: string;
|
|
100
|
+
imgSrc: string;
|
|
101
|
+
categories: string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function searchApps(query?: string): Promise<PipedreamApp[]> {
|
|
105
|
+
const client = getClient();
|
|
106
|
+
const response = await client.apps.list(query ? { q: query } : {});
|
|
107
|
+
return (response.data ?? []) as unknown as PipedreamApp[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function getApp(nameSlug: string): Promise<PipedreamApp | null> {
|
|
111
|
+
const apps = await searchApps(nameSlug);
|
|
112
|
+
return apps.find(app => app.nameSlug === nameSlug) || null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function getAccessToken(): Promise<string> {
|
|
116
|
+
const client = getClient();
|
|
117
|
+
return client.rawAccessToken;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function getMcpServerUrl(): string {
|
|
121
|
+
return 'https://remote.mcp.pipedream.net';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function getMcpHeaders(externalUserId: string, appSlug?: string): Promise<Record<string, string>> {
|
|
125
|
+
const accessToken = await getAccessToken();
|
|
126
|
+
const config = getConfig();
|
|
127
|
+
|
|
128
|
+
const headers: Record<string, string> = {
|
|
129
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
130
|
+
'x-pd-project-id': config.projectId,
|
|
131
|
+
'x-pd-environment': config.environment,
|
|
132
|
+
'x-pd-external-user-id': externalUserId,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (appSlug) {
|
|
136
|
+
headers['x-pd-app-slug'] = appSlug;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return headers;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface McpTool {
|
|
143
|
+
name: string;
|
|
144
|
+
description: string;
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: string;
|
|
147
|
+
properties: Record<string, unknown>;
|
|
148
|
+
required?: string[];
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function listMcpTools(externalUserId: string, appSlug: string): Promise<McpTool[]> {
|
|
153
|
+
const headers = await getMcpHeaders(externalUserId, appSlug);
|
|
154
|
+
|
|
155
|
+
const response = await fetch(getMcpServerUrl(), {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: {
|
|
158
|
+
...headers,
|
|
159
|
+
'Content-Type': 'application/json',
|
|
160
|
+
'Accept': 'application/json, text/event-stream',
|
|
161
|
+
},
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
jsonrpc: '2.0',
|
|
164
|
+
method: 'tools/list',
|
|
165
|
+
id: Date.now(),
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const text = await response.text();
|
|
170
|
+
// Parse SSE format: "event: message\ndata: {...}"
|
|
171
|
+
const dataMatch = text.match(/^data: (.+)$/m);
|
|
172
|
+
if (!dataMatch) {
|
|
173
|
+
throw new Error('Invalid MCP response');
|
|
174
|
+
}
|
|
175
|
+
const data = JSON.parse(dataMatch[1]) as { result?: { tools?: McpTool[] } };
|
|
176
|
+
return data.result?.tools ?? [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function invokeMcpTool(
|
|
180
|
+
externalUserId: string,
|
|
181
|
+
appSlug: string,
|
|
182
|
+
toolName: string,
|
|
183
|
+
args: Record<string, unknown>
|
|
184
|
+
): Promise<unknown> {
|
|
185
|
+
const headers = await getMcpHeaders(externalUserId, appSlug);
|
|
186
|
+
|
|
187
|
+
const response = await fetch(getMcpServerUrl(), {
|
|
188
|
+
method: 'POST',
|
|
189
|
+
headers: {
|
|
190
|
+
...headers,
|
|
191
|
+
'Content-Type': 'application/json',
|
|
192
|
+
'Accept': 'application/json, text/event-stream',
|
|
193
|
+
},
|
|
194
|
+
body: JSON.stringify({
|
|
195
|
+
jsonrpc: '2.0',
|
|
196
|
+
method: 'tools/call',
|
|
197
|
+
params: {
|
|
198
|
+
name: toolName,
|
|
199
|
+
arguments: args,
|
|
200
|
+
},
|
|
201
|
+
id: Date.now(),
|
|
202
|
+
}),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const text = await response.text();
|
|
206
|
+
// Parse SSE format: "event: message\ndata: {...}"
|
|
207
|
+
const dataMatch = text.match(/^data: (.+)$/m);
|
|
208
|
+
if (!dataMatch) {
|
|
209
|
+
throw new Error(`Invalid MCP response: ${text.slice(0, 200)}`);
|
|
210
|
+
}
|
|
211
|
+
const data = JSON.parse(dataMatch[1]) as { result?: unknown; error?: unknown };
|
|
212
|
+
if (data.error) {
|
|
213
|
+
throw new Error(JSON.stringify(data.error));
|
|
214
|
+
}
|
|
215
|
+
return data.result;
|
|
216
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|