@ubuligan/codegen 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/chunk-5WSAJTXT.js +209 -0
- package/dist/chunk-5WSAJTXT.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +43 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jsznpm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// src/emit.ts
|
|
2
|
+
import { compile } from "json-schema-to-typescript";
|
|
3
|
+
|
|
4
|
+
// src/naming.ts
|
|
5
|
+
function toCamelCase(raw) {
|
|
6
|
+
const parts = raw.split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
7
|
+
if (parts.length === 0) return "_";
|
|
8
|
+
const [first, ...rest] = parts;
|
|
9
|
+
const head = /^[0-9]/.test(first) ? `_${first}` : first;
|
|
10
|
+
return head.charAt(0).toLowerCase() + head.slice(1) + rest.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
11
|
+
}
|
|
12
|
+
function toPascalCase(raw) {
|
|
13
|
+
const camel = toCamelCase(raw);
|
|
14
|
+
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
15
|
+
}
|
|
16
|
+
function dedupe(names) {
|
|
17
|
+
const seen = /* @__PURE__ */ new Map();
|
|
18
|
+
return names.map((name) => {
|
|
19
|
+
const count = seen.get(name) ?? 0;
|
|
20
|
+
seen.set(name, count + 1);
|
|
21
|
+
return count === 0 ? name : `${name}${count + 1}`;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/emit.ts
|
|
26
|
+
async function emitSdk(intro, opts = {}) {
|
|
27
|
+
const className = opts.className ?? "GeneratedMCPClient";
|
|
28
|
+
const methods = dedupe(intro.tools.map((t) => toCamelCase(t.name)));
|
|
29
|
+
const prepared = [];
|
|
30
|
+
const typeBlocks = [];
|
|
31
|
+
for (let i = 0; i < intro.tools.length; i++) {
|
|
32
|
+
const tool = intro.tools[i];
|
|
33
|
+
const method = methods[i];
|
|
34
|
+
const inputType = `${toPascalCase(tool.name)}Input`;
|
|
35
|
+
const props = tool.inputSchema?.properties ?? {};
|
|
36
|
+
const hasInput = Object.keys(props).length > 0;
|
|
37
|
+
if (hasInput) {
|
|
38
|
+
const ts = await compileSchema(tool.inputSchema, inputType);
|
|
39
|
+
typeBlocks.push(ts);
|
|
40
|
+
}
|
|
41
|
+
prepared.push({ tool, method, inputType, hasInput });
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
header(intro),
|
|
45
|
+
`import { MCPClient, type MCPClientOptions } from "@ubuligan/client";`,
|
|
46
|
+
"",
|
|
47
|
+
typeBlocks.join("\n").trim(),
|
|
48
|
+
"",
|
|
49
|
+
renderClass(className, intro, prepared),
|
|
50
|
+
"",
|
|
51
|
+
renderFactory(className)
|
|
52
|
+
].filter((s) => s !== "").join("\n");
|
|
53
|
+
}
|
|
54
|
+
async function compileSchema(schema, name) {
|
|
55
|
+
const out = await compile(schema, name, {
|
|
56
|
+
bannerComment: "",
|
|
57
|
+
additionalProperties: false,
|
|
58
|
+
style: { singleQuote: false }
|
|
59
|
+
});
|
|
60
|
+
return out.trim();
|
|
61
|
+
}
|
|
62
|
+
function header(intro) {
|
|
63
|
+
return [
|
|
64
|
+
"/* eslint-disable */",
|
|
65
|
+
"// ---------------------------------------------------------------------------",
|
|
66
|
+
`// Auto-generated by @ubuligan/codegen from "${intro.serverName}@${intro.serverVersion}".`,
|
|
67
|
+
"// Do not edit by hand \xE2\u20AC\u201D re-run `mcp-codegen` to regenerate.",
|
|
68
|
+
"// ---------------------------------------------------------------------------"
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
function renderClass(className, intro, tools) {
|
|
72
|
+
const toolMethods = tools.map((p) => renderToolMethod(p)).join("\n\n");
|
|
73
|
+
const resourceConsts = renderResourceConsts(intro);
|
|
74
|
+
const promptMethods = renderPromptMethods(intro);
|
|
75
|
+
return `export class ${className} extends MCPClient {${resourceConsts}
|
|
76
|
+
|
|
77
|
+
${indent(toolMethods, 2)}${promptMethods ? "\n\n" + indent(promptMethods, 2) : ""}
|
|
78
|
+
}`;
|
|
79
|
+
}
|
|
80
|
+
function renderToolMethod(p) {
|
|
81
|
+
const doc = p.tool.description ? `/** ${escapeBlock(p.tool.description)} */
|
|
82
|
+
` : "";
|
|
83
|
+
const arg = p.hasInput ? `input: ${p.inputType}` : "input?: Record<string, never>";
|
|
84
|
+
const pass = p.hasInput ? "input as unknown as Record<string, unknown>" : "{}";
|
|
85
|
+
return `${doc}async ${p.method}(${arg}) {
|
|
86
|
+
return this.callTool(${JSON.stringify(p.tool.name)}, ${pass});
|
|
87
|
+
}`;
|
|
88
|
+
}
|
|
89
|
+
function renderResourceConsts(intro) {
|
|
90
|
+
if (intro.resources.length === 0) return "";
|
|
91
|
+
const entries = intro.resources.map((r) => ` ${JSON.stringify(toCamelCase(r.name ?? r.uri))}: ${JSON.stringify(r.uri)},`).join("\n");
|
|
92
|
+
return `
|
|
93
|
+
/** Known resource URIs advertised by the server. */
|
|
94
|
+
static readonly resources = {
|
|
95
|
+
${entries}
|
|
96
|
+
} as const;
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
function renderPromptMethods(intro) {
|
|
100
|
+
if (intro.prompts.length === 0) return "";
|
|
101
|
+
return intro.prompts.map((prompt) => {
|
|
102
|
+
const method = toCamelCase(`get-${prompt.name}-prompt`);
|
|
103
|
+
const doc = prompt.description ? `/** ${escapeBlock(prompt.description)} */
|
|
104
|
+
` : "";
|
|
105
|
+
const argType = prompt.arguments && prompt.arguments.length > 0 ? "{ " + prompt.arguments.map((a) => `${JSON.stringify(a.name)}${a.required ? "" : "?"}: string`).join("; ") + " }" : "Record<string, string>";
|
|
106
|
+
return `${doc}async ${method}(args?: ${argType}) {
|
|
107
|
+
return this.getPrompt(${JSON.stringify(prompt.name)}, args ?? {});
|
|
108
|
+
}`;
|
|
109
|
+
}).join("\n\n");
|
|
110
|
+
}
|
|
111
|
+
function renderFactory(className) {
|
|
112
|
+
return `/** Create and connect a typed ${className}. */
|
|
113
|
+
export async function create(options: MCPClientOptions): Promise<${className}> {
|
|
114
|
+
const client = new ${className}(options);
|
|
115
|
+
await client.connect();
|
|
116
|
+
return client;
|
|
117
|
+
}`;
|
|
118
|
+
}
|
|
119
|
+
function indent(text, spaces) {
|
|
120
|
+
const pad = " ".repeat(spaces);
|
|
121
|
+
return text.split("\n").map((line) => line ? pad + line : line).join("\n");
|
|
122
|
+
}
|
|
123
|
+
function escapeBlock(text) {
|
|
124
|
+
return text.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/introspect.ts
|
|
128
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
129
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
130
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
131
|
+
function parseTarget(raw) {
|
|
132
|
+
if (/^https?:\/\//i.test(raw)) {
|
|
133
|
+
return { type: "http", url: raw };
|
|
134
|
+
}
|
|
135
|
+
const parts = raw.trim().split(/\s+/);
|
|
136
|
+
const [command, ...args] = parts;
|
|
137
|
+
if (!command) throw new Error("Empty target");
|
|
138
|
+
return { type: "stdio", command, args };
|
|
139
|
+
}
|
|
140
|
+
function buildTransport(target) {
|
|
141
|
+
if (target.type === "http") {
|
|
142
|
+
return new StreamableHTTPClientTransport(new URL(target.url), {
|
|
143
|
+
requestInit: target.headers ? { headers: target.headers } : void 0
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return new StdioClientTransport({
|
|
147
|
+
command: target.command,
|
|
148
|
+
args: target.args,
|
|
149
|
+
env: process.env
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async function introspect(target) {
|
|
153
|
+
const client = new Client({ name: "mcp-codegen", version: "0.1.0" });
|
|
154
|
+
await client.connect(buildTransport(target));
|
|
155
|
+
try {
|
|
156
|
+
const version = client.getServerVersion();
|
|
157
|
+
const tools = await safeList(() => client.listTools(), "tools");
|
|
158
|
+
const resources = await safeList(() => client.listResources(), "resources");
|
|
159
|
+
const prompts = await safeList(() => client.listPrompts(), "prompts");
|
|
160
|
+
return {
|
|
161
|
+
serverName: version?.name ?? "mcp-server",
|
|
162
|
+
serverVersion: version?.version ?? "0.0.0",
|
|
163
|
+
tools: (tools?.tools ?? []).map((t) => ({
|
|
164
|
+
name: t.name,
|
|
165
|
+
description: t.description,
|
|
166
|
+
inputSchema: t.inputSchema ?? { type: "object" },
|
|
167
|
+
outputSchema: t.outputSchema
|
|
168
|
+
})),
|
|
169
|
+
resources: (resources?.resources ?? []).map((r) => ({
|
|
170
|
+
uri: r.uri,
|
|
171
|
+
name: r.name,
|
|
172
|
+
description: r.description,
|
|
173
|
+
mimeType: r.mimeType
|
|
174
|
+
})),
|
|
175
|
+
prompts: (prompts?.prompts ?? []).map((p) => ({
|
|
176
|
+
name: p.name,
|
|
177
|
+
description: p.description,
|
|
178
|
+
arguments: p.arguments
|
|
179
|
+
}))
|
|
180
|
+
};
|
|
181
|
+
} finally {
|
|
182
|
+
await client.close();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function safeList(fn, label) {
|
|
186
|
+
try {
|
|
187
|
+
return await fn();
|
|
188
|
+
} catch (error) {
|
|
189
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
190
|
+
if (/method not found|-32601/i.test(msg)) return void 0;
|
|
191
|
+
throw new Error(`Failed to list ${label}: ${msg}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/index.ts
|
|
196
|
+
async function generateSdk(options) {
|
|
197
|
+
const target = typeof options.target === "string" ? parseTarget(options.target) : options.target;
|
|
198
|
+
const introspection = await introspect(target);
|
|
199
|
+
const code = await emitSdk(introspection, options);
|
|
200
|
+
return { code, introspection };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
emitSdk,
|
|
205
|
+
parseTarget,
|
|
206
|
+
introspect,
|
|
207
|
+
generateSdk
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=chunk-5WSAJTXT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/emit.ts","../src/naming.ts","../src/introspect.ts","../src/index.ts"],"sourcesContent":["import { compile } from \"json-schema-to-typescript\";\r\nimport type { JSONSchema7 } from \"json-schema\";\r\nimport type { Introspection, ToolInfo } from \"./introspect.js\";\r\nimport { dedupe, toCamelCase, toPascalCase } from \"./naming.js\";\r\n\r\nexport interface EmitOptions {\r\n /** Class name for the generated SDK. Default \"GeneratedMCPClient\". */\r\n className?: string;\r\n}\r\n\r\ninterface PreparedTool {\r\n tool: ToolInfo;\r\n method: string;\r\n inputType: string;\r\n hasInput: boolean;\r\n}\r\n\r\n/**\r\n * Generate a self-contained, type-safe TypeScript SDK from an introspected\r\n * server. The output wraps `@ubuligan/client` and exposes one typed method\r\n * per tool, plus typed resource/prompt helpers.\r\n */\r\nexport async function emitSdk(intro: Introspection, opts: EmitOptions = {}): Promise<string> {\r\n const className = opts.className ?? \"GeneratedMCPClient\";\r\n\r\n const methods = dedupe(intro.tools.map((t) => toCamelCase(t.name)));\r\n const prepared: PreparedTool[] = [];\r\n const typeBlocks: string[] = [];\r\n\r\n for (let i = 0; i < intro.tools.length; i++) {\r\n const tool = intro.tools[i]!;\r\n const method = methods[i]!;\r\n const inputType = `${toPascalCase(tool.name)}Input`;\r\n const props = (tool.inputSchema?.properties ?? {}) as Record<string, unknown>;\r\n const hasInput = Object.keys(props).length > 0;\r\n\r\n if (hasInput) {\r\n const ts = await compileSchema(tool.inputSchema, inputType);\r\n typeBlocks.push(ts);\r\n }\r\n prepared.push({ tool, method, inputType, hasInput });\r\n }\r\n\r\n return [\r\n header(intro),\r\n `import { MCPClient, type MCPClientOptions } from \"@ubuligan/client\";`,\r\n \"\",\r\n typeBlocks.join(\"\\n\").trim(),\r\n \"\",\r\n renderClass(className, intro, prepared),\r\n \"\",\r\n renderFactory(className),\r\n ]\r\n .filter((s) => s !== \"\")\r\n .join(\"\\n\");\r\n}\r\n\r\nasync function compileSchema(schema: JSONSchema7, name: string): Promise<string> {\r\n const out = await compile(schema as Parameters<typeof compile>[0], name, {\r\n bannerComment: \"\",\r\n additionalProperties: false,\r\n style: { singleQuote: false },\r\n });\r\n return out.trim();\r\n}\r\n\r\nfunction header(intro: Introspection): string {\r\n return [\r\n \"/* eslint-disable */\",\r\n \"// ---------------------------------------------------------------------------\",\r\n `// Auto-generated by @ubuligan/codegen from \"${intro.serverName}@${intro.serverVersion}\".`,\r\n \"// Do not edit by hand — re-run `mcp-codegen` to regenerate.\",\r\n \"// ---------------------------------------------------------------------------\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction renderClass(className: string, intro: Introspection, tools: PreparedTool[]): string {\r\n const toolMethods = tools.map((p) => renderToolMethod(p)).join(\"\\n\\n\");\r\n const resourceConsts = renderResourceConsts(intro);\r\n const promptMethods = renderPromptMethods(intro);\r\n\r\n return `export class ${className} extends MCPClient {${resourceConsts}\r\n\r\n${indent(toolMethods, 2)}${promptMethods ? \"\\n\\n\" + indent(promptMethods, 2) : \"\"}\r\n}`;\r\n}\r\n\r\nfunction renderToolMethod(p: PreparedTool): string {\r\n const doc = p.tool.description ? `/** ${escapeBlock(p.tool.description)} */\\n` : \"\";\r\n const arg = p.hasInput ? `input: ${p.inputType}` : \"input?: Record<string, never>\";\r\n const pass = p.hasInput ? \"input as unknown as Record<string, unknown>\" : \"{}\";\r\n return `${doc}async ${p.method}(${arg}) {\r\n return this.callTool(${JSON.stringify(p.tool.name)}, ${pass});\r\n}`;\r\n}\r\n\r\nfunction renderResourceConsts(intro: Introspection): string {\r\n if (intro.resources.length === 0) return \"\";\r\n const entries = intro.resources\r\n .map((r) => ` ${JSON.stringify(toCamelCase(r.name ?? r.uri))}: ${JSON.stringify(r.uri)},`)\r\n .join(\"\\n\");\r\n return `\\n /** Known resource URIs advertised by the server. */\\n static readonly resources = {\\n${entries}\\n } as const;\\n`;\r\n}\r\n\r\nfunction renderPromptMethods(intro: Introspection): string {\r\n if (intro.prompts.length === 0) return \"\";\r\n return intro.prompts\r\n .map((prompt) => {\r\n const method = toCamelCase(`get-${prompt.name}-prompt`);\r\n const doc = prompt.description ? `/** ${escapeBlock(prompt.description)} */\\n` : \"\";\r\n const argType =\r\n prompt.arguments && prompt.arguments.length > 0\r\n ? \"{ \" +\r\n prompt.arguments\r\n .map((a) => `${JSON.stringify(a.name)}${a.required ? \"\" : \"?\"}: string`)\r\n .join(\"; \") +\r\n \" }\"\r\n : \"Record<string, string>\";\r\n return `${doc}async ${method}(args?: ${argType}) {\r\n return this.getPrompt(${JSON.stringify(prompt.name)}, args ?? {});\r\n}`;\r\n })\r\n .join(\"\\n\\n\");\r\n}\r\n\r\nfunction renderFactory(className: string): string {\r\n return `/** Create and connect a typed ${className}. */\r\nexport async function create(options: MCPClientOptions): Promise<${className}> {\r\n const client = new ${className}(options);\r\n await client.connect();\r\n return client;\r\n}`;\r\n}\r\n\r\nfunction indent(text: string, spaces: number): string {\r\n const pad = \" \".repeat(spaces);\r\n return text\r\n .split(\"\\n\")\r\n .map((line) => (line ? pad + line : line))\r\n .join(\"\\n\");\r\n}\r\n\r\nfunction escapeBlock(text: string): string {\r\n return text.replace(/\\*\\//g, \"*\\\\/\").replace(/\\r?\\n/g, \" \");\r\n}\r\n","/** Convert an arbitrary identifier into a safe camelCase method name. */\nexport function toCamelCase(raw: string): string {\n const parts = raw.split(/[^a-zA-Z0-9]+/).filter(Boolean);\n if (parts.length === 0) return \"_\";\n const [first, ...rest] = parts;\n const head = /^[0-9]/.test(first!) ? `_${first}` : first!;\n return (\n head.charAt(0).toLowerCase() +\n head.slice(1) +\n rest.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(\"\")\n );\n}\n\n/** Convert an arbitrary identifier into a safe PascalCase type name. */\nexport function toPascalCase(raw: string): string {\n const camel = toCamelCase(raw);\n return camel.charAt(0).toUpperCase() + camel.slice(1);\n}\n\n/** Ensure generated method names don't collide after normalization. */\nexport function dedupe(names: string[]): string[] {\n const seen = new Map<string, number>();\n return names.map((name) => {\n const count = seen.get(name) ?? 0;\n seen.set(name, count + 1);\n return count === 0 ? name : `${name}${count + 1}`;\n });\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { JSONSchema7 } from \"json-schema\";\n\nexport interface ToolInfo {\n name: string;\n description?: string;\n inputSchema: JSONSchema7;\n outputSchema?: JSONSchema7;\n}\n\nexport interface ResourceInfo {\n uri: string;\n name?: string;\n description?: string;\n mimeType?: string;\n}\n\nexport interface PromptInfo {\n name: string;\n description?: string;\n arguments?: { name: string; description?: string; required?: boolean }[];\n}\n\nexport interface Introspection {\n serverName: string;\n serverVersion: string;\n tools: ToolInfo[];\n resources: ResourceInfo[];\n prompts: PromptInfo[];\n}\n\n/** How to reach the server being introspected. */\nexport type Target =\n | { type: \"http\"; url: string; headers?: Record<string, string> }\n | { type: \"stdio\"; command: string; args?: string[] };\n\n/**\n * Parse a CLI target string. An http(s):// value becomes an HTTP target;\n * anything else is treated as a stdio command line (first token = command).\n */\nexport function parseTarget(raw: string): Target {\n if (/^https?:\\/\\//i.test(raw)) {\n return { type: \"http\", url: raw };\n }\n const parts = raw.trim().split(/\\s+/);\n const [command, ...args] = parts;\n if (!command) throw new Error(\"Empty target\");\n return { type: \"stdio\", command, args };\n}\n\nfunction buildTransport(target: Target): Transport {\n if (target.type === \"http\") {\n return new StreamableHTTPClientTransport(new URL(target.url), {\n requestInit: target.headers ? { headers: target.headers } : undefined,\n });\n }\n return new StdioClientTransport({\n command: target.command,\n args: target.args,\n env: process.env as Record<string, string>,\n });\n}\n\n/** Connect to a server and collect everything needed for codegen. */\nexport async function introspect(target: Target): Promise<Introspection> {\n const client = new Client({ name: \"mcp-codegen\", version: \"0.1.0\" });\n await client.connect(buildTransport(target));\n\n try {\n const version = client.getServerVersion();\n const tools = await safeList(() => client.listTools(), \"tools\");\n const resources = await safeList(() => client.listResources(), \"resources\");\n const prompts = await safeList(() => client.listPrompts(), \"prompts\");\n\n return {\n serverName: version?.name ?? \"mcp-server\",\n serverVersion: version?.version ?? \"0.0.0\",\n tools: (tools?.tools ?? []).map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: (t.inputSchema ?? { type: \"object\" }) as JSONSchema7,\n outputSchema: t.outputSchema as JSONSchema7 | undefined,\n })),\n resources: (resources?.resources ?? []).map((r) => ({\n uri: r.uri,\n name: r.name,\n description: r.description,\n mimeType: r.mimeType,\n })),\n prompts: (prompts?.prompts ?? []).map((p) => ({\n name: p.name,\n description: p.description,\n arguments: p.arguments,\n })),\n };\n } finally {\n await client.close();\n }\n}\n\n/**\n * Some servers don't implement every capability (e.g. no prompts). Treat a\n * \"Method not found\" as an empty list rather than a hard failure.\n */\nasync function safeList<T>(fn: () => Promise<T>, label: string): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (/method not found|-32601/i.test(msg)) return undefined;\n throw new Error(`Failed to list ${label}: ${msg}`);\n }\n}\n","import { emitSdk, type EmitOptions } from \"./emit.js\";\nimport { introspect, parseTarget, type Introspection, type Target } from \"./introspect.js\";\n\nexport { introspect, parseTarget } from \"./introspect.js\";\nexport type { Introspection, Target, ToolInfo, ResourceInfo, PromptInfo } from \"./introspect.js\";\nexport { emitSdk } from \"./emit.js\";\nexport type { EmitOptions } from \"./emit.js\";\n\nexport interface GenerateOptions extends EmitOptions {\n /** Server target: an http(s) URL string or a stdio command line, or a parsed Target. */\n target: string | Target;\n}\n\n/**\n * High-level entry point: connect to a server, introspect it, and return the\n * generated SDK source as a string.\n */\nexport async function generateSdk(options: GenerateOptions): Promise<{ code: string; introspection: Introspection }> {\n const target = typeof options.target === \"string\" ? parseTarget(options.target) : options.target;\n const introspection = await introspect(target);\n const code = await emitSdk(introspection, options);\n return { code, introspection };\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generateSdk
|
|
4
|
+
} from "./chunk-5WSAJTXT.js";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
8
|
+
import { dirname, resolve } from "path";
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
import pc from "picocolors";
|
|
11
|
+
var program = new Command();
|
|
12
|
+
program.name("mcp-codegen").description("Generate a type-safe TypeScript SDK from a live MCP server").argument("<target>", 'Server URL (http://...) or stdio command (e.g. "node dist/index.js")').option("-o, --out <file>", "Output file path", "mcp-sdk.ts").option("-c, --class-name <name>", "Generated class name", "GeneratedMCPClient").option("--stdout", "Print to stdout instead of writing a file", false).action(async (target, opts) => {
|
|
13
|
+
try {
|
|
14
|
+
process.stderr.write(pc.dim(`Connecting to ${target} ...
|
|
15
|
+
`));
|
|
16
|
+
const { code, introspection } = await generateSdk({
|
|
17
|
+
target,
|
|
18
|
+
className: opts.className
|
|
19
|
+
});
|
|
20
|
+
process.stderr.write(
|
|
21
|
+
pc.green(
|
|
22
|
+
`\u2713 ${introspection.tools.length} tools, ${introspection.resources.length} resources, ${introspection.prompts.length} prompts
|
|
23
|
+
`
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
if (opts.stdout) {
|
|
27
|
+
process.stdout.write(code + "\n");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const outPath = resolve(process.cwd(), opts.out);
|
|
31
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
32
|
+
await writeFile(outPath, code + "\n", "utf8");
|
|
33
|
+
process.stderr.write(pc.green(`\u2713 Wrote ${pc.bold(opts.out)}
|
|
34
|
+
`));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
37
|
+
process.stderr.write(pc.red(`\u2717 ${msg}
|
|
38
|
+
`));
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
program.parseAsync();
|
|
43
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { generateSdk } from \"./index.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"mcp-codegen\")\n .description(\"Generate a type-safe TypeScript SDK from a live MCP server\")\n .argument(\"<target>\", \"Server URL (http://...) or stdio command (e.g. \\\"node dist/index.js\\\")\")\n .option(\"-o, --out <file>\", \"Output file path\", \"mcp-sdk.ts\")\n .option(\"-c, --class-name <name>\", \"Generated class name\", \"GeneratedMCPClient\")\n .option(\"--stdout\", \"Print to stdout instead of writing a file\", false)\n .action(async (target: string, opts: { out: string; className: string; stdout: boolean }) => {\n try {\n process.stderr.write(pc.dim(`Connecting to ${target} ...\\n`));\n const { code, introspection } = await generateSdk({\n target,\n className: opts.className,\n });\n\n process.stderr.write(\n pc.green(\n `✓ ${introspection.tools.length} tools, ${introspection.resources.length} resources, ${introspection.prompts.length} prompts\\n`,\n ),\n );\n\n if (opts.stdout) {\n process.stdout.write(code + \"\\n\");\n return;\n }\n\n const outPath = resolve(process.cwd(), opts.out);\n await mkdir(dirname(outPath), { recursive: true });\n await writeFile(outPath, code + \"\\n\", \"utf8\");\n process.stderr.write(pc.green(`✓ Wrote ${pc.bold(opts.out)}\\n`));\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n process.stderr.write(pc.red(`✗ ${msg}\\n`));\n process.exitCode = 1;\n }\n });\n\nprogram.parseAsync();\n"],"mappings":";;;;;;AACA,SAAS,OAAO,iBAAiB;AACjC,SAAS,SAAS,eAAe;AACjC,SAAS,eAAe;AACxB,OAAO,QAAQ;AAGf,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,aAAa,EAClB,YAAY,4DAA4D,EACxE,SAAS,YAAY,sEAAwE,EAC7F,OAAO,oBAAoB,oBAAoB,YAAY,EAC3D,OAAO,2BAA2B,wBAAwB,oBAAoB,EAC9E,OAAO,YAAY,6CAA6C,KAAK,EACrE,OAAO,OAAO,QAAgB,SAA8D;AAC3F,MAAI;AACF,YAAQ,OAAO,MAAM,GAAG,IAAI,iBAAiB,MAAM;AAAA,CAAQ,CAAC;AAC5D,UAAM,EAAE,MAAM,cAAc,IAAI,MAAM,YAAY;AAAA,MAChD;AAAA,MACA,WAAW,KAAK;AAAA,IAClB,CAAC;AAED,YAAQ,OAAO;AAAA,MACb,GAAG;AAAA,QACD,UAAK,cAAc,MAAM,MAAM,WAAW,cAAc,UAAU,MAAM,eAAe,cAAc,QAAQ,MAAM;AAAA;AAAA,MACrH;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,cAAQ,OAAO,MAAM,OAAO,IAAI;AAChC;AAAA,IACF;AAEA,UAAM,UAAU,QAAQ,QAAQ,IAAI,GAAG,KAAK,GAAG;AAC/C,UAAM,MAAM,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,UAAM,UAAU,SAAS,OAAO,MAAM,MAAM;AAC5C,YAAQ,OAAO,MAAM,GAAG,MAAM,gBAAW,GAAG,KAAK,KAAK,GAAG,CAAC;AAAA,CAAI,CAAC;AAAA,EACjE,SAAS,OAAO;AACd,UAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,YAAQ,OAAO,MAAM,GAAG,IAAI,UAAK,GAAG;AAAA,CAAI,CAAC;AACzC,YAAQ,WAAW;AAAA,EACrB;AACF,CAAC;AAEH,QAAQ,WAAW;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { JSONSchema7 } from 'json-schema';
|
|
2
|
+
|
|
3
|
+
interface ToolInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
inputSchema: JSONSchema7;
|
|
7
|
+
outputSchema?: JSONSchema7;
|
|
8
|
+
}
|
|
9
|
+
interface ResourceInfo {
|
|
10
|
+
uri: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
mimeType?: string;
|
|
14
|
+
}
|
|
15
|
+
interface PromptInfo {
|
|
16
|
+
name: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
arguments?: {
|
|
19
|
+
name: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
interface Introspection {
|
|
25
|
+
serverName: string;
|
|
26
|
+
serverVersion: string;
|
|
27
|
+
tools: ToolInfo[];
|
|
28
|
+
resources: ResourceInfo[];
|
|
29
|
+
prompts: PromptInfo[];
|
|
30
|
+
}
|
|
31
|
+
/** How to reach the server being introspected. */
|
|
32
|
+
type Target = {
|
|
33
|
+
type: "http";
|
|
34
|
+
url: string;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
} | {
|
|
37
|
+
type: "stdio";
|
|
38
|
+
command: string;
|
|
39
|
+
args?: string[];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Parse a CLI target string. An http(s):// value becomes an HTTP target;
|
|
43
|
+
* anything else is treated as a stdio command line (first token = command).
|
|
44
|
+
*/
|
|
45
|
+
declare function parseTarget(raw: string): Target;
|
|
46
|
+
/** Connect to a server and collect everything needed for codegen. */
|
|
47
|
+
declare function introspect(target: Target): Promise<Introspection>;
|
|
48
|
+
|
|
49
|
+
interface EmitOptions {
|
|
50
|
+
/** Class name for the generated SDK. Default "GeneratedMCPClient". */
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate a self-contained, type-safe TypeScript SDK from an introspected
|
|
55
|
+
* server. The output wraps `@ubuligan/client` and exposes one typed method
|
|
56
|
+
* per tool, plus typed resource/prompt helpers.
|
|
57
|
+
*/
|
|
58
|
+
declare function emitSdk(intro: Introspection, opts?: EmitOptions): Promise<string>;
|
|
59
|
+
|
|
60
|
+
interface GenerateOptions extends EmitOptions {
|
|
61
|
+
/** Server target: an http(s) URL string or a stdio command line, or a parsed Target. */
|
|
62
|
+
target: string | Target;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* High-level entry point: connect to a server, introspect it, and return the
|
|
66
|
+
* generated SDK source as a string.
|
|
67
|
+
*/
|
|
68
|
+
declare function generateSdk(options: GenerateOptions): Promise<{
|
|
69
|
+
code: string;
|
|
70
|
+
introspection: Introspection;
|
|
71
|
+
}>;
|
|
72
|
+
|
|
73
|
+
export { type EmitOptions, type GenerateOptions, type Introspection, type PromptInfo, type ResourceInfo, type Target, type ToolInfo, emitSdk, generateSdk, introspect, parseTarget };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ubuligan/codegen",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Generate a type-safe TypeScript SDK from a live MCP server's tool/resource/prompt schemas",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-codegen": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
24
|
+
"commander": "^12.1.0",
|
|
25
|
+
"json-schema-to-typescript": "^15.0.3",
|
|
26
|
+
"picocolors": "^1.1.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/json-schema": "^7.0.15",
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"tsup": "^8.3.5"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"author": "jsznpm",
|
|
37
|
+
"homepage": "https://github.com/jsznpm/create-mcp-toolkit#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/jsznpm/create-mcp-toolkit/issues"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/jsznpm/create-mcp-toolkit.git",
|
|
44
|
+
"directory": "packages/codegen"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"mcp",
|
|
48
|
+
"model-context-protocol",
|
|
49
|
+
"ai",
|
|
50
|
+
"llm",
|
|
51
|
+
"codegen",
|
|
52
|
+
"typescript",
|
|
53
|
+
"type-safe",
|
|
54
|
+
"openapi"
|
|
55
|
+
],
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"typecheck": "tsc --noEmit"
|
|
59
|
+
}
|
|
60
|
+
}
|