Skip to content

Instantly share code, notes, and snippets.

@laiso
Last active January 18, 2025 15:46
Show Gist options
  • Save laiso/8fa4f3b686937adc4a52c1674c1d6a6a to your computer and use it in GitHub Desktop.
Save laiso/8fa4f3b686937adc4a52c1674c1d6a6a to your computer and use it in GitHub Desktop.
import Anthropic from '@anthropic-ai/sdk';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
const client = new Anthropic(); // gets API Key from environment variable ANTHROPIC_API_KEY
type MCPServersConfig = {
mcpServers: Record<string, { command: string; args: string[]; env?: Record<string, string> }>;
};
async function getMcpClients(config: MCPServersConfig): Promise<Client[]> {
const clients: Client[] = [];
for (const key in config.mcpServers) {
const params = config.mcpServers[key];
const client = new Client(
{
name: key,
version: '0.1.0',
},
{
capabilities: {
sampling: {},
},
},
);
await client.connect(new StdioClientTransport(params));
clients.push(client);
}
return clients;
}
async function buildAllTools(config: MCPServersConfig): Promise<{ allTools: Anthropic.Tool[], toolServerMap: Map<string, Client> }> {
const mcpClients = await getMcpClients(config);
let allTools: Anthropic.Tool[] = [];
const toolServerMap = new Map();
for (let i = 0; i < mcpClients.length; i++) {
const mcpClient = mcpClients[i];
const toolList = await mcpClient.listTools();
const tools = toolList.tools.map((tool) => {
toolServerMap.set(tool.name, mcpClient);
return {
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
};
});
allTools = allTools.concat(tools);
}
return { allTools, toolServerMap };
}
async function main(question: string, path: string, config: MCPServersConfig, maxSteps = 10) {
console.log('Connected to server.');
console.log('Initialized.');
const { allTools, toolServerMap } = await buildAllTools(config);
const messages: Anthropic.MessageParam[] = [];
const userMessage: Anthropic.MessageParam = {
role: 'user',
content: question,
};
messages.push(userMessage);
const system = `You are Mini Coder, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
Current Working Directory: ${path}
`
let message = await client.messages.create({
model: 'claude-3-5-sonnet-latest',
max_tokens: 1024,
system,
messages: messages,
tools: allTools,
});
console.log('Assistaunt:', message.content[0].text);
messages.push({
role: 'assistant',
content: message.content[0].text,
});
let toolUse = message.content.find(
(content): content is Anthropic.ToolUseBlock => content.type === 'tool_use',
);
let iteration = 0;
while (toolUse && iteration < maxSteps) {
console.log({ toolUse });
const mcpClient = toolServerMap.get(toolUse.name);
if (!mcpClient) {
throw new Error(`Tool server not found for tool ${toolUse.name}`);
}
const result = await mcpClient.callTool(
{
name: toolUse.name,
arguments: toolUse.input,
},
CallToolResultSchema,
);
console.log('Tool Result:', result);
result.content.forEach((content) => {
const m: Anthropic.MessageParam = {
role: 'user',
content: content.text,
};
messages.push(m);
});
message = await client.messages.create({
model: 'claude-3-5-sonnet-latest',
max_tokens: 1024,
system,
messages: messages,
tools: allTools,
});
messages.push({
role: 'assistant',
content: message.content[0].text,
});
console.log('Assistaunt:', message.content[0].text);
toolUse = message.content.find(
(content): content is Anthropic.ToolUseBlock => content.type === 'tool_use',
);
console.log({ toolUse });
iteration++;
}
const mcpClients = await getMcpClients(config);
for (let i = 0; i < mcpClients.length; i++) {
await mcpClients[i].close();
console.log('Closed.');
}
}
const projectRoot = '/tmp/hono-app';
const config = {
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', projectRoot],
},
},
};
const instruction = `
Create a login API.
`;
main(instruction, projectRoot, config);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment