#
tokens: 5804/50000 10/10 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .github
│   └── workflows
│       └── npm-publish.yml
├── .gitignore
├── .npmignore
├── build
│   ├── index.d.ts
│   └── index.js
├── build.sh
├── Dockerfile
├── docs
│   └── images
│       └── screenshot.png
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── smithery.yaml
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------

```
 1 | # Development files
 2 | .git
 3 | .github
 4 | .vscode
 5 | src/
 6 | test/
 7 | tests/
 8 | *.test.js
 9 | *.spec.js
10 | tsconfig.json
11 | .eslintrc
12 | .prettierrc
13 | .editorconfig
14 | .gitignore
15 | .travis.yml
16 | .circleci/
17 | jest.config.js
18 | 
19 | # Build scripts
20 | build.sh
21 | scripts/
22 | 
23 | # Documentation files that aren't needed in the package
24 | docs/
25 | test-instructions.md
26 | 
27 | # Node.js
28 | node_modules/
29 | npm-debug.log
30 | yarn-debug.log
31 | yarn-error.log
32 | 
33 | # macOS
34 | .DS_Store
35 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | 
 4 | # Build artifacts
 5 | dist/
 6 | 
 7 | # dotenv environment variables file
 8 | .env
 9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 | 
14 | # OS-specific files
15 | .DS_Store
16 | .DS_Store?
17 | ._*
18 | .Spotlight-V100
19 | .Trashes
20 | ehthumbs.db
21 | Thumbs.db
22 | 
23 | # Logs
24 | logs
25 | *.log
26 | npm-debug.log*
27 | yarn-debug.log*
28 | yarn-error.log*
29 | 
30 | # Yarn integrity file
31 | .yarn-integrity
32 | 
33 | # Optional npm cache directory
34 | .npm
35 | 
36 | # Editor directories and files
37 | .idea
38 | .vscode
39 | *.swp
40 | *.swo
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # MCP Easy Copy
  2 | 
  3 | [![MCP Server](https://badge.mcpx.dev?type=server)](https://modelcontextprotocol.io)
  4 | [![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows-lightgrey)](https://claude.ai/download)
  5 | [![npm version](https://img.shields.io/npm/v/@fishes/mcp-easy-copy)](https://www.npmjs.com/package/@fishes/mcp-easy-copy)
  6 | [![Node.js](https://img.shields.io/badge/node-%3E%3D14.0.0-brightgreen)](https://nodejs.org)
  7 | [![smithery badge](https://smithery.ai/badge/@fisheepx/mcp-easy-copy)](https://smithery.ai/server/@fisheepx/mcp-easy-copy)
  8 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
  9 | 
 10 | A Model Context Protocol server that makes it easy to discover and copy available MCP services in Claude Desktop.
 11 | 
 12 | <img src="docs/images/screenshot.png" alt="MCP Easy Copy in action" width="400"/>
 13 | 
 14 | ## Purpose
 15 | 
 16 | This MCP server is designed to be your first stop when working with Claude Desktop. It solves the problem of having to remember MCP service names or looking them up in configuration files by:
 17 | 
 18 | 1. Automatically reading the Claude Desktop configuration file
 19 | 2. Extracting the names of all configured MCP services
 20 | 3. Presenting them in an easy-to-copy format at the top of the tools list
 21 | 
 22 | Although Claude can now automatically select the appropriate MCP services in most scenarios, there are still situations where users need to explicitly specify an MCP service name. These situations include:
 23 | 
 24 | - When you have many MCP services configured, making the tools list long and difficult to navigate
 25 | - When specific MCP services offer multiple callable actions, further increasing the list length
 26 | - When you need to direct Claude to use a specific service rather than relying on its automatic selection
 27 | - When troubleshooting or comparing results between different MCP services
 28 | 
 29 | This tool bridges that gap, making all available services easily accessible without having to search through configuration files.
 30 | 
 31 | ## Features
 32 | 
 33 | - **Appears at the top of tools list**: Uses special name formatting to always appear first
 34 | - **Dynamic updates**: Always shows the latest available services
 35 | - **Copy-friendly format**: Numbered list for easy reference
 36 | - **Zero external dependencies**: Just needs Node.js
 37 | 
 38 | ## Installation
 39 | 
 40 | ### Option 1: Install via npm (Recommended)
 41 | 
 42 | ```bash
 43 | npm install -g @fishes/mcp-easy-copy
 44 | ```
 45 | 
 46 | Then add to your Claude Desktop configuration:
 47 | 
 48 | ```json
 49 | {
 50 |   "mcpServers": {
 51 |     "mcp-easy-copy": {
 52 |       "command": "npx",
 53 |       "args": [
 54 |         "-y",
 55 |         "@fishes/mcp-easy-copy"
 56 |       ]
 57 |     }
 58 |   }
 59 | }
 60 | ```
 61 | 
 62 | ### Option 2: Installing via Smithery
 63 | 
 64 | To install Easy Copy for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@fisheepx/mcp-easy-copy):
 65 | 
 66 | ```bash
 67 | npx -y @smithery/cli install @fisheepx/mcp-easy-copy --client claude
 68 | ```
 69 | 
 70 | ### Option 3: Manual Installation
 71 | 
 72 | 1. Clone the repository:
 73 |    ```bash
 74 |    git clone https://github.com/f-is-h/mcp-easy-copy.git
 75 |    cd mcp-easy-copy
 76 |    ```
 77 | 
 78 | 2. Install dependencies and build:
 79 |    ```bash
 80 |    npm install
 81 |    npm run build
 82 |    ```
 83 | 
 84 | 3. Configure Claude Desktop:
 85 |    
 86 |    **For macOS:**
 87 |    Edit `~/Library/Application Support/Claude/claude_desktop_config.json`
 88 |    
 89 |    **For Windows:**
 90 |    Edit `%APPDATA%\Claude\claude_desktop_config.json`
 91 |    
 92 |    Add the following configuration:
 93 |    ```json
 94 |    {
 95 |      "mcpServers": {
 96 |        "mcp-easy-copy": {
 97 |          "command": "node",
 98 |          "args": [
 99 |             "/ABSOLUTE/PATH/TO/mcp_easy_copy/build/index.js"
100 |          ]
101 |        }
102 |      }
103 |    }
104 |    ```
105 | 
106 | 4. Restart Claude Desktop
107 | 
108 | 
109 | 
110 | ## Using the Tool
111 | 
112 | Once installed, you can use the service in two ways:
113 | 
114 | 1. **Via the tools menu:** Click the hammer icon in Claude Desktop and select the service at the top of the list (it will show all available services in its description)
115 | 
116 | 2. **Via a prompt:** Ask Claude something like:
117 |    ```
118 |    Please list all MCP services that are available to you
119 |    ```
120 |    or
121 |    ```
122 |    Please use _________mcp-easy-copy_________ to show me all available MCP services
123 |    ```
124 | 
125 | ## Development
126 | 
127 | MCP Easy Copy is built with TypeScript and uses the Model Context Protocol SDK.
128 | 
129 | ```bash
130 | # Install dependencies
131 | npm install
132 | 
133 | # Build the project
134 | npm run build
135 | 
136 | # Test with the MCP Inspector
137 | npm run inspector
138 | ```
139 | 
140 | ## Troubleshooting
141 | 
142 | If the tool doesn't work as expected:
143 | 
144 | 1. **Check logs**: Look at the log files
145 |    - macOS: `~/Library/Logs/Claude/mcp-server-mcp-easy-copy.log`
146 |    - Windows: `%APPDATA%\Claude\logs\mcp-server-mcp-easy-copy.log`
147 | 
148 | 2. **Verify configuration**: Make sure your `claude_desktop_config.json` is valid JSON
149 | 
150 | 3. **Check Node.js**: Ensure Node.js is properly installed (`node --version`)
151 | 
152 | 4. **Restart Claude**: Always restart Claude Desktop after making configuration changes
153 | 
154 | 5. **Use the Inspector**: Run `npm run inspector` to debug with the MCP Inspector
155 | 
156 | ## Other Badges
157 | 
158 | ### Glama
159 | <a href="https://glama.ai/mcp/servers/@fisheepx/mcp-easy-copy">
160 |   <img width="380" height="200" src="https://glama.ai/mcp/servers/@f-is-h/mcp-easy-copy/badge" alt="Easy Copy MCP server" />
161 | </a>
162 | 
163 | ### MseeP.ai
164 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/f-is-h-mcp-easy-copy-badge.png)](https://mseep.ai/app/f-is-h-mcp-easy-copy)
165 | 
166 | ## License
167 | 
168 | [MIT License](LICENSE)
169 | 
170 | ## Future Vision
171 | 
172 | While we have no specific knowledge of Anthropic's roadmap, we imagine that future versions of Claude's client could potentially implement features like autocomplete when using the '@' symbol. Such a feature might display a dropdown list of available MCP services, making it much easier for users to explicitly instruct Claude to utilize specific services.
173 | 
174 | Even if such improvements eventually make this project obsolete, we'd be delighted to see Claude's interface evolve in ways that improve user experience. After all, the goal of this tool is to make MCP services more accessible, and having that functionality built directly into Claude would be the ultimate success.
175 | 
```

