Model Context Protocol (MCP): Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 95: Line 95:
If all goes well, when you restart Claude it will show<br>
If all goes well, when you restart Claude it will show<br>
[[File:Claude1.png]]<br>
[[File:Claude1.png]]<br>
=Writing a Server (Typescript)=
Well always a challenge but they will never win. The challenge is to avoid standard out. First the server.
<syntaxhighlight lang="ts">
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
    name: "Weather Service",
    version: "1.0.0",
});
// Add an addition tool
server.tool("add",
    { a: z.number(), b: z.number() },
    async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]
    })
);
// Add a dynamic greeting resource
server.resource(
    "greeting",
    new ResourceTemplate("greeting://{name}", { list: undefined }),
    async (uri, { name }) => ({
        contents: [{
            uri: uri.href,
            text: `Hello, ${name}!`
        }]
    })
);
// Add a tool to get the weather
server.tool("getWeather", {
        word: z.string()
    },
    async ({ word }) => {
        return {
            content: [
                {
                    type: "text",
                    text: `The weather is ${word} nice today`
                }
            ]
        };
    }
);
const transport = new StdioServerTransport();
await server.connect(transport);
</syntaxhighlight>
All went well and you can test this and other MCPs with the mcp inspector
<syntaxhighlight lang="bash">
npx @modelcontextprotocol/inspector
</syntaxhighlight>
And all goes well. But adding it to Claude proved an hour of fun. To ensure I have not issues I made a shell script to cd to the working directory and run. But this fell over with
<syntaxhighlight lang="text">
[error
] Unexpected end of JSON input {
    "context": "connection",
    "stack": "SyntaxError: Unexpected end of JSON input\n    at JSON.parse (<anonymous>)\n    at EPe (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:189)\n    at SPe.readMessage (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:115)\n    at TPe.processReadBuffer (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1842)\n    at Socket.<anonymous> (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1523)\n    at Socket.emit (node:events:518:28)\n    at addChunk (node:internal/streams/readable:561:12)\n    at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)\n    at Readable.push (node:internal/streams/readable:392:5)\n    at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)"
}
2025-03-22T03: 29: 54.581Z [add
] [error
] Unexpected token '>',
"> start" is not valid JSON {
    "context": "connection",
    "stack": "SyntaxError: Unexpected token '>', \"> start\" is not valid JSON\n    at JSON.parse (<anonymous>)\n    at EPe (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:189)\n    at SPe.readMessage (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:115)\n    at TPe.processReadBuffer (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1842)\n    at Socket.<anonymous> (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1523)\n    at Socket.emit (node:events:518:28)\n    at addChunk (node:internal/streams/readable:561:12)\n    at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)\n    at Readable.push (node:internal/streams/readable:392:5)\n    at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)"
}
</syntaxhighlight>
This is caused by npm run start going to standard out. If you want to run node you can do this.
<syntaxhighlight lang="json">
{
  "mcpServers": {
    "add": {
      "command": "node",
      "args": [
        "/home/iwiseman/dev/projects/mcpServer/tsMcpTest/dist/app.js"
      ]
    },
...
</syntaxhighlight>

Revision as of 04:14, 22 March 2025

Introduction

This is my first foray into MCPs which works

Clients

  • Claude
  • Claude Code
  • Cursor
  • Windsurf

Servers

Example server site is awesome-mcp-servers

Installing Claude on Ubuntu 24.04

This was reasonably painless. Goto here. When installing the instructions are

git clone https://github.com/aaddrick/claude-desktop-debian.git
cd claude-desktop-debian

# Build the package
sudo ./build-deb.sh
sudo dpkg -i ./build/electron-app/claude-desktop_0.8.0_amd64.deb

This all goes well except the version of claude is now 0.8.1 and the script in the repository is 0.8.0. Search and replace the build-deb.sh and then it fails to launch because of sandbox issues which can be fixed, in my case, with

sudo chmod 4755 /usr/local/lib/node_modules/electron/dist/chrome-sandbox

Writing a Server (Python)

To demonstrate how easy this is Matthew Berman. There is just this code and a config

from mcp.server.fastmcp import FastMCP
import time
import signal
import sys

# Handle SIGINT (Ctrl+C) gracefully
def signal_handler(sig, frame):
    print("Shutting down server gracefully...")
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

# Create an MCP server with increased timeout
mcp = FastMCP(
    name="count-r",
    host="127.0.0.1",
    port=5000,
    # Add this to make the server more resilient
    timeout=30  # Increase timeout to 30 seconds
)

# Define our tool
@mcp.tool()
def count_r(word: str) -> int:
    """Count the number of 'r' letters in a given word."""
    try:
        # Add robust error handling
        if not isinstance(word, str):
            return 0
        return word.lower().count("r")
    except Exception as e:
        # Return 0 on any error
        return 0

if __name__ == "__main__":
    try:
        print("Starting MCP server 'count-r' on 127.0.0.1:5000")
        # Use this approach to keep the server running
        mcp.run()
    except Exception as e:
        print(f"Error: {e}")
        # Sleep before exiting to give time for error logs
        time.sleep(5)

Build an executable as you cannot just use pip3 or pipx to install globally.

pip3 install pyinstaller
pyinstaller --onefile main.py

This produces a file in the dist directory.

Then we change the config for claude, making sure the command is appropriate to your setup. This file can be found in the following directory. ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "count-r": {
      "command": "/home/iwiseman/dev/projects/mcpServer/pyFastMCPTest/dist/main",
      "args": [
        ""
      ],
      "host": "127.0.0.1",
      "port": 8080,
      "timeout": 30000
    }
  }
}

