#
tokens: 5013/50000 12/12 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .github
│   └── workflows
│       └── publish.yml
├── .gitignore
├── .node-version
├── .npmrc
├── .vscode
│   └── settings.json
├── .zed
│   └── settings.json
├── biome.json
├── package.json
├── pnpm-lock.yaml
├── README.md
├── src
│   ├── index.ts
│   └── utils
│       ├── __tests__
│       │   └── apifox.test.ts
│       └── apifox.ts
├── tsconfig.json
└── tsup.config.ts
```

# Files

--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------

```
v20.11.0

```

--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------

```
# registry=https://registry.npmjs.org/
registry=https://registry.npmmirror.com/

```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.output
stats.html
stats-*.json
.wxt
web-ext.config.ts

# Editor directories and files
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.env

dist

```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
{
  "cSpell.words": [
    "apifox",
    "modelcontextprotocol"
  ]
}
```

--------------------------------------------------------------------------------
/.zed/settings.json:
--------------------------------------------------------------------------------

```json
{
	"formatter": {
		"language_server": {
			"name": "biome"
		}
	},
	"format_on_save": "on",
	"code_actions_on_format": {
		"source.fixAll.biome": true,
		"source.organizeImports.biome": true
	}
}

```

--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------

```yaml
name: Publish
on:
  release:
    types: [created]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20.x'
          registry-url: 'https://registry.npmjs.org'
      - run: npm install 
      - run: npm run build
      - run: npm run release
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```

--------------------------------------------------------------------------------
/src/utils/__tests__/apifox.test.ts:
--------------------------------------------------------------------------------

```typescript
import { extractProjectIdAndApiIdFromText, fetchApiInfoApi } from "../apifox.js";
import { describe, it, expect } from 'vitest'



describe('fetchApiInfoApi', () => {
  it('should fetch api info', async () => {
    const result = await fetchApiInfoApi('5333436', '269566330','')
    expect(result).toMatchInlineSnapshot(`"{"success":false,"errorCode":"403012","errorMessage":"No project maintainer privilege"}"`)
  })


  it('should extract project id and api id from text', () => {
    const result = extractProjectIdAndApiIdFromText('https://app.apifox.com/link/project/5333436/apis/api-271295333')
    expect(result).toMatchInlineSnapshot(`
      {
        "apiId": "271295333",
        "projectId": "5333436",
      }
    `)
  })
})

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-apifox",
  "version": "1.0.3",
  "bin": {
		"mcp-apifox": "dist/index.js"
	},
  "description": "",
  "type": "module",
	"main": "./dist/index.js",
	"module": "./dist/index.js",
	"types": "./dist/index.d.ts",
	"exports": {
		".": "./dist/index.js"
	},
	"files": [
		"dist",
    "*.d.ts"
	],
  "repository": {
    "type": "git",
    "url": "https://github.com/sujianqingfeng/mcp-apifox.git"
  },
  "scripts": {
    "build": "tsup",
		"release": "npm publish --no-git-checks --access public --registry https://registry.npmjs.org/",
		"dev": "tsup --watch",
		"preview": "node dist/index.js",
		"test": "vitest",
		"build:tsc": "tsc"
  },
  "keywords": [
    "mcp",
    "apifox"
  ],
  "author": "hens",
  "license": "ISC",
  "devDependencies": {
    "@biomejs/biome": "^1.9.4",
    "@types/node": "^22.13.4",
    "cross-env": "^7.0.3",
    "tsup": "^8.3.6",
    "typescript": "^5.7.3",
    "vitest": "^3.0.6"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.5.0",
    "undici": "^7.3.0",
    "zod": "^3.24.2"
  }
}

```

--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noExplicitAny": "off"
      },
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "style": {
        "noParameterAssign": "off"
      },
      "a11y": {
        "useKeyWithClickEvents": "off"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "ignore": [],
    "attributePosition": "auto",
    "indentStyle": "tab",
    "indentWidth": 2,
    "lineWidth": 80,
    "lineEnding": "lf"
  },
  "javascript": {
    "formatter": {
      "arrowParentheses": "always",
      "bracketSameLine": false,
      "bracketSpacing": true,
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "semicolons": "asNeeded",
      "trailingCommas": "all"
    }
  },
  "json": {
    "formatter": {
      "trailingCommas": "none"
    }
  }
}

```

--------------------------------------------------------------------------------
/src/utils/apifox.ts:
--------------------------------------------------------------------------------

