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:
Jem 2025-07-02 17:59:24 -07:00
commit e0743c35e4
9 changed files with 329 additions and 32 deletions

View file

@ -12,7 +12,7 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.13.0",
"@modelcontextprotocol/sdk": "^1.13.3",
"zod": "^3.25.67"
},
"devDependencies": {

View file

@ -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

View file

@ -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`,
},
},
],
}))
}
}

View file

@ -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"
}

View file

@ -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

View file

@ -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)

View file

@ -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) {

View file

@ -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,
},
]

View file

@ -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,
}
}