mirror of
https://github.com/langgenius/dify-docs-mcp-server.git
synced 2026-07-01 12:50:00 -04:00
Feat: init mcp server
This commit is contained in:
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
Generated
+1274
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "dify-6c0370d8-mcp",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "MCP server generated for the dify-6c0370d8 subdomain from Mintlify",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "node src/index.js"
|
||||
},
|
||||
"author": "Mintlify",
|
||||
"dependencies": {
|
||||
"@mintlify/openapi-types": "^0.0.0",
|
||||
"@mintlify/validation": "^0.1.320",
|
||||
"@modelcontextprotocol/sdk": "^1.6.1",
|
||||
"axios": "^1.8.1",
|
||||
"dashify": "^2.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"trieve-ts-sdk": "^0.0.62"
|
||||
}
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export declare const SERVER_NAME: string;
|
||||
export declare const SERVER_VERSION: string;
|
||||
@@ -0,0 +1,2 @@
|
||||
export const SERVER_NAME = 'mintlify';
|
||||
export const SERVER_VERSION = '1.0.0';
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export declare const SUBDOMAIN: Readonly<string>;
|
||||
export declare const SERVER_URL: Readonly<string>;
|
||||
@@ -0,0 +1,3 @@
|
||||
// read-only
|
||||
export const SUBDOMAIN = 'dify-6c0370d8';
|
||||
export const SERVER_URL = 'https://leaves.mintlify.com';
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
export declare function connectServer(server: McpServer): Promise<void>;
|
||||
@@ -0,0 +1,17 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
export function connectServer(server) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const transport = new StdioServerTransport();
|
||||
yield server.connect(transport);
|
||||
console.error('MCP Server running on stdio');
|
||||
});
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1,26 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import { connectServer } from './connect.js';
|
||||
import { initialize } from './initialize.js';
|
||||
import { createSearchTool } from './search.js';
|
||||
import { createTools } from './tools/index.js';
|
||||
function main() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const server = initialize();
|
||||
const existingTools = new Set();
|
||||
yield createSearchTool(server);
|
||||
yield createTools(server, existingTools);
|
||||
yield connectServer(server);
|
||||
});
|
||||
}
|
||||
main().catch((error) => {
|
||||
console.error('Fatal error in trying to initialize MCP server: ', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
export declare function initialize(): McpServer;
|
||||
@@ -0,0 +1,10 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { SERVER_NAME, SERVER_VERSION } from '../settings.js';
|
||||
export function initialize() {
|
||||
console.error('Initializing MCP Server...');
|
||||
const server = new McpServer({
|
||||
name: SERVER_NAME,
|
||||
version: SERVER_VERSION,
|
||||
});
|
||||
return server;
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { InitializationConfiguration } from './types.js';
|
||||
export declare function fetchSearchConfigurationAndTools(subdomain: string): Promise<InitializationConfiguration>;
|
||||
export declare function createSearchTool(server: McpServer): Promise<void>;
|
||||
@@ -0,0 +1,81 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import axios from 'axios';
|
||||
import { TrieveSDK } from 'trieve-ts-sdk';
|
||||
import { z } from 'zod';
|
||||
import { SUBDOMAIN } from './config.readonly.js';
|
||||
import { SERVER_URL } from './config.readonly.js';
|
||||
import { formatErr, throwOnAxiosError } from './utils.js';
|
||||
const DEFAULT_BASE_URL = 'https://api.mintlifytrieve.com';
|
||||
export function fetchSearchConfigurationAndTools(subdomain) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const response = yield axios.get(`${SERVER_URL}/api/mcp/config/${subdomain}`, {
|
||||
validateStatus() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
throwOnAxiosError(response, 'Failed to fetch MCP config');
|
||||
return response.data;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(formatErr(err).replace('Request failed with status code 404', `${subdomain} not found`));
|
||||
}
|
||||
});
|
||||
}
|
||||
function search(query, config) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const trieve = new TrieveSDK({
|
||||
apiKey: config.trieveApiKey,
|
||||
datasetId: config.trieveDatasetId,
|
||||
baseUrl: DEFAULT_BASE_URL,
|
||||
});
|
||||
const data = yield trieve.autocomplete({
|
||||
page_size: 10,
|
||||
query,
|
||||
search_type: 'fulltext',
|
||||
extend_results: true,
|
||||
score_threshold: 1,
|
||||
});
|
||||
if (data.chunks === undefined || data.chunks.length === 0) {
|
||||
throw new Error('No results found');
|
||||
}
|
||||
return data.chunks.map((result) => {
|
||||
const { chunk } = result;
|
||||
// TODO: Append custom domain to the link
|
||||
return {
|
||||
title: chunk.metadata.title,
|
||||
content: chunk.chunk_html,
|
||||
link: chunk.link,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
export function createSearchTool(server) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const config = yield fetchSearchConfigurationAndTools(SUBDOMAIN);
|
||||
server.tool('search', `Search across the ${config.name} documentation to fetch relevant context for a given query`, {
|
||||
query: z.string(),
|
||||
}, (_a) => __awaiter(this, [_a], void 0, function* ({ query }) {
|
||||
const results = yield search(query, config);
|
||||
const content = results.map((result) => {
|
||||
const { title, content, link } = result;
|
||||
const text = `Title: ${title}\nContent: ${content}\nLink: ${link}`;
|
||||
return {
|
||||
type: 'text',
|
||||
text,
|
||||
};
|
||||
});
|
||||
return {
|
||||
content,
|
||||
};
|
||||
}));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"tool": {
|
||||
"name": "search",
|
||||
"description": "Search across the Dify Docs documentation to fetch relevant context for a given query"
|
||||
}
|
||||
}
|
||||
]
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
import { OpenAPI } from '@mintlify/openapi-types';
|
||||
import { HttpMethod } from '@mintlify/validation';
|
||||
import { Endpoint } from '@mintlify/validation';
|
||||
import { DataSchemaArray } from '@mintlify/validation';
|
||||
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
||||
import { ServerParams, ToolWithEndpoint } from '../types.js';
|
||||
import { SimpleRecord } from '../utils.js';
|
||||
export declare function convertStrToTitle(str: string): string;
|
||||
export declare function findNextIteration(set: Set<string>, str: string): number;
|
||||
export declare function getMcpEnabledEndpointsFromOpenApiSpec(spec: OpenAPI.Document): Endpoint<DataSchemaArray>[];
|
||||
export declare function convertEndpointToTool(endpoint: Endpoint<DataSchemaArray>): Omit<Tool, 'inputSchema'>;
|
||||
export declare function getMcpToolsAndEndpointsFromOpenApiSpec(spec: OpenAPI.Document): ToolWithEndpoint[];
|
||||
export declare function getEndpointsFromOpenApi(specification: OpenAPI.Document): Endpoint<DataSchemaArray>[];
|
||||
export declare function loadEnv(key: string): SimpleRecord;
|
||||
export declare function convertEndpointToCategorizedZod(envKey: string, endpoint: Endpoint): {
|
||||
url: string;
|
||||
method: HttpMethod;
|
||||
paths: ServerParams;
|
||||
queries: ServerParams;
|
||||
body: ServerParams | undefined;
|
||||
headers: ServerParams;
|
||||
cookies: ServerParams;
|
||||
};
|
||||
@@ -0,0 +1,176 @@
|
||||
import { OpenApiToEndpointConverter, } from '@mintlify/validation';
|
||||
import dashify from 'dashify';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { OpenAPIV3 } from 'openapi-types';
|
||||
import { z } from 'zod';
|
||||
import { initializeObject } from '../utils.js';
|
||||
import { dataSchemaArrayToZod, dataSchemaToZod } from './zod.js';
|
||||
export function convertStrToTitle(str) {
|
||||
const spacedString = str.replace(/[-_]/g, ' ');
|
||||
const words = spacedString.split(/(?=[A-Z])|\s+/);
|
||||
const titleCasedWords = words.map((word) => {
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
});
|
||||
return titleCasedWords.join(' ');
|
||||
}
|
||||
export function findNextIteration(set, str) {
|
||||
let count = 1;
|
||||
set.forEach((val) => {
|
||||
if (val.startsWith(`${str}---`)) {
|
||||
count = Number(val.replace(`${str}---`, ''));
|
||||
}
|
||||
});
|
||||
return count + 1;
|
||||
}
|
||||
export function getMcpEnabledEndpointsFromOpenApiSpec(spec) {
|
||||
var _a;
|
||||
const mcpEnabledEndpoints = [];
|
||||
const isMcpEnabledGloballyInSpec = ((_a = spec['x-mcp']) === null || _a === void 0 ? void 0 : _a.enabled) === true;
|
||||
const endpoints = getEndpointsFromOpenApi(spec);
|
||||
if (isMcpEnabledGloballyInSpec) {
|
||||
const notDisabledEndpoints = endpoints.filter((endpoint) => { var _a; return ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.enabled) !== false; });
|
||||
mcpEnabledEndpoints.push(...notDisabledEndpoints);
|
||||
}
|
||||
else {
|
||||
const enabledEndpoints = endpoints.filter((endpoint) => { var _a; return ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.enabled) === true; });
|
||||
mcpEnabledEndpoints.push(...enabledEndpoints);
|
||||
}
|
||||
return mcpEnabledEndpoints;
|
||||
}
|
||||
export function convertEndpointToTool(endpoint) {
|
||||
var _a, _b;
|
||||
let name;
|
||||
if ((_a = endpoint.xMcp) === null || _a === void 0 ? void 0 : _a.name) {
|
||||
name = endpoint.xMcp.name;
|
||||
}
|
||||
else if (endpoint.title) {
|
||||
name = dashify(endpoint.title);
|
||||
}
|
||||
else {
|
||||
name = convertStrToTitle(endpoint.path);
|
||||
}
|
||||
let description;
|
||||
if ((_b = endpoint.xMcp) === null || _b === void 0 ? void 0 : _b.description) {
|
||||
description = endpoint.xMcp.description;
|
||||
}
|
||||
else if (endpoint.description) {
|
||||
description = endpoint.description;
|
||||
}
|
||||
else {
|
||||
description = `${endpoint.method} ${endpoint.path}`;
|
||||
}
|
||||
return {
|
||||
name,
|
||||
description,
|
||||
};
|
||||
}
|
||||
export function getMcpToolsAndEndpointsFromOpenApiSpec(spec) {
|
||||
const endpoints = getMcpEnabledEndpointsFromOpenApiSpec(spec);
|
||||
const toolsWithEndpoints = [];
|
||||
endpoints.forEach((endpoint) => {
|
||||
const tool = convertEndpointToTool(endpoint);
|
||||
toolsWithEndpoints.push({
|
||||
tool,
|
||||
endpoint,
|
||||
});
|
||||
});
|
||||
return toolsWithEndpoints;
|
||||
}
|
||||
export function getEndpointsFromOpenApi(specification) {
|
||||
const endpoints = [];
|
||||
const paths = specification.paths;
|
||||
for (const path in paths) {
|
||||
const pathObj = paths[path];
|
||||
const httpMethods = Object.values(OpenAPIV3.HttpMethods);
|
||||
for (const method of httpMethods) {
|
||||
if (!pathObj || !(method in pathObj)) {
|
||||
continue;
|
||||
}
|
||||
const endpoint = OpenApiToEndpointConverter.convert(specification, path, method, true);
|
||||
endpoints.push(endpoint);
|
||||
}
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
export function loadEnv(key) {
|
||||
var _a;
|
||||
let envVars = {};
|
||||
try {
|
||||
const envPath = path.join(fileURLToPath(import.meta.url), '../../../../', '.env.json');
|
||||
if (fs.existsSync(envPath)) {
|
||||
envVars = JSON.parse(fs.readFileSync(envPath).toString());
|
||||
return (_a = envVars[key]) !== null && _a !== void 0 ? _a : {};
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// if there's no env, the user will be prompted
|
||||
// for their auth info at runtime if necessary
|
||||
// (shouldn't happen either way)
|
||||
}
|
||||
return envVars;
|
||||
}
|
||||
function convertParameterSection(parameters, paramSection) {
|
||||
Object.entries(parameters).forEach(([key, value]) => {
|
||||
const schema = value.schema;
|
||||
paramSection[key] = dataSchemaArrayToZod(schema);
|
||||
});
|
||||
}
|
||||
function convertParametersAndAddToRelevantParamGroups(parameters, paths, queries, headers, cookies) {
|
||||
convertParameterSection(parameters.path, paths);
|
||||
convertParameterSection(parameters.query, queries);
|
||||
convertParameterSection(parameters.header, headers);
|
||||
convertParameterSection(parameters.cookie, cookies);
|
||||
}
|
||||
function convertSecurityParameterSection(securityParameters, securityParamSection, envVariables, location) {
|
||||
Object.entries(securityParameters).forEach(([key, value]) => {
|
||||
let envKeyList = [];
|
||||
let targetKey = '';
|
||||
switch (value.type) {
|
||||
case 'apiKey':
|
||||
envKeyList = [location, key];
|
||||
targetKey = 'API_KEY';
|
||||
break;
|
||||
case 'http':
|
||||
envKeyList = [location, key, 'HTTP'];
|
||||
targetKey = value.scheme;
|
||||
break;
|
||||
case 'oauth2':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const target = initializeObject(Object.assign({}, envVariables), envKeyList);
|
||||
if (envKeyList.length && !target[targetKey]) {
|
||||
securityParamSection[key] = z.string();
|
||||
}
|
||||
});
|
||||
}
|
||||
function convertSecurityParametersAndAddToRelevantParamGroups(securityParameters, queries, headers, cookies, envVariables) {
|
||||
convertSecurityParameterSection(securityParameters.query, queries, envVariables, 'query');
|
||||
convertSecurityParameterSection(securityParameters.header, headers, envVariables, 'header');
|
||||
convertSecurityParameterSection(securityParameters.cookie, cookies, envVariables, 'cookie');
|
||||
}
|
||||
export function convertEndpointToCategorizedZod(envKey, endpoint) {
|
||||
var _a, _b, _c;
|
||||
const envVariables = loadEnv(envKey);
|
||||
const url = `${((_b = (_a = endpoint.servers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url) || ''}${endpoint.path}`;
|
||||
const method = endpoint.method;
|
||||
const paths = {};
|
||||
const queries = {};
|
||||
const headers = {};
|
||||
const cookies = {};
|
||||
let body = undefined;
|
||||
convertParametersAndAddToRelevantParamGroups(endpoint.request.parameters, paths, queries, headers, cookies);
|
||||
if ((_c = endpoint.request.security[0]) === null || _c === void 0 ? void 0 : _c.parameters) {
|
||||
convertSecurityParametersAndAddToRelevantParamGroups(endpoint.request.security[0].parameters, queries, headers, cookies, envVariables);
|
||||
}
|
||||
const jsonBodySchema = endpoint.request.body['application/json'];
|
||||
const bodySchemaArray = jsonBodySchema === null || jsonBodySchema === void 0 ? void 0 : jsonBodySchema.schemaArray;
|
||||
const bodySchema = bodySchemaArray === null || bodySchemaArray === void 0 ? void 0 : bodySchemaArray[0];
|
||||
if (bodySchema) {
|
||||
const zodBodySchema = dataSchemaToZod(bodySchema);
|
||||
body = { body: zodBodySchema };
|
||||
}
|
||||
return { url, method, paths, queries, body, headers, cookies };
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
export declare function createTools(server: McpServer, existingTools: Set<string>): Promise<void>;
|
||||
@@ -0,0 +1,138 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import axios, { isAxiosError } from 'axios';
|
||||
import dashify from 'dashify';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { convertEndpointToCategorizedZod, convertStrToTitle, findNextIteration, loadEnv, } from './helpers.js';
|
||||
export function createTools(server, existingTools) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const toolsDir = path.join(fileURLToPath(import.meta.url), '..', '..');
|
||||
let tools = JSON.parse(fs.readFileSync(path.join(toolsDir, 'tools.json'), 'utf-8'));
|
||||
tools = tools.filter((tool) => tool.endpoint);
|
||||
tools.forEach(({ uuid, endpoint }) => {
|
||||
const envVars = loadEnv(uuid);
|
||||
const { url: urlSchema, method: methodSchema, paths: pathsSchema, queries: queriesSchema, body: bodySchema, headers: headersSchema, cookies: cookiesSchema, } = convertEndpointToCategorizedZod(uuid, endpoint);
|
||||
const serverArgumentsSchemas = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, pathsSchema), queriesSchema), bodySchema), headersSchema), cookiesSchema);
|
||||
if (!endpoint.title) {
|
||||
endpoint.title = `${endpoint.method} ${convertStrToTitle(endpoint.path)}`;
|
||||
}
|
||||
if (existingTools.has(endpoint.title)) {
|
||||
const lastCount = findNextIteration(existingTools, endpoint.title);
|
||||
endpoint.title = `${endpoint.title}---${lastCount}`;
|
||||
}
|
||||
if (endpoint.title.length > 64) {
|
||||
endpoint.title = endpoint.title.slice(0, -64);
|
||||
}
|
||||
existingTools.add(endpoint.title);
|
||||
server.tool(dashify(endpoint.title), endpoint.description || endpoint.title, serverArgumentsSchemas, (inputArgs) => __awaiter(this, void 0, void 0, function* () {
|
||||
var _a;
|
||||
const inputParams = {};
|
||||
const inputHeaders = {};
|
||||
const inputCookies = {};
|
||||
let urlWithPathParams = urlSchema;
|
||||
let inputBody = undefined;
|
||||
if ('body' in inputArgs) {
|
||||
inputBody = inputArgs.body;
|
||||
delete inputArgs.body;
|
||||
}
|
||||
Object.entries(inputArgs).forEach(([key, value]) => {
|
||||
if (key in pathsSchema) {
|
||||
urlWithPathParams = urlWithPathParams.replace(`{${key}}`, value);
|
||||
}
|
||||
else if (key in queriesSchema) {
|
||||
inputParams[key] = value;
|
||||
}
|
||||
else if (key in headersSchema) {
|
||||
inputHeaders[key] = value;
|
||||
}
|
||||
else if (key in cookiesSchema) {
|
||||
inputCookies[key] = value;
|
||||
}
|
||||
});
|
||||
if (endpoint.request.security.length > 0) {
|
||||
const securityParams = (_a = endpoint.request.security[0]) === null || _a === void 0 ? void 0 : _a.parameters;
|
||||
if (securityParams) {
|
||||
Object.entries(securityParams.query).forEach(([key, value]) => {
|
||||
let envKey = '';
|
||||
if (value.type === 'apiKey') {
|
||||
envKey = `query_${key}_APIKEY`;
|
||||
}
|
||||
else if (value.type === 'http') {
|
||||
envKey = `query_${key}_HTTP_${value.scheme}`;
|
||||
}
|
||||
if (envKey && envKey in envVars) {
|
||||
inputParams[key] = envVars[envKey];
|
||||
}
|
||||
});
|
||||
Object.entries(securityParams.header).forEach(([key, value]) => {
|
||||
let envKey = '';
|
||||
if (value.type === 'apiKey') {
|
||||
envKey = `header_${key}_APIKEY`;
|
||||
}
|
||||
else if (value.type === 'http') {
|
||||
envKey = `header_${key}_HTTP_${value.scheme}`;
|
||||
if (value.scheme === 'bearer' && envKey in envVars) {
|
||||
inputHeaders['Authorization'] = `Bearer ${envVars[envKey]}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (envKey && envKey in envVars) {
|
||||
inputHeaders[key] = envVars[envKey];
|
||||
}
|
||||
});
|
||||
Object.entries(securityParams.cookie).forEach(([key, value]) => {
|
||||
let envKey = '';
|
||||
if (value.type === 'apiKey') {
|
||||
envKey = `cookie_${key}_APIKEY`;
|
||||
}
|
||||
else if (value.type === 'http') {
|
||||
envKey = `cookie_${key}_HTTP_${value.scheme}`;
|
||||
}
|
||||
if (envKey && envKey in envVars) {
|
||||
inputCookies[key] = envVars[envKey];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
try {
|
||||
const response = yield axios({
|
||||
url: urlWithPathParams,
|
||||
method: methodSchema,
|
||||
params: inputParams,
|
||||
data: inputBody,
|
||||
headers: inputHeaders,
|
||||
});
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(response.data, undefined, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errMsg = JSON.stringify(error, undefined, 2);
|
||||
return {
|
||||
isError: true,
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: isAxiosError(error) ? `${error.message}\n\n${errMsg}` : errMsg,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
import { DataSchema, DataSchemaArray, IncrementalDataSchema, IncrementalDataSchemaArray } from '@mintlify/validation';
|
||||
import { z } from 'zod';
|
||||
type SchemaInput = DataSchema | IncrementalDataSchema;
|
||||
export declare function dataSchemaArrayToZod(schemas: DataSchemaArray | IncrementalDataSchemaArray): z.ZodTypeAny;
|
||||
export declare function dataSchemaToZod(schema: SchemaInput): z.ZodTypeAny;
|
||||
export {};
|
||||
@@ -0,0 +1,185 @@
|
||||
import { Blob } from 'node:buffer';
|
||||
import { z } from 'zod';
|
||||
function panic(error) {
|
||||
throw error;
|
||||
}
|
||||
// WebFile polyfill implementation partly taken from the fetch-blob package:
|
||||
// https://github.com/node-fetch/fetch-blob/blob/main/file.js - MIT License
|
||||
const WebFile = class File extends Blob {
|
||||
constructor(init, name = panic(new TypeError('File constructor requires name argument')), options = {}) {
|
||||
if (arguments.length < 2) {
|
||||
throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`);
|
||||
}
|
||||
super(init, options);
|
||||
this._lastModified = 0;
|
||||
this._name = '';
|
||||
// Simulate WebIDL type casting for NaN value in lastModified option.
|
||||
const lastModified = options.lastModified === undefined ? Date.now() : Number(options.lastModified);
|
||||
if (!Number.isNaN(lastModified)) {
|
||||
this._lastModified = lastModified;
|
||||
}
|
||||
this._name = String(name);
|
||||
}
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
get lastModified() {
|
||||
return this._lastModified;
|
||||
}
|
||||
get [Symbol.toStringTag]() {
|
||||
return 'File';
|
||||
}
|
||||
static [Symbol.hasInstance](object) {
|
||||
return (!!object && object instanceof Blob && /^(File)$/.test(String(object[Symbol.toStringTag])));
|
||||
}
|
||||
};
|
||||
const File = typeof global.File === 'undefined' ? WebFile : global.File;
|
||||
const ANY = z.any();
|
||||
const ANY_OPT = ANY.optional();
|
||||
const BOOLEAN = z.boolean();
|
||||
const BOOLEAN_OPT = BOOLEAN.optional();
|
||||
const DATE = z.coerce.date();
|
||||
const DATE_OPT = DATE.optional();
|
||||
const FILE = z.instanceof(File);
|
||||
const FILE_OPT = FILE.optional();
|
||||
const NULL = z.null();
|
||||
const NULL_OPT = NULL.optional();
|
||||
const RECORD = z.record(z.any());
|
||||
const RECORD_WITH_DEFAULT = RECORD.default({});
|
||||
const RECORD_OPT = RECORD.optional();
|
||||
const STRING = z.string();
|
||||
const NUMBER = z.number();
|
||||
const INTEGER = z.number().int();
|
||||
export function dataSchemaArrayToZod(schemas) {
|
||||
const firstSchema = dataSchemaToZod(schemas[0]);
|
||||
if (!schemas[1]) {
|
||||
return firstSchema;
|
||||
}
|
||||
const secondSchema = dataSchemaToZod(schemas[1]);
|
||||
const zodSchemas = [firstSchema, secondSchema];
|
||||
for (const schema of schemas.slice(2)) {
|
||||
zodSchemas.push(dataSchemaToZod(schema));
|
||||
}
|
||||
return z.union(zodSchemas).array();
|
||||
}
|
||||
function getEnumSchema(enumList, type) {
|
||||
const zodSchema = z.enum(enumList.map(String));
|
||||
if (type === 'string')
|
||||
return zodSchema;
|
||||
return zodSchema.transform(Number);
|
||||
}
|
||||
export function dataSchemaToZod(schema) {
|
||||
if (!('type' in schema) || Object.keys(schema).length === 0) {
|
||||
return schema.required ? ANY : ANY_OPT;
|
||||
}
|
||||
switch (schema.type) {
|
||||
case 'null':
|
||||
return schema.required ? NULL : NULL_OPT;
|
||||
case 'boolean':
|
||||
return schema.required ? BOOLEAN : BOOLEAN_OPT;
|
||||
case 'enum<string>':
|
||||
const strEnumSchema = getEnumSchema(schema.enum, 'string');
|
||||
return schema.required ? strEnumSchema : strEnumSchema.optional();
|
||||
case 'enum<number>':
|
||||
case 'enum<integer>':
|
||||
const numEnumSchema = getEnumSchema(schema.enum, 'number');
|
||||
return schema.required ? numEnumSchema : numEnumSchema.optional();
|
||||
case 'file':
|
||||
return schema.required ? FILE : FILE_OPT;
|
||||
case 'any':
|
||||
return schema.required ? ANY : ANY_OPT;
|
||||
case 'string':
|
||||
if ('enum' in schema && Array.isArray(schema.enum)) {
|
||||
return schema.required
|
||||
? z.enum(schema.enum)
|
||||
: z.enum(schema.enum).optional();
|
||||
}
|
||||
if (schema.format === 'binary') {
|
||||
return schema.required ? FILE : FILE_OPT;
|
||||
}
|
||||
let stringSchema = STRING;
|
||||
if (schema.minLength !== undefined) {
|
||||
stringSchema = stringSchema.min(schema.minLength);
|
||||
}
|
||||
if (schema.maxLength !== undefined) {
|
||||
stringSchema = stringSchema.max(schema.maxLength);
|
||||
}
|
||||
if (schema.pattern !== undefined) {
|
||||
stringSchema = stringSchema.regex(new RegExp(schema.pattern));
|
||||
}
|
||||
switch (schema.format) {
|
||||
case 'email':
|
||||
stringSchema = stringSchema.email();
|
||||
break;
|
||||
case 'uri':
|
||||
case 'url':
|
||||
stringSchema = stringSchema.url();
|
||||
break;
|
||||
case 'uuid':
|
||||
stringSchema = stringSchema.uuid();
|
||||
break;
|
||||
case 'date-time':
|
||||
return schema.required ? DATE : DATE_OPT;
|
||||
}
|
||||
return schema.required ? stringSchema : stringSchema.optional();
|
||||
case 'number':
|
||||
case 'integer':
|
||||
if ('enum' in schema && Array.isArray(schema.enum)) {
|
||||
const numEnumSchema = getEnumSchema(schema.enum, schema.type);
|
||||
return schema.required ? numEnumSchema : numEnumSchema.optional();
|
||||
}
|
||||
let numberSchema = schema.type === 'integer' ? INTEGER : NUMBER;
|
||||
if (schema.minimum !== undefined) {
|
||||
numberSchema = numberSchema.min(schema.minimum);
|
||||
}
|
||||
if (schema.maximum !== undefined) {
|
||||
numberSchema = numberSchema.max(schema.maximum);
|
||||
}
|
||||
if (schema.exclusiveMinimum !== undefined && schema.minimum !== undefined) {
|
||||
numberSchema = numberSchema.gt(schema.minimum);
|
||||
}
|
||||
if (schema.exclusiveMaximum !== undefined && schema.maximum !== undefined) {
|
||||
numberSchema = numberSchema.lt(schema.maximum);
|
||||
}
|
||||
return schema.required ? numberSchema : numberSchema.optional();
|
||||
case 'array':
|
||||
let itemSchema;
|
||||
let arraySchema = z.any().array();
|
||||
if (Array.isArray(schema.items)) {
|
||||
itemSchema = dataSchemaArrayToZod(schema.items);
|
||||
if (schema.items.length > 1) {
|
||||
arraySchema = itemSchema;
|
||||
}
|
||||
else {
|
||||
arraySchema = itemSchema.array();
|
||||
}
|
||||
}
|
||||
else {
|
||||
itemSchema = dataSchemaToZod(schema.items);
|
||||
arraySchema = itemSchema.array();
|
||||
}
|
||||
if (schema.minItems !== undefined) {
|
||||
arraySchema = arraySchema.min(schema.minItems);
|
||||
}
|
||||
if (schema.maxItems !== undefined) {
|
||||
arraySchema = arraySchema.max(schema.maxItems);
|
||||
}
|
||||
return schema.required ? arraySchema : arraySchema.optional();
|
||||
case 'object':
|
||||
const shape = {};
|
||||
const requiredProperties = schema.requiredProperties;
|
||||
const requiredPropertiesSet = new Set(requiredProperties !== null && requiredProperties !== void 0 ? requiredProperties : []);
|
||||
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
||||
const zodPropSchema = Array.isArray(propSchema)
|
||||
? dataSchemaArrayToZod(propSchema)
|
||||
: dataSchemaToZod(propSchema);
|
||||
shape[key] = requiredPropertiesSet.has(key) ? zodPropSchema : zodPropSchema.optional();
|
||||
}
|
||||
if (Object.keys(shape).length === 0) {
|
||||
return schema.required ? RECORD_WITH_DEFAULT : RECORD_OPT;
|
||||
}
|
||||
return schema.required ? z.object(shape) : z.object(shape).optional();
|
||||
default:
|
||||
return ANY;
|
||||
}
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
import { OpenAPI } from '@mintlify/openapi-types';
|
||||
import { AxiosResponse } from 'axios';
|
||||
export type NestedRecord = string | {
|
||||
[key: string]: NestedRecord;
|
||||
};
|
||||
export type SimpleRecord = Record<string, NestedRecord>;
|
||||
export declare function initializeObject(obj: SimpleRecord, path: string[]): SimpleRecord;
|
||||
export declare function getFileId(spec: OpenAPI.Document, index: number): string | number;
|
||||
export declare function throwOnAxiosError(response: AxiosResponse<any, any>, errMsg: string): void;
|
||||
export declare function formatErr(err: unknown): any;
|
||||
@@ -0,0 +1,55 @@
|
||||
import axios from 'axios';
|
||||
export function initializeObject(obj, path) {
|
||||
let current = obj;
|
||||
for (const key of path) {
|
||||
if (!current[key] || typeof current[key] !== 'object') {
|
||||
current[key] = {};
|
||||
}
|
||||
current = current[key];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
export function getFileId(spec, index) {
|
||||
var _a;
|
||||
return ((_a = spec.info) === null || _a === void 0 ? void 0 : _a.title) && spec.info.version
|
||||
? `${spec.info.title} - ${spec.info.version}`
|
||||
: index;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function throwOnAxiosError(response, errMsg) {
|
||||
var _a, _b;
|
||||
if (response.status !== 200) {
|
||||
if (((_a = response.headers['content-type']) === null || _a === void 0 ? void 0 : _a.includes('application/json')) && ((_b = response.data) === null || _b === void 0 ? void 0 : _b.error)) {
|
||||
throw new Error(`${errMsg}: ${response.data.error}`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`${errMsg}: ${response.status} ${response.statusText || ''}`);
|
||||
}
|
||||
}
|
||||
if (!response.data) {
|
||||
throw new Error(`${errMsg}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
export function formatErr(err) {
|
||||
var _a, _b;
|
||||
if (axios.isAxiosError(err)) {
|
||||
if (err.message) {
|
||||
return err.message;
|
||||
}
|
||||
else if (err.response) {
|
||||
return (_b = (_a = err.response.data) === null || _a === void 0 ? void 0 : _a.error) !== null && _b !== void 0 ? _b : `${err.response.status} ${err.response.statusText}`;
|
||||
}
|
||||
else if (err.request) {
|
||||
return 'No response received from server';
|
||||
}
|
||||
else {
|
||||
err = 'An unknown error occurred';
|
||||
}
|
||||
}
|
||||
else if (err instanceof Error) {
|
||||
return err.message;
|
||||
}
|
||||
else {
|
||||
return JSON.stringify(err, undefined, 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user