```typescript

import { request } from 'undici';

export async function fetchApiInfoApi(projectId: string, apiId: string, accessToken: string) {

  const response = await request(`https://api.apifox.com/v1/projects/${projectId}/export-openapi`, {
    method: 'POST',
    headers: {
      'X-Apifox-Api-Version': '2024-03-28',
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      scope: {
        type: 'SELECTED_ENDPOINTS',
        selectedEndpointIds: [apiId]
      },
      options: {
        includeApifoxExtensionProperties: false,
        addFoldersToTags: false
      },
      oasVersion: '3.1',
      exportFormat: 'JSON'
    })
  });

  const result = await response.body.text();
  return result
}


export function extractProjectIdAndApiIdFromText(text: string) {
	const urlPattern = /apifox\.com\/link\/project\/(\d+)\/apis\/api-(\d+)/
	const contentPattern = /project\/(\d+).*api-(\d+)/

		let projectId = ""
		let apiId = ""

		// 寻找输入中的 URL 或相关内容
		const lines = text.split("\n")
		for (const line of lines) {
			const trimmedLine = line.trim()

			// 尝试匹配完整 URL
			const urlMatch = trimmedLine.match(urlPattern)
			if (urlMatch) {
				projectId = urlMatch[1]
				apiId = urlMatch[2]
				break
			}

			// 尝试匹配部分路径
			const contentMatch = trimmedLine.match(contentPattern)
			if (contentMatch) {
				projectId = contentMatch[1]
				apiId = contentMatch[2]
				break
			}
		}


  return {
    projectId,
    apiId
  }
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { z } from "zod"
import { extractProjectIdAndApiIdFromText, fetchApiInfoApi } from "./utils/apifox.js"

const server = new McpServer({
	name: "apifox",
	version: "0.0.1",
})

server.tool(
	"get_apifox_project_id_and_api_id_from_url",
	"Get the project ID and API ID of Apifox from the URL.",
	{
		text: z
			.string()
			.describe("The text to extract the project id and api id from"),
	},
	({ text }) => {
    const { projectId, apiId } = extractProjectIdAndApiIdFromText(text)

		return {
			content: [
				{
					type: "text",
					text: JSON.stringify({ projectId, apiId }),
				},
			],
		}
	},
)

server.tool(
	"get_apifox_api_info",
	"Get the info of Apifox API.",
	{
		projectId: z.string().describe("The project ID of Apifox"),
		apiId: z.string().describe("The API ID of Apifox"),
	},
	async ({ projectId, apiId }) => {
		try {
      // Get token from command line arguments or environment variable
      let token = process.env.APIFOX_ACCESS_TOKEN
      
      // Check if token is provided in command line arguments
      // Format: --token=your_token or --apifox-token=your_token
      const args = process.argv.slice(2)
      for (const arg of args) {
        const tokenArg = arg.match(/^--(?:apifox-)?token=(.+)$/)
        if (tokenArg) {
          token = tokenArg[1]
          break
        }
      }
      if (!token) {
        throw new Error("No token provided")
      }
      
			const result = await fetchApiInfoApi(projectId, apiId, token)

			return {
				content: [
					{
						type: "text",
						text: result,
					},
				],
			}
		} catch (error: any) {
			return {
				content: [
					{
						type: "text",
						text: `Error fetching API info: ${error.message}`,
					},
				],
				isError: true,
			}
		}
	},
)

async function main() {
	const transport = new StdioServerTransport()
	await server.connect(transport)
	console.error("Apifox MCP Server running on stdio")
}

main().catch((error) => {
	console.error("Fatal error in main():", error)
	process.exit(1)
})

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig to read more about this file */
    /* Projects */
    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
    /* Language and Environment */
    "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
    /* Modules */
    "module": "Node16", /* Specify what module code is generated. */
    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
    "moduleResolution": "Node16", /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
    // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
    // "rewriteRelativeImportExtensions": true,          /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
    // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */
    // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */
    // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
    // "noUncheckedSideEffectImports": true,             /* Check side effect imports. */
    // "resolveJsonModule": true,                        /* Enable importing .json files. */
    // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */
    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
    /* JavaScript Support */
    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
    /* Emit */
    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./",                                   /* Specify an output folder for all emitted files. */
    // "removeComments": true,                           /* Disable emitting comments. */
    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
    /* Interop Constraints */
    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
    // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
    // "isolatedDeclarations": true,                     /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
    /* Type Checking */
    "strict": true, /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
    // "strictBuiltinIteratorReturn": true,              /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
    /* Completeness */
    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
    "skipLibCheck": true /* Skip type checking all .d.ts files. */
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

```