--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | 
 3 | # Change to the directory where the script is located
 4 | cd "$(dirname "$0")"
 5 | 
 6 | # Build the project
 7 | npm run build
 8 | 
 9 | # Show success message
10 | echo "Build completed successfully!"
11 | echo "To use this MCP service, configure it in Claude Desktop."
12 | 
13 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "esModuleInterop": true,
 7 |     "outDir": "./build",
 8 |     "strict": true,
 9 |     "declaration": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules", "**/*.test.ts"]
15 | }
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
 2 | FROM node:lts-alpine
 3 | 
 4 | WORKDIR /app
 5 | 
 6 | # Copy package files and install dependencies
 7 | COPY package*.json ./
 8 | RUN npm install --ignore-scripts
 9 | 
10 | # Copy the rest of the source code and build
11 | COPY . .
12 | RUN npm run build
13 | 
14 | # Expose any required ports (if applicable)
15 | # EXPOSE 3000
16 | 
17 | CMD ["npm", "start"]
18 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     type: object
 8 |     properties: {}
 9 |   commandFunction:
10 |     # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
11 |     |-
12 |     (config) => ({
13 |       command: 'node',
14 |       args: ['build/index.js']
15 |     })
16 |   exampleConfig: {}
17 | 
```

--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: Node.js Package
 2 | 
 3 | on:
 4 |   release:
 5 |     types: [created]
 6 | 
 7 | jobs:
 8 |   build:
 9 |     runs-on: ubuntu-latest
10 |     steps:
11 |       - uses: actions/checkout@v2
12 |       - uses: actions/setup-node@v2
13 |         with:
14 |           node-version: 16
15 |       - run: npm ci
16 |       - run: npm test
17 |       - run: npm run build
18 | 
19 |   publish-npm:
20 |     needs: build
21 |     runs-on: ubuntu-latest
22 |     steps:
23 |       - uses: actions/checkout@v2
24 |       - uses: actions/setup-node@v2
25 |         with:
26 |           node-version: 16
27 |           registry-url: https://registry.npmjs.org/
28 |       - run: npm ci
29 |       - run: npm run build
30 |       - run: npm publish --access public
31 |         env:
32 |           NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
33 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "@fishes/mcp-easy-copy",
 3 |   "version": "1.0.1",
 4 |   "description": "A MCP server that lists all available MCP services for easy copying and usage",
 5 |   "main": "build/index.js",
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "mcp-easy-copy": "build/index.js"
 9 |   },
10 |   "scripts": {
11 |     "build": "tsc",
12 |     "start": "node build/index.js",
13 |     "inspector": "npx @modelcontextprotocol/inspector node build/index.js",
14 |     "prepublishOnly": "npm run build"
15 |   },
16 |   "repository": {
17 |     "type": "git",
18 |     "url": "git+https://github.com/fisheepx/mcp-easy-copy.git"
19 |   },
20 |   "keywords": [
21 |     "mcp",
22 |     "claude",
23 |     "service-list",
24 |     "tools",
25 |     "utility"
26 |   ],
27 |   "author": "fisheep",
28 |   "license": "MIT",
29 |   "dependencies": {
30 |     "@modelcontextprotocol/sdk": "^1.7.0"
31 |   },
32 |   "devDependencies": {
33 |     "@types/node": "^20.8.0",
34 |     "typescript": "^5.2.2"
35 |   },
36 |   "engines": {
37 |     "node": ">=14.0.0"
38 |   }
39 | }
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * MCP Easy Copy Server
  5 |  * 
  6 |  * This MCP server lists all configured MCP services in the Claude Desktop application.
  7 |  * It makes it easy for users to copy service names for use in their prompts.
  8 |  */
  9 | 
 10 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
 11 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 12 | import fs from "fs/promises";
 13 | import path from "path";
 14 | import os from "os";
 15 | 
 16 | // Create an MCP server that will appear at the top of the tools list
 17 | const server = new McpServer({
 18 |   name: "mcp-easy-copy", // Use hyphens consistently for npm naming convention
 19 |   version: "1.0.0"
 20 | });
 21 | 
 22 | // Configure logging to stderr (doesn't interfere with the MCP protocol)
 23 | const logDebug = (message: string) => {
 24 |   // Uncomment for debugging
 25 |   // console.error(`[DEBUG] ${message}`);
 26 | };
 27 | 
 28 | /**
 29 |  * Configuration file paths for different operating systems
 30 |  * - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
 31 |  * - Linux: ~/.config/Claude/claude_desktop_config.json
 32 |  * - Windows: %APPDATA%/Claude/claude_desktop_config.json
 33 |  */
 34 | const possibleConfigPaths = [
 35 |   path.join(os.homedir(), "Library/Application Support/Claude/claude_desktop_config.json"),
 36 |   path.join(os.homedir(), ".config/Claude/claude_desktop_config.json"),
 37 |   path.join(os.homedir(), "AppData/Roaming/Claude/claude_desktop_config.json")
 38 | ];
 39 | 
 40 | /**
 41 |  * Finds the Claude Desktop configuration file
 42 |  * @returns The path to the config file if found, null otherwise
 43 |  */
 44 | async function findConfigFile(): Promise<string | null> {
 45 |   for (const configPath of possibleConfigPaths) {
 46 |     try {
 47 |       await fs.access(configPath);
 48 |       logDebug(`Found config file at: ${configPath}`);
 49 |       return configPath;
 50 |     } catch (error) {
 51 |       logDebug(`Config file not found at: ${configPath}`);
 52 |     }
 53 |   }
 54 |   return null;
 55 | }
 56 | 
 57 | /**
 58 |  * Retrieves all MCP service names from the Claude Desktop configuration file
 59 |  * @returns Array of MCP service names
 60 |  */
 61 | async function getMcpServices(): Promise<string[]> {
 62 |   try {
 63 |     // Find the config file
 64 |     const configPath = await findConfigFile();
 65 |     if (!configPath) {
 66 |       return [];
 67 |     }
 68 |     
 69 |     // Read and parse the config file
 70 |     const configContent = await fs.readFile(configPath, 'utf-8');
 71 |     const config = JSON.parse(configContent);
 72 |     
 73 |     // Extract and return MCP service names
 74 |     return config.mcpServers ? Object.keys(config.mcpServers) : [];
 75 |   } catch (error) {
 76 |     logDebug(`Error getting MCP services: ${error}`);
 77 |     return [];
 78 |   }
 79 | }
 80 | 
 81 | /**
 82 |  * Resource that returns the list of configured MCP services
 83 |  * This resource is exposed through URI: mcp-services://list
 84 |  */
 85 | server.resource(
 86 |   "mcp-services-list",
 87 |   "mcp-services://list",
 88 |   async (uri) => {
 89 |     try {
 90 |       // Find the config file
 91 |       const configPath = await findConfigFile();
 92 |       if (!configPath) {
 93 |         return {
 94 |           contents: [{
 95 |             uri: uri.href,
 96 |             text: "Error: Claude Desktop configuration file not found."
 97 |           }]
 98 |         };
 99 |       }
100 |       
101 |       // Read and parse the config file
102 |       const configContent = await fs.readFile(configPath, 'utf-8');
103 |       const config = JSON.parse(configContent);
104 |       
105 |       // Extract MCP service names
106 |       const services = config.mcpServers ? Object.keys(config.mcpServers) : [];
107 |       
108 |       // Format the output in a user-friendly way
109 |       const formattedList = services.length > 0 
110 |         ? "📋 AVAILABLE MCP SERVICES:\n" + services.map((name) => `- ${name}`).join("\n") + "\n\nCopy a service name to use in prompts like:\n" +
111 |           "• Can you use [service name] to...\n" +
112 |           "• Please call [service name] to..."
113 |         : "No MCP services configured.";
114 |       
115 |       return {
116 |         contents: [{
117 |           uri: uri.href,
118 |           text: formattedList
119 |         }]
120 |       };
121 |     } catch (error) {
122 |       console.error("Error reading MCP config:", error);
123 |       return {
124 |         contents: [{
125 |           uri: uri.href,
126 |           text: `Error reading MCP configuration: ${error instanceof Error ? error.message : String(error)}`
127 |         }]
128 |       };
129 |     }
130 |   }
131 | );
132 | 
133 | /**
134 |  * Initializes and starts the MCP server
135 |  */
136 | async function main() {
137 |   try {
138 |     // Get initial MCP services to include in the tool description
139 |     let toolDescription = "List all MCP services available in this Claude instance";
140 |     const services = await getMcpServices();
141 |     
142 |     if (services.length > 0) {
143 |       // Format service names with separators for better visibility in the UI
144 |       // (newlines don't work well in Claude's tool descriptions)
145 |       const servicesList = services.map(name => `${name}`).join(" │ ");
146 |       toolDescription = `│ ${servicesList} │`;
147 |     }
148 |     
149 |     // Register the tool with underscores to appear at the top of tool listings
150 |     server.tool(
151 |       "_________available_mcp_services_for_easy_copy_________",
152 |       toolDescription,
153 |       {}, // No parameters needed
154 |       async () => {
155 |         // Always fetch the latest services when the tool is called
156 |         const currentServices = await getMcpServices();
157 |         
158 |         if (currentServices.length === 0) {
159 |           return {
160 |             content: [{ 
161 |               type: "text", 
162 |               text: "No MCP services configured." 
163 |             }]
164 |           };
165 |         }
166 |         
167 |         // Format the output with numbered list and usage instructions
168 |         const formattedList = "📋 AVAILABLE MCP SERVICES:\n" + 
169 |           currentServices.map((name, index) => `${index + 1}. ${name}`).join("\n") + 
170 |           "\n\nCopy a service name to use in prompts like:\n" +
171 |           "• Can you use [service name] to...\n" +
172 |           "• Please call [service name] to...";
173 |         
174 |         return {
175 |           content: [{ 
176 |             type: "text", 
177 |             text: formattedList 
178 |           }]
179 |         };
180 |       }
181 |     );
182 |     
183 |     // Connect the server using stdio transport (standard for MCP)
184 |     const transport = new StdioServerTransport();
185 |     await server.connect(transport);
186 |     console.error("MCP Easy Copy server running...");
187 |   } catch (error) {
188 |     console.error("Failed to start server:", error);
189 |     process.exit(1);
190 |   }
191 | }
192 | 
193 | // Start the server
194 | main();
```