chore: fix prettier formatting and update example server dependencies
- Fix formatting issues in cf-agents, hono-mcp, and test files - Update dependencies in example servers 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b909730ae2
commit
e0743c35e4
9 changed files with 329 additions and 32 deletions
|
|
@ -12,7 +12,7 @@
|
|||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.13.0",
|
||||
"@modelcontextprotocol/sdk": "^1.13.3",
|
||||
"zod": "^3.25.67"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
13
examples/servers/cf-agents/pnpm-lock.yaml
generated
13
examples/servers/cf-agents/pnpm-lock.yaml
generated
|
|
@ -9,8 +9,8 @@ importers:
|
|||
.:
|
||||
dependencies:
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.13.0
|
||||
version: 1.13.2
|
||||
specifier: ^1.13.3
|
||||
version: 1.13.3
|
||||
zod:
|
||||
specifier: ^3.25.67
|
||||
version: 3.25.67
|
||||
|
|
@ -443,8 +443,8 @@ packages:
|
|||
'@jridgewell/trace-mapping@0.3.9':
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.13.2':
|
||||
resolution: {integrity: sha512-Vx7qOcmoKkR3qhaQ9qf3GxiVKCEu+zfJddHv6x3dY/9P6+uIwJnmuAur5aB+4FDXf41rRrDnOEGkviX5oYZ67w==}
|
||||
'@modelcontextprotocol/sdk@1.13.3':
|
||||
resolution: {integrity: sha512-bGwA78F/U5G2jrnsdRkPY3IwIwZeWUEfb5o764b79lb0rJmMT76TLwKhdNZOWakOQtedYefwIR4emisEMvInKA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@opentelemetry/api@1.9.0':
|
||||
|
|
@ -1314,13 +1314,14 @@ snapshots:
|
|||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.2
|
||||
|
||||
'@modelcontextprotocol/sdk@1.13.2':
|
||||
'@modelcontextprotocol/sdk@1.13.3':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
content-type: 1.0.5
|
||||
cors: 2.8.5
|
||||
cross-spawn: 7.0.6
|
||||
eventsource: 3.0.7
|
||||
eventsource-parser: 3.0.3
|
||||
express: 5.1.0
|
||||
express-rate-limit: 7.5.1(express@5.1.0)
|
||||
pkce-challenge: 5.0.0
|
||||
|
|
@ -1349,7 +1350,7 @@ snapshots:
|
|||
|
||||
agents@0.0.100(@cloudflare/workers-types@4.20250628.0)(react@19.1.0):
|
||||
dependencies:
|
||||
'@modelcontextprotocol/sdk': 1.13.2
|
||||
'@modelcontextprotocol/sdk': 1.13.3
|
||||
ai: 4.3.16(react@19.1.0)(zod@3.25.67)
|
||||
cron-schedule: 5.0.4
|
||||
nanoid: 5.1.5
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { McpAgent } from 'agents/mcp'
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { z } from 'zod'
|
||||
import OAuthProvider, { OAuthHelpers } from '@cloudflare/workers-oauth-provider'
|
||||
import OAuthProvider, { type OAuthHelpers } from '@cloudflare/workers-oauth-provider'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
// Define our MCP agent with tools
|
||||
|
|
@ -53,6 +53,95 @@ export class MyMCP extends McpAgent {
|
|||
return { content: [{ type: 'text', text: String(result) }] }
|
||||
},
|
||||
)
|
||||
|
||||
// Register sample resources using the agents framework API
|
||||
this.server.resource('calc://history', 'Calculation History', async () => ({
|
||||
contents: [
|
||||
{
|
||||
uri: 'calc://history',
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
calculations: [
|
||||
{ operation: 'add', a: 5, b: 3, result: 8, timestamp: '2024-01-01T10:00:00Z' },
|
||||
{ operation: 'multiply', a: 4, b: 7, result: 28, timestamp: '2024-01-01T10:01:00Z' },
|
||||
],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
this.server.resource('calc://settings', 'Calculator Settings', async () => ({
|
||||
contents: [
|
||||
{
|
||||
uri: 'calc://settings',
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
precision: 2,
|
||||
allowNegative: true,
|
||||
maxValue: 1000000,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
// Register a dynamic resource
|
||||
this.server.resource('calc://stats', 'Calculation Statistics', async () => ({
|
||||
contents: [
|
||||
{
|
||||
uri: 'calc://stats',
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
totalCalculations: Math.floor(Math.random() * 100),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
// Register sample prompts using the agents framework API
|
||||
this.server.prompt(
|
||||
'math_problem',
|
||||
'Generate a math problem',
|
||||
{
|
||||
difficulty: z.string(),
|
||||
topic: z.string().optional(),
|
||||
},
|
||||
async ({ difficulty, topic }) => ({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Generate a ${difficulty} math problem${topic ? ` about ${topic}` : ''}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
this.server.prompt('explain_calculation', 'Explain a calculation', { operation: z.string() }, async ({ operation }) => ({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Please explain how to perform ${operation} step by step with examples`,
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@hono/mcp": "^0.1.0",
|
||||
"@modelcontextprotocol/sdk": "^1.13.1",
|
||||
"@modelcontextprotocol/sdk": "^1.13.3",
|
||||
"wrangler": "^4.21.0",
|
||||
"zod": "^3.25.67"
|
||||
}
|
||||
|
|
|
|||
17
examples/servers/hono-mcp/pnpm-lock.yaml
generated
17
examples/servers/hono-mcp/pnpm-lock.yaml
generated
|
|
@ -14,10 +14,10 @@ importers:
|
|||
devDependencies:
|
||||
'@hono/mcp':
|
||||
specifier: ^0.1.0
|
||||
version: 0.1.0(@modelcontextprotocol/sdk@1.13.1)(hono@4.8.2)
|
||||
version: 0.1.0(@modelcontextprotocol/sdk@1.13.3)(hono@4.8.2)
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.13.1
|
||||
version: 1.13.1
|
||||
specifier: ^1.13.3
|
||||
version: 1.13.3
|
||||
wrangler:
|
||||
specifier: ^4.21.0
|
||||
version: 4.21.0
|
||||
|
|
@ -352,8 +352,8 @@ packages:
|
|||
'@jridgewell/trace-mapping@0.3.9':
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.13.1':
|
||||
resolution: {integrity: sha512-8q6+9aF0yA39/qWT/uaIj6zTpC+Qu07DnN/lb9mjoquCJsAh6l3HyYqc9O3t2j7GilseOQOQimLg7W3By6jqvg==}
|
||||
'@modelcontextprotocol/sdk@1.13.3':
|
||||
resolution: {integrity: sha512-bGwA78F/U5G2jrnsdRkPY3IwIwZeWUEfb5o764b79lb0rJmMT76TLwKhdNZOWakOQtedYefwIR4emisEMvInKA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
accepts@2.0.0:
|
||||
|
|
@ -972,9 +972,9 @@ snapshots:
|
|||
|
||||
'@fastify/busboy@2.1.1': {}
|
||||
|
||||
'@hono/mcp@0.1.0(@modelcontextprotocol/sdk@1.13.1)(hono@4.8.2)':
|
||||
'@hono/mcp@0.1.0(@modelcontextprotocol/sdk@1.13.3)(hono@4.8.2)':
|
||||
dependencies:
|
||||
'@modelcontextprotocol/sdk': 1.13.1
|
||||
'@modelcontextprotocol/sdk': 1.13.3
|
||||
hono: 4.8.2
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.5':
|
||||
|
|
@ -1061,13 +1061,14 @@ snapshots:
|
|||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
'@modelcontextprotocol/sdk@1.13.1':
|
||||
'@modelcontextprotocol/sdk@1.13.3':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
content-type: 1.0.5
|
||||
cors: 2.8.5
|
||||
cross-spawn: 7.0.6
|
||||
eventsource: 3.0.7
|
||||
eventsource-parser: 3.0.2
|
||||
express: 5.1.0
|
||||
express-rate-limit: 7.5.1(express@5.1.0)
|
||||
pkce-challenge: 5.0.0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { McpServer, type ReadResourceTemplateCallback, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { StreamableHTTPTransport } from '@hono/mcp'
|
||||
import { Hono } from 'hono'
|
||||
import { z } from 'zod'
|
||||
|
|
@ -42,7 +42,8 @@ mcpServer.registerTool(
|
|||
inputSchema: {},
|
||||
},
|
||||
async () => {
|
||||
await scheduler.wait(100 + Math.random() * 100)
|
||||
// Simulate some async work
|
||||
await new Promise((resolve) => setTimeout(resolve, 100 + Math.random() * 100))
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
|
|
@ -54,6 +55,139 @@ mcpServer.registerTool(
|
|||
},
|
||||
)
|
||||
|
||||
// Register sample resources
|
||||
mcpServer.registerResource(
|
||||
'config',
|
||||
'config://app',
|
||||
{
|
||||
title: 'Application Configuration',
|
||||
description: 'Current application configuration settings',
|
||||
mimeType: 'application/json',
|
||||
},
|
||||
async (uri: URL) => ({
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
version: '1.0.0',
|
||||
environment: 'test',
|
||||
features: {
|
||||
vengabus: true,
|
||||
calculator: true,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
mcpServer.registerResource(
|
||||
'readme',
|
||||
'file://readme.md',
|
||||
{
|
||||
title: 'README',
|
||||
description: 'Server documentation',
|
||||
mimeType: 'text/markdown',
|
||||
},
|
||||
async (uri: URL) => ({
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
mimeType: 'text/markdown',
|
||||
text: '# Test MCP Server\n\nThis is a test server for the use-mcp integration tests.\n\n## Features\n- Addition tool\n- Vengabus schedule checker\n- Sample resources\n- Sample prompts',
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
// Register a resource template
|
||||
mcpServer.registerResource(
|
||||
'stats',
|
||||
new ResourceTemplate('data://stats/{type}', { list: undefined }),
|
||||
{
|
||||
title: 'Statistics Data',
|
||||
description: 'Get statistics for different types',
|
||||
mimeType: 'application/json',
|
||||
},
|
||||
// @ts-expect-error - type is missing in the callback
|
||||
async (uri: URL, { type }) => ({
|
||||
contents: [
|
||||
{
|
||||
uri: uri.href,
|
||||
mimeType: 'application/json',
|
||||
text: JSON.stringify(
|
||||
{
|
||||
type: type,
|
||||
count: Math.floor(Math.random() * 100),
|
||||
lastUpdated: new Date().toISOString(),
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
// Register sample prompts
|
||||
mcpServer.registerPrompt(
|
||||
'greeting',
|
||||
{
|
||||
title: 'Generate Greeting',
|
||||
description: 'Generate a greeting message',
|
||||
argsSchema: {
|
||||
name: z.string().describe('Name of the person to greet'),
|
||||
style: z.string().optional().describe('Style of greeting (formal/casual)'),
|
||||
},
|
||||
},
|
||||
({ name, style }) => ({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Generate a ${style || 'casual'} greeting for ${name}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: style === 'formal' ? `Good day, ${name}. I hope this message finds you well.` : `Hey ${name}! How's it going?`,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
mcpServer.registerPrompt(
|
||||
'code_review',
|
||||
{
|
||||
title: 'Code Review Template',
|
||||
description: 'Template for code review requests',
|
||||
argsSchema: {
|
||||
language: z.string().describe('Programming language'),
|
||||
focus: z.string().optional().describe('What to focus on (performance/security/style)'),
|
||||
},
|
||||
},
|
||||
({ language, focus }) => ({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Please review the following ${language} code${focus ? ` with a focus on ${focus}` : ''}:`,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
app.post('/mcp', async (c) => {
|
||||
const transport = new StreamableHTTPTransport()
|
||||
await mcpServer.connect(transport)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, test, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'
|
||||
import { chromium, Browser, Page } from 'playwright'
|
||||
import { chromium, type Browser, type Page } from 'playwright'
|
||||
import { SERVER_CONFIGS } from './server-configs.js'
|
||||
import { getTestState, connectToMCPServer, cleanupProcess } from './test-utils.js'
|
||||
|
||||
|
|
@ -82,9 +82,33 @@ describe('MCP Connection Integration Tests', () => {
|
|||
console.log(` ${index + 1}. ${tool}`)
|
||||
})
|
||||
|
||||
if (result.resources.length > 0) {
|
||||
console.log(`📂 Available resources (${result.resources.length}):`)
|
||||
result.resources.forEach((resource, index) => {
|
||||
console.log(` ${index + 1}. ${resource}`)
|
||||
})
|
||||
}
|
||||
|
||||
if (result.prompts.length > 0) {
|
||||
console.log(`💬 Available prompts (${result.prompts.length}):`)
|
||||
result.prompts.forEach((prompt, index) => {
|
||||
console.log(` ${index + 1}. ${prompt}`)
|
||||
})
|
||||
}
|
||||
|
||||
// Verify connection success
|
||||
expect(result.success).toBe(true)
|
||||
expect(result.tools.length).toBeGreaterThanOrEqual(serverConfig.expectedTools)
|
||||
|
||||
// Verify resources if expected
|
||||
if (serverConfig.expectedResources !== undefined) {
|
||||
expect(result.resources.length).toBeGreaterThanOrEqual(serverConfig.expectedResources)
|
||||
}
|
||||
|
||||
// Verify prompts if expected
|
||||
if (serverConfig.expectedPrompts !== undefined) {
|
||||
expect(result.prompts.length).toBeGreaterThanOrEqual(serverConfig.expectedPrompts)
|
||||
}
|
||||
} else {
|
||||
console.log(`❌ Failed to connect to ${serverConfig.name}`)
|
||||
if (result.debugLog) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { join, dirname } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { ServerConfig } from './test-utils.js'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { ServerConfig } from './test-utils.js'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const rootDir = join(__dirname, '../..')
|
||||
|
|
@ -19,7 +19,9 @@ export const SERVER_CONFIGS: ServerConfig[] = [
|
|||
transportTypes: ['auto', 'http'],
|
||||
},
|
||||
],
|
||||
expectedTools: 1,
|
||||
expectedTools: 2,
|
||||
expectedResources: 2, // 2 direct resources (templates are counted separately)
|
||||
expectedPrompts: 2,
|
||||
},
|
||||
{
|
||||
name: 'cf-agents',
|
||||
|
|
@ -43,6 +45,8 @@ export const SERVER_CONFIGS: ServerConfig[] = [
|
|||
transportTypes: ['auto', 'sse'],
|
||||
},
|
||||
],
|
||||
expectedTools: 1,
|
||||
expectedTools: 2,
|
||||
expectedResources: 3, // 3 direct resources (no templates in cf-agents)
|
||||
expectedPrompts: 2,
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { spawn, ChildProcess } from 'child_process'
|
||||
import { Page } from 'playwright'
|
||||
import { readFileSync } from 'fs'
|
||||
import { join, dirname } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { spawn, type ChildProcess } from 'node:child_process'
|
||||
import type { Page } from 'playwright'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const testDir = join(__dirname, '..')
|
||||
|
|
@ -25,6 +25,8 @@ export interface ServerConfig {
|
|||
portKey: keyof TestState
|
||||
endpoints: ServerEndpoint[]
|
||||
expectedTools: number
|
||||
expectedResources?: number
|
||||
expectedPrompts?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -132,7 +134,7 @@ export async function connectToMCPServer(
|
|||
page: Page,
|
||||
serverUrl: string,
|
||||
transportType: 'auto' | 'http' | 'sse' = 'auto',
|
||||
): Promise<{ success: boolean; tools: string[]; debugLog: string }> {
|
||||
): Promise<{ success: boolean; tools: string[]; resources: string[]; prompts: string[]; debugLog: string }> {
|
||||
const state = getTestState()
|
||||
|
||||
if (!state.staticPort) {
|
||||
|
|
@ -197,7 +199,9 @@ export async function connectToMCPServer(
|
|||
// Extract available tools
|
||||
const tools: string[] = []
|
||||
try {
|
||||
const toolCards = page.locator('.bg-white.rounded.border')
|
||||
// Look for the Available Tools section
|
||||
const toolsSection = page.locator('h3:has-text("Available Tools")').locator('..')
|
||||
const toolCards = toolsSection.locator('.bg-white.rounded.border')
|
||||
const toolCount = await toolCards.count()
|
||||
|
||||
for (let i = 0; i < toolCount; i++) {
|
||||
|
|
@ -211,6 +215,44 @@ export async function connectToMCPServer(
|
|||
console.warn('Could not extract tools list:', e)
|
||||
}
|
||||
|
||||
// Extract available resources
|
||||
const resources: string[] = []
|
||||
try {
|
||||
// Look for the Available Resources section
|
||||
const resourcesSection = page.locator('h3:has-text("Available Resources")').locator('..')
|
||||
const resourceCards = resourcesSection.locator('.bg-white.rounded.border')
|
||||
const resourceCount = await resourceCards.count()
|
||||
|
||||
for (let i = 0; i < resourceCount; i++) {
|
||||
const resourceNameElement = resourceCards.nth(i).locator('h4.font-medium.text-sm')
|
||||
const resourceName = await resourceNameElement.textContent()
|
||||
if (resourceName?.trim()) {
|
||||
resources.push(resourceName.trim())
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not extract resources list:', e)
|
||||
}
|
||||
|
||||
// Extract available prompts
|
||||
const prompts: string[] = []
|
||||
try {
|
||||
// Look for the Available Prompts section
|
||||
const promptsSection = page.locator('h3:has-text("Available Prompts")').locator('..')
|
||||
const promptCards = promptsSection.locator('.bg-white.rounded.border')
|
||||
const promptCount = await promptCards.count()
|
||||
|
||||
for (let i = 0; i < promptCount; i++) {
|
||||
const promptNameElement = promptCards.nth(i).locator('h4.font-medium.text-sm')
|
||||
const promptName = await promptNameElement.textContent()
|
||||
if (promptName?.trim()) {
|
||||
prompts.push(promptName.trim())
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not extract prompts list:', e)
|
||||
}
|
||||
|
||||
// Extract debug log
|
||||
let debugLog = ''
|
||||
try {
|
||||
|
|
@ -225,6 +267,8 @@ export async function connectToMCPServer(
|
|||
return {
|
||||
success: isConnected,
|
||||
tools,
|
||||
resources,
|
||||
prompts,
|
||||
debugLog,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue