Skip to content

Instantly share code, notes, and snippets.

@kuc-arc-f
Created October 18, 2025 00:33
Show Gist options
  • Save kuc-arc-f/ae773bd07b4e4a6dc5e06e91661a9932 to your computer and use it in GitHub Desktop.
Save kuc-arc-f/ae773bd07b4e4a6dc5e06e91661a9932 to your computer and use it in GitHub Desktop.
test-code , workers + remoto MCP Server JSON-RPC 2.0
/**
* Cloudflare Workers - MCP Server with JSON-RPC 2.0
* Model Context Protocol Remote Server Implementation
*/
export default {
async fetch(request, env, ctx) {
// CORS headers
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
// Handle CORS preflight
if (request.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
// Only accept POST requests
if (request.method !== 'POST') {
return new Response('Method not allowed', {
status: 405,
headers: corsHeaders
});
}
try {
const body = await request.json();
const response = await handleJsonRpc(body, env);
return new Response(JSON.stringify(response), {
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
} catch (error) {
return new Response(JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32700,
message: 'Parse error',
data: error.message
},
id: null
}), {
status: 400,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
}
};
/**
* Handle JSON-RPC 2.0 requests
*/
async function handleJsonRpc(request, env) {
// Validate JSON-RPC 2.0 request
if (request.jsonrpc !== '2.0') {
return {
jsonrpc: '2.0',
error: {
code: -32600,
message: 'Invalid Request'
},
id: request.id || null
};
}
const { method, params, id } = request;
try {
let result;
switch (method) {
case 'initialize':
result = await handleInitialize(params);
break;
case 'tools/list':
result = await handleToolsList(params);
break;
case 'tools/call':
result = await handleToolsCall(params, env);
break;
case 'resources/list':
result = await handleResourcesList(params);
break;
case 'resources/read':
result = await handleResourcesRead(params, env);
break;
case 'prompts/list':
result = await handlePromptsList(params);
break;
case 'prompts/get':
result = await handlePromptsGet(params);
break;
default:
return {
jsonrpc: '2.0',
error: {
code: -32601,
message: 'Method not found',
data: { method }
},
id
};
}
return {
jsonrpc: '2.0',
result,
id
};
} catch (error) {
return {
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal error',
data: error.message
},
id
};
}
}
/**
* MCP Protocol Handlers
*/
async function handleInitialize(params) {
return {
protocolVersion: '2024-11-05',
capabilities: {
tools: {},
resources: {},
prompts: {}
},
serverInfo: {
name: 'cloudflare-mcp-server',
version: '1.0.0'
}
};
}
async function handleToolsList(params) {
return {
tools: [
{
name: 'get_time',
description: 'Get current server time',
inputSchema: {
type: 'object',
properties: {
timezone: {
type: 'string',
description: 'Timezone (optional)',
default: 'UTC'
}
}
}
},
{
name: 'fetch_data',
description: 'Fetch data from external API',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'URL to fetch'
}
},
required: ['url']
}
}
]
};
}
async function handleToolsCall(params, env) {
const { name, arguments: args } = params;
switch (name) {
case 'get_time':
return {
content: [
{
type: 'text',
text: `Current time: ${new Date().toISOString()}`
}
]
};
case 'fetch_data':
try {
const response = await fetch(args.url);
const data = await response.text();
return {
content: [
{
type: 'text',
text: data
}
]
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error fetching data: ${error.message}`
}
],
isError: true
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
}
async function handleResourcesList(params) {
return {
resources: [
{
uri: 'cloudflare://worker/info',
name: 'Worker Information',
description: 'Information about this Cloudflare Worker',
mimeType: 'application/json'
}
]
};
}
async function handleResourcesRead(params, env) {
const { uri } = params;
if (uri === 'cloudflare://worker/info') {
return {
contents: [
{
uri,
mimeType: 'application/json',
text: JSON.stringify({
name: 'Cloudflare MCP Server',
runtime: 'Cloudflare Workers',
version: '1.0.0'
}, null, 2)
}
]
};
}
throw new Error(`Resource not found: ${uri}`);
}
async function handlePromptsList(params) {
return {
prompts: [
{
name: 'greeting',
description: 'Generate a greeting message',
arguments: [
{
name: 'name',
description: 'Name to greet',
required: true
}
]
}
]
};
}
async function handlePromptsGet(params) {
const { name, arguments: args } = params;
if (name === 'greeting') {
return {
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Hello, ${args?.name || 'World'}!`
}
}
]
};
}
throw new Error(`Prompt not found: ${name}`);
}
{
"name": "workers26mcp",
"version": "0.0.0",
"type": "module",
"private": true,
"scripts": {
"build": "npx vite build --config vite.app.config.ts && npm run build:css",
"build:css": "npx tailwindcss -i ./src/input.css -o ./public/main.css",
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
"test": "vitest",
"cf-typegen": "wrangler types"
},
"dependencies": {
"@libsql/client": "^0.15.15",
"@tailwindcss/cli": "^4.1.4",
"@tanstack/react-table": "^8.21.3",
"axios": "^1.12.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwindcss": "^4.1.4",
"vite": "^6.2.0",
"zod": "^3.24.2"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "^0.9.7",
"@cloudflare/workers-types": "^4.20250410.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"nodemon": "^3.1.9",
"typescript": "^5.5.2",
"vitest": "~3.0.7",
"wrangler": "^4.10.0"
}
}
const start = async function() {
try{
const item = {
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}
const response = await fetch("http://localhost:8787", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': '',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}else{
console.log("OK");
const json = await response.json();
console.log(json);
console.log(json.result);
}
}catch(e){console.log(e)}
}
start();
const start = async function() {
try{
const item = {
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_time",
"arguments": {}
},
"id": 2
}
const response = await fetch("http://localhost:8787", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': '',
},
body: JSON.stringify(item),
});
if (!response.ok) {
const text = await response.text();
console.log(text);
throw new Error('Failed to create item');
}else{
console.log("OK");
const json = await response.json();
console.log(json);
console.log(json.result.content[0].text);
}
}catch(e){console.log(e)}
}
start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment