openapi-dynamic-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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +247 -0
  3. package/dist/auth/env.d.ts +14 -0
  4. package/dist/auth/env.js +64 -0
  5. package/dist/auth/env.js.map +1 -0
  6. package/dist/auth/oauthClient.d.ts +12 -0
  7. package/dist/auth/oauthClient.js +55 -0
  8. package/dist/auth/oauthClient.js.map +1 -0
  9. package/dist/auth/resolveAuth.d.ts +10 -0
  10. package/dist/auth/resolveAuth.js +118 -0
  11. package/dist/auth/resolveAuth.js.map +1 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.js +50 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/config/loadConfig.d.ts +2 -0
  16. package/dist/config/loadConfig.js +89 -0
  17. package/dist/config/loadConfig.js.map +1 -0
  18. package/dist/errors.d.ts +11 -0
  19. package/dist/errors.js +31 -0
  20. package/dist/errors.js.map +1 -0
  21. package/dist/http/requestExecutor.d.ts +19 -0
  22. package/dist/http/requestExecutor.js +342 -0
  23. package/dist/http/requestExecutor.js.map +1 -0
  24. package/dist/index.d.ts +7 -0
  25. package/dist/index.js +7 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/mcp/context.d.ts +7 -0
  28. package/dist/mcp/context.js +2 -0
  29. package/dist/mcp/context.js.map +1 -0
  30. package/dist/mcp/server.d.ts +2 -0
  31. package/dist/mcp/server.js +125 -0
  32. package/dist/mcp/server.js.map +1 -0
  33. package/dist/mcp/tools/common.d.ts +16 -0
  34. package/dist/mcp/tools/common.js +60 -0
  35. package/dist/mcp/tools/common.js.map +1 -0
  36. package/dist/mcp/tools/getApiEndpoint.d.ts +3 -0
  37. package/dist/mcp/tools/getApiEndpoint.js +59 -0
  38. package/dist/mcp/tools/getApiEndpoint.js.map +1 -0
  39. package/dist/mcp/tools/getApiSchema.d.ts +3 -0
  40. package/dist/mcp/tools/getApiSchema.js +27 -0
  41. package/dist/mcp/tools/getApiSchema.js.map +1 -0
  42. package/dist/mcp/tools/index.d.ts +5 -0
  43. package/dist/mcp/tools/index.js +6 -0
  44. package/dist/mcp/tools/index.js.map +1 -0
  45. package/dist/mcp/tools/listApiEndpoints.d.ts +3 -0
  46. package/dist/mcp/tools/listApiEndpoints.js +55 -0
  47. package/dist/mcp/tools/listApiEndpoints.js.map +1 -0
  48. package/dist/mcp/tools/listApis.d.ts +3 -0
  49. package/dist/mcp/tools/listApis.js +18 -0
  50. package/dist/mcp/tools/listApis.js.map +1 -0
  51. package/dist/mcp/tools/makeEndpointRequest.d.ts +3 -0
  52. package/dist/mcp/tools/makeEndpointRequest.js +63 -0
  53. package/dist/mcp/tools/makeEndpointRequest.js.map +1 -0
  54. package/dist/openapi/endpointIndex.d.ts +6 -0
  55. package/dist/openapi/endpointIndex.js +75 -0
  56. package/dist/openapi/endpointIndex.js.map +1 -0
  57. package/dist/openapi/jsonPointer.d.ts +1 -0
  58. package/dist/openapi/jsonPointer.js +40 -0
  59. package/dist/openapi/jsonPointer.js.map +1 -0
  60. package/dist/openapi/loadSpec.d.ts +2 -0
  61. package/dist/openapi/loadSpec.js +67 -0
  62. package/dist/openapi/loadSpec.js.map +1 -0
  63. package/dist/types.d.ts +98 -0
  64. package/dist/types.js +2 -0
  65. package/dist/types.js.map +1 -0
  66. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andrey Starostin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,247 @@
