diff --git a/.gitattributes b/.gitattributes index b11f1d6..f6a30e1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -yarn.lock linguist-generated=true -packages/**/* linguist-generated=true +dist/**/* linguist-generated=true diff --git a/packages/mcp-typescript/.github/workflows/main.yml b/.github/workflows/main.yml similarity index 100% rename from packages/mcp-typescript/.github/workflows/main.yml rename to .github/workflows/main.yml diff --git a/.gitignore b/.gitignore index 3e71bf2..6e28fb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,131 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + .DS_Store -node_modules -server/build -client/dist -client/tsconfig.app.tsbuildinfo diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index b7c83c0..0000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -packages -server/build diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md index bbdad57..a9371ba 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,2 @@ -# MCP Inspector - -The MCP inspector is a developer tool for testing and debugging MCP servers. - -Setup: - -```bash -yarn -``` - -You can run it in dev mode via: - -```bash -yarn dev -``` - -This will start both the client and server. - -To run in production mode: - -```bash -yarn build -yarn start -``` +# mcp-typescript +TypeScript implementation of the Model Context Protocol diff --git a/client/.gitignore b/client/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/client/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/client/README.md b/client/README.md deleted file mode 100644 index 780c92d..0000000 --- a/client/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: - -- Configure the top-level `parserOptions` property like this: - -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ["./tsconfig.node.json", "./tsconfig.app.json"], - tsconfigRootDir: import.meta.dirname, - }, - }, -}); -``` - -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from "eslint-plugin-react"; - -export default tseslint.config({ - // Set the react version - settings: { react: { version: "18.3" } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs["jsx-runtime"].rules, - }, -}); -``` diff --git a/client/components.json b/client/components.json deleted file mode 100644 index cd5af28..0000000 --- a/client/components.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/index.css", - "baseColor": "slate", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - } -} \ No newline at end of file diff --git a/client/eslint.config.js b/client/eslint.config.js deleted file mode 100644 index 79a552e..0000000 --- a/client/eslint.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { ignores: ["dist"] }, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ["**/*.{ts,tsx}"], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - }, - }, -); diff --git a/client/index.html b/client/index.html deleted file mode 100644 index e4b78ea..0000000 --- a/client/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React + TS - - -
- - - diff --git a/client/package.json b/client/package.json deleted file mode 100644 index cf896a8..0000000 --- a/client/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "client", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-select": "^2.1.2", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-tabs": "^1.1.1", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "lucide-react": "^0.447.0", - "mcp-typescript": "file:../packages/mcp-typescript", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "tailwind-merge": "^2.5.3", - "tailwindcss-animate": "^1.0.7" - }, - "devDependencies": { - "@eslint/js": "^9.11.1", - "@types/node": "^22.7.5", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.2", - "autoprefixer": "^10.4.20", - "eslint": "^9.11.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.12", - "globals": "^15.9.0", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.13", - "typescript": "^5.5.3", - "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" - } -} diff --git a/client/postcss.config.js b/client/postcss.config.js deleted file mode 100644 index 2e7af2b..0000000 --- a/client/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/client/public/vite.svg b/client/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/client/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/App.css b/client/src/App.css deleted file mode 100644 index b9d355d..0000000 --- a/client/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/client/src/App.tsx b/client/src/App.tsx deleted file mode 100644 index deba38d..0000000 --- a/client/src/App.tsx +++ /dev/null @@ -1,323 +0,0 @@ -import { Client } from "mcp-typescript/client/index.js"; -import { SSEClientTransport } from "mcp-typescript/client/sse.js"; -import { - ListResourcesResultSchema, - GetPromptResultSchema, - ListToolsResultSchema, - ReadResourceResultSchema, - CallToolResultSchema, - ListPromptsResultSchema, - Tool, - ClientRequest, -} from "mcp-typescript/types.js"; -import { useState } from "react"; -import { - Send, - Bell, - Terminal, - Files, - MessageSquare, - Hammer, - Play, -} from "lucide-react"; -import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; - -import ConsoleTab from "./components/ConsoleTab"; -import Sidebar from "./components/Sidebar"; -import RequestsTab from "./components/RequestsTabs"; -import ResourcesTab, { Resource } from "./components/ResourcesTab"; -import NotificationsTab from "./components/NotificationsTab"; -import PromptsTab, { Prompt } from "./components/PromptsTab"; -import ToolsTab from "./components/ToolsTab"; -import History from "./components/History"; -import { AnyZodObject } from "node_modules/zod/lib"; - -const App = () => { - const [connectionStatus, setConnectionStatus] = useState< - "disconnected" | "connected" | "error" - >("disconnected"); - const [resources, setResources] = useState([]); - const [resourceContent, setResourceContent] = useState(""); - const [prompts, setPrompts] = useState([]); - const [promptContent, setPromptContent] = useState(""); - const [tools, setTools] = useState([]); - const [toolResult, setToolResult] = useState(""); - const [error, setError] = useState(null); - const [command, setCommand] = useState( - "/Users/ashwin/.nvm/versions/node/v18.20.4/bin/node", - ); - const [args, setArgs] = useState( - "/Users/ashwin/code/example-servers/build/everything/stdio.js", - ); - const [url, setUrl] = useState("http://localhost:3001/sse"); - const [transportType, setTransportType] = useState<"stdio" | "sse">("stdio"); - const [requestHistory, setRequestHistory] = useState< - { request: string; response: string }[] - >([]); - const [mcpClient, setMcpClient] = useState(null); - - const [selectedResource, setSelectedResource] = useState( - null, - ); - const [selectedPrompt, setSelectedPrompt] = useState(null); - const [selectedTool, setSelectedTool] = useState(null); - - const pushHistory = (request: object, response: object) => { - setRequestHistory((prev) => [ - ...prev, - { request: JSON.stringify(request), response: JSON.stringify(response) }, - ]); - }; - - const makeRequest = async ( - request: ClientRequest, - schema: T, - ) => { - if (!mcpClient) { - throw new Error("MCP client not connected"); - } - - try { - const response = await mcpClient.request(request, schema); - pushHistory(request, response); - return response; - } catch (e: unknown) { - setError((e as Error).message); - throw e; - } - }; - - const listResources = async () => { - const response = await makeRequest( - { - method: "resources/list" as const, - }, - ListResourcesResultSchema, - ); - if (response.resources) { - setResources(response.resources); - } - }; - - const readResource = async (uri: string) => { - const response = await makeRequest( - { - method: "resources/read" as const, - params: { uri }, - }, - ReadResourceResultSchema, - ); - setResourceContent(JSON.stringify(response, null, 2)); - }; - - const listPrompts = async () => { - const response = await makeRequest( - { - method: "prompts/list" as const, - }, - ListPromptsResultSchema, - ); - setPrompts(response.prompts); - }; - - const getPrompt = async (name: string, args: Record = {}) => { - const response = await makeRequest( - { - method: "prompts/get" as const, - params: { name, arguments: args }, - }, - GetPromptResultSchema, - ); - setPromptContent(JSON.stringify(response, null, 2)); - }; - - const listTools = async () => { - const response = await makeRequest( - { - method: "tools/list" as const, - }, - ListToolsResultSchema, - ); - setTools(response.tools); - }; - - const callTool = async (name: string, params: Record) => { - const response = await makeRequest( - { - method: "tools/call" as const, - params: { name, arguments: params }, - }, - CallToolResultSchema, - ); - setToolResult(JSON.stringify(response.toolResult, null, 2)); - }; - - const connectMcpServer = async () => { - try { - const client = new Client({ - name: "mcp-inspector", - version: "0.0.1", - }); - - const clientTransport = new SSEClientTransport(); - const backendUrl = new URL("http://localhost:3000/sse"); - - backendUrl.searchParams.append("transportType", transportType); - if (transportType === "stdio") { - backendUrl.searchParams.append("command", command); - backendUrl.searchParams.append("args", args); - } else { - backendUrl.searchParams.append("url", url); - } - - await clientTransport.connect(backendUrl); - await client.connect(clientTransport); - - setMcpClient(client); - setConnectionStatus("connected"); - } catch (e) { - console.error(e); - setConnectionStatus("error"); - } - }; - - return ( -
- -
-

MCP Inspector

-
-
-
-

Connect MCP Server

-
- - {transportType === "stdio" ? ( - <> - setCommand(e.target.value)} - /> - setArgs(e.target.value)} - /> - - ) : ( - setUrl(e.target.value)} - /> - )} - -
-
- {mcpClient ? ( - - - - - Resources - - - - Prompts - - - - Requests - - - - Notifications - - - - Tools - - - - Console - - - -
- - - - - { - setSelectedTool(tool); - setToolResult(""); - }} - toolResult={toolResult} - error={error} - /> - -
-
- ) : ( -
-

- Connect to an MCP server to start inspecting -

-
- )} -
-
-
- -
- ); -}; - -export default App; diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/client/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/components/ConsoleTab.tsx b/client/src/components/ConsoleTab.tsx deleted file mode 100644 index 8f05f70..0000000 --- a/client/src/components/ConsoleTab.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { TabsContent } from "@/components/ui/tabs"; - -const ConsoleTab = () => ( - -
-
Welcome to MCP Client Console
- {/* Console output would go here */} -
-
-); - -export default ConsoleTab; diff --git a/client/src/components/History.tsx b/client/src/components/History.tsx deleted file mode 100644 index c0ac2d1..0000000 --- a/client/src/components/History.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useState } from "react"; -import { Copy } from "lucide-react"; - -const History = ({ - requestHistory, -}: { - requestHistory: Array<{ request: string; response: string | null }>; -}) => { - const [expandedRequests, setExpandedRequests] = useState<{ - [key: number]: boolean; - }>({}); - - const toggleRequestExpansion = (index: number) => { - setExpandedRequests((prev) => ({ ...prev, [index]: !prev[index] })); - }; - - const copyToClipboard = (text: string) => { - navigator.clipboard.writeText(text); - }; - - return ( -
-

History

-
    - {requestHistory - .slice() - .reverse() - .map((request, index) => ( -
  • -
    - toggleRequestExpansion(requestHistory.length - 1 - index) - } - > - - {requestHistory.length - index}.{" "} - {JSON.parse(request.request).method} - - - {expandedRequests[requestHistory.length - 1 - index] - ? "▼" - : "▶"} - -
    - {expandedRequests[requestHistory.length - 1 - index] && ( - <> -
    -
    - - Request: - - -
    -
    -                      {JSON.stringify(JSON.parse(request.request), null, 2)}
    -                    
    -
    - {request.response && ( -
    -
    - - Response: - - -
    -
    -                        {JSON.stringify(JSON.parse(request.response), null, 2)}
    -                      
    -
    - )} - - )} -
  • - ))} -
-
- ); -}; - -export default History; diff --git a/client/src/components/ListPane.tsx b/client/src/components/ListPane.tsx deleted file mode 100644 index 0a0760b..0000000 --- a/client/src/components/ListPane.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Button } from "./ui/button"; - -type ListPaneProps = { - items: T[]; - listItems: () => void; - setSelectedItem: (item: T) => void; - renderItem: (item: T) => React.ReactNode; - title: string; - buttonText: string; -}; - -const ListPane = ({ - items, - listItems, - setSelectedItem, - renderItem, - title, - buttonText, -}: ListPaneProps) => ( -
-
-

{title}

-
-
- -
- {items.map((item, index) => ( -
setSelectedItem(item)} - > - {renderItem(item)} -
- ))} -
-
-
-); - -export default ListPane; diff --git a/client/src/components/NotificationsTab.tsx b/client/src/components/NotificationsTab.tsx deleted file mode 100644 index 7e23b99..0000000 --- a/client/src/components/NotificationsTab.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Bell } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { TabsContent } from "@/components/ui/tabs"; - -const NotificationsTab = () => ( - -
-
-
- - -
-