Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules
.mcp-cli
dist
.env
.aider*

**/.claude/settings.local.json
/public
18 changes: 18 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
51 changes: 51 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=22.17.0
FROM node:${NODE_VERSION}-slim AS base

LABEL fly_launch_runtime="Node.js"

# Node.js app lives here
WORKDIR /app

# Set production environment
ENV NODE_ENV="production"

# Install pnpm
ARG PNPM_VERSION=10.11.0
RUN npm install -g pnpm@$PNPM_VERSION


# Throw-away build stage to reduce size of final image
FROM base AS build

# Install node modules
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod=false

# Copy application code
COPY . .
RUN pnpm build
RUN pnpm prune --prod --ignore-scripts

WORKDIR /app/examples/chat-ui

RUN pnpm install --frozen-lockfile --prod=false

# Build application
RUN pnpm run build
RUN pnpm prune --prod --ignore-scripts

# Final stage for app image
FROM base

RUN npm install -g serve

# Copy built application
COPY --from=build /app /app

WORKDIR /app/examples/chat-ui

# Start the server by default, this can be overwritten at runtime
CMD [ "serve", "-s", "-p", "3000", "/app/examples/chat-ui/dist" ]
2 changes: 1 addition & 1 deletion examples/chat-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"rehype-highlight": "^7.0.2",
"remark-gfm": "^4.0.1",
"tailwindcss": "^4.0.14",
"use-mcp": "link:../..",
"workers-ai-provider": "^0.1.3"
},
"devDependencies": {
Expand All @@ -51,7 +52,6 @@
"tsx": "^4.20.3",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"use-mcp": "link:../..",
"vite": "^6.2.0",
"wrangler": "^4.1.0"
},
Expand Down
43 changes: 29 additions & 14 deletions examples/chat-ui/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 16 additions & 20 deletions examples/chat-ui/src/components/ChatApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,26 +207,22 @@ const ChatApp: React.FC<ChatAppProps> = () => {
>
<div className="flex flex-row flex-grow flex-1 min-h-screen relative">
{/* Sidebar and Navbar components */}
{false && (
<>
<ChatSidebar
sidebarVisible={sidebarVisible}
setSidebarVisible={setSidebarVisible}
conversations={conversations}
conversationId={conversationId}
setConversationId={setConversationId}
deleteConversation={deleteConversation}
editConversationTitle={editConversationTitle}
startNewConversation={startNewConversation}
selectedModel={selectedModel}
onModelChange={handleModelChange}
apiKeyUpdateTrigger={apiKeyUpdateTrigger}
onMcpToolsUpdate={setMcpTools}
mcpTools={mcpTools}
/>
<ChatNavbar sidebarVisible={sidebarVisible} setSidebarVisible={setSidebarVisible} />
</>
)}
<ChatSidebar
sidebarVisible={sidebarVisible}
setSidebarVisible={setSidebarVisible}
conversations={conversations}
conversationId={conversationId}
setConversationId={setConversationId}
deleteConversation={deleteConversation}
editConversationTitle={editConversationTitle}
startNewConversation={startNewConversation}
selectedModel={selectedModel}
onModelChange={handleModelChange}
apiKeyUpdateTrigger={apiKeyUpdateTrigger}
onMcpToolsUpdate={setMcpTools}
mcpTools={mcpTools}
/>
<ChatNavbar sidebarVisible={sidebarVisible} setSidebarVisible={setSidebarVisible} />
<div className="flex flex-col flex-grow h-full w-full">
<ConversationThread
conversations={conversations}
Expand Down
1 change: 0 additions & 1 deletion examples/chat-ui/src/components/ChatNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const ChatNavbar: React.FC<ChatNavbarProps> = ({ sidebarVisible, setSidebarVisib
</button>
</div>
)}
<h1 className="text-base font-semibold text-zinc-600 ml-2">AI Chat Template</h1>
</div>
</div>
</div>
Expand Down
14 changes: 13 additions & 1 deletion examples/chat-ui/src/components/McpServerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ function McpConnection({ server, onConnectionUpdate }: { server: McpServer; onCo
autoRetry: false,
popupFeatures: 'width=500,height=600,resizable=yes,scrollbars=yes',
transportType: server.transportType,
preventAutoAuth: true, // Prevent automatic popups on page load
})

// Update parent component with connection data
Expand Down Expand Up @@ -99,6 +98,19 @@ const McpServerModal: React.FC<McpServerModalProps> = ({ isOpen, onClose, onTool
}
}, [isOpen])

useEffect(() => {
if (!isOpen) return
servers.forEach((server) => {
if (!server.enabled) return
const conn = connectionData[server.id]
if (conn?.state === 'ready' && typeof conn.refreshTools === 'function') {
try {
conn.refreshTools()
} catch {}
}
})
}, [isOpen, servers, connectionData])

// Aggregate all tools from enabled servers and notify parent
useEffect(() => {
const allTools: Tool[] = []
Expand Down
3 changes: 1 addition & 2 deletions examples/chat-ui/src/components/McpServers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ function McpConnection({ serverUrl, onConnectionUpdate }: { serverUrl: string; o
debug: true,
autoRetry: false,
popupFeatures: 'width=500,height=600,resizable=yes,scrollbars=yes',
preventAutoAuth: true, // Prevent automatic popups on page load
})

// Update parent component with connection data
Expand Down Expand Up @@ -220,7 +219,7 @@ export function McpServers({ onToolsUpdate }: { onToolsUpdate?: (tools: Tool[])
{state === 'ready' && tools.length > 0 && (
<div>
<h3 className="font-medium text-xs mb-2">Available Tools ({tools.length})</h3>
<div className="border border-gray-200 rounded p-2 bg-gray-50 max-h-32 overflow-y-auto space-y-2">
<div className="border border-gray-200 rounded p-2 bg-gray-50 space-y-2">
{tools.map((tool: Tool, index: number) => (
<div key={index} className="text-xs pb-2 border-b border-gray-100 last:border-b-0">
<span className="font-medium">{tool.name}</span>
Expand Down
Loading