Skip to content

Commit a136797

Browse files
authored
MCP (#1981)
* Update ServerCard.svelte feat(mcp): add Model Context Protocol integration with tool support Improve MCP tools caching and server selection logic Replaces single-entry MCP tools cache with a multi-keyed cache based on server configuration, improving cache accuracy for different server sets. Refactors server selection logic in runMcpFlow to better handle custom server lists and selected server names. Removes MCP flow from generate.ts, streamlining text generation logic. * Add OAuth authentication for MCP servers Introduces browser-based OAuth flow for MCP servers, including new auth helpers, localStorage management, and UI actions for authentication and sign-out. Server cards now support authentication, and enabled servers include persisted auth headers for API requests. Adds callback handler and route for OAuth completion. * Add server authentication status and UI indicators Introduces an 'authRequired' property to MCPServer and health check responses to indicate when authentication is needed. Updates ServerCard UI to show authentication badges and conditionally display Authenticate/Sign out buttons. Store now tracks authenticated server IDs and updates them on auth changes. Health check logic and error handling improved to detect and signal authentication requirements. * Show MCP Servers button only for authenticated users The MCP Servers button in NavMenu is now conditionally rendered for users with a username or email, ensuring only authenticated users can access server management. Also, MCPServerManager modal width and help text background color have been updated for improved UI consistency. * format * Refactor MCP client management and tool invocation Introduces a pooled MCP client system for efficient reuse and connection management. Refactors tool invocation to support per-call timeouts, abort signals, and parallel execution with improved error handling. Ensures MCP clients are properly closed after each flow and updates related modules to use the new client pool and signal-aware APIs. * Improve OAuth state generation and error handling Replaces Math.random-based OAuth state with a cryptographically-strong random generator using Web Crypto API. Sanitizes error messages in the callback handler to prevent unsafe HTML embedding. Ensures token_type is trimmed and defaults to 'Bearer' in authentication headers. * Update blue color shades and improve MCP server UI Standardizes blue color usage across components for consistency, switching from blue-500 to blue-600 in buttons, borders, and backgrounds. Refactors MCPServerManager and ServerCard to use a Switch component for enabling servers, improving accessibility and code clarity. Increases loop count in runMcpFlow.ts for more robust streaming. Updates multimodal model indicators to use blue-600 in dark mode for better visual alignment. * Adjust input padding and card border styling Reduced horizontal padding on AddServerForm input fields for improved layout. Updated ServerCard selected state to use semi-transparent blue border for better visual distinction. * Improve provider metadata handling in text generation Sanitizes tool/function names to comply with provider guidelines by replacing disallowed characters and limiting length. Enhances router metadata emission to support cases where only provider information is available, and captures the x-inference-provider header from upstream OpenAI-compatible servers to notify the UI of the provider used. * Update ServerCard.svelte * Add per-model tool calling support and overrides Introduces a `supportsTools` flag for models to indicate tool/function calling capability, aggregates provider support, and adds per-model user overrides via settings. Updates UI to display tool support, enables forced tool calling, and ensures backend respects these settings during text generation and conversation flows. * lint * Enhance MCP client to append structuredContent Updates the MCP HTTP client to append structuredContent as JSON to the textual output if provided by the server. Also bumps @modelcontextprotocol/sdk dependency to version 1.21.1. * Refactor settings bindings for Svelte 5 compatibility Replaces direct store mutations with functional bindings for settings fields in model and application settings pages, ensuring proper updates via store methods. Also updates ToolUpdate.svelte to use $derived.by for availableTools and initializes state variables with explicit undefined values. * Update MCPServerManager.svelte * Improve MCP server management UI and validation Added a security warning to the AddServerForm and improved form styling. Updated MCPServerManager to clarify views, use a larger add icon, and show quick tips. ServerCard header styling was refined. MCP server store now prunes invalid selected server IDs after refresh. * Add router tool support configuration Introduces LLM_ROUTER_ENABLE_TOOLS environment variable and configures its usage in both .env and prod.yaml. Updates model processing to enable tool support for the router when the variable is set to true. * Improve MCP server manager and card UI * Refactor MCP icon and update app name usage Extracted the MCP icon into a reusable IconMCP.svelte component and replaced inline SVG usage in MCPServerManager.svelte. Updated references to 'HuggingChat' to use the dynamic PUBLIC_APP_NAME from public config for better branding flexibility. * Update model badges to use colored backgrounds Replaces border-based styling for tool and multimodal badges with colored backgrounds and text for improved visual clarity in models and settings pages. * Remove 'Base' label from ServerCard Eliminates the conditional rendering of the 'Base' label for servers of type 'base' in the ServerCard component. * Add router bypass for tool-capable models Implements logic to bypass Arch routing and select a configured tool-capable model when tools are enabled and active, using new helpers in toolsRoute.ts. Updates environment and documentation to describe new LLM_ROUTER_TOOLS_MODEL config. Ensures fallback to Arch routing if no suitable model is found. * Add <think> block handling for reasoning tokens Introduces logic to merge provider-specific reasoning fields into <think> blocks within the token stream, mirroring OpenAI adapter behavior. Ensures <think> blocks are closed before final output and strips them from tool call messages to prevent confusion in follow-up reasoning. * Update ChatInput.svelte * Update ChatInput.svelte * Update ChatInput.svelte * Refactor formatting and fix indentation in server code Improves code readability in toolsRoute.ts and runMcpFlow.ts by reformatting multi-line statements and correcting indentation. No functional changes were made. * Handle user aborts quietly in runMcpFlow * Remove namespaced tool aliases from OpenAI tools * Update Switch.svelte * Add navigation for tool update groups in chat * Add MCP server favicon support and update config * Fix router details rendering with missing metadata Updates conditional rendering to check for the presence of 'route' in streamingRouterMetadata, preventing errors when metadata is undefined or missing the 'route' property. * format * Add model tool support indicator to chat UI Introduces a `modelSupportsTools` prop to ChatInput and ChatWindow components to reflect whether the selected model supports tool calling. The MCP server indicator now visually changes and updates its tooltip based on tool support, improving user feedback for models without tool capabilities. * Improve MCP health check URL validation and timeout * Update server manager and card UI styles and labels * Update prod.yaml * Remove obsolete LLM log files Deleted three outdated LLM log files related to chat completions for improved log management and reduced clutter. * derive tool name in tool group * Make MCP server count clickable to open manager Replaces the MCP server count text in ChatInput with a button that opens the MCPServerManager. Also improves layout responsiveness in MCPServerManager for small screens. * Update MCPServerManager.svelte * Improve MCP server health check and tool response handling * remove mcp oauth ...for now * feat(chat): allow manual navigation of tool-call groups while streaming\n\n- Add toolAutoFollowLatest state to stop auto-snapping when user pages\n- Default to newest group while streaming; clamp index as groups change\n- Resume auto-follow when streaming ends or user returns to newest group\n\nAffects: src/lib/components/chat/ChatMessage.svelte * feat(chat): show active tool call in footer and hide routing while calling\n\n- Derive current in-flight tool from assistant updates\n- Map to human-friendly displayName using page.data.tools\n- When a tool is actively running: render "Calling tool <name>" and skip the router/model status\n\nAffects: src/lib/components/chat/ChatWindow.svelte * feat(mcp): optionally forward HF user token to official HF MCP endpoint\n\n- Add MCP_FORWARD_HF_USER_TOKEN config flag\n- Forward logged-in user's HF token to https://huggingface.co/mcp?login when no Authorization header is set\n- Apply overlay in runMcpFlow and in /api/mcp/health endpoint\n- Add shared helpers (hasAuthHeader, isStrictHfMcpLogin, hasNonEmptyToken)\n- Clarify client store comment about server-side overlay\n\nAffects: src/lib/server/config.ts, src/lib/server/textGeneration/mcp/runMcpFlow.ts, src/routes/api/mcp/health/+server.ts, src/lib/server/mcp/hf.ts, src/lib/stores/mcpServers.ts * infra(chart): add read-mcp scope to OPENID_SCOPES for MCP access\n\n- Update dev and prod charts to request 'read-mcp' alongside 'openid profile inference-api' * feat(prompt): include current date and image markdown hint in tool preprompt\n\n- Add today's date to tool preprompt for time-aware tools\n- Document how to inline generated images via markdown\n\nAffects: src/lib/server/textGeneration/utils/toolPrompt.ts * chore(ui): minor formatting and cleanup in MCP ServerCard and conversation page import\n\n- Collapse named imports and remove stray blank lines in ServerCard\n- Normalize import whitespace in +page.svelte\n\nNo functional changes * Update .env * infra(chart): enable HF MCP token forwarding in dev and prod\n\n- Set MCP_FORWARD_HF_USER_TOKEN: 'true' in both dev and prod envs * feat(mcp-ui): add Hugging Face MCP Settings button next to Health Check\n\n- Detects servers hosted on huggingface.co\n- Opens https://huggingface.co/settings/mcp in a new tab\n- Matches existing button styling and Svelte 5 runes patterns * style(chat): remove image margins and add rounded-lg in conversation prose\n\n- Apply prose-img:my-0 and prose-img:rounded-lg to message and reasoning prose containers\n- Keeps change scoped to chat UI only * Update toolPrompt.ts * note sure about this * Update MCP_SERVERS and tool config in dev and prod envs * security: enforce URL safety in MCP generation path and factorize check\n\n- Add shared isValidUrl (HTTPS only, basic localhost/private checks; exact behavior from /api/mcp/health)\n- Apply guard in runMcpFlow before any MCP connections\n- Reuse the same validator in /api/mcp/health and /api/fetch-url\n- Keep function semantics identical to existing health route implementation * ui: show HF MCP Settings button only for exact base URL (https://huggingface.co/mcp?login)\n\n- Add client util isStrictHfMcpLogin\n- Update ServerCard to check exact login URL instead of hostname match * Handle tool name collisions with server suffixes * Add documentation for MCP Tools integration * format
1 parent 0f4475d commit a136797

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+5067
-281
lines changed

.env

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ COUPLE_SESSION_WITH_COOKIE_NAME=
3434
# when OPEN_ID is configured, users are required to login after the welcome modal
3535
OPENID_CLIENT_ID=
3636
OPENID_CLIENT_SECRET=
37-
OPENID_SCOPES="openid profile inference-api"
37+
OPENID_SCOPES="openid profile inference-api read-mcp"
3838
USE_USER_TOKEN=
3939
AUTOMATIC_LOGIN=# if true authentication is required on all routes
4040

@@ -73,10 +73,15 @@ LLM_ROUTER_MAX_ASSISTANT_LENGTH=500
7373
LLM_ROUTER_MAX_PREV_USER_LENGTH=400
7474

7575
# Enable router multimodal fallback (set to true to allow image inputs via router)
76-
LLM_ROUTER_ENABLE_MULTIMODAL=false
76+
LLM_ROUTER_ENABLE_MULTIMODAL=
7777
# Optional: specific model to use for multimodal requests. If not set, uses first multimodal model
7878
LLM_ROUTER_MULTIMODAL_MODEL=
7979

80+
# Enable router tool support (set to true to allow tool calling via router)
81+
LLM_ROUTER_ENABLE_TOOLS=
82+
# Required when tools are active: id or name of the model to use for MCP tool calls.
83+
LLM_ROUTER_TOOLS_MODEL=
84+
8085
# Router UI overrides (client-visible)
8186
# Public display name for the router entry in the model list. Defaults to "Omni".
8287
PUBLIC_LLM_ROUTER_DISPLAY_NAME=Omni
@@ -113,6 +118,11 @@ ADMIN_TOKEN=#We recommend leaving this empty, you can get the token from the ter
113118
LLM_SUMMARIZATION=true # generate conversation titles with LLMs
114119

115120
ALLOW_IFRAME=true # Allow the app to be embedded in an iframe
121+
122+
# Base servers list (JSON array). Example: MCP_SERVERS=[{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"}, {"name": "Hugging Face", "url": "https://huggingface.co/mcp"}]
123+
MCP_SERVERS=
124+
# When true, forward the logged-in user's Hugging Face access token
125+
MCP_FORWARD_HF_USER_TOKEN=
116126
ENABLE_DATA_EXPORT=true
117127

118128
### Rate limits ###

.github/workflows/slugify.yaml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ on:
44
workflow_call:
55
inputs:
66
value:
7-
description: 'Value to slugify'
7+
description: "Value to slugify"
88
required: true
99
type: string
1010
outputs:
1111
slug:
12-
description: 'Slugified value'
12+
description: "Slugified value"
1313
value: ${{ jobs.generate-slug.outputs.slug }}
1414

1515
jobs:
@@ -22,51 +22,51 @@ jobs:
2222
- name: Setup Go
2323
uses: actions/setup-go@v5
2424
with:
25-
go-version: '1.21'
25+
go-version: "1.21"
2626

2727
- name: Generate slug
2828
id: slugify
2929
run: |
3030
# Create working directory
3131
mkdir -p $HOME/slugify
3232
cd $HOME/slugify
33-
33+
3434
# Create Go script
3535
cat > main.go << 'EOF'
3636
package main
37-
37+
3838
import (
3939
"fmt"
4040
"os"
4141
"github.com/gosimple/slug"
4242
)
43-
43+
4444
func main() {
4545
if len(os.Args) < 2 {
4646
fmt.Println("Usage: slugify <text>")
4747
os.Exit(1)
4848
}
49-
49+
5050
text := os.Args[1]
5151
slugged := slug.Make(text)
5252
fmt.Println(slugged)
5353
}
5454
EOF
55-
55+
5656
# Initialize module and install dependency
5757
go mod init slugify
5858
go mod tidy
5959
go get github.com/gosimple/slug
60-
60+
6161
# Build
6262
go build -o slugify main.go
63-
63+
6464
# Generate slug
6565
VALUE="${{ inputs.value }}"
6666
echo "Input value: $VALUE"
67-
67+
6868
SLUG=$(./slugify "$VALUE")
6969
echo "Generated slug: $SLUG"
70-
70+
7171
# Export
72-
echo "slug=$SLUG" >> $GITHUB_OUTPUT
72+
echo "slug=$SLUG" >> $GITHUB_OUTPUT

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,43 @@ When you select Omni in the UI, Chat UI will:
142142
- Emit RouterMetadata immediately (route and actual model used) so the UI can display it.
143143
- Stream from the selected model via your configured `OPENAI_BASE_URL`. On errors, it tries route fallbacks.
144144

145+
Tool and multimodal shortcuts:
146+
147+
- Multimodal: If `LLM_ROUTER_ENABLE_MULTIMODAL=true` and the user sends an image, the router bypasses Arch and uses `LLM_ROUTER_MULTIMODAL_MODEL` (or the first multimodal model). Route name: `multimodal`.
148+
- Tools: If `LLM_ROUTER_ENABLE_TOOLS=true` and the user has at least one MCP server enabled, the router bypasses Arch and uses `LLM_ROUTER_TOOLS_MODEL`. If that model is missing or misconfigured, it falls back to Arch routing. Route name: `agentic`.
149+
150+
### MCP Tools (Optional)
151+
152+
Chat UI can call tools exposed by Model Context Protocol (MCP) servers and feed results back to the model using OpenAI function calling. You can preconfigure trusted servers via env, let users add their own, and optionally have the Omni router auto‑select a tools‑capable model.
153+
154+
Configure servers (base list for all users):
155+
156+
```env
157+
# JSON array of servers: name, url, optional headers
158+
MCP_SERVERS=[
159+
{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"},
160+
{"name": "Hugging Face MCP Login", "url": "https://huggingface.co/mcp?login"}
161+
]
162+
163+
# Forward the signed-in user's Hugging Face token to the official HF MCP login endpoint
164+
# when no Authorization header is set on that server entry.
165+
MCP_FORWARD_HF_USER_TOKEN=true
166+
```
167+
168+
Enable router tool path (Omni):
169+
170+
- Set `LLM_ROUTER_ENABLE_TOOLS=true` and choose a tools‑capable target with `LLM_ROUTER_TOOLS_MODEL=<model id or name>`.
171+
- The target must support OpenAI tools/function calling. Chat UI surfaces a “tools” badge on models that advertise this; you can also force‑enable it per‑model in settings (see below).
172+
173+
Use tools in the UI:
174+
175+
- Open “MCP Servers” from the top‑right menu or from the `+` menu in the chat input to add servers, toggle them on, and run Health Check. The server card lists available tools.
176+
- When a model calls a tool, the message shows a compact “tool” block with parameters, a progress bar while running, and the result (or error). Results are also provided back to the model for follow‑up.
177+
178+
Per‑model overrides:
179+
180+
- In Settings → Model, you can toggle “Tool calling (functions)” and “Multimodal input” per model. These overrides apply even if the provider metadata doesn’t advertise the capability.
181+
145182
## Building
146183

147184
To create a production version of your app:

chart/env/dev.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ ingressInternal:
3838
envVars:
3939
TEST: "test"
4040
COUPLE_SESSION_WITH_COOKIE_NAME: "token"
41-
OPENID_SCOPES: "openid profile inference-api"
41+
OPENID_SCOPES: "openid profile inference-api read-mcp"
4242
USE_USER_TOKEN: "true"
43+
MCP_FORWARD_HF_USER_TOKEN: "true"
4344
AUTOMATIC_LOGIN: "false"
4445

4546
ADDRESS_HEADER: "X-Forwarded-For"
@@ -67,6 +68,10 @@ envVars:
6768
LLM_ROUTER_ARCH_TIMEOUT_MS: "10000"
6869
LLM_ROUTER_ENABLE_MULTIMODAL: "true"
6970
LLM_ROUTER_MULTIMODAL_MODEL: "Qwen/Qwen3-VL-235B-A22B-Thinking"
71+
LLM_ROUTER_ENABLE_TOOLS: "true"
72+
LLM_ROUTER_TOOLS_MODEL: "moonshotai/Kimi-K2-Instruct-0905"
73+
MCP_SERVERS: >
74+
[{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"}, {"name": "Hugging Face", "url": "https://huggingface.co/mcp?login"}]
7075
PUBLIC_LLM_ROUTER_DISPLAY_NAME: "Omni"
7176
PUBLIC_LLM_ROUTER_LOGO_URL: "https://cdn-uploads.huggingface.co/production/uploads/5f17f0a0925b9863e28ad517/C5V0v1xZXv6M7FXsdJH9b.png"
7277
PUBLIC_LLM_ROUTER_ALIAS_ID: "omni"

chart/env/prod.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ ingressInternal:
4848

4949
envVars:
5050
COUPLE_SESSION_WITH_COOKIE_NAME: "token"
51-
OPENID_SCOPES: "openid profile inference-api"
51+
OPENID_SCOPES: "openid profile inference-api read-mcp"
5252
USE_USER_TOKEN: "true"
53+
MCP_FORWARD_HF_USER_TOKEN: "true"
5354
AUTOMATIC_LOGIN: "false"
5455

5556
ADDRESS_HEADER: "X-Forwarded-For"
@@ -76,7 +77,11 @@ envVars:
7677
LLM_ROUTER_OTHER_ROUTE: "casual_conversation"
7778
LLM_ROUTER_ARCH_TIMEOUT_MS: "10000"
7879
LLM_ROUTER_ENABLE_MULTIMODAL: "true"
79-
LLM_ROUTER_MULTIMODAL_MODEL: "Qwen/Qwen3-VL-235B-A22B-Thinking"
80+
LLM_ROUTER_MULTIMODAL_MODEL: "Qwen/Qwen3-VL-30B-A3B-Instruct"
81+
LLM_ROUTER_ENABLE_TOOLS: "true"
82+
LLM_ROUTER_TOOLS_MODEL: "moonshotai/Kimi-K2-Instruct-0905"
83+
MCP_SERVERS: >
84+
[{"name": "Web Search (Exa)", "url": "https://mcp.exa.ai/mcp"}, {"name": "Hugging Face", "url": "https://huggingface.co/mcp?login"}]
8085
PUBLIC_LLM_ROUTER_DISPLAY_NAME: "Omni"
8186
PUBLIC_LLM_ROUTER_LOGO_URL: "https://cdn-uploads.huggingface.co/production/uploads/5f17f0a0925b9863e28ad517/C5V0v1xZXv6M7FXsdJH9b.png"
8287
PUBLIC_LLM_ROUTER_ALIAS_ID: "omni"

0 commit comments

Comments
 (0)