zudoku 0.83.1 → 0.84.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/dist/cli/cli.js +72 -19
- package/dist/cli/worker.js +1 -0
- package/dist/declarations/app/notFoundRoute.d.ts +2 -0
- package/dist/declarations/config/validators/ZudokuConfig.d.ts +8 -0
- package/dist/declarations/lib/components/context/RenderContext.d.ts +3 -0
- package/dist/declarations/lib/plugins/api-catalog/index.d.ts +1 -0
- package/dist/declarations/lib/plugins/openapi/MCPEndpoint.d.ts +2 -1
- package/dist/declarations/lib/plugins/openapi/McpCatalog.d.ts +5 -0
- package/dist/declarations/lib/plugins/openapi/components/SelectOnClick.d.ts +2 -1
- package/dist/declarations/lib/plugins/openapi/graphql/gql.d.ts +1 -0
- package/dist/declarations/lib/plugins/openapi/graphql/graphql.d.ts +26 -0
- package/dist/declarations/lib/plugins/openapi/index.d.ts +1 -1
- package/dist/declarations/lib/plugins/openapi/interfaces.d.ts +5 -0
- package/dist/declarations/lib/plugins/openapi/mcp-configs.d.ts +14 -0
- package/dist/declarations/lib/plugins/openapi/util/documentType.d.ts +8 -0
- package/dist/declarations/lib/plugins/openapi/util/getRoutes.d.ts +1 -1
- package/dist/declarations/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.d.ts +1 -0
- package/dist/flat-config.d.ts +1 -0
- package/docs/configuration/api-reference.md +7 -0
- package/docs/guides/mcp-servers.md +33 -0
- package/docs/openapi-extensions/x-mcp-server.md +9 -0
- package/docs/openapi-extensions/x-zudoku-type.md +80 -0
- package/package.json +1 -1
- package/src/app/main.tsx +2 -1
- package/src/app/notFoundRoute.tsx +21 -0
- package/src/config/validators/ZudokuConfig.ts +1 -0
- package/src/lib/components/context/RenderContext.ts +10 -0
- package/src/lib/core/RouteGuard.tsx +6 -3
- package/src/lib/plugins/api-catalog/Catalog.tsx +1 -1
- package/src/lib/plugins/api-catalog/index.tsx +3 -0
- package/src/lib/plugins/openapi/MCPEndpoint.tsx +6 -4
- package/src/lib/plugins/openapi/McpCatalog.tsx +467 -0
- package/src/lib/plugins/openapi/OperationListItem.tsx +5 -1
- package/src/lib/plugins/openapi/components/SelectOnClick.tsx +16 -0
- package/src/lib/plugins/openapi/graphql/gql.ts +9 -0
- package/src/lib/plugins/openapi/graphql/graphql.ts +51 -0
- package/src/lib/plugins/openapi/index.tsx +6 -1
- package/src/lib/plugins/openapi/interfaces.ts +14 -0
- package/src/lib/plugins/openapi/mcp-configs.ts +73 -0
- package/src/lib/plugins/openapi/util/documentType.ts +59 -0
- package/src/lib/plugins/openapi/util/getRoutes.tsx +29 -1
- package/src/lib/plugins/openapi/util/sanitizeMarkdownForMetatag.tsx +18 -6
- package/src/vite/plugin-api.ts +100 -23
package/dist/cli/cli.js
CHANGED
|
@@ -3152,6 +3152,7 @@ var ApiOptionsSchema = z7.object({
|
|
|
3152
3152
|
expandAllTags: z7.boolean(),
|
|
3153
3153
|
showInfoPage: z7.boolean(),
|
|
3154
3154
|
disableSecurity: z7.boolean(),
|
|
3155
|
+
disableMcpAuthInstructions: z7.boolean(),
|
|
3155
3156
|
schemaDownload: z7.object({
|
|
3156
3157
|
enabled: z7.boolean(),
|
|
3157
3158
|
fileName: z7.string().regex(/^[A-Za-z0-9_-]+$/).optional()
|
|
@@ -4178,6 +4179,7 @@ import fs2 from "node:fs/promises";
|
|
|
4178
4179
|
import path12 from "node:path";
|
|
4179
4180
|
import { deepEqual as deepEqual2 } from "fast-equals";
|
|
4180
4181
|
import { runnerImport as runnerImport3 } from "vite";
|
|
4182
|
+
import { parse as parseYaml } from "yaml";
|
|
4181
4183
|
|
|
4182
4184
|
// src/config/validators/BuildSchema.ts
|
|
4183
4185
|
import path7 from "node:path";
|
|
@@ -5365,6 +5367,34 @@ builder.queryType({
|
|
|
5365
5367
|
var schema = builder.toSchema();
|
|
5366
5368
|
var createGraphQLServer = (options) => createYoga({ schema, batching: true, ...options });
|
|
5367
5369
|
|
|
5370
|
+
// src/lib/plugins/openapi/interfaces.ts
|
|
5371
|
+
var DOCUMENT_TYPE_EXTENSION = "x-zudoku-type";
|
|
5372
|
+
var MCP_CATALOG = "mcp-catalog";
|
|
5373
|
+
|
|
5374
|
+
// src/lib/plugins/openapi/util/documentType.ts
|
|
5375
|
+
var MCP_SERVER_EXTENSION = "x-mcp-server";
|
|
5376
|
+
var HTTP_METHODS = [
|
|
5377
|
+
"get",
|
|
5378
|
+
"post",
|
|
5379
|
+
"put",
|
|
5380
|
+
"patch",
|
|
5381
|
+
"delete",
|
|
5382
|
+
"options",
|
|
5383
|
+
"head",
|
|
5384
|
+
"trace"
|
|
5385
|
+
];
|
|
5386
|
+
var httpMethods = new Set(HTTP_METHODS);
|
|
5387
|
+
var KNOWN_DOCUMENT_TYPES = [MCP_CATALOG];
|
|
5388
|
+
var readDocumentType = (schema2) => schema2[DOCUMENT_TYPE_EXTENSION];
|
|
5389
|
+
var isKnownDocumentType = (value) => typeof value === "string" && KNOWN_DOCUMENT_TYPES.includes(value);
|
|
5390
|
+
var operationsOf = (schema2) => Object.values(schema2.paths ?? {}).flatMap(
|
|
5391
|
+
(pathItem) => pathItem && typeof pathItem === "object" ? Object.entries(pathItem).filter(([method]) => httpMethods.has(method.toLowerCase())).map(([, operation]) => operation) : []
|
|
5392
|
+
);
|
|
5393
|
+
var countOperations = (schema2) => operationsOf(schema2).length;
|
|
5394
|
+
var countMcpServers = (schema2) => operationsOf(schema2).filter(
|
|
5395
|
+
(operation) => !!operation && typeof operation === "object" && MCP_SERVER_EXTENSION in operation
|
|
5396
|
+
).length;
|
|
5397
|
+
|
|
5368
5398
|
// src/lib/util/ensureArray.ts
|
|
5369
5399
|
var ensureArray = (value) => Array.isArray(value) ? value : [value];
|
|
5370
5400
|
|
|
@@ -6067,6 +6097,25 @@ var viteConfigReloadPlugin = () => ({
|
|
|
6067
6097
|
|
|
6068
6098
|
// src/vite/plugin-api.ts
|
|
6069
6099
|
var PROCESSED_STORE_SUBPATH = "node_modules/.zudoku/processed";
|
|
6100
|
+
var warn = (message) => {
|
|
6101
|
+
console.warn(`[zudoku] ${message}`);
|
|
6102
|
+
};
|
|
6103
|
+
var resolveDocumentType = (schema2, apiPath = "<unknown>") => {
|
|
6104
|
+
const value = readDocumentType(schema2);
|
|
6105
|
+
if (value === void 0) return void 0;
|
|
6106
|
+
if (isKnownDocumentType(value)) return value;
|
|
6107
|
+
warn(
|
|
6108
|
+
`Unknown "x-zudoku-type" value ${JSON.stringify(value)} in "${apiPath}". Rendering the default API view.`
|
|
6109
|
+
);
|
|
6110
|
+
return void 0;
|
|
6111
|
+
};
|
|
6112
|
+
var resolveRawDocumentType = (input, apiPath = "<unknown>") => {
|
|
6113
|
+
try {
|
|
6114
|
+
return resolveDocumentType(parseYaml(input), apiPath);
|
|
6115
|
+
} catch {
|
|
6116
|
+
return void 0;
|
|
6117
|
+
}
|
|
6118
|
+
};
|
|
6070
6119
|
var viteApiPlugin = async () => {
|
|
6071
6120
|
const virtualModuleId4 = "virtual:zudoku-api-plugins";
|
|
6072
6121
|
const resolvedVirtualModuleId4 = `\0${virtualModuleId4}`;
|
|
@@ -6167,28 +6216,12 @@ var viteApiPlugin = async () => {
|
|
|
6167
6216
|
);
|
|
6168
6217
|
const apis = ensureArray(config.apis);
|
|
6169
6218
|
const apiMetadata = [];
|
|
6170
|
-
const httpMethods = /* @__PURE__ */ new Set([
|
|
6171
|
-
"get",
|
|
6172
|
-
"post",
|
|
6173
|
-
"put",
|
|
6174
|
-
"patch",
|
|
6175
|
-
"delete",
|
|
6176
|
-
"options",
|
|
6177
|
-
"head",
|
|
6178
|
-
"trace"
|
|
6179
|
-
]);
|
|
6180
6219
|
for (const apiConfig of apis) {
|
|
6181
6220
|
if (apiConfig.type === "file" && apiConfig.path) {
|
|
6182
6221
|
const latestSchema = schemaManager.getLatestSchema(apiConfig.path);
|
|
6183
6222
|
if (!latestSchema?.schema.info) continue;
|
|
6184
|
-
const
|
|
6185
|
-
|
|
6186
|
-
).reduce((sum, pathItem) => {
|
|
6187
|
-
if (!pathItem || typeof pathItem !== "object") return sum;
|
|
6188
|
-
return sum + Object.keys(pathItem).filter(
|
|
6189
|
-
(m) => httpMethods.has(m.toLowerCase())
|
|
6190
|
-
).length;
|
|
6191
|
-
}, 0);
|
|
6223
|
+
const isCatalog = resolveDocumentType(latestSchema.schema, apiConfig.path) === MCP_CATALOG;
|
|
6224
|
+
const operationCount = isCatalog ? countMcpServers(latestSchema.schema) : countOperations(latestSchema.schema);
|
|
6192
6225
|
const rawVersion = latestSchema.schema.info.version;
|
|
6193
6226
|
const version = rawVersion ? rawVersion.startsWith("v") || rawVersion.startsWith("V") ? rawVersion : `v${rawVersion}` : void 0;
|
|
6194
6227
|
apiMetadata.push({
|
|
@@ -6197,7 +6230,8 @@ var viteApiPlugin = async () => {
|
|
|
6197
6230
|
description: latestSchema.schema.info.description ?? "",
|
|
6198
6231
|
categories: apiConfig.categories ?? [],
|
|
6199
6232
|
version,
|
|
6200
|
-
operationCount
|
|
6233
|
+
operationCount,
|
|
6234
|
+
countLabel: isCatalog ? operationCount === 1 ? "server" : "servers" : void 0
|
|
6201
6235
|
});
|
|
6202
6236
|
}
|
|
6203
6237
|
}
|
|
@@ -6228,18 +6262,34 @@ var viteApiPlugin = async () => {
|
|
|
6228
6262
|
});
|
|
6229
6263
|
const tags = Array.from(allSlugs);
|
|
6230
6264
|
const schemaImports = schemaManager.getSchemaImports();
|
|
6265
|
+
const latest = schemas.at(0);
|
|
6266
|
+
const documentType = latest ? resolveDocumentType(latest.schema, apiConfig.path) : void 0;
|
|
6267
|
+
if (documentType === MCP_CATALOG) {
|
|
6268
|
+
if (schemas.length > 1) {
|
|
6269
|
+
warn(
|
|
6270
|
+
`"${apiConfig.path}" is an MCP catalog with ${schemas.length} versions. Only the latest is rendered; catalog documents do not support version switching.`
|
|
6271
|
+
);
|
|
6272
|
+
}
|
|
6273
|
+
if (latest && countMcpServers(latest.schema) === 0) {
|
|
6274
|
+
warn(
|
|
6275
|
+
`"${apiConfig.path}" is marked as an MCP catalog but has no operations with "x-mcp-server". The catalog will render empty.`
|
|
6276
|
+
);
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6231
6279
|
code.push(
|
|
6232
6280
|
"configuredApiPlugins.push(openApiPlugin({",
|
|
6233
6281
|
` type: "file",`,
|
|
6234
6282
|
` input: ${JSON.stringify(versionedInput)},`,
|
|
6235
6283
|
` path: ${JSON.stringify(apiConfig.path)},`,
|
|
6236
6284
|
` tagPages: ${JSON.stringify(tags)},`,
|
|
6285
|
+
...documentType ? [` documentType: ${JSON.stringify(documentType)},`] : [],
|
|
6237
6286
|
` options: {`,
|
|
6238
6287
|
` examplesLanguage: config.defaults?.apis?.examplesLanguage ?? config.defaults?.examplesLanguage,`,
|
|
6239
6288
|
` supportedLanguages: config.defaults?.apis?.supportedLanguages,`,
|
|
6240
6289
|
` disablePlayground: config.defaults?.apis?.disablePlayground,`,
|
|
6241
6290
|
` disableSidecar: config.defaults?.apis?.disableSidecar,`,
|
|
6242
6291
|
` disableSecurity: config.defaults?.apis?.disableSecurity ?? true,`,
|
|
6292
|
+
` disableMcpAuthInstructions: config.defaults?.apis?.disableMcpAuthInstructions,`,
|
|
6243
6293
|
` showVersionSelect: config.defaults?.apis?.showVersionSelect ?? "if-available",`,
|
|
6244
6294
|
` expandAllTags: config.defaults?.apis?.expandAllTags ?? true,`,
|
|
6245
6295
|
` showInfoPage: config.defaults?.apis?.showInfoPage,`,
|
|
@@ -6256,15 +6306,18 @@ var viteApiPlugin = async () => {
|
|
|
6256
6306
|
"}));"
|
|
6257
6307
|
);
|
|
6258
6308
|
} else {
|
|
6309
|
+
const documentType = apiConfig.type === "raw" ? resolveRawDocumentType(apiConfig.input, apiConfig.path) : void 0;
|
|
6259
6310
|
code.push(
|
|
6260
6311
|
"configuredApiPlugins.push(openApiPlugin({",
|
|
6261
6312
|
` ...${JSON.stringify(apiConfig)},`,
|
|
6313
|
+
...documentType ? [` documentType: ${JSON.stringify(documentType)},`] : [],
|
|
6262
6314
|
" options: {",
|
|
6263
6315
|
` examplesLanguage: config.defaults?.apis?.examplesLanguage ?? config.defaults?.examplesLanguage,`,
|
|
6264
6316
|
` supportedLanguages: config.defaults?.apis?.supportedLanguages,`,
|
|
6265
6317
|
` disablePlayground: config.defaults?.apis?.disablePlayground,`,
|
|
6266
6318
|
` disableSidecar: config.defaults?.apis?.disableSidecar,`,
|
|
6267
6319
|
` disableSecurity: config.defaults?.apis?.disableSecurity ?? true,`,
|
|
6320
|
+
` disableMcpAuthInstructions: config.defaults?.apis?.disableMcpAuthInstructions,`,
|
|
6268
6321
|
` showVersionSelect: config.defaults?.apis?.showVersionSelect ?? "if-available",`,
|
|
6269
6322
|
` expandAllTags: config.defaults?.apis?.expandAllTags ?? false,`,
|
|
6270
6323
|
` showInfoPage: config.defaults?.apis?.showInfoPage,`,
|
package/dist/cli/worker.js
CHANGED
|
@@ -2386,6 +2386,7 @@ var ApiOptionsSchema = z4.object({
|
|
|
2386
2386
|
expandAllTags: z4.boolean(),
|
|
2387
2387
|
showInfoPage: z4.boolean(),
|
|
2388
2388
|
disableSecurity: z4.boolean(),
|
|
2389
|
+
disableMcpAuthInstructions: z4.boolean(),
|
|
2389
2390
|
schemaDownload: z4.object({
|
|
2390
2391
|
enabled: z4.boolean(),
|
|
2391
2392
|
fileName: z4.string().regex(/^[A-Za-z0-9_-]+$/).optional()
|
|
@@ -57,6 +57,7 @@ declare const ApiOptionsSchema: z.ZodObject<{
|
|
|
57
57
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
58
58
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
59
59
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
60
61
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
61
62
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
62
63
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7297,6 +7298,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7297
7298
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7298
7299
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7299
7300
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7301
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7300
7302
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7301
7303
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7302
7304
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7333,6 +7335,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7333
7335
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7334
7336
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7335
7337
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7338
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7336
7339
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7337
7340
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7338
7341
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7369,6 +7372,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7369
7372
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7370
7373
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7371
7374
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7375
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7372
7376
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7373
7377
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7374
7378
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7401,6 +7405,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7401
7405
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7402
7406
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7403
7407
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7408
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7404
7409
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7405
7410
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7406
7411
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7437,6 +7442,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7437
7442
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7438
7443
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7439
7444
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7445
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7440
7446
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7441
7447
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7442
7448
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7473,6 +7479,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7473
7479
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7474
7480
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7475
7481
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7482
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7476
7483
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7477
7484
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7478
7485
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -7574,6 +7581,7 @@ export declare const ZudokuConfig: z.ZodObject<{
|
|
|
7574
7581
|
expandAllTags: z.ZodOptional<z.ZodBoolean>;
|
|
7575
7582
|
showInfoPage: z.ZodOptional<z.ZodBoolean>;
|
|
7576
7583
|
disableSecurity: z.ZodOptional<z.ZodBoolean>;
|
|
7584
|
+
disableMcpAuthInstructions: z.ZodOptional<z.ZodBoolean>;
|
|
7577
7585
|
schemaDownload: z.ZodOptional<z.ZodObject<{
|
|
7578
7586
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
7579
7587
|
fileName: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
@@ -9,3 +9,6 @@ export type RenderContextValue = {
|
|
|
9
9
|
ssrAuth?: SSRAuthState;
|
|
10
10
|
};
|
|
11
11
|
export declare const RenderContext: import("react").Context<RenderContextValue>;
|
|
12
|
+
export declare const setSsrStatus: (renderContext: RenderContextValue, status: number, { onlyIfUnset }?: {
|
|
13
|
+
onlyIfUnset?: boolean;
|
|
14
|
+
}) => void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type McpServerData } from "./mcp-configs.js";
|
|
2
|
-
export declare const MCPEndpoint: ({ serverUrl, operationPath, summary, data, }: {
|
|
2
|
+
export declare const MCPEndpoint: ({ serverUrl, operationPath, summary, data, disableAuthInstructions, }: {
|
|
3
3
|
serverUrl?: string;
|
|
4
4
|
operationPath?: string;
|
|
5
5
|
data?: McpServerData;
|
|
6
6
|
summary?: string;
|
|
7
|
+
disableAuthInstructions?: boolean;
|
|
7
8
|
}) => import("react").JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const GetMcpCatalogQuery: import("./graphql/graphql.js").TypedDocumentString<import("./graphql/graphql.js").GetMcpCatalogQuery, {
|
|
2
|
+
input: any;
|
|
3
|
+
type: import("./graphql/graphql.js").SchemaType;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const McpCatalog: () => import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SlotProps } from "@radix-ui/react-slot";
|
|
2
|
-
export declare const SelectOnClick: ({ asChild, onClick, enabled, ...props }: {
|
|
2
|
+
export declare const SelectOnClick: ({ asChild, onClick, copyValue, enabled, ...props }: {
|
|
3
3
|
asChild?: boolean;
|
|
4
4
|
enabled?: boolean;
|
|
5
|
+
copyValue?: string;
|
|
5
6
|
} & SlotProps) => import("react").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function graphql(source: "\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n"): typeof import("./graphql.js").ServersQueryDocument;
|
|
2
|
+
export declare function graphql(source: "\n query GetMcpCatalog($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n title\n description\n tags {\n name\n slug\n operations {\n slug\n summary\n description\n operationId\n path\n extensions\n servers {\n url\n }\n }\n }\n }\n }\n"): typeof import("./graphql.js").GetMcpCatalogDocument;
|
|
2
3
|
export declare function graphql(source: "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n servers {\n url\n description\n }\n parameters {\n name\n in\n description\n required\n schema\n style\n explode\n allowReserved\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n security {\n schemes {\n scopes\n scheme {\n name\n type\n description\n in\n paramName\n scheme\n bearerFormat\n openIdConnectUrl\n flows {\n implicit {\n authorizationUrl\n scopes {\n name\n description\n }\n }\n password {\n tokenUrl\n scopes {\n name\n description\n }\n }\n clientCredentials {\n tokenUrl\n scopes {\n name\n description\n }\n }\n authorizationCode {\n authorizationUrl\n tokenUrl\n scopes {\n name\n description\n }\n }\n }\n }\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n"): typeof import("./graphql.js").OperationsFragmentFragmentDoc;
|
|
3
4
|
export declare function graphql(source: "\n query OperationsForTag(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n servers {\n url\n }\n description\n summary\n title\n url\n version\n tag(slug: $tag, untagged: $untagged) {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n extensions\n next {\n name\n slug\n extensions\n }\n prev {\n name\n slug\n extensions\n }\n }\n }\n }\n"): typeof import("./graphql.js").OperationsForTagDocument;
|
|
4
5
|
export declare function graphql(source: "\n query SchemaInfo($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n servers {\n url\n description\n }\n license {\n name\n url\n identifier\n }\n termsOfService\n externalDocs {\n description\n url\n }\n contact {\n name\n url\n email\n }\n description\n summary\n title\n url\n version\n tags {\n name\n description\n extensions\n }\n components {\n securitySchemes {\n name\n type\n description\n in\n paramName\n scheme\n bearerFormat\n openIdConnectUrl\n flows {\n implicit {\n authorizationUrl\n scopes {\n name\n description\n }\n }\n password {\n tokenUrl\n scopes {\n name\n description\n }\n }\n clientCredentials {\n tokenUrl\n scopes {\n name\n description\n }\n }\n authorizationCode {\n authorizationUrl\n tokenUrl\n scopes {\n name\n description\n }\n }\n }\n }\n }\n webhooks {\n name\n method\n summary\n description\n }\n }\n }\n"): typeof import("./graphql.js").SchemaInfoDocument;
|
|
@@ -23,6 +23,31 @@ export type ServersQueryQuery = {
|
|
|
23
23
|
}>;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
+
export type GetMcpCatalogQueryVariables = Exact<{
|
|
27
|
+
input: any;
|
|
28
|
+
type: SchemaType;
|
|
29
|
+
}>;
|
|
30
|
+
export type GetMcpCatalogQuery = {
|
|
31
|
+
schema: {
|
|
32
|
+
title: string;
|
|
33
|
+
description: string | null;
|
|
34
|
+
tags: Array<{
|
|
35
|
+
name: string | null;
|
|
36
|
+
slug: string | null;
|
|
37
|
+
operations: Array<{
|
|
38
|
+
slug: string;
|
|
39
|
+
summary: string | null;
|
|
40
|
+
description: string | null;
|
|
41
|
+
operationId: string | null;
|
|
42
|
+
path: string;
|
|
43
|
+
extensions: any;
|
|
44
|
+
servers: Array<{
|
|
45
|
+
url: string;
|
|
46
|
+
}>;
|
|
47
|
+
}>;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
26
51
|
export type OperationsFragmentFragment = {
|
|
27
52
|
slug: string;
|
|
28
53
|
summary: string | null;
|
|
@@ -342,6 +367,7 @@ export declare class TypedDocumentString<TResult, TVariables> extends String imp
|
|
|
342
367
|
}
|
|
343
368
|
export declare const OperationsFragmentFragmentDoc: TypedDocumentString<OperationsFragmentFragment, unknown>;
|
|
344
369
|
export declare const ServersQueryDocument: TypedDocumentString<ServersQueryQuery, ServersQueryQueryVariables>;
|
|
370
|
+
export declare const GetMcpCatalogDocument: TypedDocumentString<GetMcpCatalogQuery, GetMcpCatalogQueryVariables>;
|
|
345
371
|
export declare const OperationsForTagDocument: TypedDocumentString<OperationsForTagQuery, OperationsForTagQueryVariables>;
|
|
346
372
|
export declare const SchemaInfoDocument: TypedDocumentString<SchemaInfoQuery, SchemaInfoQueryVariables>;
|
|
347
373
|
export declare const GetSchemasDocument: TypedDocumentString<GetSchemasQuery, GetSchemasQueryVariables>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ZudokuPlugin } from "../../core/plugins.js";
|
|
2
2
|
import type { GetNavigationOperationsQuery as GetNavigationOperationsQueryResult } from "./graphql/graphql.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type OasPluginConfig } from "./interfaces.js";
|
|
4
4
|
export declare const GetNavigationOperationsQuery: import("./graphql/graphql.js").TypedDocumentString<GetNavigationOperationsQueryResult, {
|
|
5
5
|
input: any;
|
|
6
6
|
type: import("./graphql/graphql.js").SchemaType;
|
|
@@ -58,12 +58,16 @@ export type GenerateCodeSnippetFn = (options: {
|
|
|
58
58
|
example?: any | null;
|
|
59
59
|
resolvedAuth?: ResolvedAuth;
|
|
60
60
|
}) => string | false;
|
|
61
|
+
export declare const DOCUMENT_TYPE_EXTENSION = "x-zudoku-type";
|
|
62
|
+
export declare const MCP_CATALOG = "mcp-catalog";
|
|
63
|
+
export type OasDocumentType = typeof MCP_CATALOG;
|
|
61
64
|
type BaseOasConfig = {
|
|
62
65
|
server?: string;
|
|
63
66
|
path?: string;
|
|
64
67
|
skipPreload?: boolean;
|
|
65
68
|
tagPages?: Array<string>;
|
|
66
69
|
schemaImports?: SchemaImports;
|
|
70
|
+
documentType?: OasDocumentType;
|
|
67
71
|
options?: {
|
|
68
72
|
examplesLanguage?: string;
|
|
69
73
|
supportedLanguages?: {
|
|
@@ -73,6 +77,7 @@ type BaseOasConfig = {
|
|
|
73
77
|
disablePlayground?: boolean;
|
|
74
78
|
disableSidecar?: boolean;
|
|
75
79
|
disableSecurity?: boolean;
|
|
80
|
+
disableMcpAuthInstructions?: boolean;
|
|
76
81
|
showVersionSelect?: "always" | "if-available" | "hide";
|
|
77
82
|
expandAllTags?: boolean;
|
|
78
83
|
showInfoPage?: boolean;
|
|
@@ -6,6 +6,12 @@ export interface AuthHeader {
|
|
|
6
6
|
export type AuthType = "none" | "apiKey" | "oauth";
|
|
7
7
|
export declare const getAuthType: (data?: McpServerData) => AuthType;
|
|
8
8
|
export declare const getAuthHeader: (data?: McpServerData) => AuthHeader | undefined;
|
|
9
|
+
export declare const resolveMcpAuth: (data?: McpServerData, options?: {
|
|
10
|
+
disableAuthInstructions?: boolean;
|
|
11
|
+
}) => {
|
|
12
|
+
authType: AuthType;
|
|
13
|
+
auth?: AuthHeader;
|
|
14
|
+
};
|
|
9
15
|
export interface McpSubApp {
|
|
10
16
|
id: string;
|
|
11
17
|
label: string;
|
|
@@ -19,6 +25,14 @@ export interface McpApp {
|
|
|
19
25
|
export declare const MCP_APPS: McpApp[];
|
|
20
26
|
export declare const getVisibleApps: (authType: AuthType) => McpApp[];
|
|
21
27
|
export declare const getMcpServerName: (data?: McpServerData, summary?: string) => string;
|
|
28
|
+
export type McpTool = {
|
|
29
|
+
name: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
};
|
|
32
|
+
export declare const isMcpServerObject: (data?: McpServerData) => data is Record<string, unknown>;
|
|
33
|
+
export declare const isMcpServerData: (value: unknown) => value is McpServerData;
|
|
34
|
+
export declare const getMcpServerTitle: (data?: McpServerData, summary?: string | null, operationId?: string | null) => string;
|
|
35
|
+
export declare const getMcpTools: (data?: McpServerData) => McpTool[];
|
|
22
36
|
export declare const getMcpUrl: (serverUrl?: string, operationPath?: string, data?: McpServerData) => string;
|
|
23
37
|
export declare const getClaudeCodeCommand: (name: string, mcpUrl: string, auth?: AuthHeader) => string;
|
|
24
38
|
export declare const getCodexCliCommand: (name: string, mcpUrl: string, auth?: AuthHeader) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OpenAPIDocument } from "../../../oas/parser/index.js";
|
|
2
|
+
import { type OasDocumentType } from "../interfaces.js";
|
|
3
|
+
export declare const MCP_SERVER_EXTENSION = "x-mcp-server";
|
|
4
|
+
export declare const HTTP_METHODS: readonly ["get", "post", "put", "patch", "delete", "options", "head", "trace"];
|
|
5
|
+
export declare const readDocumentType: (schema: OpenAPIDocument) => unknown;
|
|
6
|
+
export declare const isKnownDocumentType: (value: unknown) => value is OasDocumentType;
|
|
7
|
+
export declare const countOperations: (schema: OpenAPIDocument) => number;
|
|
8
|
+
export declare const countMcpServers: (schema: OpenAPIDocument) => number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type RouteObject } from "react-router";
|
|
2
2
|
import type { GraphQLClient } from "../client/GraphQLClient.js";
|
|
3
3
|
import { type OpenApiPluginOptions } from "../index.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type OasPluginConfig, type VersionEntry } from "../interfaces.js";
|
|
5
5
|
export declare const getVersionMetadata: (config: OasPluginConfig) => {
|
|
6
6
|
versions: string[];
|
|
7
7
|
versionMap: Record<string, {
|
package/dist/flat-config.d.ts
CHANGED
|
@@ -207,6 +207,7 @@ const config = {
|
|
|
207
207
|
disablePlayground: false, // Disable the interactive API playground
|
|
208
208
|
disableSidecar: false, // Disable the sidecar completely
|
|
209
209
|
disableSecurity: true, // Disable security scheme display and playground auth (default)
|
|
210
|
+
disableMcpAuthInstructions: false, // Hide auth steps in the MCP server card
|
|
210
211
|
showVersionSelect: "if-available", // Control version selector visibility
|
|
211
212
|
expandAllTags: true, // Control initial expanded state of tag categories
|
|
212
213
|
showInfoPage: true, // Always show the info page (unset = show only if a description is set)
|
|
@@ -229,6 +230,11 @@ Available options:
|
|
|
229
230
|
- `disableSecurity`: Disable OpenAPI security scheme display (auth badges on operations, security
|
|
230
231
|
schemes section on the info page, and the Authorize dialog in the playground). Disabled by default
|
|
231
232
|
(`true`). Set to `false` to enable security scheme support
|
|
233
|
+
- `disableMcpAuthInstructions`: Hide the authentication instructions on
|
|
234
|
+
[MCP server](../guides/mcp-servers.md) endpoints. The MCP card normally derives a credential
|
|
235
|
+
header from the operation's security scheme and shows it in every install snippet. Set to `true`
|
|
236
|
+
to render the server as unauthenticated instead — no header snippets and no "replace
|
|
237
|
+
`YOUR_API_KEY`" steps
|
|
232
238
|
- `showVersionSelect`: Control version selector visibility
|
|
233
239
|
- `"if-available"`: Show version selector only when multiple versions exist (default)
|
|
234
240
|
- `"always"`: Always show version selector (disabled if only one version)
|
|
@@ -260,6 +266,7 @@ const config = {
|
|
|
260
266
|
disablePlayground: false, // Disable the interactive API playground
|
|
261
267
|
disableSidecar: false, // Disable the sidecar completely
|
|
262
268
|
disableSecurity: true, // Disable security scheme display and playground auth (default)
|
|
269
|
+
disableMcpAuthInstructions: false, // Hide auth steps in the MCP server card
|
|
263
270
|
showVersionSelect: "if-available", // Control version selector visibility
|
|
264
271
|
expandAllTags: false, // Control initial expanded state of tag categories
|
|
265
272
|
showInfoPage: true, // Always show the info page (unset = show only if a description is set)
|
|
@@ -107,6 +107,39 @@ server dropdown. A value without a scheme (such as `/v2/mcp`) is treated as a pa
|
|
|
107
107
|
instead. See the
|
|
108
108
|
[`x-mcp-server` reference](/docs/openapi-extensions/x-mcp-server#overriding-the-url) for details.
|
|
109
109
|
|
|
110
|
+
## Authentication instructions
|
|
111
|
+
|
|
112
|
+
When the `x-mcp-server` extension carries `security` and `securitySchemes` (Zuplo adds these
|
|
113
|
+
automatically for authenticated routes), the card derives the credential header from the first
|
|
114
|
+
scheme and threads it through every install snippet — for example an
|
|
115
|
+
`Authorization: Bearer YOUR_API_KEY` header in the `mcp.json` samples, plus a step telling users to
|
|
116
|
+
replace the placeholder with their key. API key auth also hides the clients that cannot send custom
|
|
117
|
+
headers (Claude Desktop and ChatGPT), and the one-click install buttons for Cursor and VS Code,
|
|
118
|
+
since those links cannot carry a secret.
|
|
119
|
+
|
|
120
|
+
If your users get their credentials some other way — the key is injected by a proxy, handled by your
|
|
121
|
+
own login flow, or simply documented elsewhere — turn the authentication instructions off in your
|
|
122
|
+
Zudoku config:
|
|
123
|
+
|
|
124
|
+
```tsx title="zudoku.config.tsx"
|
|
125
|
+
const config: ZudokuConfig = {
|
|
126
|
+
apis: [
|
|
127
|
+
{
|
|
128
|
+
type: "file",
|
|
129
|
+
input: "./mcp-api.json",
|
|
130
|
+
path: "mcp",
|
|
131
|
+
options: {
|
|
132
|
+
disableMcpAuthInstructions: true,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The card then renders the server as if it were unauthenticated, whatever its security says: no
|
|
140
|
+
header in the snippets, no placeholder step, and every client available again. Set it under
|
|
141
|
+
`defaults.apis` instead to apply it to all APIs.
|
|
142
|
+
|
|
110
143
|
## Complete example
|
|
111
144
|
|
|
112
145
|
This is a minimal but complete OpenAPI spec that produces an MCP endpoint page:
|
|
@@ -130,5 +130,14 @@ When detected, the operation page shows:
|
|
|
130
130
|
The standard method badge, request body, parameters, and sidecar panels are hidden for MCP
|
|
131
131
|
endpoints.
|
|
132
132
|
|
|
133
|
+
When the extension carries `security` and `securitySchemes`, the card also documents the credential
|
|
134
|
+
header and adds it to every install snippet. Set the
|
|
135
|
+
[`disableMcpAuthInstructions`](/docs/configuration/api-reference#options) API option to render the
|
|
136
|
+
server as unauthenticated instead.
|
|
137
|
+
|
|
133
138
|
For a full walkthrough including Zudoku configuration, see the
|
|
134
139
|
[Documenting MCP Servers guide](/docs/guides/mcp-servers).
|
|
140
|
+
|
|
141
|
+
If a document describes several MCP servers, mark it with
|
|
142
|
+
[`x-zudoku-type: mcp-catalog`](./x-zudoku-type) to render them as a searchable catalog instead of
|
|
143
|
+
individual operation pages.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: x-zudoku-type
|
|
3
|
+
sidebar_icon: layout-grid
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use `x-zudoku-type` to change how Zudoku renders an entire OpenAPI document, instead of the default
|
|
7
|
+
REST API view.
|
|
8
|
+
|
|
9
|
+
## Location
|
|
10
|
+
|
|
11
|
+
The extension is added at the **Root Object** level — the outermost level of the OpenAPI
|
|
12
|
+
description.
|
|
13
|
+
|
|
14
|
+
| Option | Type | Description |
|
|
15
|
+
| --------------- | -------- | -------------------------------------- |
|
|
16
|
+
| `x-zudoku-type` | `string` | The renderer to use for this document. |
|
|
17
|
+
|
|
18
|
+
| Value | Renders as |
|
|
19
|
+
| --------------- | --------------------------------------------------------------- |
|
|
20
|
+
| `"mcp-catalog"` | A searchable, filterable catalog of the document's MCP servers. |
|
|
21
|
+
|
|
22
|
+
Values Zudoku does not recognise are ignored with a build warning, and the document falls back to
|
|
23
|
+
the default API view. This keeps a description written for a newer version of Zudoku building
|
|
24
|
+
against an older one.
|
|
25
|
+
|
|
26
|
+
## `mcp-catalog`
|
|
27
|
+
|
|
28
|
+
A catalog document renders as a **single page** listing every operation marked with
|
|
29
|
+
[`x-mcp-server`](./x-mcp-server) as a card, in one grid that can be searched and filtered by tag.
|
|
30
|
+
Selecting a card opens the server's install instructions and its tool list.
|
|
31
|
+
|
|
32
|
+
Because the whole document becomes a catalog, a few things change:
|
|
33
|
+
|
|
34
|
+
- **Only MCP servers are rendered.** Operations without `x-mcp-server` are not shown, and the
|
|
35
|
+
document contributes no sidebar entries, tag pages, or schema page. If you also want to document
|
|
36
|
+
plain REST endpoints, put them in a separate OpenAPI document with its own `apis` entry.
|
|
37
|
+
- **Tags become filters** rather than pages or headings. Each tag appears as a filter chip and as a
|
|
38
|
+
badge on its servers' cards; the grid itself stays flat. Servers without a tag are filed under
|
|
39
|
+
"Other". The active filter is kept in the URL as `?tag=`, so a filtered view can be linked.
|
|
40
|
+
- **Only the latest version is rendered.** Catalog documents do not support version switching; a
|
|
41
|
+
versioned API marked as a catalog warns at build time.
|
|
42
|
+
|
|
43
|
+
The extension is read while your schema is processed, so it applies to `type: "file"` and
|
|
44
|
+
`type: "raw"` APIs. `type: "url"` schemas are fetched in the browser after routing is decided, so
|
|
45
|
+
the flag has no effect on them.
|
|
46
|
+
|
|
47
|
+
## Example
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
openapi: 3.1.0
|
|
51
|
+
x-zudoku-type: mcp-catalog
|
|
52
|
+
info:
|
|
53
|
+
title: Employee MCP Servers
|
|
54
|
+
version: 1.0.0
|
|
55
|
+
servers:
|
|
56
|
+
- url: https://mcp.example.com
|
|
57
|
+
tags:
|
|
58
|
+
- name: CRM & Customer Operations
|
|
59
|
+
paths:
|
|
60
|
+
/v1/salesforce/sales-cloud/mcp:
|
|
61
|
+
post:
|
|
62
|
+
summary: Salesforce Sales Cloud
|
|
63
|
+
description: Read-only access to accounts, opportunities and contacts.
|
|
64
|
+
tags:
|
|
65
|
+
- CRM & Customer Operations
|
|
66
|
+
x-mcp-server:
|
|
67
|
+
name: salesforce-sales-cloud
|
|
68
|
+
version: 1.0.0
|
|
69
|
+
tools:
|
|
70
|
+
- name: searchAccounts
|
|
71
|
+
description: Find accounts by name, domain or owner.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This renders one catalog page with a single `Salesforce Sales Cloud` card, reachable via a
|
|
75
|
+
`CRM & Customer Operations` filter chip. The card opens install snippets for Claude, ChatGPT,
|
|
76
|
+
Cursor, VS Code and Codex, alongside the server's tools.
|
|
77
|
+
|
|
78
|
+
## Related
|
|
79
|
+
|
|
80
|
+
- [`x-mcp-server`](./x-mcp-server) — mark an individual operation as an MCP server
|
package/package.json
CHANGED
package/src/app/main.tsx
CHANGED
|
@@ -29,6 +29,7 @@ import { RouteGuard } from "../lib/core/RouteGuard.js";
|
|
|
29
29
|
import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
|
|
30
30
|
import { RouterError } from "../lib/errors/RouterError.js";
|
|
31
31
|
import { ZuploEnv } from "./env.js";
|
|
32
|
+
import { notFoundRoute } from "./notFoundRoute.js";
|
|
32
33
|
import { processRoutes } from "./processRoutes.js";
|
|
33
34
|
import { createRedirectRoutes } from "./utils/createRedirectRoutes.js";
|
|
34
35
|
import {
|
|
@@ -109,7 +110,7 @@ export const getRoutesByOptions = (
|
|
|
109
110
|
}))
|
|
110
111
|
: [],
|
|
111
112
|
)
|
|
112
|
-
.concat([
|
|
113
|
+
.concat([notFoundRoute])
|
|
113
114
|
.map((route) => ({
|
|
114
115
|
...route,
|
|
115
116
|
errorElement: <RouterError className="w-full m-0" />,
|