### Start Production Server Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Starts the production server after building the project. This is typically used for deployment. ```bash npm run start # or yarn start # or pnpm start ``` -------------------------------- ### Run Development Server with npm, yarn, or pnpm Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Starts the development server for local testing. Access the application at http://localhost:3000. ```bash npm run dev # or yarn dev # or pnpm dev ``` -------------------------------- ### Install Dependencies with npm, yarn, or pnpm Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Installs project dependencies using your preferred package manager. Ensure Node.js LTS is installed. ```bash npm install # or yarn install # or pnpm install ``` -------------------------------- ### Root Provider Tree Setup Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Wraps the application with necessary providers including CopilotKit, QueryClientProvider, ServerConfigsContext, McpServerManager, and ToolRenderer. Initializes CopilotKit with a Cloud API key and loads MCP server configurations from localStorage. ```tsx "use client"; import { CopilotKit } from "@copilotkit/react-core"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import React from "react"; import McpServerManager from "@/components/McpServerManager"; import { ToolRenderer } from "@/components/ToolRenderer"; import { CoAgentsProvider } from "@/components/coagents-provider"; import { useLocalStorage } from "@/hooks/use-local-storage"; export interface Config { endpoint: string; serverName: string; } export interface ConfigContextType { config: Config[]; setConfig: (c: Config[]) => void; } const queryClient = new QueryClient(); export const ServerConfigsContext = React.createContext(undefined); export default function Providers({ children }: { children: React.ReactNode }) { const [mcpConfig] = useLocalStorage("mcpConfig", []); const [config, setConfig] = React.useState(mcpConfig || []); return ( // 1. Expose server configs globally {/* 2. Bootstrap CopilotKit with your Cloud API key */} {/* 3. Push MCP server list into CopilotKit runtime */} {/* 4. Render tool-call status cards for every agent action */} {children} ); } // Usage in src/app/layout.tsx: // {children} ``` -------------------------------- ### TodoContext and TodoProvider Setup Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Defines the interfaces for Todo and SubTask, and provides the TodoProvider component to wrap the application subtree. It initializes state with sample data and exposes functions for managing todos and subtasks. ```tsx import React, { createContext, useContext, useState } from "react"; export interface SubTask { id: number; text: string; completed: boolean; parentId?: number; } export interface Todo { id: number; text: string; completed: boolean; subtasks: SubTask[]; expanded: boolean; } // Wrap any subtree that needs todo access export const TodoProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [todos, setTodos] = useState([ { id: Date.now(), text: "Blog Posts", completed: false, expanded: true, subtasks: [ { id: 1, text: "Agents 101: Build an Agent in 30 Minutes", completed: true }, { id: 2, text: "Simple Stack for Powerful Agents", completed: false }, ], }, ]); const addTodo = (str: string | null = null): number | null => { if (str === null) return null; setTodos(prev => [...prev, { id: Date.now(), text: str, completed: false, subtasks: [], expanded: false }]); return todos.length; }; const addSubtask = (parentId: number, subtask: string | null = null) => { if (!subtask) return; setTodos(prev => prev.map(t => t.id === parentId ? { ...t, subtasks: [...t.subtasks, { id: Date.now() + Math.random(), text: subtask, completed: false }] } : t )); }; // … toggleTodo, deleteTodo, toggleSubtask, deleteSubtask, addTaskAndSubtask return {children}; }; // Consume anywhere inside TodoProvider export const useTodo = () => { const ctx = useContext(TodoContext); if (!ctx) throw new Error("useTodo must be used within a TodoProvider"); return ctx; }; // Example const { todos, addTodo, addSubtask, deleteTodo } = useTodo(); addTodo("Deploy to Vercel"); // → adds parent task addSubtask(todos[0].id, "Run npm run build"); // → adds subtask to first todo deleteTodo(todos[1].id); // → removes second todo ``` -------------------------------- ### Display MCPConfigModal in a React Component Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt This example shows how to use the MCPConfigModal component in a parent React component. It manages the modal's open/closed state using React's useState hook and provides a button to trigger the modal. ```tsx "use client"; import { MCPConfigModal } from "@/components/mcp-config-modal"; import { useState } from "react"; export default function CanvasPage() { const [open, setOpen] = useState(false); return ( <> {/* Modal handles its own state for the server list */} setOpen(false)} /> ); } ``` -------------------------------- ### Set up Environment Variables Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Create a .env file in the root directory to store your API keys. An OpenAI API key is required. ```bash OPENAI_API_KEY = YOUR_API_KEY ``` -------------------------------- ### Build for Production with npm, yarn, or pnpm Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Compiles the project for production deployment. ```bash npm run build # or yarn build # or pnpm build ``` -------------------------------- ### Configure ChatWindow with MCP-aware Instructions Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt This component renders a CopilotChat interface. It's pre-configured with instructions that direct the AI to always use registered MCP servers for task completion and includes the current list of todos serialized into the system prompt for up-to-date context. ```tsx "use client"; import { CopilotChat } from "@copilotkit/react-ui"; import "@copilotkit/react-ui/styles.css"; import { useTodo } from "@/contexts/TodoContext"; export const ChatWindow = () => { const { todos } = useTodo(); return ( ); }; // Suggestion chips are wired in canvas.tsx: // useCopilotChatSuggestions({ // instructions: "Ask which MCP connection the agent should check. Once the // agent has checked the MCP connection, ask the agent to // suggest a task to do.", // minSuggestions: 1, // maxSuggestions: 3, // }, []); ``` -------------------------------- ### Implementing a Universal Tool Renderer with CopilotKit Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Use `useCopilotAction` with `name: "*"` to create a catch-all handler for any tool invocation. This allows for a unified display of tool call statuses (in progress, complete, error) using a custom component like `MCPToolCall`. ```tsx "use client"; import { useCopilotAction, CatchAllActionRenderProps } from "@copilotkit/react-core"; import MCPToolCall from "./MCPToolCall"; export function ToolRenderer() { useCopilotAction({ name: "*", // matches every tool call render: ({ name, status, args, result }: CatchAllActionRenderProps<[]>) => ( ), }); return null; } // MCPToolCall renders inline in the chat thread: // status === "inProgress" → animated Loader2 spinner // status === "complete" → green checkmark (or red X if result.error is set) // Clicking the card would expand args/result (currently commented out) // Example chat output when the AI calls a Linear MCP tool: // ┌─────────────────────────────────┐ // │ ✓ linear_create_issue │ // └─────────────────────────────────┘ ``` -------------------------------- ### Registering Todo App Actions with CopilotKit Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Use `useCopilotAction` to expose CRUD operations for a todo list to an AI agent. `useCopilotReadable` provides continuous visibility of the todo list state to the LLM. Ensure all necessary context providers are set up. ```tsx "use client"; import { useCopilotAction, useCopilotReadable } from "@copilotkit/react-core"; import { useTodo } from "@/contexts/TodoContext"; export const TodoApp = () => { const { todos, addTodo, addSubtask, addTaskAndSubtask, deleteTodo, deleteSubtask, toggleTodo, toggleSubtask } = useTodo(); // Always-on context: LLM can read the current todo list at any point useCopilotReadable({ description: "The current state of the todo list", value: JSON.stringify(todos) }); // Add a parent task useCopilotAction({ name: "ADD_TASK", description: "Adds a task to the todo list", parameters: [{ name: "title", type: "string", description: "The title of the task", required: true }], handler: ({ title }) => addTodo(title), }); // Add a subtask under a parent useCopilotAction({ name: "ADD_SUBTASK", description: "Adds a subtask to the todo list", parameters: [ { name: "id", type: "number", description: "Parent task id", required: true }, { name: "subtask", type: "string", description: "Subtask text", required: true }, ], handler: ({ id, subtask }) => addSubtask(id, subtask), }); // Add a task together with multiple subtasks in one shot useCopilotAction({ name: "ADD_TASK_AND_SUBTASK", description: "Adds a task and its subtask to the todo list", parameters: [ { name: "title", type: "string", description: "Task title", required: true }, { name: "subtask", type: "string[]", description: "Array of subtask texts", required: true }, ], handler: ({ title, subtask }) => addTaskAndSubtask(title, subtask), }); // Delete / complete actions follow the same pattern useCopilotAction({ name: "DELETE_TASK", parameters: [{ name: "id", type: "number", required: true }], handler: ({ id }) => deleteTodo(id) }); useCopilotAction({ name: "DELETE_SUBTASK", parameters: [{ name: "parentId", type: "number", required: true }, { name: "subtaskId", type: "number", required: true }], handler: ({ parentId, subtaskId }) => deleteSubtask(parentId, subtaskId) }); useCopilotAction({ name: "COMPLETE_TASK", parameters: [{ name: "id", type: "number", required: true }], handler: ({ id }) => toggleTodo(id) }); useCopilotAction({ name: "COMPLETE_SUBTASK", parameters: [{ name: "parentId", type: "number", required: true }, { name: "subtaskId", type: "number", required: true }], handler: ({ parentId, subtaskId }) => toggleSubtask(parentId, subtaskId) }); // … render JSX for the accordion list }; ``` -------------------------------- ### Lint Code with npm, yarn, or pnpm Source: https://github.com/copilotkit/copilotkit-mcp-demo/blob/main/README.md Runs the linter to check for code style issues and potential errors. ```bash npm run lint # or yarn lint # or pnpm lint ``` -------------------------------- ### Discriminated Union Usage for ServerConfig Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Demonstrates how to use a discriminated union (`ServerConfig`) to handle different transport types (stdio and sse) based on the `transport` property. This pattern is useful for type-safe conditional logic. ```typescript // Discriminated union usage: function describe(cfg: ServerConfig): string { if (cfg.transport === "stdio") return `${cfg.command} ${cfg.args.join(" ")}`; return cfg.url; } describe({ transport: "sse", url: "https://mcp.composio.dev/linear/TOKEN/sse" }); // → "https://mcp.composio.dev/linear/TOKEN/sse" describe({ transport: "stdio", command: "python", args: ["mcp_server.py"] }); // → "python mcp_server.py" ``` -------------------------------- ### MCP Server Configuration Types Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Defines the TypeScript types for MCP server configurations, including connection types, stdio configuration, SSE configuration, and the overall MCP configuration structure. Includes a constant for localStorage persistence. ```typescript // src/lib/mcp-config-types.ts export type ConnectionType = "stdio" | "sse"; export interface StdioConfig { command: string; // e.g. "python" args: string[]; // e.g. ["server.py", "--port", "8080"] transport: "stdio"; } export interface SSEConfig { url: string; // e.g. "http://localhost:8000/events" transport: "sse"; } export type ServerConfig = StdioConfig | SSEConfig; export interface MCPConfig { mcp_config: Record; } // Key used for localStorage persistence export const MCP_STORAGE_KEY = "mcp-server-configs"; ``` -------------------------------- ### Sync MCP Servers into CopilotKit Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt A component that synchronizes the list of configured MCP endpoints with the CopilotKit runtime using `setMcpServers`. It's rendered within `CopilotKit` and ensures active connections are kept up-to-date with the `ServerConfigsContext` state. ```tsx "use client"; import { useCopilotChat } from "@copilotkit/react-core"; import { useEffect } from "react"; import { Config } from "@/providers/Providers"; function McpServerManager({ configs }: { configs: Config[] }) { const { setMcpServers } = useCopilotChat(); useEffect(() => { // Registers all SSE endpoints with the CopilotKit runtime. // Each Config object must have { endpoint: string; serverName: string }. setMcpServers(configs); }, [setMcpServers]); return null; } export default McpServerManager; // Example: connecting a Linear MCP server // configs = [{ serverName: "linear", endpoint: "https://mcp.composio.dev/linear/YOUR_TOKEN/sse" }] // After this renders, the AI assistant can call any tool exposed by that server. ``` -------------------------------- ### Type-Safe Local Storage Hook Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Synchronizes state with localStorage, handling SSR safely by returning initialValue on the server. JSON serializes values on write and re-syncs if the key changes. ```tsx import { useState, useEffect } from "react"; export function useLocalStorage(key: string, initialValue: T): [T, (value: T) => void] { const [storedValue, setStoredValue] = useState(() => { if (typeof window === "undefined") return initialValue; // SSR guard try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch { return initialValue; } }); const setValue = (value: T) => { try { setStoredValue(value); if (typeof window !== "undefined") window.localStorage.setItem(key, JSON.stringify(value)); } catch (error) { console.error("Error writing to localStorage:", error); } }; return [storedValue, setValue]; } // Usage examples: const [mcpConfig, setMcpConfig] = useLocalStorage("mcpConfig", []); // Persist the MCP server list so it survives a page refresh setMcpConfig([ { serverName: "linear", endpoint: "https://mcp.composio.dev/linear/TOKEN/sse" }, { serverName: "github", endpoint: "https://mcp.composio.dev/github/TOKEN/sse" }, ]); // Read back on next mount — the hook initialises from localStorage automatically console.log(mcpConfig); // → [{ serverName: "linear", endpoint: "…" }, { serverName: "github", endpoint: "…" }] ``` -------------------------------- ### Render Todo Hierarchy with React Flow Source: https://context7.com/copilotkit/copilotkit-mcp-demo/llms.txt Renders todos as an interactive graph with parent and child nodes. Handles node clicks to toggle todo completion and subtask status. Rebuilds the graph when todos change. ```tsx import { ReactFlow, ReactFlowProvider, Background, useNodesState, useEdgesState, useReactFlow } from "reactflow"; import { ParentNode, ChildNode } from "./Nodes"; import { useTodo } from "@/contexts/TodoContext"; const nodeTypes = { ParentNode, ChildNode }; const VisualRepresentation = () => { const { todos, toggleTodo, toggleSubtask } = useTodo(); const [nodes, setNodes, onNodesChange] = useNodesState([]); const [edges, setEdges] = useEdgesState([]); const { fitView } = useReactFlow(); // Rebuild graph whenever todos change useEffect(() => { const units = todos.flatMap(item => { if (!item.expanded && todos.length !== 1) return []; const arr = [{ id: item.id.toString(), data: item, position: { x: 0, y: 0 }, type: "ParentNode" }]; item.subtasks.forEach((sub, i) arr.push({ id: sub.id.toString(), data: { ...sub, parentId: item.id.toString() }, position: { x: i % 2 === 0 ? -100 : 100, y: (i * 100) + 100 }, type: "ChildNode" }) ); return arr; }); setNodes(units); setEdges(todos.flatMap(item => item.subtasks.map(sub => ({ id: `${item.id}-${sub.id}`, source: item.id.toString(), target: sub.id.toString(), animated: true })) )); }, [todos]); return ( // Must be wrapped in ReactFlowProvider (done in the default export) { if (node.type === "ParentNode") toggleTodo(node.data.id); else toggleSubtask(parseInt(node.data.parentId), node.data.id); }} defaultViewport={{ x: 200, y: 100, zoom: 1 }} > ); }; export default function Test() { return ; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.