If all goes well, when you restart Claude it will show

Writing a Server (Typescript)

Well always a challenge but they will never win. The challenge is to avoid standard out. First the server.

import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

import { z } from "zod";

const server = new McpServer({
    name: "Weather Service",
    version: "1.0.0",
});


// Add an addition tool
server.tool("add",
    { a: z.number(), b: z.number() },
    async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]
    })
);

// Add a dynamic greeting resource
server.resource(
    "greeting",
    new ResourceTemplate("greeting://{name}", { list: undefined }),
    async (uri, { name }) => ({
        contents: [{
            uri: uri.href,
            text: `Hello, ${name}!`
        }]
    })
);

// Add a tool to get the weather
server.tool("getWeather", {
        word: z.string()
    },
    async ({ word }) => {
        return {
            content: [
                {
                    type: "text",
                    text: `The weather is ${word} nice today`
                }
            ]
        };
    }
);

const transport = new StdioServerTransport();
await server.connect(transport);

All went well and you can test this and other MCPs with the mcp inspector

npx @modelcontextprotocol/inspector

And all goes well. But adding it to Claude proved an hour of fun. To ensure I have not issues I made a shell script to cd to the working directory and run. But this fell over with

[error
] Unexpected end of JSON input {
    "context": "connection",
    "stack": "SyntaxError: Unexpected end of JSON input\n    at JSON.parse (<anonymous>)\n    at EPe (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:189)\n    at SPe.readMessage (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:115)\n    at TPe.processReadBuffer (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1842)\n    at Socket.<anonymous> (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1523)\n    at Socket.emit (node:events:518:28)\n    at addChunk (node:internal/streams/readable:561:12)\n    at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)\n    at Readable.push (node:internal/streams/readable:392:5)\n    at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)"
}
2025-03-22T03: 29: 54.581Z [add
] [error
] Unexpected token '>',
"> start" is not valid JSON {
    "context": "connection",
    "stack": "SyntaxError: Unexpected token '>', \"> start\" is not valid JSON\n    at JSON.parse (<anonymous>)\n    at EPe (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:189)\n    at SPe.readMessage (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:82:115)\n    at TPe.processReadBuffer (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1842)\n    at Socket.<anonymous> (/usr/lib/claude-desktop/app.asar/.vite/build/index.js:83:1523)\n    at Socket.emit (node:events:518:28)\n    at addChunk (node:internal/streams/readable:561:12)\n    at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)\n    at Readable.push (node:internal/streams/readable:392:5)\n    at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)"
}

This is caused by npm run start going to standard out. If you want to run node you can do this.

{
  "mcpServers": {
    "add": {
      "command": "node",
      "args": [
        "/home/iwiseman/dev/projects/mcpServer/tsMcpTest/dist/app.js"
      ]
    },
...