@powerduck/openapi-mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ import { Document, ParameterObject, OperationObject, PathItemObject } from '@scalar/openapi-types/3.2';
2
+ import { Tool, GetPromptResult } from '@modelcontextprotocol/sdk/types.js';
3
+ import { P as ParameterLocation, B as BodyEncoding, G as GeneratedPrompt, a as GeneratedResource, R as ResourceContentItem, E as ExecutionContext, b as ProtocolHint } from './admin-server-B4fQWUnc.js';
4
+ export { A as AdminStatus, c as AppState, d as BODY_ENCODINGS, e as GeneratedTool, L as LOG_DIRECTIONS, f as LOG_LEVELS, g as LogDirection, h as LogLevel, i as LogQueryOptions, j as LogQueryResult, k as LoggedQuery, M as ManagedServiceRecord, l as PARAMETER_LOCATIONS, m as PROTOCOL_HINTS, n as PersistedState, o as PromptMessageShape, p as RequestLogEntry, q as ResolvedPrompt, S as SERVICE_STATUSES, r as SPEC_SOURCES, s as SecurityContext, t as ServerConfig, u as ServiceEndpointInfo, v as ServiceStatus, w as SpecIssue, x as SpecSource, T as TRANSPORT_MODES, y as TransportMode, z as isBodyEncoding, C as isParameterLocation, D as isPlainRecord, F as isProtocolHint, H as isServiceStatus, I as isSpecSource, J as startAdminServer } from './admin-server-B4fQWUnc.js';
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import express, { RequestHandler } from 'express';
7
+ import 'node:http';
8
+
9
+ declare function loadOpenApiSpec(filePath: string): Promise<Document>;
10
+ declare function parseSpecContent(rawText: string, isYaml: boolean): Promise<Document>;
11
+
12
+ /**
13
+ * A parameter validated to carry the fields this library relies on.
14
+ *
15
+ * The upstream `ParameterObject` type is a union (schema form vs. content
16
+ * form), so it is normalized into a single permissive shape after runtime
17
+ * validation.
18
+ */
19
+ interface NormalizedParameter {
20
+ name: string;
21
+ in: ParameterLocation;
22
+ required: boolean;
23
+ description?: string | undefined;
24
+ deprecated?: boolean | undefined;
25
+ style?: string | undefined;
26
+ explode?: boolean | undefined;
27
+ allowReserved?: boolean | undefined;
28
+ allowEmptyValue?: boolean | undefined;
29
+ /** Present when the parameter uses the `schema` form. */
30
+ schema?: Record<string, unknown> | undefined;
31
+ /** Present when the parameter uses the `content` form. */
32
+ content?: Record<string, unknown> | undefined;
33
+ /** Media type selected from `content`, when the content form is used. */
34
+ contentMediaType?: string | undefined;
35
+ /** True when the transport owns this value and it must not be exposed. */
36
+ reserved?: boolean | undefined;
37
+ /** The original object, kept for callers that need untouched data. */
38
+ raw: ParameterObject;
39
+ }
40
+ /** A single resolved operation together with its owning path item. */
41
+ interface ResolvedOperation {
42
+ path: string;
43
+ /**
44
+ * Lower-cased HTTP method. Normally a {@link HttpMethod}, but may be any
45
+ * token when it originates from the OpenAPI 3.2 `additionalOperations` map.
46
+ */
47
+ method: string;
48
+ operation: OperationObject;
49
+ pathItem: PathItemObject;
50
+ /** Guaranteed non-empty and unique across the document. */
51
+ operationId: string;
52
+ /** True when the id was synthesized because the document omitted it. */
53
+ operationIdGenerated: boolean;
54
+ /** False when the method came from `additionalOperations`. */
55
+ isStandardMethod: boolean;
56
+ }
57
+ /**
58
+ * Public alias kept for library consumers. `ResolvedOperation` is the internal
59
+ * name; both refer to the exact same shape.
60
+ */
61
+ type OperationEntry = ResolvedOperation;
62
+ /** Codes attached to non-fatal problems found while walking a document. */
63
+ type SpecWalkIssueCode = "invalid-paths-object" | "invalid-path-template" | "invalid-path-item" | "invalid-operation" | "invalid-parameter" | "unsupported-parameter-location" | "reserved-parameter" | "unresolved-ref" | "duplicate-operation-id" | "generated-operation-id" | "truncated-operation-id";
64
+ /** Non-fatal issues collected while walking the document. */
65
+ interface SpecWalkIssue {
66
+ path: string;
67
+ method?: string | undefined;
68
+ code: SpecWalkIssueCode;
69
+ message: string;
70
+ }
71
+ /**
72
+ * Extracts the `{name}` template variables from a path template.
73
+ * Duplicates are collapsed; order follows first appearance.
74
+ */
75
+ declare function extractPathTemplateVariables(pathTemplate: string): string[];
76
+ /**
77
+ * Normalizes a raw parameter entry. Returns null when the entry is unusable,
78
+ * which happens for unresolved references, missing `name` / `in`, unsupported
79
+ * locations, or a malformed schema/content combination.
80
+ */
81
+ declare function normalizeParameter(candidate: unknown): NormalizedParameter | null;
82
+ /**
83
+ * Effective style for a parameter, applying the defaults mandated by the spec
84
+ * when the document does not state one explicitly.
85
+ */
86
+ declare function effectiveStyle(parameter: NormalizedParameter): string;
87
+ /** Effective explode flag. The spec default is true only when style is `form`. */
88
+ declare function effectiveExplode(parameter: NormalizedParameter): boolean;
89
+ /**
90
+ * Merges path-item level parameters with operation level parameters.
91
+ *
92
+ * Per the specification the merge key is the pair (name, in), and an operation
93
+ * level entry overrides an inherited one. Entries that cannot be normalized are
94
+ * dropped and reported through `issues` instead of silently corrupting output.
95
+ */
96
+ declare function collectOperationParameters(pathItem: PathItemObject | undefined, operation: OperationObject | undefined, issues?: SpecWalkIssue[], context?: {
97
+ path: string;
98
+ method: string;
99
+ }): NormalizedParameter[];
100
+ /**
101
+ * Builds a deterministic, identifier-safe fallback name for an operation that
102
+ * omits `operationId`. The result is stable across runs for the same document,
103
+ * which matters because tool names are persisted by clients.
104
+ */
105
+ declare function synthesizeOperationId(method: string, pathTemplate: string): string;
106
+ /**
107
+ * Ensures a candidate name is unique within `taken` by appending a numeric
108
+ * suffix, and registers the result. The original name is returned untouched
109
+ * when it is already free.
110
+ */
111
+ declare function ensureUniqueName(candidate: string, taken: Set<string>): string;
112
+ /**
113
+ * Walks every operation in the document.
114
+ *
115
+ * Guarantees for consumers:
116
+ * - only operation keys are yielded, never path item metadata;
117
+ * - OpenAPI 3.2 `additionalOperations` entries are included, flagged via
118
+ * `isStandardMethod: false`;
119
+ * - malformed path items and operations are skipped, never thrown on;
120
+ * - `operationId` is always a non-empty string, unique across the document,
121
+ * and no longer than {@link MAX_GENERATED_NAME_LENGTH}.
122
+ *
123
+ * Non-fatal problems are appended to `issues` when the caller supplies an array.
124
+ */
125
+ declare function iterateOperations(spec: Document | null | undefined, issues?: SpecWalkIssue[]): Generator<ResolvedOperation>;
126
+ /**
127
+ * Locates an operation by id, in O(1) after the first call.
128
+ *
129
+ * The effective id produced by {@link iterateOperations} always wins, because
130
+ * that is the name the tool generator exposes and therefore the only value a
131
+ * client can legitimately send. A declared id is consulted only as a fallback,
132
+ * and only when it is unambiguous — otherwise a document mixing declared and
133
+ * synthesized ids could route a call to the wrong endpoint without any error.
134
+ *
135
+ * Returns null instead of throwing: an unknown id is a caller-level condition
136
+ * (bad tool name), not a malformed document.
137
+ */
138
+ declare function findOperationById(spec: Document | null | undefined, operationId: string): OperationEntry | null;
139
+ /** Describes one operationId claimed by more than one operation. */
140
+ interface DuplicateOperationId {
141
+ operationId: string;
142
+ occurrences: Array<{
143
+ method: string;
144
+ path: string;
145
+ }>;
146
+ }
147
+ /**
148
+ * Reports every operationId declared more than once. Synthesized ids are
149
+ * excluded because they are derived from method + path and are unique by
150
+ * construction; only author-declared ids can collide.
151
+ *
152
+ * This is a validation helper, not part of the generation path — tool naming
153
+ * already de-duplicates via {@link ensureUniqueName}, so a duplicate id
154
+ * degrades the tool names rather than breaking the server. Use it to warn the
155
+ * operator.
156
+ */
157
+ declare function findDuplicateOperationIds(spec: Document | null | undefined): DuplicateOperationId[];
158
+ /**
159
+ * Throws when the document declares the same operationId twice. Kept as a
160
+ * separate strict entry point so library consumers can choose between failing
161
+ * fast at load time and merely surfacing a warning.
162
+ */
163
+ declare function assertUniqueOperationIds(spec: Document | null | undefined): void;
164
+
165
+ interface ArgumentBinding {
166
+ key: string;
167
+ name: string;
168
+ in: "path" | "query" | "header" | "cookie";
169
+ parameter: NormalizedParameter;
170
+ }
171
+ interface OmittedParameter {
172
+ name: string;
173
+ in: string;
174
+ reason: string;
175
+ }
176
+ interface ToolBinding {
177
+ toolName: string;
178
+ path: string;
179
+ pathItem: PathItemObject;
180
+ method: string;
181
+ isStandardMethod: boolean;
182
+ operation: OperationObject;
183
+ arguments: ArgumentBinding[];
184
+ bodyKey: string | null;
185
+ bodyEncoding: BodyEncoding | null;
186
+ bodyMediaType: string | null;
187
+ bodyRequired: boolean;
188
+ omittedParameters: OmittedParameter[];
189
+ fullySupported: boolean;
190
+ degradationReasons: string[];
191
+ usageNotes: string[];
192
+ }
193
+ interface GeneratedTool {
194
+ tool: Tool;
195
+ binding: ToolBinding;
196
+ }
197
+ interface GenerateToolsResult {
198
+ tools: Tool[];
199
+ bindings: ToolBinding[];
200
+ issues: SpecWalkIssue[];
201
+ }
202
+ declare function generateToolsDetailed(spec: Document | null | undefined): GenerateToolsResult;
203
+ declare function generateTools(spec: Document | null | undefined): Tool[];
204
+ declare function getBindingIndex(spec: Document | null | undefined): Map<string, ToolBinding>;
205
+ declare const buildBindingIndex: typeof getBindingIndex;
206
+
207
+ /** List every prompt exposed for the given specification. */
208
+ declare function generatePrompts(spec: Document): GeneratedPrompt[];
209
+ /**
210
+ * Resolve a prompt by name. Returns null when the prompt is unknown so the
211
+ * transport layer can answer with the correct JSON-RPC error.
212
+ */
213
+ declare function resolvePrompt(spec: Document, name: string, args?: Record<string, unknown>): GetPromptResult | null;
214
+
215
+ declare function generateResources(spec: Document): GeneratedResource[];
216
+ declare function readResource(spec: Document, uri: string): ResourceContentItem | null;
217
+
218
+ interface ToolCallResult {
219
+ status: number;
220
+ statusText: string;
221
+ headers: Record<string, unknown>;
222
+ data: unknown;
223
+ truncated: boolean;
224
+ url: string;
225
+ method: string;
226
+ durationMs: number;
227
+ /** Ties the request and response log entries together. */
228
+ correlationId: string;
229
+ }
230
+ /**
231
+ * Executes one generated tool against the upstream API.
232
+ *
233
+ * A non-2xx upstream response is returned as data rather than thrown: the model
234
+ * must be able to read the status and body to decide what to do next. Only
235
+ * transport-level failures throw.
236
+ */
237
+ declare function executeToolCall(spec: Document, toolName: string, args: Record<string, unknown> | undefined, context?: ExecutionContext): Promise<ToolCallResult>;
238
+
239
+ /** A parameter or argument that was deliberately not sent, with the reason. */
240
+ interface DroppedArgument {
241
+ key: string;
242
+ reason: string;
243
+ }
244
+ interface BuiltRequest {
245
+ /**
246
+ * Absolute URL without a query string. The query is kept separate so the
247
+ * executor can log it in a structured form and so encoding happens exactly
248
+ * once, inside `query`.
249
+ */
250
+ url: string;
251
+ /**
252
+ * Fully-formed query parameters. `URLSearchParams` is the only shape that can
253
+ * represent the repeated keys produced by an exploded array — the default for
254
+ * query parameters — and it applies percent-encoding once on `toString()`.
255
+ */
256
+ query: URLSearchParams;
257
+ headers: Record<string, string>;
258
+ body: unknown;
259
+ /** Reported so the executor can surface silently ignored arguments in a log. */
260
+ dropped: DroppedArgument[];
261
+ }
262
+ declare function buildRequest(baseUrl: string, templatePath: string, pathItem: PathItemObject, operation: OperationObject, args: Record<string, unknown>, binding?: ToolBinding): BuiltRequest;
263
+
264
+ /** Returns the active document, or null when no service is running. */
265
+ type SpecProvider = () => Document | null;
266
+ /** Returns the upstream execution context for the current call. */
267
+ type ContextProvider = () => ExecutionContext;
268
+ interface BuildMcpServerOptions {
269
+ protocol?: ProtocolHint | undefined;
270
+ /** Advertised server name. Clients may display this to end users. */
271
+ name?: string | undefined;
272
+ /** Advertised server version. */
273
+ version?: string | undefined;
274
+ /**
275
+ * Maximum entries returned by a single list request. Large documents must be
276
+ * paginated, otherwise a single response can exceed what the transport (and
277
+ * some clients) will accept.
278
+ */
279
+ pageSize?: number | undefined;
280
+ /** Human-readable usage hint surfaced through `instructions`. */
281
+ instructions?: string | undefined;
282
+ }
283
+ /**
284
+ * Builds one MCP server instance.
285
+ *
286
+ * A fresh instance is created per transport session so that per-session state
287
+ * (client capabilities, negotiated protocol version, in-flight requests) is
288
+ * never shared. The document itself is read through `specProvider` on every
289
+ * request rather than captured, so a session always reflects the currently
290
+ * running service instead of a stale snapshot.
291
+ */
292
+ declare function buildMcpServer(specProvider: SpecProvider, contextProvider?: ContextProvider, options?: BuildMcpServerOptions): Server<{
293
+ method: string;
294
+ params?: {
295
+ [x: string]: unknown;
296
+ _meta?: {
297
+ [x: string]: unknown;
298
+ progressToken?: string | number | undefined;
299
+ "io.modelcontextprotocol/related-task"?: {
300
+ taskId: string;
301
+ } | undefined;
302
+ } | undefined;
303
+ } | undefined;
304
+ }, {
305
+ method: string;
306
+ params?: {
307
+ [x: string]: unknown;
308
+ _meta?: {
309
+ [x: string]: unknown;
310
+ progressToken?: string | number | undefined;
311
+ "io.modelcontextprotocol/related-task"?: {
312
+ taskId: string;
313
+ } | undefined;
314
+ } | undefined;
315
+ } | undefined;
316
+ }, {
317
+ [x: string]: unknown;
318
+ _meta?: {
319
+ [x: string]: unknown;
320
+ progressToken?: string | number | undefined;
321
+ "io.modelcontextprotocol/related-task"?: {
322
+ taskId: string;
323
+ } | undefined;
324
+ } | undefined;
325
+ }>;
326
+
327
+ interface StdioServerHandle {
328
+ /** Resolves when the peer closes stdin or {@link close} is called. */
329
+ closed: Promise<void>;
330
+ close(): Promise<void>;
331
+ }
332
+ interface StartStdioServerOptions {
333
+ /**
334
+ * Install process signal handlers so the transport is shut down cleanly.
335
+ * Defaults to true, which is what a CLI entry point wants; a host embedding
336
+ * this in a larger process should pass false and drive `close()` itself.
337
+ */
338
+ handleSignals?: boolean;
339
+ }
340
+ /**
341
+ * Serves a single specification over stdio.
342
+ *
343
+ * The specification is captured once: unlike the HTTP transports there is no
344
+ * admin surface able to swap it, and a stdio client holds exactly one session
345
+ * whose tool list it caches after `initialize`.
346
+ */
347
+ declare function startStdioServer(spec: Document, context?: ExecutionContext, options?: StartStdioServerOptions): Promise<StdioServerHandle>;
348
+
349
+ /**
350
+ * Backwards-compatible alias for the previous export name.
351
+ *
352
+ * @deprecated Use {@link attachMcpRoutes}. This wrapper keeps the old
353
+ * positional signature working but no longer serves the legacy SSE stream at
354
+ * `GET /mcp`, because that path now belongs to the Streamable HTTP transport.
355
+ * It also drops the sweeper handle, so callers cannot fully shut down; migrate.
356
+ */
357
+ declare function attachSseRoutes(app: express.Express, specProvider: SpecProvider, contextProvider: ContextProvider, routeGuard?: express.RequestHandler): {
358
+ activeSessionCount: () => number;
359
+ closeAll: () => Promise<void>;
360
+ };
361
+
362
+ /**
363
+ * Guards the admin API with a shared secret.
364
+ *
365
+ * Passing `undefined` disables the guard, which is the documented default for
366
+ * loopback-only use. An empty or whitespace-only string is rejected instead of
367
+ * being treated as "disabled": that case almost always means an environment
368
+ * variable was set but never populated, and silently serving an unprotected
369
+ * admin API to an operator who believes it is locked down is the worst possible
370
+ * outcome.
371
+ */
372
+ declare function createAuthMiddleware(apiKey?: string): RequestHandler;
373
+
374
+ export { BodyEncoding, type ContextProvider, type DuplicateOperationId, ExecutionContext, GeneratedPrompt, GeneratedResource, type GeneratedTool as GeneratedToolWithBinding, type OperationEntry, ParameterLocation, ProtocolHint, ResourceContentItem, type SpecProvider, type ToolBinding, assertUniqueOperationIds, attachSseRoutes, buildBindingIndex, buildMcpServer, buildRequest, collectOperationParameters, createAuthMiddleware, effectiveExplode, effectiveStyle, ensureUniqueName, executeToolCall, extractPathTemplateVariables, findDuplicateOperationIds, findOperationById, generatePrompts, generateResources, generateTools, generateToolsDetailed, iterateOperations, loadOpenApiSpec, normalizeParameter, parseSpecContent, readResource, resolvePrompt, startStdioServer, synthesizeOperationId };