├── .prettierrc ├── client ├── src │ ├── __mocks__ │ │ └── styleMock.js │ ├── vite-env.d.ts │ ├── lib │ │ ├── utils.ts │ │ ├── notificationTypes.ts │ │ ├── auth-types.ts │ │ ├── configurationTypes.ts │ │ ├── hooks │ │ │ ├── useDraggablePane.ts │ │ │ ├── useTheme.ts │ │ │ ├── useCompletionState.ts │ │ │ ├── useToast.ts │ │ │ └── __tests__ │ │ │ │ └── useConnection.test.tsx │ │ ├── constants.ts │ │ ├── auth.ts │ │ └── oauth-state-machine.ts │ ├── components │ │ ├── ConsoleTab.tsx │ │ ├── PingTab.tsx │ │ ├── ui │ │ │ ├── label.tsx │ │ │ ├── textarea.tsx │ │ │ ├── input.tsx │ │ │ ├── toaster.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── popover.tsx │ │ │ ├── alert.tsx │ │ │ ├── tabs.tsx │ │ │ ├── button.tsx │ │ │ ├── combobox.tsx │ │ │ ├── dialog.tsx │ │ │ ├── toast.tsx │ │ │ ├── command.tsx │ │ │ └── select.tsx │ │ ├── SamplingTab.tsx │ │ ├── ListPane.tsx │ │ ├── __tests__ │ │ │ ├── samplingTab.test.tsx │ │ │ ├── samplingRequest.test.tsx │ │ │ └── DynamicJsonForm.test.tsx │ │ ├── JsonEditor.tsx │ │ ├── RootsTab.tsx │ │ ├── OAuthCallback.tsx │ │ ├── OAuthDebugCallback.tsx │ │ ├── SamplingRequest.tsx │ │ ├── History.tsx │ │ ├── PromptsTab.tsx │ │ └── ToolResults.tsx │ ├── main.tsx │ ├── utils │ │ ├── escapeUnicode.ts │ │ ├── __tests__ │ │ │ ├── escapeUnicode.test.ts │ │ │ └── oauthUtils.ts │ │ ├── oauthUtils.ts │ │ ├── schemaUtils.ts │ │ ├── configUtils.ts │ │ └── jsonUtils.ts │ ├── App.css │ └── index.css ├── postcss.config.js ├── tsconfig.jest.json ├── tsconfig.json ├── .gitignore ├── index.html ├── components.json ├── vite.config.ts ├── tsconfig.node.json ├── tsconfig.app.json ├── eslint.config.js ├── jest.config.cjs ├── public │ └── mcp.svg ├── bin │ ├── client.js │ └── start.js ├── README.md ├── tailwind.config.js └── package.json ├── .gitattributes ├── cli ├── src │ ├── client │ │ ├── types.ts │ │ ├── index.ts │ │ ├── prompts.ts │ │ ├── resources.ts │ │ ├── connection.ts │ │ └── tools.ts │ ├── error-handler.ts │ ├── transport.ts │ ├── index.ts │ └── cli.ts ├── tsconfig.json ├── package.json └── scripts │ └── make-executable.js ├── .prettierignore ├── mcp-inspector.png ├── .npmrc ├── .gitignore ├── sample-config.json ├── server ├── tsconfig.json ├── package.json └── src │ └── mcpProxy.ts ├── SECURITY.md ├── LICENSE ├── CLAUDE.md ├── CONTRIBUTING.md ├── .github └── workflows │ └── main.yml ├── package.json └── CODE_OF_CONDUCT.md /.prettierrc: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json linguist-generated=true 2 | -------------------------------------------------------------------------------- /client/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /cli/src/client/types.ts: -------------------------------------------------------------------------------- 1 | export type McpResponse = Record; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | packages 2 | server/build 3 | CODE_OF_CONDUCT.md 4 | SECURITY.md 5 | -------------------------------------------------------------------------------- /mcp-inspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baruchiro/inspector/main/mcp-inspector.png -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry="https://registry.npmjs.org/" 2 | @modelcontextprotocol:registry="https://registry.npmjs.org/" 3 | -------------------------------------------------------------------------------- /client/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /client/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode 3 | .idea 4 | node_modules/ 5 | *-workspace/ 6 | server/build 7 | client/dist 8 | client/tsconfig.app.tsbuildinfo 9 | client/tsconfig.node.tsbuildinfo 10 | cli/build 11 | test-output 12 | -------------------------------------------------------------------------------- /cli/src/client/index.ts: -------------------------------------------------------------------------------- 1 | // Re-export everything from the client modules 2 | export * from "./connection.js"; 3 | export * from "./prompts.js"; 4 | export * from "./resources.js"; 5 | export * from "./tools.js"; 6 | export * from "./types.js"; 7 | -------------------------------------------------------------------------------- /client/tsconfig.jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.app.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "esModuleInterop": true, 6 | "module": "ESNext", 7 | "moduleResolution": "node" 8 | }, 9 | "include": ["src"] 10 | } 11 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MCP Inspector 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "everything": { 4 | "command": "npx", 5 | "args": ["@modelcontextprotocol/server-everything"], 6 | "env": { 7 | "HELLO": "Hello MCP!" 8 | } 9 | }, 10 | "myserver": { 11 | "command": "node", 12 | "args": ["build/index.js", "arg1", "arg2"], 13 | "env": { 14 | "KEY": "value", 15 | "KEY2": "value2" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/components/ConsoleTab.tsx: -------------------------------------------------------------------------------- 1 | import { TabsContent } from "@/components/ui/tabs"; 2 | 3 | const ConsoleTab = () => ( 4 | 5 |
6 |
Welcome to MCP Client Console
7 | {/* Console output would go here */} 8 |
9 |
10 | ); 11 | 12 | export default ConsoleTab; 13 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "Node16", 5 | "moduleResolution": "Node16", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "resolveJsonModule": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules", "packages", "**/*.spec.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /client/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import { Toaster } from "@/components/ui/toaster.tsx"; 4 | import App from "./App.tsx"; 5 | import "./index.css"; 6 | import { TooltipProvider } from "./components/ui/tooltip.tsx"; 7 | 8 | createRoot(document.getElementById("root")!).render( 9 | 10 | 11 | 12 | 13 | 14 | , 15 | ); 16 | -------------------------------------------------------------------------------- /cli/src/error-handler.ts: -------------------------------------------------------------------------------- 1 | function formatError(error: unknown): string { 2 | let message: string; 3 | 4 | if (error instanceof Error) { 5 | message = error.message; 6 | } else if (typeof error === "string") { 7 | message = error; 8 | } else { 9 | message = "Unknown error"; 10 | } 11 | 12 | return message; 13 | } 14 | 15 | export function handleError(error: unknown): never { 16 | const errorMessage = formatError(error); 17 | console.error(errorMessage); 18 | 19 | process.exit(1); 20 | } 21 | -------------------------------------------------------------------------------- /client/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/index.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "resolveJsonModule": true, 13 | "noUncheckedIndexedAccess": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "packages", "**/*.spec.ts", "build"] 17 | } 18 | -------------------------------------------------------------------------------- /client/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import path from "path"; 3 | import { defineConfig } from "vite"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react()], 8 | server: { 9 | host: true, 10 | }, 11 | resolve: { 12 | alias: { 13 | "@": path.resolve(__dirname, "./src"), 14 | }, 15 | }, 16 | build: { 17 | minify: false, 18 | rollupOptions: { 19 | output: { 20 | manualChunks: undefined, 21 | }, 22 | }, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /client/src/utils/escapeUnicode.ts: -------------------------------------------------------------------------------- 1 | // Utility function to escape Unicode characters 2 | export function escapeUnicode(obj: unknown): string { 3 | return JSON.stringify( 4 | obj, 5 | (_key: string, value) => { 6 | if (typeof value === "string") { 7 | // Replace non-ASCII characters with their Unicode escape sequences 8 | return value.replace(/[^\0-\x7F]/g, (char) => { 9 | return "\\u" + ("0000" + char.charCodeAt(0).toString(16)).slice(-4); 10 | }); 11 | } 12 | return value; 13 | }, 14 | 2, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /client/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /client/src/components/PingTab.tsx: -------------------------------------------------------------------------------- 1 | import { TabsContent } from "@/components/ui/tabs"; 2 | import { Button } from "@/components/ui/button"; 3 | 4 | const PingTab = ({ onPingClick }: { onPingClick: () => void }) => { 5 | return ( 6 | 7 |
8 |
9 | 15 |
16 |
17 |
18 | ); 19 | }; 20 | 21 | export default PingTab; 22 | -------------------------------------------------------------------------------- /client/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | margin: 0 auto; 3 | } 4 | 5 | .logo { 6 | height: 6em; 7 | padding: 1.5em; 8 | will-change: filter; 9 | transition: filter 300ms; 10 | } 11 | .logo:hover { 12 | filter: drop-shadow(0 0 2em #646cffaa); 13 | } 14 | .logo.react:hover { 15 | filter: drop-shadow(0 0 2em #61dafbaa); 16 | } 17 | 18 | @keyframes logo-spin { 19 | from { 20 | transform: rotate(0deg); 21 | } 22 | to { 23 | transform: rotate(360deg); 24 | } 25 | } 26 | 27 | @media (prefers-reduced-motion: no-preference) { 28 | a:nth-of-type(2) .logo { 29 | animation: logo-spin infinite 20s linear; 30 | } 31 | } 32 | 33 | .card { 34 | padding: 2em; 35 | } 36 | 37 | .read-the-docs { 38 | color: #888; 39 | } 40 | -------------------------------------------------------------------------------- /client/src/lib/notificationTypes.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NotificationSchema as BaseNotificationSchema, 3 | ClientNotificationSchema, 4 | ServerNotificationSchema, 5 | } from "@modelcontextprotocol/sdk/types.js"; 6 | import { z } from "zod"; 7 | 8 | export const StdErrNotificationSchema = BaseNotificationSchema.extend({ 9 | method: z.literal("notifications/stderr"), 10 | params: z.object({ 11 | content: z.string(), 12 | }), 13 | }); 14 | 15 | export const NotificationSchema = ClientNotificationSchema.or( 16 | StdErrNotificationSchema, 17 | ) 18 | .or(ServerNotificationSchema) 19 | .or(BaseNotificationSchema); 20 | 21 | export type StdErrNotification = z.infer; 22 | export type Notification = z.infer; 23 | -------------------------------------------------------------------------------- /client/src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as LabelPrimitive from "@radix-ui/react-label"; 3 | import { cva, type VariantProps } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | const labelVariants = cva( 8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", 9 | ); 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )); 22 | Label.displayName = LabelPrimitive.Root.displayName; 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /client/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export type TextareaProps = React.TextareaHTMLAttributes; 6 | 7 | const Textarea = React.forwardRef( 8 | ({ className, ...props }, ref) => { 9 | return ( 10 |