Merge pull request #23 from modelcontextprotocol/jerome/dev-scripts-and-fixes

Add dev scripts for mitmproxy debugging and fix JSON-RPC error responses
This commit is contained in:
Jerome 2025-12-07 17:24:38 +00:00 • committed by GitHub
commit d87c1262cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 848 additions and 1211 deletions

31
dev-with-mitm.sh Executable file
View file

@ -0,0 +1,31 @@
#!/bin/bash
# Easy script to run MCP server with mitmproxy intercepting client traffic
echo "🚀 Starting MCP server with mitmproxy..."
echo ""
echo "This will:"
echo " 1. Start your MCP server on port 3232"
echo " 2. Start mitmproxy reverse proxy on port 8080"
echo " 3. Intercept all client → server traffic"
echo ""
echo "📡 Connect your MCP client to: http://localhost:8080/mcp"
echo "🔍 View traffic in mitmproxy TUI"
echo ""
echo "Press Ctrl+C to stop both processes"
echo ""
# Trap Ctrl+C to kill both processes
trap 'kill 0' EXIT
# Start the MCP server in background
npm run dev &
SERVER_PID=$!
# Give server time to start
sleep 3
# Start mitmproxy in reverse proxy mode (foreground so we see the TUI)
mitmproxy --mode reverse:http://localhost:3232 --listen-port 8080
# This line won't be reached until mitmproxy exits
wait

31
dev-with-mitmweb.sh Executable file
View file

@ -0,0 +1,31 @@
#!/bin/bash
# Easy script to run MCP server with mitmproxy web interface
echo "🚀 Starting MCP server with mitmproxy web UI..."
echo ""
echo "This will:"
echo " 1. Start your MCP server on port 3232"
echo " 2. Start mitmproxy with web UI on port 8081"
echo " 3. Proxy client traffic through port 8080"
echo ""
echo "📡 Connect your MCP client to: http://localhost:8080/mcp"
echo "🌐 View traffic in browser at: http://localhost:8081"
echo ""
echo "Press Ctrl+C to stop both processes"
echo ""
# Trap Ctrl+C to kill both processes
trap 'kill 0' EXIT
# Start the MCP server in background
npm run dev &
SERVER_PID=$!
# Give server time to start
sleep 3
# Start mitmweb in reverse proxy mode
mitmweb --mode reverse:http://localhost:3232 --listen-port 8080 --web-port 8081
# This line won't be reached until mitmweb exits
wait

1991
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@
"clean": "rm -rf dist"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
"@modelcontextprotocol/sdk": "^1.24.2",
"@redis/client": "^1.6.0",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
@ -53,4 +53,4 @@
},
"author": "",
"license": "MIT"
}
}

View file

@ -67,6 +67,7 @@ export async function handleStreamableHTTP(req: Request, res: Response) {
});
res.status(401).json({
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32002,
"message": "User ID required"
@ -87,6 +88,7 @@ export async function handleStreamableHTTP(req: Request, res: Response) {
});
res.status(401).json({
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32001,
"message": "Session not found or access denied"
@ -148,6 +150,7 @@ export async function handleStreamableHTTP(req: Request, res: Response) {
});
res.status(400).json({
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32600,
"message": "Invalid request method for existing session"
@ -167,6 +170,7 @@ export async function handleStreamableHTTP(req: Request, res: Response) {
if (!res.headersSent) {
res.status(500).json({
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32603,
"message": "Internal error during request processing"

View file

@ -19,12 +19,13 @@ import {
UnsubscribeRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
type ToolInput = {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
type ToolInput = Tool["inputSchema"];
// Helper to convert Zod schema to JSON schema using Zod v4's native support
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const toJsonSchema = (schema: z.ZodType<any>): ToolInput => {
return z.toJSONSchema(schema) as ToolInput;
};
/* Input schemas for tools implemented in this server */
@ -413,40 +414,40 @@ export const createMcpServer = (): McpServerWrapper => {
{
name: ToolName.ECHO,
description: "Echoes back the input",
inputSchema: zodToJsonSchema(EchoSchema) as ToolInput,
inputSchema: toJsonSchema(EchoSchema),
},
{
name: ToolName.ADD,
description: "Adds two numbers",
inputSchema: zodToJsonSchema(AddSchema) as ToolInput,
inputSchema: toJsonSchema(AddSchema),
},
{
name: ToolName.LONG_RUNNING_OPERATION,
description:
"Demonstrates a long running operation with progress updates",
inputSchema: zodToJsonSchema(LongRunningOperationSchema) as ToolInput,
inputSchema: toJsonSchema(LongRunningOperationSchema),
},
{
name: ToolName.SAMPLE_LLM,
description: "Samples from an LLM using MCP's sampling feature",
inputSchema: zodToJsonSchema(SampleLLMSchema) as ToolInput,
inputSchema: toJsonSchema(SampleLLMSchema),
},
{
name: ToolName.GET_TINY_IMAGE,
description: "Returns the MCP_TINY_IMAGE",
inputSchema: zodToJsonSchema(GetTinyImageSchema) as ToolInput,
inputSchema: toJsonSchema(GetTinyImageSchema),
},
{
name: ToolName.ANNOTATED_MESSAGE,
description:
"Demonstrates how annotations can be used to provide metadata about content",
inputSchema: zodToJsonSchema(AnnotatedMessageSchema) as ToolInput,
inputSchema: toJsonSchema(AnnotatedMessageSchema),
},
{
name: ToolName.GET_RESOURCE_REFERENCE,
description:
"Returns a resource reference that can be used by MCP clients",
inputSchema: zodToJsonSchema(GetResourceReferenceSchema) as ToolInput,
inputSchema: toJsonSchema(GetResourceReferenceSchema),
},
{
name: ToolName.ELICIT_INPUTS,
@ -524,9 +525,12 @@ export const createMcpServer = (): McpServerWrapper => {
ToolName.SAMPLE_LLM,
maxTokens
);
const contentArray = Array.isArray(result.content) ? result.content : [result.content];
const firstContent = contentArray[0];
const textContent = firstContent && "text" in firstContent ? firstContent.text : JSON.stringify(result.content);
return {
content: [
{ type: "text", text: `LLM sampling result: ${result.content.text}` },
{ type: "text", text: `LLM sampling result: ${textContent}` },
],
};
}