swagger-digest 0.1.1 → 0.2.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/LICENSE +2 -2
- package/README.md +135 -1
- package/dist/chunk-2NORV6KM.js +143 -0
- package/dist/{chunk-UZQM2SHL.js → chunk-U7OLLL6J.js} +1313 -517
- package/dist/cli.js +90 -8
- package/dist/index.d.ts +107 -5
- package/dist/index.js +9 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +16 -0
- package/package.json +14 -13
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 VladLegkowski
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -25,8 +25,99 @@ For a direct spec URL:
|
|
|
25
25
|
npx swagger-digest --url https://example.com/openapi.yaml --out-dir ./docs
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
If the Swagger UI initializer lists several spec definitions (`urls: [{ url, name }, …]`), the tool probes them in the order they appear and uses the first one that parses, printing a notice to stderr naming the pick and the alternatives. To choose a specific spec yourself, pass it explicitly:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx swagger-digest --url https://api.example.com/swagger-ui \
|
|
32
|
+
--spec https://api.example.com/v2/tenant-a.json --out-dir ./docs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--spec` overrides all discovery: the given URL is fetched directly (with the same header scoping and size limits) and the Swagger UI page is never consulted when it parses successfully.
|
|
36
|
+
|
|
37
|
+
### Writing to stdout
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx swagger-digest --url https://petstore.swagger.io/ --stdout > petstore.md
|
|
41
|
+
npx swagger-digest --url https://api.example.com/openapi.json --stdout | pbcopy
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`--stdout` prints the digest to standard output instead of saving a file — handy for piping into other tools or copying to the clipboard. Progress and warnings go to stderr, so the pipe receives only the Markdown. `--stdout` cannot be combined with `--out-dir` or `--filename`; the CLI exits with a clear error if you try.
|
|
45
|
+
|
|
28
46
|
Run `npx swagger-digest --help` for all CLI options. The package requires Node.js 20 or newer.
|
|
29
47
|
|
|
48
|
+
## MCP server
|
|
49
|
+
|
|
50
|
+
The package ships an [MCP](https://modelcontextprotocol.io) server exposing the same pipeline as a tool for AI agents, so they can fetch and digest API docs on their own instead of being handed a Markdown file.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx swagger-digest-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
It speaks the stdio transport: the MCP client spawns the process and communicates over stdin/stdout. Register it in your client's configuration:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcp": {
|
|
61
|
+
"swagger-digest": {
|
|
62
|
+
"command": ["npx", "-y", "swagger-digest-mcp"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### The `swagger_digest` tool
|
|
69
|
+
|
|
70
|
+
| Argument | Type | Description |
|
|
71
|
+
| --------------- | ---------------- | -------------------------------------------------------------------------- |
|
|
72
|
+
| `url` | string, required | Swagger UI page URL or direct OpenAPI spec URL |
|
|
73
|
+
| `spec_url` | string, optional | Explicit spec URL; overrides discovery from the page |
|
|
74
|
+
| `headers` | object, optional | Request headers (e.g. `Authorization`); sent only to the origin of `url` |
|
|
75
|
+
| `include_tags` | string[] | Keep only operations with these tags |
|
|
76
|
+
| `exclude_tags` | string[] | Drop operations with these tags |
|
|
77
|
+
| `path_prefix` | string | Keep only paths starting with this prefix |
|
|
78
|
+
| `max_tokens` | number | Trim the digest to an approximate token budget |
|
|
79
|
+
| `write_to_file` | object, optional | `{ directory, filename }` — save the digest instead of returning it inline |
|
|
80
|
+
|
|
81
|
+
By default the digest is returned directly in the tool result (so it lands in the agent's context), with a metadata footer: retrieval method, operation/model counts, and a token estimate.
|
|
82
|
+
|
|
83
|
+
### Environment variables
|
|
84
|
+
|
|
85
|
+
- `SWAGGER_DIGEST_HEADER` — newline-separated `Name: value` pairs, merged with (and overridden by) the tool call's `headers` argument. Keeps secrets out of the conversation.
|
|
86
|
+
- `SWAGGER_DIGEST_ALLOW_PRIVATE=1` — opt out of the private-network guard (see below).
|
|
87
|
+
|
|
88
|
+
### Security differences from the CLI
|
|
89
|
+
|
|
90
|
+
- **SSRF guard on by default:** URLs resolving to loopback, private, or link-local (cloud metadata) addresses are rejected, because MCP clients supply URLs on the model's behalf. Opt out with `SWAGGER_DIGEST_ALLOW_PRIVATE=1` — for example to digest an internal corporate API — only if you trust the hosts involved.
|
|
91
|
+
- **No headless-browser fallback:** the optional Playwright fallback is disabled in the MCP server.
|
|
92
|
+
- Diagnostics go to stderr only; stdout carries protocol frames exclusively.
|
|
93
|
+
|
|
94
|
+
### Filtering and token budget
|
|
95
|
+
|
|
96
|
+
Large specs produce large digests. The CLI can remove whole operations before rendering and/or trim the remaining digest to an approximate token budget:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Keep only operations tagged "Payments", plus everything under /invoices
|
|
100
|
+
npx swagger-digest --url https://api.example.com/openapi.json \
|
|
101
|
+
--include-tag Payments --path-prefix /payments/ --out-dir ./docs
|
|
102
|
+
|
|
103
|
+
# Drop a noisy tag
|
|
104
|
+
npx swagger-digest --url https://api.example.com/openapi.json --exclude-tag Internal
|
|
105
|
+
|
|
106
|
+
# Fit the digest into a model's context window
|
|
107
|
+
npx swagger-digest --url https://api.example.com/openapi.json --max-tokens 50000
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
How `--max-tokens` trims (in this fixed order, re-checked against the estimate after each step):
|
|
111
|
+
|
|
112
|
+
1. Drop declared example payloads (synthetic examples are never emitted).
|
|
113
|
+
2. Shorten long descriptions.
|
|
114
|
+
3. Collapse parameter/response detail per tag — the **tag priority rule** is that the tag appearing **last in the document** is collapsed first (lowest priority), one tag per step.
|
|
115
|
+
4. Keep only the Quick index entries (no endpoint detail, no data types).
|
|
116
|
+
|
|
117
|
+
A `## Trimmed` note at the end of the digest records exactly which steps were applied. After every step, schemas that became unreachable (referenced only by collapsed/removed operations) are dropped from the Data types section. The token estimator is a heuristic, **not** a real tokenizer — treat `--max-tokens` as a guide, not a guarantee. Unknown tag names passed to `--include-tag`/`--exclude-tag` produce a warning on stderr listing the tags that exist in the spec.
|
|
118
|
+
|
|
119
|
+
The same options are available programmatically via the third argument of `transformOpenApiToMarkdown(spec, sourceUrl, { includeTags, excludeTags, pathPrefix, maxTokens, onWarning })`.
|
|
120
|
+
|
|
30
121
|
## What it extracts
|
|
31
122
|
|
|
32
123
|
The retrieval strategy deliberately avoids scraping rendered operation accordions or simulating UI clicks:
|
|
@@ -45,6 +136,37 @@ npx playwright install chromium
|
|
|
45
136
|
|
|
46
137
|
Then run the CLI again. Use `--no-browser` to disable the fallback.
|
|
47
138
|
|
|
139
|
+
### Authentication headers
|
|
140
|
+
|
|
141
|
+
Some Swagger UI pages and spec URLs live behind authentication. Pass custom headers with `-H`/`--header` (repeatable) or `--cookie`:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx swagger-digest \
|
|
145
|
+
--url https://api.example.com/swagger-ui \
|
|
146
|
+
--header "Authorization: Bearer eyJhbGciOi..." \
|
|
147
|
+
--out-dir ./docs
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or with a session cookie:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx swagger-digest --url https://api.example.com/swagger-ui --cookie "session=abc123"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
You can also supply headers through the `SWAGGER_DIGEST_HEADER` environment variable, with one `Name: value` pair per line. `-H` flags override environment entries on conflicting header names:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
export SWAGGER_DIGEST_HEADER=$'Authorization: Bearer eyJ…\nX-Tenant: acme'
|
|
160
|
+
npx swagger-digest --url https://api.example.com/swagger-ui
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Scoping and safety:**
|
|
164
|
+
|
|
165
|
+
- Custom headers are sent **only** to the origin of the URL you supply. If the discovered spec, a redirect, or a Swagger UI script lives on a different origin, that request is made without your headers and a warning naming the other origin is printed to stderr.
|
|
166
|
+
- In the headless-browser fallback, headers are injected per-request (only for your origin) — they never reach CDNs or third-party scripts loaded by the page.
|
|
167
|
+
- Header values are never logged, written to the digest, or included in error messages.
|
|
168
|
+
- ⚠️ **Shell history:** secrets passed with `-H` can end up in your shell history file (`~/.bash_history`, `~/.zsh_history`). Prefer the `SWAGGER_DIGEST_HEADER` environment variable, or prefix the command with a space if your shell is configured to ignore leading-space entries.
|
|
169
|
+
|
|
48
170
|
### Troubleshooting access through a VPN
|
|
49
171
|
|
|
50
172
|
The ordinary HTTP fetches use Node.js networking; they do not automatically reuse a browser's VPN extension, cookies, or signed-in session. If the Swagger page works in Chrome but not in the CLI, first test the same URL from the terminal:
|
|
@@ -55,6 +177,14 @@ curl -v -L 'https://your-host.example/path/to/swagger-ui' -o /tmp/swagger-page.h
|
|
|
55
177
|
|
|
56
178
|
If `curl` cannot connect or receives `401`/`403`, connect a system-level VPN that also routes terminal applications, or configure the relevant corporate proxy/authentication for the terminal. Installing Playwright alone does not make a browser-only VPN extension available to its separate Chromium instance. If terminal access succeeds, the extractor now also reads same-origin Swagger UI initializer/config scripts and tries spec paths relative to the supplied page's context path.
|
|
57
179
|
|
|
180
|
+
## Security notes
|
|
181
|
+
|
|
182
|
+
**What the tool fetches:** the URL you supply (a Swagger UI page or direct OpenAPI JSON/YAML URL), same-origin Swagger UI initializer/config scripts, the spec URL referenced by that page, and a short list of common spec paths on the same origin (`/v3/api-docs`, `/swagger.json`, …). The optional Playwright fallback loads the same page in a headless browser.
|
|
183
|
+
|
|
184
|
+
**What it does not forward:** cookies or Authorization headers are never sent automatically. Custom headers you pass with `--header`/`--cookie` (see below) are sent **only** to the origin of the URL you supplied. If the page redirects to another origin, or the discovered spec lives on a different origin, those requests are made without your headers and a warning naming the other origin is printed to stderr. Response bodies are capped (10 MB by default, configurable with `--max-bytes`), and redirects are followed at most 5 times.
|
|
185
|
+
|
|
186
|
+
**Embedding in a server:** if you call `fetchOpenApiSpec` from a server that accepts user-supplied URLs, enable `blockPrivateNetworks: true` in the fetch options. Without it, a caller can point the tool at `http://169.254.169.254/…` or other internal addresses from your infrastructure (SSRF). The check rejects loopback, link-local (including the cloud-metadata address 169.254.169.254), private, and unique-local addresses, and applies after redirects. Note the documented DNS-rebinding limitation in the code — for hostile multi-tenant input, use a dedicated egress proxy.
|
|
187
|
+
|
|
58
188
|
## Markdown format
|
|
59
189
|
|
|
60
190
|
The generated document includes:
|
|
@@ -95,12 +225,16 @@ src/
|
|
|
95
225
|
transformer.ts OpenAPI/Swagger to compact Markdown and TypeScript-like types
|
|
96
226
|
writer.ts Output path, filename defaults and file writing
|
|
97
227
|
index.ts Public exports
|
|
228
|
+
mcp/
|
|
229
|
+
index.ts MCP stdio entry point (`swagger-digest-mcp` bin)
|
|
230
|
+
server.ts MCP server and tool registration (transport-agnostic)
|
|
231
|
+
digest.ts Tool handler: fetch → transform → tool result
|
|
98
232
|
```
|
|
99
233
|
|
|
100
234
|
## Limitations
|
|
101
235
|
|
|
102
236
|
- The tool downloads specs exposed by the supplied server. It does not bypass authentication, browser access controls, or network restrictions.
|
|
103
|
-
- External
|
|
237
|
+
- External `$ref` documents are bundled best-effort: references to other HTTP(S) documents are fetched (one level deep, at most 5 documents) and their schemas inlined under namespaced names such as `meta_SharedMeta`. If an external document is unreachable or unparsable, the reference degrades to a named type reference and the digest still succeeds.
|
|
104
238
|
- Declared request/response examples are preserved. When an example is absent but a schema exists, a representative JSON example is generated from that schema and clearly marked as illustrative rather than spec-authored. The transformer includes the primary success response and applicable common error responses to balance useful payload context against digest size.
|
|
105
239
|
- A generated digest is a compact developer reference, not a replacement for the source OpenAPI contract.
|
|
106
240
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERSION,
|
|
3
|
+
estimateTokens,
|
|
4
|
+
fetchOpenApiSpec,
|
|
5
|
+
mergeHeaders,
|
|
6
|
+
parseHeaderPairs,
|
|
7
|
+
transformOpenApiToMarkdown,
|
|
8
|
+
writeDigest
|
|
9
|
+
} from "./chunk-U7OLLL6J.js";
|
|
10
|
+
|
|
11
|
+
// src/mcp/digest.ts
|
|
12
|
+
var TOKEN_HINT_THRESHOLD = 8e4;
|
|
13
|
+
function textContent(text) {
|
|
14
|
+
return [{ type: "text", text }];
|
|
15
|
+
}
|
|
16
|
+
function asError(message) {
|
|
17
|
+
return { content: textContent(message), isError: true };
|
|
18
|
+
}
|
|
19
|
+
function isHttpUrl(value) {
|
|
20
|
+
try {
|
|
21
|
+
const url = new URL(value);
|
|
22
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function countDigestOperations(markdown) {
|
|
28
|
+
return (markdown.match(/^\| \*\*(?:GET|PUT|POST|DELETE|OPTIONS|HEAD|PATCH|TRACE)\*\* \|/gm) ?? []).length;
|
|
29
|
+
}
|
|
30
|
+
function countDigestModels(markdown) {
|
|
31
|
+
return (markdown.match(/^export (?:interface|type) \w+/gm) ?? []).length;
|
|
32
|
+
}
|
|
33
|
+
function buildRequestHeaders(args) {
|
|
34
|
+
const fromEnv = process.env.SWAGGER_DIGEST_HEADER ? parseHeaderPairs(process.env.SWAGGER_DIGEST_HEADER) : {};
|
|
35
|
+
return mergeHeaders(fromEnv, args.headers);
|
|
36
|
+
}
|
|
37
|
+
async function runSwaggerDigest(args, options = {}) {
|
|
38
|
+
if (!isHttpUrl(args.url)) {
|
|
39
|
+
return asError(`Invalid url "${args.url}": use an http:// or https:// URL.`);
|
|
40
|
+
}
|
|
41
|
+
if (args.spec_url !== void 0 && !isHttpUrl(args.spec_url)) {
|
|
42
|
+
return asError(`Invalid spec_url "${args.spec_url}": use an http:// or https:// URL.`);
|
|
43
|
+
}
|
|
44
|
+
if (args.max_tokens !== void 0 && (!Number.isInteger(args.max_tokens) || args.max_tokens <= 0)) {
|
|
45
|
+
return asError(`Invalid max_tokens ${args.max_tokens}: use a positive integer.`);
|
|
46
|
+
}
|
|
47
|
+
const blockPrivateNetworks = options.blockPrivateNetworks ?? process.env.SWAGGER_DIGEST_ALLOW_PRIVATE !== "1";
|
|
48
|
+
const warnings = [];
|
|
49
|
+
const warn = (message) => {
|
|
50
|
+
warnings.push(message);
|
|
51
|
+
};
|
|
52
|
+
let fetchResult;
|
|
53
|
+
try {
|
|
54
|
+
const fetchOptions = {
|
|
55
|
+
useBrowserFallback: false,
|
|
56
|
+
maxBytes: 1e7,
|
|
57
|
+
headers: buildRequestHeaders(args),
|
|
58
|
+
specUrl: args.spec_url,
|
|
59
|
+
blockPrivateNetworks,
|
|
60
|
+
warn
|
|
61
|
+
};
|
|
62
|
+
fetchResult = await fetchOpenApiSpec(args.url, fetchOptions);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
+
return asError(`Could not extract an OpenAPI definition from ${args.url}: ${message}`);
|
|
66
|
+
}
|
|
67
|
+
const markdown = transformOpenApiToMarkdown(fetchResult.spec, fetchResult.sourceUrl, {
|
|
68
|
+
includeTags: args.include_tags,
|
|
69
|
+
excludeTags: args.exclude_tags,
|
|
70
|
+
pathPrefix: args.path_prefix,
|
|
71
|
+
maxTokens: args.max_tokens,
|
|
72
|
+
onWarning: warn
|
|
73
|
+
});
|
|
74
|
+
const operationCount = countDigestOperations(markdown);
|
|
75
|
+
const modelCount = countDigestModels(markdown);
|
|
76
|
+
const tokens = estimateTokens(markdown).models.claude.tokens;
|
|
77
|
+
const metadata = [
|
|
78
|
+
`source: ${fetchResult.sourceUrl} (via ${fetchResult.retrievalMethod})`,
|
|
79
|
+
`${operationCount} operation${operationCount === 1 ? "" : "s"}`,
|
|
80
|
+
`${modelCount} data model${modelCount === 1 ? "" : "s"}`,
|
|
81
|
+
`~${tokens.toLocaleString("en-US")} tokens estimated`
|
|
82
|
+
].join(" \xB7 ");
|
|
83
|
+
const warningBlock = warnings.length > 0 ? `
|
|
84
|
+
|
|
85
|
+
_Warnings:_
|
|
86
|
+
${warnings.map((w) => `- ${w}`).join("\n")}` : "";
|
|
87
|
+
const budgetHint = tokens > TOKEN_HINT_THRESHOLD && args.max_tokens === void 0 ? "\n\n_This digest is large. Consider re-running with max_tokens, include_tags, exclude_tags or path_prefix to fit it into context._" : "";
|
|
88
|
+
if (args.write_to_file) {
|
|
89
|
+
try {
|
|
90
|
+
const outputPath = await writeDigest({
|
|
91
|
+
markdown,
|
|
92
|
+
directory: args.write_to_file.directory,
|
|
93
|
+
filename: args.write_to_file.filename
|
|
94
|
+
});
|
|
95
|
+
return { content: textContent(`Digest written to ${outputPath}
|
|
96
|
+
|
|
97
|
+
_${metadata}_${warningBlock}`) };
|
|
98
|
+
} catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
return asError(`Could not write digest: ${message}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { content: textContent(`${markdown}
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
_Digest metadata: ${metadata}_${warningBlock}${budgetHint}`) };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/mcp/server.ts
|
|
110
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
111
|
+
import { z } from "zod";
|
|
112
|
+
function createMcpServer(options = {}) {
|
|
113
|
+
const server = new McpServer({ name: "swagger-digest", version: VERSION });
|
|
114
|
+
server.registerTool(
|
|
115
|
+
"swagger_digest",
|
|
116
|
+
{
|
|
117
|
+
title: "Generate API digest",
|
|
118
|
+
description: "Fetch a Swagger UI page or an OpenAPI/Swagger spec (JSON or YAML, versions 2.0/3.0/3.1) and convert it into a compact Markdown API reference optimized for LLM context: endpoint index, request/response details, authentication schemes, and TypeScript-like data types. Handles Swagger UI discovery automatically (initializer scripts, multi-spec dropdowns, common spec paths). Use this whenever the user asks to understand, summarize, or work against an API documented with Swagger/OpenAPI.",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
url: z.string().describe("Swagger UI page URL or direct OpenAPI spec URL (http/https)"),
|
|
121
|
+
spec_url: z.string().optional().describe("Explicit OpenAPI spec URL; overrides discovery from the Swagger UI page"),
|
|
122
|
+
headers: z.record(z.string(), z.string()).optional().describe(
|
|
123
|
+
"Request headers (e.g. Authorization or Cookie). Sent ONLY to the origin of url; cross-origin requests never receive them. Values are not logged."
|
|
124
|
+
),
|
|
125
|
+
include_tags: z.array(z.string()).optional().describe("Keep only operations carrying at least one of these tags"),
|
|
126
|
+
exclude_tags: z.array(z.string()).optional().describe("Drop operations carrying any of these tags"),
|
|
127
|
+
path_prefix: z.string().optional().describe("Keep only operations whose path starts with this prefix"),
|
|
128
|
+
max_tokens: z.number().int().positive().optional().describe(
|
|
129
|
+
"Trim the digest until an approximate token estimate fits this budget (heuristic, not tokenizer-accurate)"
|
|
130
|
+
),
|
|
131
|
+
write_to_file: z.object({ directory: z.string(), filename: z.string() }).optional().describe("Save the digest to a file instead of returning it inline")
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
(args) => runSwaggerDigest(args, options)
|
|
135
|
+
);
|
|
136
|
+
return server;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
buildRequestHeaders,
|
|
141
|
+
runSwaggerDigest,
|
|
142
|
+
createMcpServer
|
|
143
|
+
};
|