1
+ # openapi-dynamic-mcp
2
+
3
+ TypeScript MCP stdio server that loads one or more OpenAPI 3.x specs from YAML config and exposes generic tools for API discovery and request execution.
4
+
5
+ ## What It Does
6
+
7
+ - Runs as a single MCP stdio server for multiple APIs.
8
+ - Supports OpenAPI `3.x` local spec files.
9
+ - Exposes generic MCP tools:
10
+ - `list_apis`
11
+ - `list_api_endpoints`
12
+ - `get_api_endpoint`
13
+ - `get_api_schema`
14
+ - `make_endpoint_request`
15
+ - Supports auth:
16
+ - `apiKey`
17
+ - OAuth2 client credentials (`oauth2`)
18
+ - combined OpenAPI security requirements (AND inside object, OR across array)
19
+ - Supports per-API environment overrides for:
20
+ - base URL
21
+ - extra headers
22
+
23
+ ## Requirements
24
+
25
+ - Node.js `20+`
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ npx openapi-dynamic-mcp --config ./examples/config.yaml
31
+ ```
32
+
33
+ ## Client Configuration
34
+
35
+ ### Claude Code
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "openapi": {
41
+ "command": "npx",
42
+ "args": [
43
+ "-y",
44
+ "openapi-dynamic-mcp@latest",
45
+ "--config",
46
+ "/absolute/path/to/config.yaml"
47
+ ],
48
+ "env": {
49
+ "PET_API_BASE_URL": "http://localhost:3000",
50
+ "PET_API_APIKEY_API_KEY": "secret",
51
+ "PET_API_OAUTH2_CLIENT_ID": "client_id",
52
+ "PET_API_OAUTH2_CLIENT_SECRET": "client_secret"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Cursor
60
+
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "openapi": {
65
+ "command": "npx",
66
+ "args": [
67
+ "-y",
68
+ "openapi-dynamic-mcp@latest",
69
+ "--config",
70
+ "/absolute/path/to/config.yaml"
71
+ ],
72
+ "env": {
73
+ "PET_API_BASE_URL": "http://localhost:3000",
74
+ "PET_API_APIKEY_API_KEY": "secret",
75
+ "PET_API_OAUTH2_CLIENT_ID": "client_id",
76
+ "PET_API_OAUTH2_CLIENT_SECRET": "client_secret"
77
+ }
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## Configuration
84
+
85
+ ```yaml
86
+ # Config file version
87
+ version: 1
88
+ apis:
89
+ # Unique ID for this API
90
+ - name: pet-api
91
+ # Path to local OpenAPI spec
92
+ specPath: ./pet-api.yaml
93
+ # Base URL override
94
+ baseUrl: https://api.example.com/v1
95
+ # Request timeout in milliseconds
96
+ timeoutMs: 30000
97
+ headers:
98
+ # Custom headers for all requests
99
+ X-Client: openapi-dynamic-mcp
100
+ # Configuration for exponential retries on 429 Too Many Requests responses
101
+ retry429:
102
+ # Maximum number of retries
103
+ maxRetries: 2
104
+ # Initial retry delay in milliseconds
105
+ baseDelayMs: 250
106
+ # Maximum retry delay in milliseconds
107
+ maxDelayMs: 5000
108
+ # Jitter factor (0-1)
109
+ jitterRatio: 0.2
110
+ # Respect Retry-After header
111
+ respectRetryAfter: true
112
+ # OAuth2 client credentials configuration
113
+ oauth2:
114
+ # Optional token URL override
115
+ tokenUrlOverride: https://auth.example.com/oauth2/token
116
+ # Scopes to request
117
+ scopes: [read:pets, write:pets]
118
+ # How to pass Client Credentials to the token endpoint:
119
+ # Via HTTP Basic Authorization header: "client_secret_basic"
120
+ # Via POST body: "client_secret_post"
121
+ tokenEndpointAuthMethod: client_secret_basic
122
+ ```
123
+
124
+ ### Validation Rules
125
+
126
+ - `apis[].name` must be unique (case-insensitive after normalization).
127
+ - `apis[].specPath` must point to a readable local file.
128
+ - OpenAPI version must be `3.x`.
129
+ - Base URL resolution order: env -> config -> `openapi.servers[0].url`.
130
+
131
+ ## Environment Variables
132
+
133
+ Environment variables allow specifying sensitive or environment-specific configuration for APIs. Variables are defined for each API separately.
134
+
135
+ ### Name Normalization
136
+
137
+ API and auth scheme names are normalized as:
138
+
139
+ - uppercase
140
+ - non-alphanumeric -> `_`
141
+ - repeated `_` collapsed
142
+ - leading/trailing `_` removed
143
+
144
+ Examples:
145
+
146
+ - `pet-api` -> `PET_API`
147
+ - `OAuth2` -> `OAUTH2`
148
+
149
+ ### API-Level Variables
150
+
151
+ - `<API>_BASE_URL` - Overrides the API's base URL.
152
+ - `<API>_HEADERS` (JSON object string) - Adds custom headers to all requests.
153
+
154
+ ### API Key Variables
155
+
156
+ For each API key security scheme defined in the OpenAPI spec, the following environment variables can be set:
157
+
158
+ - `<API>_<SCHEME>_API_KEY` - The API key value for the specified security scheme.
159
+
160
+ ### OAuth2 Client Credentials Variables
161
+
162
+ For each OAuth2 client credentials security scheme defined in the OpenAPI spec, the following environment variables can be set:
163
+
164
+ - `<API>_<SCHEME>_CLIENT_ID` - The client ID for OAuth2.
165
+ - `<API>_<SCHEME>_CLIENT_SECRET` - The client secret for OAuth2.
166
+ - `<API>_<SCHEME>_TOKEN_URL` - The token endpoint URL for OAuth2.
167
+ - `<API>_<SCHEME>_SCOPES` (space-delimited) - The scopes required for the OAuth2 token.
168
+ - `<API>_<SCHEME>_TOKEN_AUTH_METHOD` (`client_secret_basic` or `client_secret_post`) - The authentication method for the token endpoint.
169
+
170
+ ### Precedence
171
+
172
+ - Base URL: env > config > OpenAPI servers.
173
+ - OAuth token URL: scheme env > config override > OpenAPI flow `tokenUrl`.
174
+ - OAuth scopes: scheme env > config scopes > OpenAPI flow scopes.
175
+ - Headers: config headers + env headers + tool-request headers (later wins), then auth is applied.
176
+
177
+ ## MCP Tools
178
+
179
+ ### `list_apis`
180
+
181
+ Returns all available APIs.
182
+
183
+ Input: Nothing
184
+
185
+ ### `list_api_endpoints`
186
+
187
+ Paginate or search through endpoints in a given APIs.
188
+
189
+ Input fields:
190
+
191
+ - required: `apiName`
192
+ - optional: `method`, `tag`, `pathContains`, `search`, `limit`, `cursor`
193
+
194
+ ### `get_api_endpoint`
195
+
196
+ Returns endpoint metadata including parameters, request body content types, responses, and security requirements.
197
+
198
+ Input fields: `apiName`, `endpointId`
199
+
200
+ ### `get_api_schema`
201
+
202
+ Returns the detailed specification of a given schema object.
203
+
204
+ Input fields: `apiName`, optional `pointer` (JSON Pointer)
205
+
206
+ ### `make_endpoint_request`
207
+
208
+ Executes an API endpoint request.
209
+
210
+ Input fields:
211
+
212
+ - `apiName`
213
+ - `endpointId`
214
+ - `pathParams`
215
+ - `query`
216
+ - `headers`
217
+ - `cookies`
218
+ - `body`
219
+ - `contentType`
220
+ - `accept`
221
+ - `timeoutMs`
222
+ - `retry429` object
223
+ - `maxRetries`
224
+ - `baseDelayMs`
225
+ - `maxDelayMs`
226
+ - `jitterRatio` (0..1)
227
+ - `respectRetryAfter`
228
+
229
+ Output includes:
230
+
231
+ - `request` metadata with redacted sensitive headers
232
+ - `response` status, headers, and body
233
+ - `timingMs`
234
+ - `authUsed`
235
+
236
+ ## Development
237
+
238
+ ```bash
239
+ npm test
240
+ npm run build
241
+ ```
242
+
243
+ ## Notes
244
+
245
+ - Supports local OpenAPI files only.
246
+ - 429 retries are supported and disabled by default (`maxRetries: 0`).
247
+ - JSON responses are parsed first; non-JSON is returned as text or base64 binary.
@@ -0,0 +1,14 @@
1
+ export interface OAuthClientCredentialsFromEnv {
2
+ clientId?: string;
3
+ clientSecret?: string;
4
+ tokenUrl?: string;
5
+ scopes?: string[];
6
+ tokenAuthMethod?: "client_secret_basic" | "client_secret_post";
7
+ }
8
+ export declare function normalizeEnvSegment(value: string): string;
9
+ export declare function apiPrefix(apiName: string): string;
10
+ export declare function schemePrefix(apiName: string, schemeName: string): string;
11
+ export declare function readApiBaseUrl(apiName: string, env?: NodeJS.ProcessEnv): string | undefined;
12
+ export declare function readApiExtraHeaders(apiName: string, env?: NodeJS.ProcessEnv): Record<string, string>;
13
+ export declare function readApiKeyValue(apiName: string, schemeName: string, env?: NodeJS.ProcessEnv): string | undefined;
14
+ export declare function readOAuthClientCredentials(apiName: string, schemeName: string, env?: NodeJS.ProcessEnv): OAuthClientCredentialsFromEnv;
@@ -0,0 +1,64 @@
1
+ import { OpenApiMcpError } from "../errors.js";
2
+ export function normalizeEnvSegment(value) {
3
+ return value
4
+ .toUpperCase()
5
+ .replace(/[^A-Z0-9]+/g, "_")
6
+ .replace(/_+/g, "_")
7
+ .replace(/^_+|_+$/g, "");
8
+ }
9
+ export function apiPrefix(apiName) {
10
+ return normalizeEnvSegment(apiName);
11
+ }
12
+ export function schemePrefix(apiName, schemeName) {
13
+ return `${apiPrefix(apiName)}_${normalizeEnvSegment(schemeName)}`;
14
+ }
15
+ export function readApiBaseUrl(apiName, env = process.env) {
16
+ return env[`${apiPrefix(apiName)}_BASE_URL`];
17
+ }
18
+ export function readApiExtraHeaders(apiName, env = process.env) {
19
+ const raw = env[`${apiPrefix(apiName)}_HEADERS`];
20
+ if (!raw) {
21
+ return {};
22
+ }
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(raw);
26
+ }
27
+ catch {
28
+ throw new OpenApiMcpError("CONFIG_ERROR", `Invalid JSON in ${apiPrefix(apiName)}_HEADERS`, { value: raw });
29
+ }
30
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
31
+ throw new OpenApiMcpError("CONFIG_ERROR", `${apiPrefix(apiName)}_HEADERS must be a JSON object`);
32
+ }
33
+ const out = {};
34
+ for (const [key, value] of Object.entries(parsed)) {
35
+ if (typeof value !== "string") {
36
+ throw new OpenApiMcpError("CONFIG_ERROR", `${apiPrefix(apiName)}_HEADERS values must be strings`, { key });
37
+ }
38
+ out[key] = value;
39
+ }
40
+ return out;
41
+ }
42
+ export function readApiKeyValue(apiName, schemeName, env = process.env) {
43
+ return env[`${schemePrefix(apiName, schemeName)}_API_KEY`];
44
+ }
45
+ export function readOAuthClientCredentials(apiName, schemeName, env = process.env) {
46
+ const prefix = schemePrefix(apiName, schemeName);
47
+ const scopesRaw = env[`${prefix}_SCOPES`];
48
+ const tokenAuthMethodRaw = env[`${prefix}_TOKEN_AUTH_METHOD`];
49
+ let tokenAuthMethod;
50
+ if (tokenAuthMethodRaw === "client_secret_basic" || tokenAuthMethodRaw === "client_secret_post") {
51
+ tokenAuthMethod = tokenAuthMethodRaw;
52
+ }
53
+ else if (tokenAuthMethodRaw) {
54
+ throw new OpenApiMcpError("CONFIG_ERROR", `Invalid ${prefix}_TOKEN_AUTH_METHOD value`, { value: tokenAuthMethodRaw });
55
+ }
56
+ return {
57
+ clientId: env[`${prefix}_CLIENT_ID`],
58
+ clientSecret: env[`${prefix}_CLIENT_SECRET`],
59
+ tokenUrl: env[`${prefix}_TOKEN_URL`],
60
+ scopes: scopesRaw ? scopesRaw.split(/\s+/).filter(Boolean) : undefined,
61
+ tokenAuthMethod
62
+ };
63
+ }
64
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/auth/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface OAuthTokenRequest {
2
+ cacheKey: string;
3
+ tokenUrl: string;
4
+ clientId: string;
5
+ clientSecret: string;
6
+ scopes: string[];
7
+ tokenEndpointAuthMethod: "client_secret_basic" | "client_secret_post";
8
+ }
9
+ export declare class OAuthClient {
10
+ private readonly cache;
11
+ getClientCredentialsToken(request: OAuthTokenRequest): Promise<string>;
12
+ }
@@ -0,0 +1,55 @@
1
+ import * as oauth from "oauth4webapi";
2
+ import { OpenApiMcpError } from "../errors.js";
3
+ const TOKEN_EXPIRY_SAFETY_MS = 60_000;
4
+ export class OAuthClient {
5
+ cache = new Map();
6
+ async getClientCredentialsToken(request) {
7
+ const cached = this.cache.get(request.cacheKey);
8
+ if (cached && cached.expiresAtMs - Date.now() > TOKEN_EXPIRY_SAFETY_MS) {
9
+ return cached.accessToken;
10
+ }
11
+ const as = {
12
+ issuer: new URL(request.tokenUrl).origin,
13
+ token_endpoint: request.tokenUrl
14
+ };
15
+ const client = {
16
+ client_id: request.clientId
17
+ };
18
+ const clientAuth = request.tokenEndpointAuthMethod === "client_secret_post"
19
+ ? oauth.ClientSecretPost(request.clientSecret)
20
+ : oauth.ClientSecretBasic(request.clientSecret);
21
+ const parameters = new URLSearchParams();
22
+ if (request.scopes.length > 0) {
23
+ parameters.set("scope", request.scopes.join(" "));
24
+ }
25
+ try {
26
+ const tokenResponse = await oauth.clientCredentialsGrantRequest(as, client, clientAuth, parameters);
27
+ const tokenResult = await oauth.processClientCredentialsResponse(as, client, tokenResponse);
28
+ this.cache.set(request.cacheKey, {
29
+ accessToken: tokenResult.access_token,
30
+ expiresAtMs: Date.now() + Math.max(tokenResult.expires_in ?? 3600, 1) * 1000
31
+ });
32
+ return tokenResult.access_token;
33
+ }
34
+ catch (error) {
35
+ if (error instanceof oauth.ResponseBodyError) {
36
+ throw new OpenApiMcpError("AUTH_ERROR", "OAuth2 token request failed", {
37
+ tokenUrl: request.tokenUrl,
38
+ oauthError: error.cause
39
+ });
40
+ }
41
+ if (error instanceof oauth.OperationProcessingError) {
42
+ throw new OpenApiMcpError("AUTH_ERROR", "OAuth2 operation failed", {
43
+ tokenUrl: request.tokenUrl,
44
+ code: error.code,
45
+ cause: error.message
46
+ });
47
+ }
48
+ throw new OpenApiMcpError("AUTH_ERROR", "OAuth2 token request failed", {
49
+ tokenUrl: request.tokenUrl,
50
+ cause: error instanceof Error ? error.message : String(error)
51
+ });
52
+ }
53
+ }
54
+ }
55
+ //# sourceMappingURL=oauthClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthClient.js","sourceRoot":"","sources":["../../src/auth/oauthClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { OAuthClient } from "./oauthClient.js";
2
+ import type { EndpointDefinition, LoadedApi, ResolvedAuthResult } from "../types.js";
3
+ interface ResolveAuthInput {
4
+ api: LoadedApi;
5
+ endpoint: EndpointDefinition;
6
+ oauthClient: OAuthClient;
7
+ env?: NodeJS.ProcessEnv;
8
+ }
9
+ export declare function resolveAuth({ api, endpoint, oauthClient, env }: ResolveAuthInput): Promise<ResolvedAuthResult>;
10
+ export {};
@@ -0,0 +1,118 @@
1
+ import { readApiKeyValue, readOAuthClientCredentials, schemePrefix } from "./env.js";
2
+ import { OpenApiMcpError } from "../errors.js";
3
+ export async function resolveAuth({ api, endpoint, oauthClient, env = process.env }) {
4
+ const requirements = endpoint.operation.security ?? api.schema.security ?? [];
5
+ if (!requirements || requirements.length === 0) {
6
+ return { authUsed: [], schemes: [] };
7
+ }
8
+ const securitySchemes = api.schema.components?.securitySchemes ?? {};
9
+ const failures = [];
10
+ for (const requirementObject of requirements) {
11
+ if (Object.keys(requirementObject).length === 0) {
12
+ return { authUsed: [], schemes: [] };
13
+ }
14
+ const resolved = [];
15
+ const missingEnv = new Set();
16
+ let failedReason;
17
+ for (const [schemeName, requestedScopes] of Object.entries(requirementObject)) {
18
+ const scheme = securitySchemes[schemeName];
19
+ if (!scheme || "$ref" in scheme) {
20
+ failedReason = `Security scheme '${schemeName}' not found or unresolved`;
21
+ break;
22
+ }
23
+ if (scheme.type === "apiKey") {
24
+ const value = readApiKeyValue(api.config.name, schemeName, env);
25
+ if (!value) {
26
+ missingEnv.add(`${schemePrefix(api.config.name, schemeName)}_API_KEY`);
27
+ failedReason = `Missing API key for scheme '${schemeName}'`;
28
+ break;
29
+ }
30
+ resolved.push({
31
+ type: "apiKey",
32
+ schemeName,
33
+ in: scheme.in,
34
+ name: scheme.name,
35
+ value
36
+ });
37
+ continue;
38
+ }
39
+ if (scheme.type === "oauth2") {
40
+ const flow = scheme.flows.clientCredentials;
41
+ if (!flow) {
42
+ failedReason = `Scheme '${schemeName}' does not support clientCredentials flow`;
43
+ break;
44
+ }
45
+ const fromEnv = readOAuthClientCredentials(api.config.name, schemeName, env);
46
+ const clientId = fromEnv.clientId;
47
+ const clientSecret = fromEnv.clientSecret;
48
+ if (!clientId || !clientSecret) {
49
+ missingEnv.add(`${schemePrefix(api.config.name, schemeName)}_CLIENT_ID`);
50
+ missingEnv.add(`${schemePrefix(api.config.name, schemeName)}_CLIENT_SECRET`);
51
+ failedReason = `Missing OAuth2 client credentials for '${schemeName}'`;
52
+ break;
53
+ }
54
+ const tokenUrl = fromEnv.tokenUrl ?? api.config.oauth2?.tokenUrlOverride ?? flow.tokenUrl;
55
+ if (!tokenUrl) {
56
+ failedReason = `No OAuth2 token URL resolved for scheme '${schemeName}'`;
57
+ break;
58
+ }
59
+ const tokenEndpointAuthMethod = fromEnv.tokenAuthMethod ??
60
+ api.config.oauth2?.tokenEndpointAuthMethod ??
61
+ "client_secret_basic";
62
+ const scopes = resolveScopes(requestedScopes, fromEnv.scopes, api.config.oauth2?.scopes, flow);
63
+ const cacheKey = [
64
+ api.config.name,
65
+ schemeName,
66
+ clientId,
67
+ tokenUrl,
68
+ tokenEndpointAuthMethod,
69
+ scopes.sort().join(",")
70
+ ].join("|");
71
+ const token = await oauthClient.getClientCredentialsToken({
72
+ cacheKey,
73
+ tokenUrl,
74
+ clientId,
75
+ clientSecret,
76
+ scopes,
77
+ tokenEndpointAuthMethod
78
+ });
79
+ resolved.push({
80
+ type: "oauth2",
81
+ schemeName,
82
+ token
83
+ });
84
+ continue;
85
+ }
86
+ failedReason = `Unsupported security scheme type '${scheme.type}' for '${schemeName}'`;
87
+ break;
88
+ }
89
+ if (!failedReason) {
90
+ return {
91
+ authUsed: resolved.map((item) => item.schemeName),
92
+ schemes: resolved
93
+ };
94
+ }
95
+ failures.push({
96
+ requirement: Object.keys(requirementObject),
97
+ reason: failedReason,
98
+ missingEnv: [...missingEnv]
99
+ });
100
+ }
101
+ throw new OpenApiMcpError("AUTH_ERROR", `Could not resolve authentication for '${api.config.name}'`, {
102
+ endpointId: endpoint.endpointId,
103
+ failures
104
+ });
105
+ }
106
+ function resolveScopes(requestedScopes, envScopes, configScopes, flow) {
107
+ if (envScopes && envScopes.length > 0) {
108
+ return envScopes;
109
+ }
110
+ if (configScopes && configScopes.length > 0) {
111
+ return configScopes;
112
+ }
113
+ if (requestedScopes && requestedScopes.length > 0) {
114
+ return requestedScopes;
115
+ }
116
+ return Object.keys(flow.scopes ?? {});
117
+ }
118
+ //# sourceMappingURL=resolveAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveAuth.js","sourceRoot":"","sources":["../../src/auth/resolveAuth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runCli(argv?: string[]): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import { loadConfig } from "./config/loadConfig.js";
3
+ import { OAuthClient } from "./auth/oauthClient.js";
4
+ import { OpenApiMcpError } from "./errors.js";
5
+ import { startMcpServer } from "./mcp/server.js";
6
+ import { loadApiRegistry } from "./openapi/loadSpec.js";
7
+ function parseConfigPath(argv) {
8
+ for (let i = 0; i < argv.length; i += 1) {
9
+ if (argv[i] === "--config") {
10
+ const value = argv[i + 1];
11
+ if (!value) {
12
+ throw new OpenApiMcpError("CONFIG_ERROR", "Missing value for --config");
13
+ }
14
+ return value;
15
+ }
16
+ }
17
+ throw new OpenApiMcpError("CONFIG_ERROR", "Missing required argument --config");
18
+ }
19
+ export async function runCli(argv = process.argv.slice(2)) {
20
+ const configPath = parseConfigPath(argv);
21
+ const config = await loadConfig(configPath);
22
+ const registry = await loadApiRegistry(config, process.env);
23
+ console.error(`[openapi-mcp] loaded ${registry.byName.size} API(s)`);
24
+ for (const api of registry.byName.values()) {
25
+ console.error(`[openapi-mcp] api=${api.config.name} endpoints=${api.endpoints.length} authSchemes=${api.authSchemeNames.join(",")}`);
26
+ }
27
+ await startMcpServer({
28
+ registry,
29
+ oauthClient: new OAuthClient(),
30
+ env: process.env
31
+ });
32
+ }
33
+ runCli().catch((error) => {
34
+ if (error instanceof OpenApiMcpError) {
35
+ console.error(JSON.stringify({
36
+ code: error.code,
37
+ message: error.message,
38
+ details: error.details
39
+ }, null, 2));
40
+ process.exit(1);
41
+ }
42
+ if (error instanceof Error) {
43
+ console.error(error.stack ?? error.message);
44
+ }
45
+ else {
46
+ console.error(String(error));
47
+ }
48
+ process.exit(1);
49
+ });
50
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,eAAe,CAAC,IAAc;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,eAAe,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;YAC1E,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,MAAM,IAAI,eAAe,CAAC,cAAc,EAAE,oCAAoC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAE5D,OAAO,CAAC,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC;IACrE,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,OAAO,CAAC,KAAK,CACX,qBAAqB,GAAG,CAAC,MAAM,CAAC,IAAI,cAAc,GAAG,CAAC,SAAS,CAAC,MAAM,gBAAgB,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACtH,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,CAAC;QACnB,QAAQ;QACR,WAAW,EAAE,IAAI,WAAW,EAAE;QAC9B,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAChC,IAAI,KAAK,YAAY,eAAe,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,CACX,IAAI,CAAC,SAAS,CACZ;YACE,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { RootConfig } from "../types.js";
2
+ export declare function loadConfig(configPath: string): Promise<RootConfig>;