-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
Here is my MCP client app:
class MCPClient {
private mcp: Client;
private openai: OpenAI;
private transport: StdioClientTransport | null = null;
private tools: ChatCompletionTool[] = [];
constructor() {
this.openai = new OpenAI({
baseURL: OLLAMA_BASE_URL,
apiKey: OLLAMA_API_KEY || "ollama", // Ollama doesn't require an API key for local instances
});
this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" });
console.log("MCP Client initialized");
}
async connectToServer() {
const transport = new StdioClientTransport({
command: "node",
args: ["../mcp-servers/echo/build/index.js"],
});
await this.mcp.connect(transport);
console.log("Connected to server");
this.transport = transport;
}
async processQuery(query: string) {
const messages: ChatCompletionMessageParam[] = [
{
role: "user",
content: query,
},
];
try {
const response = await this.openai.chat.completions.create({
model: OLLAMA_MODEL,
messages,
tools: this.tools,
});
const finalText = [];
const toolResults = [];
// Get the assistant's response
const assistantMessage = response.choices[0].message;
// Check if there's a text response
if (assistantMessage.content) {
finalText.push(assistantMessage.content);
}
// Check if there are tool calls
if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
for (const toolCall of assistantMessage.tool_calls) {
const toolName = toolCall.function.name;
let toolArgs;
try {
toolArgs = JSON.parse(toolCall.function.arguments);
} catch (e) {
console.error("Failed to parse tool arguments:", e);
toolArgs = {};
}
const result = await this.mcp.callTool({
name: toolName,
arguments: toolArgs,
});
toolResults.push(result);
finalText.push(
`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`
);
// Add the tool result to the messages
messages.push({
role: "user",
content: result.content as string,
});
// Get a follow-up response from the model
const followUpResponse = await this.openai.chat.completions.create({
model: OLLAMA_MODEL,
max_tokens: 1000,
messages,
});
if (followUpResponse.choices[0].message.content) {
finalText.push(followUpResponse.choices[0].message.content);
}
}
}
return finalText.join("\n");
} catch (error) {
console.error("Error querying Ollama:", error);
return `Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`;
}
}
async chatLoop() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
try {
console.log("\nMCP Client Started!");
console.log("Type your queries or 'quit' to exit.");
while (true) {
const message = await rl.question("\nQuery: ");
if (message.toLowerCase() === "quit") {
break;
}
const response = await this.processQuery(message);
console.log("\n" + response);
}
} finally {
rl.close();
}
}
async cleanup() {
await this.mcp.close();
}
}
async function main() {
const mcpClient = new MCPClient();
try {
await mcpClient.connectToServer();
await mcpClient.chatLoop();
} finally {
await mcpClient.cleanup();
process.exit(0);
}
}
main();
Every time, the app exit without any console log when I call await this.mcp.connect(transport);
. The MCP server is in the correct path. Here is the code:
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "Echo",
version: "1.0.0"
});
server.resource(
"echo",
new ResourceTemplate("echo://{message}", { list: undefined }),
async (uri, { message }) => ({
contents: [{
uri: uri.href,
text: `Resource echo: ${message}`
}]
})
);
server.tool(
"echo",
{ message: z.string() },
async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }]
})
);
server.prompt(
"echo",
{ message: z.string() },
({ message }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please process this message: ${message}`
}
}]
})
);
export default server;
I compile it with tsc
command. The result is in build/index.js
.
Metadata
Metadata
Assignees
Labels
No labels