mirror of
https://github.com/netbirdio/explain.git
synced 2026-05-22 18:44:28 -07:00
Add MCP server-side tools support for Anthropic provider
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
33bc9fb789
commit
d8fac71d18
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@netbirdio/explain",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"description": "Full-stack AI assistant library with React frontend components and Node.js backend handler",
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "./dist/client/index.js",
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Message } from "../types";
|
||||
import { AnthropicProvider } from "./providers/anthropic";
|
||||
import { DifyProvider } from "./providers/dify";
|
||||
import { OpenAIProvider } from "./providers/openai";
|
||||
import type { LLMProvider, Middleware, Tool } from "./providers/types";
|
||||
import type { LLMProvider, McpServer, Middleware, Tool } from "./providers/types";
|
||||
|
||||
export type AssistantConfig = {
|
||||
provider: "anthropic" | "openai" | "dify" | LLMProvider;
|
||||
@@ -12,6 +12,7 @@ export type AssistantConfig = {
|
||||
systemPrompt?: string;
|
||||
middleware?: Middleware[];
|
||||
tools?: Tool[];
|
||||
mcpServers?: McpServer[];
|
||||
};
|
||||
|
||||
type HandlerOptions = {
|
||||
@@ -133,7 +134,7 @@ export function createAssistant(config: AssistantConfig) {
|
||||
systemPrompt = result.systemPrompt;
|
||||
}
|
||||
|
||||
const reply = await provider.chat(messages, systemPrompt, config.tools);
|
||||
const reply = await provider.chat(messages, systemPrompt, config.tools, config.mcpServers);
|
||||
return { reply };
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ export type { AssistantConfig } from "./handler";
|
||||
export { AnthropicProvider } from "./providers/anthropic";
|
||||
export { DifyProvider } from "./providers/dify";
|
||||
export { OpenAIProvider } from "./providers/openai";
|
||||
export type { LLMProvider, ProviderConfig, Middleware, Tool } from "./providers/types";
|
||||
export type { LLMProvider, McpServer, ProviderConfig, Middleware, Tool } from "./providers/types";
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Message } from "../../types";
|
||||
import type { LLMProvider, ProviderConfig, Tool } from "./types";
|
||||
import type { LLMProvider, McpServer, ProviderConfig, Tool } from "./types";
|
||||
|
||||
type AnthropicMessage = {
|
||||
role: "user" | "assistant";
|
||||
@@ -20,17 +20,36 @@ export class AnthropicProvider implements LLMProvider {
|
||||
this.model = config.model || "claude-sonnet-4-20250514";
|
||||
}
|
||||
|
||||
async chat(messages: Message[], systemPrompt?: string, tools?: Tool[]): Promise<string> {
|
||||
async chat(messages: Message[], systemPrompt?: string, tools?: Tool[], mcpServers?: McpServer[]): Promise<string> {
|
||||
const anthropicMessages: AnthropicMessage[] = messages.map((m) => ({
|
||||
role: m.role === "context" || m.role === "system" ? ("user" as const) : m.role,
|
||||
content: m.role === "context" ? `[Context]: ${m.content}` : m.content,
|
||||
}));
|
||||
|
||||
const toolDefs = tools?.map((t) => ({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
input_schema: t.input_schema,
|
||||
}));
|
||||
const toolDefs: Record<string, unknown>[] = [];
|
||||
|
||||
if (tools?.length) {
|
||||
for (const t of tools) {
|
||||
toolDefs.push({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
input_schema: t.input_schema,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mcpServers?.length) {
|
||||
for (const mcp of mcpServers) {
|
||||
const mcpTool: Record<string, unknown> = {
|
||||
type: "mcp",
|
||||
server_label: mcp.server_label,
|
||||
server_url: mcp.server_url,
|
||||
};
|
||||
if (mcp.headers) mcpTool.headers = mcp.headers;
|
||||
if (mcp.allowed_tools) mcpTool.allowed_tools = mcp.allowed_tools;
|
||||
toolDefs.push(mcpTool);
|
||||
}
|
||||
}
|
||||
|
||||
const toolsByName = new Map(tools?.map((t) => [t.name, t]));
|
||||
|
||||
@@ -52,13 +71,19 @@ export class AnthropicProvider implements LLMProvider {
|
||||
body.tools = toolDefs;
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
"x-api-key": this.apiKey,
|
||||
"anthropic-version": "2023-06-01",
|
||||
};
|
||||
|
||||
if (mcpServers?.length) {
|
||||
headers["anthropic-beta"] = "mcp-client-2025-04-04";
|
||||
}
|
||||
|
||||
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-api-key": this.apiKey,
|
||||
"anthropic-version": "2023-06-01",
|
||||
},
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
@@ -76,6 +101,12 @@ export class AnthropicProvider implements LLMProvider {
|
||||
lastTextResponse = textBlock.text;
|
||||
}
|
||||
|
||||
// MCP server-side tools hit iteration limit — re-send to continue
|
||||
if (data.stop_reason === "pause_turn") {
|
||||
anthropicMessages.push({ role: "assistant", content: data.content });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.stop_reason !== "tool_use") {
|
||||
if (!lastTextResponse) {
|
||||
throw new Error("No text content in Anthropic response");
|
||||
@@ -83,7 +114,7 @@ export class AnthropicProvider implements LLMProvider {
|
||||
return lastTextResponse;
|
||||
}
|
||||
|
||||
// Handle tool calls
|
||||
// Handle client-side tool calls
|
||||
const toolUseBlocks = data.content.filter(
|
||||
(block: { type: string }) => block.type === "tool_use",
|
||||
);
|
||||
|
||||
@@ -7,8 +7,15 @@ export type Tool = {
|
||||
execute: (input: Record<string, unknown>) => Promise<string>;
|
||||
};
|
||||
|
||||
export type McpServer = {
|
||||
server_label: string;
|
||||
server_url: string;
|
||||
headers?: Record<string, string>;
|
||||
allowed_tools?: string[];
|
||||
};
|
||||
|
||||
export interface LLMProvider {
|
||||
chat(messages: Message[], systemPrompt?: string, tools?: Tool[]): Promise<string>;
|
||||
chat(messages: Message[], systemPrompt?: string, tools?: Tool[], mcpServers?: McpServer[]): Promise<string>;
|
||||
}
|
||||
|
||||
export type ProviderConfig = {
|
||||
|
||||
Reference in New Issue
Block a user