Skip to content

Commit 9ffab69

Browse files
committed
First draft
1 parent 4abd81f commit 9ffab69

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

packages/inference/src/McpClient.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3+
import { InferenceClient } from "./InferenceClient";
4+
import { homedir } from "os";
5+
import { join } from "path";
6+
import type { InferenceProvider } from "./types";
7+
import type {
8+
ChatCompletionInputTool,
9+
ChatCompletionOutput,
10+
} from "@huggingface/tasks/src/tasks/chat-completion/inference";
11+
12+
type ToolName = string;
13+
14+
export class McpClient {
15+
private client: InferenceClient;
16+
private provider: string;
17+
private model: string;
18+
private clients: Map<ToolName, Client> = new Map();
19+
private availableTools: ChatCompletionInputTool[] = [];
20+
21+
constructor({ provider, model, apiKey }: { provider: InferenceProvider; model: string; apiKey: string }) {
22+
this.client = new InferenceClient(apiKey);
23+
this.provider = provider;
24+
this.model = model;
25+
}
26+
27+
async addMcpServer(command: string, args: string[], env: Record<string, string>): Promise<void> {
28+
const transport = new StdioClientTransport({
29+
command,
30+
args,
31+
env,
32+
});
33+
const mcp = new Client({ name: "@huggingface/mcp-client", version: "1.0.0" });
34+
await mcp.connect(transport);
35+
36+
const toolsResult = await mcp.listTools();
37+
console.log(
38+
"Connected to server with tools:",
39+
toolsResult.tools.map(({ name }) => name)
40+
);
41+
42+
for (const tool of toolsResult.tools) {
43+
this.clients.set(tool.name, mcp);
44+
}
45+
46+
this.availableTools.push(
47+
...toolsResult.tools.map((tool) => {
48+
return {
49+
type: "function",
50+
function: {
51+
name: tool.name,
52+
description: tool.description,
53+
parameters: tool.inputSchema,
54+
},
55+
} satisfies ChatCompletionInputTool;
56+
})
57+
);
58+
}
59+
60+
async processQuery(query: string): Promise<ChatCompletionOutput> {
61+
/// TODO
62+
}
63+
64+
async cleanup(): Promise<void> {
65+
const clients = new Set(this.clients.values());
66+
await Promise.all([...clients].map((client) => client.close()));
67+
}
68+
}
69+
70+
async function main() {
71+
if (!process.env.HF_TOKEN) {
72+
console.error(`a valid HF_TOKEN must be passed`);
73+
process.exit(1);
74+
}
75+
76+
const client = new McpClient({
77+
provider: "together",
78+
model: "Qwen/Qwen2.5-72B-Instruct",
79+
apiKey: process.env.HF_TOKEN,
80+
});
81+
82+
try {
83+
await client.addMcpServer(
84+
"node",
85+
["--disable-warning=ExperimentalWarning", join(homedir(), "Desktop/hf-mcp/index.ts")],
86+
{
87+
HF_TOKEN: process.env.HF_TOKEN,
88+
}
89+
);
90+
91+
const response = await client.processQuery(`
92+
find an app that generates 3D models from text,
93+
and also get the best paper about transformers
94+
`);
95+
96+
console.log("\n" + response.choices[0].message.content);
97+
} finally {
98+
await client.cleanup();
99+
}
100+
}
101+
102+
if (require.main === module) {
103+
main();
104+
}

0 commit comments

Comments
 (0)