@c4a/mcp-client 0.3.7-alpha.1
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/index.js +205513 -0
- package/package.json +44 -0
- package/src/__tests__/smoke.test.ts +9 -0
- package/src/index.ts +38 -0
- package/src/schemas/inputSchemas.ts +87 -0
- package/src/server.ts +13 -0
- package/src/shared/handler.ts +42 -0
- package/src/tools/extract.ts +50 -0
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@c4a/mcp-client",
|
|
3
|
+
"version": "0.3.7-alpha.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"c4a-mcp-client": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./src/index.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./server": {
|
|
16
|
+
"types": "./src/server.ts",
|
|
17
|
+
"default": "./dist/server.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "bun --watch src/index.ts",
|
|
30
|
+
"start": "bun run src/index.ts",
|
|
31
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
32
|
+
"test": "bun test",
|
|
33
|
+
"lint": "tsc --noEmit",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
38
|
+
"@c4a/core": "workspace:*",
|
|
39
|
+
"@c4a/extract": "workspace:*",
|
|
40
|
+
"zod": "^3.23.0",
|
|
41
|
+
"typescript": "^5.4.0",
|
|
42
|
+
"@types/bun": "latest"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @c4a/mcp-client - 本地 extract MCP Server
|
|
4
|
+
*
|
|
5
|
+
* 提供 extract_* 工具(接口提取/分析/AST/契约)
|
|
6
|
+
*
|
|
7
|
+
* 运行方式: stdio(必须本地)
|
|
8
|
+
*
|
|
9
|
+
* 环境变量:
|
|
10
|
+
* - MCP_TRANSPORT: 仅允许 stdio(默认 stdio)
|
|
11
|
+
*/
|
|
12
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
+
import { createServer } from "./server.js";
|
|
14
|
+
|
|
15
|
+
const transport = process.env.MCP_TRANSPORT || "stdio";
|
|
16
|
+
|
|
17
|
+
async function startStdioServer() {
|
|
18
|
+
const server = createServer();
|
|
19
|
+
const stdioTransport = new StdioServerTransport();
|
|
20
|
+
await server.connect(stdioTransport);
|
|
21
|
+
console.error("c4a-mcp-client server started (stdio)");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function main() {
|
|
25
|
+
if (transport !== "stdio") {
|
|
26
|
+
console.error(
|
|
27
|
+
`c4a-mcp-client 仅支持 stdio 模式,当前 MCP_TRANSPORT=${transport}`
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await startStdioServer();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch((error) => {
|
|
36
|
+
console.error("Fatal error:", error);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const SupportedLanguageSchema = z.enum(["typescript", "go"]);
|
|
4
|
+
|
|
5
|
+
export const ExtractInputSchema = z.object({
|
|
6
|
+
path: z.string().describe("File or directory path to extract from"),
|
|
7
|
+
language: SupportedLanguageSchema.optional().describe(
|
|
8
|
+
"Language hint (auto-detected if not provided)"
|
|
9
|
+
),
|
|
10
|
+
recursive: z
|
|
11
|
+
.boolean()
|
|
12
|
+
.optional()
|
|
13
|
+
.default(false)
|
|
14
|
+
.describe("Recursively process directories"),
|
|
15
|
+
include: z
|
|
16
|
+
.array(z.string())
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Glob patterns to include (e.g., ['**/*.ts'])"),
|
|
19
|
+
exclude: z
|
|
20
|
+
.array(z.string())
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Glob patterns to exclude (e.g., ['node_modules/**'])"),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const AnalyzeInputSchema = z.object({
|
|
26
|
+
path: z.string().describe("File or directory path to analyze"),
|
|
27
|
+
language: SupportedLanguageSchema.optional().describe(
|
|
28
|
+
"Language hint (auto-detected if not provided)"
|
|
29
|
+
),
|
|
30
|
+
includeMetrics: z
|
|
31
|
+
.boolean()
|
|
32
|
+
.optional()
|
|
33
|
+
.default(true)
|
|
34
|
+
.describe("Include code metrics"),
|
|
35
|
+
includeDependencies: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.default(true)
|
|
39
|
+
.describe("Analyze and include dependencies"),
|
|
40
|
+
summary_only: z
|
|
41
|
+
.boolean()
|
|
42
|
+
.optional()
|
|
43
|
+
.default(false)
|
|
44
|
+
.describe("Only return summary without file details"),
|
|
45
|
+
limit: z
|
|
46
|
+
.number()
|
|
47
|
+
.int()
|
|
48
|
+
.min(1)
|
|
49
|
+
.default(100)
|
|
50
|
+
.describe("File details limit"),
|
|
51
|
+
offset: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(0)
|
|
55
|
+
.default(0)
|
|
56
|
+
.describe("Pagination offset"),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const ASTInputSchema = z.object({
|
|
60
|
+
path: z.string().describe("File path to parse"),
|
|
61
|
+
language: SupportedLanguageSchema.optional().describe(
|
|
62
|
+
"Language hint (auto-detected if not provided)"
|
|
63
|
+
),
|
|
64
|
+
maxDepth: z
|
|
65
|
+
.number()
|
|
66
|
+
.min(0)
|
|
67
|
+
.default(10)
|
|
68
|
+
.describe("Maximum AST depth to return"),
|
|
69
|
+
nodeTypes: z.array(z.string()).optional().describe("Filter to specific node types"),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const ContractInputSchema = z.object({
|
|
73
|
+
path: z.string().describe("File or directory path to generate contract from"),
|
|
74
|
+
format: z
|
|
75
|
+
.enum(["openapi", "asyncapi", "proto"])
|
|
76
|
+
.default("openapi")
|
|
77
|
+
.describe("Output format"),
|
|
78
|
+
version: z.string().optional().default("3.0.0").describe("Spec version"),
|
|
79
|
+
title: z.string().optional().describe("API title"),
|
|
80
|
+
description: z.string().optional().describe("API description"),
|
|
81
|
+
baseUrl: z.string().optional().describe("Base URL for API"),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export type ExtractInput = z.infer<typeof ExtractInputSchema>;
|
|
85
|
+
export type AnalyzeInput = z.infer<typeof AnalyzeInputSchema>;
|
|
86
|
+
export type ASTInput = z.infer<typeof ASTInputSchema>;
|
|
87
|
+
export type ContractInput = z.infer<typeof ContractInputSchema>;
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { registerExtractTools } from "./tools/extract.js";
|
|
3
|
+
|
|
4
|
+
export function createServer(): McpServer {
|
|
5
|
+
const server = new McpServer({
|
|
6
|
+
name: "c4a-mcp-client",
|
|
7
|
+
version: "0.1.0",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
registerExtractTools(server);
|
|
11
|
+
|
|
12
|
+
return server;
|
|
13
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { errorToMcpResponse } from "@c4a/core/types";
|
|
2
|
+
|
|
3
|
+
export type McpToolResponse = {
|
|
4
|
+
content: Array<{ type: "text"; text: string }>;
|
|
5
|
+
isError?: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function formatSuccess(result: unknown): McpToolResponse {
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: JSON.stringify(result, null, 2),
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatError(error: unknown): McpToolResponse {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: "text",
|
|
24
|
+
text: JSON.stringify(errorToMcpResponse(error), null, 2),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function buildToolHandler<TArgs, TResult>(
|
|
32
|
+
handler: (args: TArgs) => Promise<TResult>
|
|
33
|
+
): (args: TArgs) => Promise<McpToolResponse> {
|
|
34
|
+
return async (args) => {
|
|
35
|
+
try {
|
|
36
|
+
const result = await handler(args);
|
|
37
|
+
return formatSuccess(result);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return formatError(error);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type {
|
|
3
|
+
AnalyzeInput,
|
|
4
|
+
ASTInput,
|
|
5
|
+
ContractInput,
|
|
6
|
+
ExtractInput,
|
|
7
|
+
} from "../schemas/inputSchemas.js";
|
|
8
|
+
import {
|
|
9
|
+
AnalyzeInputSchema,
|
|
10
|
+
ASTInputSchema,
|
|
11
|
+
ContractInputSchema,
|
|
12
|
+
ExtractInputSchema,
|
|
13
|
+
} from "../schemas/inputSchemas.js";
|
|
14
|
+
import {
|
|
15
|
+
extractAnalyze,
|
|
16
|
+
extractAST,
|
|
17
|
+
extractContract,
|
|
18
|
+
extractInterfaces,
|
|
19
|
+
} from "@c4a/extract";
|
|
20
|
+
import { buildToolHandler } from "../shared/handler.js";
|
|
21
|
+
|
|
22
|
+
export function registerExtractTools(server: McpServer): void {
|
|
23
|
+
server.tool(
|
|
24
|
+
"extract_interfaces",
|
|
25
|
+
"从代码文件中提取接口、类型、类等定义",
|
|
26
|
+
ExtractInputSchema.shape,
|
|
27
|
+
buildToolHandler((args: ExtractInput) => extractInterfaces(args))
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
server.tool(
|
|
31
|
+
"extract_analyze",
|
|
32
|
+
"分析代码结构和依赖关系",
|
|
33
|
+
AnalyzeInputSchema.shape,
|
|
34
|
+
buildToolHandler((args: AnalyzeInput) => extractAnalyze(args))
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
server.tool(
|
|
38
|
+
"extract_ast",
|
|
39
|
+
"获取代码文件的 AST 抽象语法树结构",
|
|
40
|
+
ASTInputSchema.shape,
|
|
41
|
+
buildToolHandler((args: ASTInput) => extractAST(args))
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
server.tool(
|
|
45
|
+
"extract_contract",
|
|
46
|
+
"从代码生成 API 契约(OpenAPI、AsyncAPI、Proto)",
|
|
47
|
+
ContractInputSchema.shape,
|
|
48
|
+
buildToolHandler((args: ContractInput) => extractContract(args))
|
|
49
|
+
);
|
|
50
|
+
}
|