@spec2tools/core 0.1.0 → 0.1.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/dist/auth-manager.d.ts +13 -6
- package/dist/auth-manager.js +71 -35
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/openapi-parser.d.ts +6 -1
- package/dist/openapi-parser.js +30 -4
- package/dist/tool-executor.d.ts +2 -1
- package/dist/tool-executor.js +32 -5
- package/dist/types.d.ts +2 -1
- package/package.json +1 -1
package/dist/auth-manager.d.ts
CHANGED
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
import { AuthConfig } from './types.js';
|
|
2
2
|
export declare class AuthManager {
|
|
3
|
-
private
|
|
3
|
+
private globalAuthConfig;
|
|
4
4
|
private accessToken?;
|
|
5
5
|
private refreshToken?;
|
|
6
6
|
private clientId?;
|
|
7
7
|
private clientSecret?;
|
|
8
8
|
private codeVerifier?;
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(globalAuthConfig: AuthConfig);
|
|
10
10
|
/**
|
|
11
11
|
* Check if authentication is required
|
|
12
12
|
*/
|
|
13
|
-
requiresAuth(): boolean;
|
|
13
|
+
requiresAuth(authConfig?: AuthConfig): boolean;
|
|
14
14
|
/**
|
|
15
15
|
* Get the current access token
|
|
16
16
|
*/
|
|
17
17
|
getAccessToken(): string | undefined;
|
|
18
18
|
/**
|
|
19
19
|
* Get authorization headers for requests
|
|
20
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
20
21
|
*/
|
|
21
|
-
getAuthHeaders(): Record<string, string>;
|
|
22
|
+
getAuthHeaders(authConfig?: AuthConfig): Record<string, string>;
|
|
22
23
|
/**
|
|
23
24
|
* Get query parameters for API key auth
|
|
25
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
24
26
|
*/
|
|
25
|
-
getAuthQueryParams(): Record<string, string>;
|
|
27
|
+
getAuthQueryParams(authConfig?: AuthConfig): Record<string, string>;
|
|
26
28
|
/**
|
|
27
29
|
* Perform authentication based on config type
|
|
30
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
28
31
|
*/
|
|
29
|
-
authenticate(): Promise<void>;
|
|
32
|
+
authenticate(authConfig?: AuthConfig): Promise<void>;
|
|
30
33
|
/**
|
|
31
34
|
* Prompt user for API key
|
|
32
35
|
*/
|
|
@@ -35,6 +38,10 @@ export declare class AuthManager {
|
|
|
35
38
|
* Prompt user for bearer token
|
|
36
39
|
*/
|
|
37
40
|
private promptForBearerToken;
|
|
41
|
+
/**
|
|
42
|
+
* Prompt user for basic auth credentials
|
|
43
|
+
*/
|
|
44
|
+
private promptForBasicAuth;
|
|
38
45
|
/**
|
|
39
46
|
* Perform OAuth2 authorization code flow
|
|
40
47
|
*/
|
package/dist/auth-manager.js
CHANGED
|
@@ -7,20 +7,21 @@ import * as readline from 'readline';
|
|
|
7
7
|
const CALLBACK_PORT = 54321;
|
|
8
8
|
const CALLBACK_PATH = '/callback';
|
|
9
9
|
export class AuthManager {
|
|
10
|
-
|
|
10
|
+
globalAuthConfig;
|
|
11
11
|
accessToken;
|
|
12
12
|
refreshToken;
|
|
13
13
|
clientId;
|
|
14
14
|
clientSecret;
|
|
15
15
|
codeVerifier;
|
|
16
|
-
constructor(
|
|
17
|
-
this.
|
|
16
|
+
constructor(globalAuthConfig) {
|
|
17
|
+
this.globalAuthConfig = globalAuthConfig;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Check if authentication is required
|
|
21
21
|
*/
|
|
22
|
-
requiresAuth() {
|
|
23
|
-
|
|
22
|
+
requiresAuth(authConfig) {
|
|
23
|
+
const config = authConfig ?? this.globalAuthConfig;
|
|
24
|
+
return config.type !== 'none';
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* Get the current access token
|
|
@@ -30,18 +31,22 @@ export class AuthManager {
|
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
33
|
* Get authorization headers for requests
|
|
34
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
33
35
|
*/
|
|
34
|
-
getAuthHeaders() {
|
|
36
|
+
getAuthHeaders(authConfig) {
|
|
35
37
|
if (!this.accessToken) {
|
|
36
38
|
return {};
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
const config = authConfig ?? this.globalAuthConfig;
|
|
41
|
+
switch (config.type) {
|
|
39
42
|
case 'oauth2':
|
|
40
43
|
case 'bearer':
|
|
41
44
|
return { Authorization: `Bearer ${this.accessToken}` };
|
|
45
|
+
case 'basic':
|
|
46
|
+
return { Authorization: `Basic ${this.accessToken}` };
|
|
42
47
|
case 'apiKey':
|
|
43
|
-
if (
|
|
44
|
-
return { [
|
|
48
|
+
if (config.apiKeyIn === 'header' && config.apiKeyHeader) {
|
|
49
|
+
return { [config.apiKeyHeader]: this.accessToken };
|
|
45
50
|
}
|
|
46
51
|
return {};
|
|
47
52
|
default:
|
|
@@ -50,30 +55,37 @@ export class AuthManager {
|
|
|
50
55
|
}
|
|
51
56
|
/**
|
|
52
57
|
* Get query parameters for API key auth
|
|
58
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
53
59
|
*/
|
|
54
|
-
getAuthQueryParams() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
getAuthQueryParams(authConfig) {
|
|
61
|
+
const config = authConfig ?? this.globalAuthConfig;
|
|
62
|
+
if (config.type === 'apiKey' &&
|
|
63
|
+
config.apiKeyIn === 'query' &&
|
|
64
|
+
config.apiKeyHeader &&
|
|
58
65
|
this.accessToken) {
|
|
59
|
-
return { [
|
|
66
|
+
return { [config.apiKeyHeader]: this.accessToken };
|
|
60
67
|
}
|
|
61
68
|
return {};
|
|
62
69
|
}
|
|
63
70
|
/**
|
|
64
71
|
* Perform authentication based on config type
|
|
72
|
+
* @param authConfig Optional tool-specific auth config that overrides the global config
|
|
65
73
|
*/
|
|
66
|
-
async authenticate() {
|
|
67
|
-
|
|
74
|
+
async authenticate(authConfig) {
|
|
75
|
+
const config = authConfig ?? this.globalAuthConfig;
|
|
76
|
+
switch (config.type) {
|
|
68
77
|
case 'oauth2':
|
|
69
|
-
await this.performOAuth2Flow();
|
|
78
|
+
await this.performOAuth2Flow(config);
|
|
70
79
|
break;
|
|
71
80
|
case 'apiKey':
|
|
72
|
-
await this.promptForApiKey();
|
|
81
|
+
await this.promptForApiKey(config);
|
|
73
82
|
break;
|
|
74
83
|
case 'bearer':
|
|
75
84
|
await this.promptForBearerToken();
|
|
76
85
|
break;
|
|
86
|
+
case 'basic':
|
|
87
|
+
await this.promptForBasicAuth();
|
|
88
|
+
break;
|
|
77
89
|
case 'none':
|
|
78
90
|
// No authentication needed
|
|
79
91
|
break;
|
|
@@ -82,12 +94,12 @@ export class AuthManager {
|
|
|
82
94
|
/**
|
|
83
95
|
* Prompt user for API key
|
|
84
96
|
*/
|
|
85
|
-
async promptForApiKey() {
|
|
97
|
+
async promptForApiKey(config) {
|
|
86
98
|
const rl = readline.createInterface({
|
|
87
99
|
input: process.stdin,
|
|
88
100
|
output: process.stdout,
|
|
89
101
|
});
|
|
90
|
-
const headerName =
|
|
102
|
+
const headerName = config.apiKeyHeader || 'API-Key';
|
|
91
103
|
this.accessToken = await new Promise((resolve) => {
|
|
92
104
|
rl.question(`Enter your API key (${headerName}): `, (answer) => {
|
|
93
105
|
rl.close();
|
|
@@ -116,26 +128,50 @@ export class AuthManager {
|
|
|
116
128
|
throw new AuthenticationError('Bearer token is required');
|
|
117
129
|
}
|
|
118
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Prompt user for basic auth credentials
|
|
133
|
+
*/
|
|
134
|
+
async promptForBasicAuth() {
|
|
135
|
+
const rl = readline.createInterface({
|
|
136
|
+
input: process.stdin,
|
|
137
|
+
output: process.stdout,
|
|
138
|
+
});
|
|
139
|
+
const question = (prompt) => {
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
rl.question(prompt, (answer) => {
|
|
142
|
+
resolve(answer.trim());
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
const username = await question('Enter username: ');
|
|
147
|
+
const password = await question('Enter password: ');
|
|
148
|
+
rl.close();
|
|
149
|
+
if (!username || !password) {
|
|
150
|
+
throw new AuthenticationError('Username and password are required for Basic auth');
|
|
151
|
+
}
|
|
152
|
+
// Base64 encode the credentials
|
|
153
|
+
this.accessToken = Buffer.from(`${username}:${password}`).toString('base64');
|
|
154
|
+
}
|
|
119
155
|
/**
|
|
120
156
|
* Perform OAuth2 authorization code flow
|
|
121
157
|
*/
|
|
122
|
-
async performOAuth2Flow() {
|
|
123
|
-
if (!
|
|
158
|
+
async performOAuth2Flow(config) {
|
|
159
|
+
if (!config.authorizationUrl || !config.tokenUrl) {
|
|
124
160
|
throw new AuthenticationError('OAuth2 requires authorizationUrl and tokenUrl');
|
|
125
161
|
}
|
|
126
162
|
// Register client dynamically
|
|
127
|
-
await this.registerClient();
|
|
163
|
+
await this.registerClient(config);
|
|
128
164
|
// Start local callback server
|
|
129
|
-
const authCode = await this.startCallbackServerAndAuthorize();
|
|
165
|
+
const authCode = await this.startCallbackServerAndAuthorize(config);
|
|
130
166
|
// Exchange code for token
|
|
131
|
-
await this.exchangeCodeForToken(authCode);
|
|
167
|
+
await this.exchangeCodeForToken(authCode, config);
|
|
132
168
|
}
|
|
133
169
|
/**
|
|
134
170
|
* Register OAuth2 client dynamically
|
|
135
171
|
*/
|
|
136
|
-
async registerClient() {
|
|
172
|
+
async registerClient(config) {
|
|
137
173
|
// Derive registration URL from token URL (replace /token with /register)
|
|
138
|
-
const registrationUrl =
|
|
174
|
+
const registrationUrl = config.tokenUrl.replace(/\/token$/, '/register');
|
|
139
175
|
const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
140
176
|
console.log('Registering OAuth2 client...');
|
|
141
177
|
const response = await fetch(registrationUrl, {
|
|
@@ -162,7 +198,7 @@ export class AuthManager {
|
|
|
162
198
|
/**
|
|
163
199
|
* Start local callback server and initiate authorization
|
|
164
200
|
*/
|
|
165
|
-
async startCallbackServerAndAuthorize() {
|
|
201
|
+
async startCallbackServerAndAuthorize(config) {
|
|
166
202
|
return new Promise((resolve, reject) => {
|
|
167
203
|
const app = express();
|
|
168
204
|
let server;
|
|
@@ -211,7 +247,7 @@ export class AuthManager {
|
|
|
211
247
|
server = createServer(app);
|
|
212
248
|
server.listen(CALLBACK_PORT, '127.0.0.1', () => {
|
|
213
249
|
const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
214
|
-
const authUrl = this.buildAuthorizationUrl(redirectUri);
|
|
250
|
+
const authUrl = this.buildAuthorizationUrl(redirectUri, config);
|
|
215
251
|
console.log('\nAuthentication required. Opening browser...');
|
|
216
252
|
console.log(`If browser doesn't open, visit: ${authUrl}\n`);
|
|
217
253
|
open(authUrl).catch(() => {
|
|
@@ -249,8 +285,8 @@ export class AuthManager {
|
|
|
249
285
|
/**
|
|
250
286
|
* Build the OAuth2 authorization URL
|
|
251
287
|
*/
|
|
252
|
-
buildAuthorizationUrl(redirectUri) {
|
|
253
|
-
const url = new URL(
|
|
288
|
+
buildAuthorizationUrl(redirectUri, config) {
|
|
289
|
+
const url = new URL(config.authorizationUrl);
|
|
254
290
|
// Generate PKCE
|
|
255
291
|
const pkce = this.generatePKCE();
|
|
256
292
|
this.codeVerifier = pkce.verifier;
|
|
@@ -259,8 +295,8 @@ export class AuthManager {
|
|
|
259
295
|
url.searchParams.set('redirect_uri', redirectUri);
|
|
260
296
|
url.searchParams.set('code_challenge', pkce.challenge);
|
|
261
297
|
url.searchParams.set('code_challenge_method', 'S256');
|
|
262
|
-
if (
|
|
263
|
-
url.searchParams.set('scope',
|
|
298
|
+
if (config.scopes && config.scopes.length > 0) {
|
|
299
|
+
url.searchParams.set('scope', config.scopes.join(' '));
|
|
264
300
|
}
|
|
265
301
|
// Generate state for CSRF protection
|
|
266
302
|
const state = crypto.randomBytes(16).toString('base64url');
|
|
@@ -270,7 +306,7 @@ export class AuthManager {
|
|
|
270
306
|
/**
|
|
271
307
|
* Exchange authorization code for access token
|
|
272
308
|
*/
|
|
273
|
-
async exchangeCodeForToken(code) {
|
|
309
|
+
async exchangeCodeForToken(code, config) {
|
|
274
310
|
const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
275
311
|
const params = new URLSearchParams({
|
|
276
312
|
grant_type: 'authorization_code',
|
|
@@ -283,7 +319,7 @@ export class AuthManager {
|
|
|
283
319
|
if (this.clientSecret) {
|
|
284
320
|
params.set('client_secret', this.clientSecret);
|
|
285
321
|
}
|
|
286
|
-
const response = await fetch(
|
|
322
|
+
const response = await fetch(config.tokenUrl, {
|
|
287
323
|
method: 'POST',
|
|
288
324
|
headers: {
|
|
289
325
|
'Content-Type': 'application/x-www-form-urlencoded',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { UnsupportedSchemaError, AuthenticationError, ToolExecutionError, SpecLoadError, } from './errors.js';
|
|
2
2
|
export type { HttpMethod, Tool, AuthType, AuthConfig, Session, OpenAPISpec, PathItem, Operation, Parameter, RequestBody, MediaType, Response, SchemaObject, SecurityScheme, } from './types.js';
|
|
3
|
-
export { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, formatToolSchema, formatToolSignature, } from './openapi-parser.js';
|
|
3
|
+
export { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, extractOperationAuthConfig, parseOperations, formatToolSchema, formatToolSignature, } from './openapi-parser.js';
|
|
4
4
|
export { AuthManager } from './auth-manager.js';
|
|
5
5
|
export { createExecutableTools, executeToolByName } from './tool-executor.js';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Error classes
|
|
2
2
|
export { UnsupportedSchemaError, AuthenticationError, ToolExecutionError, SpecLoadError, } from './errors.js';
|
|
3
3
|
// OpenAPI Parser
|
|
4
|
-
export { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, formatToolSchema, formatToolSignature, } from './openapi-parser.js';
|
|
4
|
+
export { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, extractOperationAuthConfig, parseOperations, formatToolSchema, formatToolSignature, } from './openapi-parser.js';
|
|
5
5
|
// Auth Manager
|
|
6
6
|
export { AuthManager } from './auth-manager.js';
|
|
7
7
|
// Tool Executor
|
package/dist/openapi-parser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OpenAPISpec, Tool, AuthConfig } from './types.js';
|
|
1
|
+
import { OpenAPISpec, Operation, Tool, AuthConfig } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Fetch and parse an OpenAPI specification from URL or file path
|
|
4
4
|
*/
|
|
@@ -11,6 +11,11 @@ export declare function extractBaseUrl(spec: OpenAPISpec): string;
|
|
|
11
11
|
* Extract authentication configuration from security schemes
|
|
12
12
|
*/
|
|
13
13
|
export declare function extractAuthConfig(spec: OpenAPISpec): AuthConfig;
|
|
14
|
+
/**
|
|
15
|
+
* Extract authentication configuration for a specific operation
|
|
16
|
+
* Uses operation-level security if defined, otherwise falls back to global security
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractOperationAuthConfig(spec: OpenAPISpec, operation: Operation): AuthConfig;
|
|
14
19
|
/**
|
|
15
20
|
* Parse all operations from the OpenAPI spec and generate tool definitions
|
|
16
21
|
*/
|
package/dist/openapi-parser.js
CHANGED
|
@@ -47,13 +47,33 @@ export function extractBaseUrl(spec) {
|
|
|
47
47
|
* Extract authentication configuration from security schemes
|
|
48
48
|
*/
|
|
49
49
|
export function extractAuthConfig(spec) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
return extractAuthConfigFromSecurity(spec.security, spec.components?.securitySchemes);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extract authentication configuration for a specific operation
|
|
54
|
+
* Uses operation-level security if defined, otherwise falls back to global security
|
|
55
|
+
*/
|
|
56
|
+
export function extractOperationAuthConfig(spec, operation) {
|
|
57
|
+
// If operation has its own security field, use it (even if empty array = no auth)
|
|
58
|
+
if (operation.security !== undefined) {
|
|
59
|
+
return extractAuthConfigFromSecurity(operation.security, spec.components?.securitySchemes);
|
|
60
|
+
}
|
|
61
|
+
// Fall back to global security
|
|
62
|
+
return extractAuthConfig(spec);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extract auth config from a security requirement array
|
|
66
|
+
*/
|
|
67
|
+
function extractAuthConfigFromSecurity(security, securitySchemes) {
|
|
68
|
+
// Empty security array means explicitly no auth required
|
|
69
|
+
if (security !== undefined && security.length === 0) {
|
|
70
|
+
return { type: 'none' };
|
|
71
|
+
}
|
|
72
|
+
if (!securitySchemes || !security || security.length === 0) {
|
|
53
73
|
return { type: 'none' };
|
|
54
74
|
}
|
|
55
75
|
// Get the first security requirement
|
|
56
|
-
const securityReq =
|
|
76
|
+
const securityReq = security[0];
|
|
57
77
|
const schemeName = Object.keys(securityReq)[0];
|
|
58
78
|
const scheme = securitySchemes[schemeName];
|
|
59
79
|
if (!scheme) {
|
|
@@ -84,6 +104,9 @@ function parseSecurityScheme(scheme, scopes) {
|
|
|
84
104
|
if (scheme.type === 'http' && scheme.scheme === 'bearer') {
|
|
85
105
|
return { type: 'bearer' };
|
|
86
106
|
}
|
|
107
|
+
if (scheme.type === 'http' && scheme.scheme === 'basic') {
|
|
108
|
+
return { type: 'basic' };
|
|
109
|
+
}
|
|
87
110
|
return { type: 'none' };
|
|
88
111
|
}
|
|
89
112
|
/**
|
|
@@ -273,12 +296,15 @@ export function parseOperations(spec) {
|
|
|
273
296
|
const bodyShape = buildRequestBodySchema(operation, operationId);
|
|
274
297
|
const combinedShape = { ...parameterShape, ...bodyShape };
|
|
275
298
|
const parameters = z.object(combinedShape);
|
|
299
|
+
// Extract operation-specific auth config
|
|
300
|
+
const authConfig = extractOperationAuthConfig(spec, operation);
|
|
276
301
|
tools.push({
|
|
277
302
|
name: operationId,
|
|
278
303
|
description: operation.summary || operation.description || `${method} ${path}`,
|
|
279
304
|
parameters,
|
|
280
305
|
httpMethod: method,
|
|
281
306
|
path,
|
|
307
|
+
authConfig,
|
|
282
308
|
});
|
|
283
309
|
}
|
|
284
310
|
}
|
package/dist/tool-executor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { Tool, HttpMethod } from './types.js';
|
|
2
|
+
import { Tool, HttpMethod, AuthConfig } from './types.js';
|
|
3
3
|
import { AuthManager } from './auth-manager.js';
|
|
4
4
|
interface ToolDefinition {
|
|
5
5
|
name: string;
|
|
@@ -7,6 +7,7 @@ interface ToolDefinition {
|
|
|
7
7
|
parameters: z.ZodObject<z.ZodRawShape>;
|
|
8
8
|
httpMethod: HttpMethod;
|
|
9
9
|
path: string;
|
|
10
|
+
authConfig?: AuthConfig;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* Create executable tools from tool definitions
|
package/dist/tool-executor.js
CHANGED
|
@@ -28,15 +28,20 @@ function createExecutor(tool, baseUrl, authManager) {
|
|
|
28
28
|
urlObj.searchParams.set(key, String(value));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
// Check if this tool requires auth (respects operation-level security)
|
|
32
|
+
// Tool-level authConfig overrides the global authConfig
|
|
33
|
+
const toolRequiresAuth = authManager.requiresAuth(tool.authConfig);
|
|
31
34
|
// Add auth query params if needed
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
if (toolRequiresAuth) {
|
|
36
|
+
const authQueryParams = authManager.getAuthQueryParams(tool.authConfig);
|
|
37
|
+
for (const [key, value] of Object.entries(authQueryParams)) {
|
|
38
|
+
urlObj.searchParams.set(key, value);
|
|
39
|
+
}
|
|
35
40
|
}
|
|
36
41
|
url = urlObj.toString();
|
|
37
42
|
// Build request options
|
|
38
43
|
const headers = {
|
|
39
|
-
...authManager.getAuthHeaders(),
|
|
44
|
+
...(toolRequiresAuth ? authManager.getAuthHeaders(tool.authConfig) : {}),
|
|
40
45
|
};
|
|
41
46
|
const fetchOptions = {
|
|
42
47
|
method: tool.httpMethod,
|
|
@@ -62,7 +67,29 @@ function createExecutor(tool, baseUrl, authManager) {
|
|
|
62
67
|
responseData = await response.text();
|
|
63
68
|
}
|
|
64
69
|
if (!response.ok) {
|
|
65
|
-
|
|
70
|
+
// Build detailed error message
|
|
71
|
+
const errorDetails = [
|
|
72
|
+
`HTTP ${response.status} ${response.statusText}`,
|
|
73
|
+
`URL: ${tool.httpMethod} ${url}`,
|
|
74
|
+
`Response: ${typeof responseData === 'string' ? responseData : JSON.stringify(responseData, null, 2)}`
|
|
75
|
+
];
|
|
76
|
+
// Add helpful context for common errors
|
|
77
|
+
if (response.status === 401) {
|
|
78
|
+
errorDetails.push('Authentication failed. Check your API key/token.');
|
|
79
|
+
}
|
|
80
|
+
else if (response.status === 403) {
|
|
81
|
+
errorDetails.push('Access forbidden. Verify your permissions.');
|
|
82
|
+
}
|
|
83
|
+
else if (response.status === 404) {
|
|
84
|
+
errorDetails.push('Resource not found.');
|
|
85
|
+
}
|
|
86
|
+
else if (response.status === 429) {
|
|
87
|
+
errorDetails.push('Rate limit exceeded. Try again later.');
|
|
88
|
+
}
|
|
89
|
+
else if (response.status >= 500) {
|
|
90
|
+
errorDetails.push('Server error. The API service may be experiencing issues.');
|
|
91
|
+
}
|
|
92
|
+
throw new Error(errorDetails.join('\n'));
|
|
66
93
|
}
|
|
67
94
|
return responseData;
|
|
68
95
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -7,8 +7,9 @@ export interface Tool {
|
|
|
7
7
|
execute: (params: unknown) => Promise<unknown>;
|
|
8
8
|
httpMethod: HttpMethod;
|
|
9
9
|
path: string;
|
|
10
|
+
authConfig?: AuthConfig;
|
|
10
11
|
}
|
|
11
|
-
export type AuthType = 'oauth2' | 'apiKey' | 'bearer' | 'none';
|
|
12
|
+
export type AuthType = 'oauth2' | 'apiKey' | 'bearer' | 'basic' | 'none';
|
|
12
13
|
export interface AuthConfig {
|
|
13
14
|
type: AuthType;
|
|
14
15
|
authorizationUrl?: string;
|