@mastra/mcp-docs-server 1.0.0-beta.4 → 1.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/changelogs/%40internal%2Fstorage-test-utils.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fagent-builder.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fai-sdk.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fastra.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fchroma.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fconvex.md +29 -0
- package/.docs/organized/changelogs/%40mastra%2Fcore.md +411 -211
- package/.docs/organized/changelogs/%40mastra%2Fcouchbase.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloud.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fduckdb.md +42 -0
- package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Felasticsearch.md +52 -0
- package/.docs/organized/changelogs/%40mastra%2Fevals.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Flance.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Flibsql.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Floggers.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmcp-registry-registry.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmcp.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmemory.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fmssql.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fopensearch.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fpg.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fpinecone.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Frag.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Freact.md +89 -1
- package/.docs/organized/changelogs/%40mastra%2Fs3vectors.md +9 -0
- package/.docs/organized/changelogs/%40mastra%2Fschema-compat.md +42 -0
- package/.docs/organized/changelogs/%40mastra%2Fserver.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fupstash.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvectorize.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-azure.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-cloudflare.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-deepgram.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-elevenlabs.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-gladia.md +92 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-google-gemini-live.md +67 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-google.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-murf.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-playai.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-sarvam.md +201 -1
- package/.docs/organized/changelogs/%40mastra%2Fvoice-speechify.md +201 -1
- package/.docs/organized/changelogs/create-mastra.md +201 -1
- package/.docs/organized/changelogs/mastra.md +201 -1
- package/.docs/organized/code-examples/agui.md +1 -0
- package/.docs/organized/code-examples/ai-sdk-v5.md +1 -0
- package/.docs/organized/code-examples/mcp-server-adapters.md +721 -0
- package/.docs/organized/code-examples/memory-with-processors.md +1 -1
- package/.docs/organized/code-examples/quick-start.md +1 -1
- package/.docs/organized/code-examples/server-app-access.md +342 -0
- package/.docs/raw/agents/adding-voice.mdx +7 -10
- package/.docs/raw/agents/agent-approval.mdx +189 -0
- package/.docs/raw/agents/guardrails.mdx +26 -23
- package/.docs/raw/agents/networks.mdx +2 -2
- package/.docs/raw/agents/overview.mdx +27 -62
- package/.docs/raw/agents/processors.mdx +279 -0
- package/.docs/raw/agents/using-tools.mdx +4 -5
- package/.docs/raw/course/01-first-agent/05-running-playground.md +5 -5
- package/.docs/raw/course/01-first-agent/09-testing-your-agent.md +3 -3
- package/.docs/raw/course/01-first-agent/13-testing-your-tool.md +3 -3
- package/.docs/raw/course/01-first-agent/17-testing-memory.md +2 -2
- package/.docs/raw/course/04-workflows/07-using-playground.md +1 -1
- package/.docs/raw/deployment/building-mastra.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/amazon-ec2.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/aws-lambda.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/azure-app-services.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/digital-ocean.mdx +1 -1
- package/.docs/raw/deployment/cloud-providers/index.mdx +20 -27
- package/.docs/raw/deployment/cloud-providers/netlify-deployer.mdx +44 -13
- package/.docs/raw/deployment/mastra-cloud/observability.mdx +19 -17
- package/.docs/raw/deployment/mastra-cloud/setting-up.mdx +1 -1
- package/.docs/raw/deployment/overview.mdx +2 -2
- package/.docs/raw/deployment/web-framework.mdx +5 -5
- package/.docs/raw/evals/custom-scorers.mdx +3 -5
- package/.docs/raw/evals/overview.mdx +2 -3
- package/.docs/raw/evals/running-in-ci.mdx +0 -2
- package/.docs/raw/{guides/guide → getting-started}/manual-install.mdx +2 -2
- package/.docs/raw/getting-started/project-structure.mdx +1 -1
- package/.docs/raw/getting-started/start.mdx +72 -0
- package/.docs/raw/getting-started/studio.mdx +1 -1
- package/.docs/raw/{frameworks/agentic-uis/ai-sdk.mdx → guides/build-your-ui/ai-sdk-ui.mdx} +113 -11
- package/.docs/raw/{frameworks/web-frameworks → guides/getting-started}/astro.mdx +23 -25
- package/.docs/raw/{frameworks/servers → guides/getting-started}/express.mdx +3 -4
- package/.docs/raw/guides/{quickstarts/nextjs.mdx → getting-started/next-js.mdx} +11 -11
- package/.docs/raw/guides/{quickstarts/standalone-server.mdx → getting-started/quickstart.mdx} +7 -7
- package/.docs/raw/{frameworks/web-frameworks → guides/getting-started}/sveltekit.mdx +23 -25
- package/.docs/raw/{frameworks/web-frameworks → guides/getting-started}/vite-react.mdx +7 -7
- package/.docs/raw/guides/guide/ai-recruiter.mdx +2 -3
- package/.docs/raw/guides/guide/chef-michel.mdx +2 -3
- package/.docs/raw/guides/guide/notes-mcp-server.mdx +2 -2
- package/.docs/raw/guides/guide/research-assistant.mdx +7 -8
- package/.docs/raw/guides/guide/stock-agent.mdx +4 -6
- package/.docs/raw/guides/guide/web-search.mdx +12 -10
- package/.docs/raw/guides/guide/whatsapp-chat-bot.mdx +421 -0
- package/.docs/raw/guides/index.mdx +3 -35
- package/.docs/raw/guides/migrations/agentnetwork.mdx +4 -4
- package/.docs/raw/guides/migrations/ai-sdk-v4-to-v5.mdx +1 -1
- package/.docs/raw/guides/migrations/upgrade-to-v1/agent.mdx +40 -0
- package/.docs/raw/guides/migrations/upgrade-to-v1/tools.mdx +5 -0
- package/.docs/raw/guides/migrations/upgrade-to-v1/workflows.mdx +51 -0
- package/.docs/raw/guides/migrations/vnext-to-standard-apis.mdx +2 -2
- package/.docs/raw/index.mdx +2 -2
- package/.docs/raw/mcp/overview.mdx +3 -5
- package/.docs/raw/memory/memory-processors.mdx +264 -79
- package/.docs/raw/memory/semantic-recall.mdx +7 -7
- package/.docs/raw/memory/storage/memory-with-libsql.mdx +2 -4
- package/.docs/raw/memory/storage/memory-with-mongodb.mdx +2 -4
- package/.docs/raw/memory/storage/memory-with-pg.mdx +2 -4
- package/.docs/raw/memory/storage/memory-with-upstash.mdx +2 -4
- package/.docs/raw/memory/threads-and-resources.mdx +3 -3
- package/.docs/raw/memory/working-memory.mdx +14 -7
- package/.docs/raw/{logging.mdx → observability/logging.mdx} +1 -1
- package/.docs/raw/observability/overview.mdx +2 -3
- package/.docs/raw/observability/tracing/bridges/otel.mdx +176 -0
- package/.docs/raw/observability/tracing/exporters/arize.mdx +17 -0
- package/.docs/raw/observability/tracing/exporters/braintrust.mdx +19 -0
- package/.docs/raw/observability/tracing/exporters/langfuse.mdx +20 -0
- package/.docs/raw/observability/tracing/exporters/langsmith.mdx +12 -0
- package/.docs/raw/observability/tracing/exporters/otel.mdx +25 -5
- package/.docs/raw/observability/tracing/exporters/posthog.mdx +107 -0
- package/.docs/raw/observability/tracing/overview.mdx +74 -8
- package/.docs/raw/observability/tracing/processors/sensitive-data-filter.mdx +0 -1
- package/.docs/raw/rag/chunking-and-embedding.mdx +16 -17
- package/.docs/raw/rag/overview.mdx +3 -2
- package/.docs/raw/rag/retrieval.mdx +43 -38
- package/.docs/raw/rag/vector-databases.mdx +93 -2
- package/.docs/raw/reference/agents/agent.mdx +7 -10
- package/.docs/raw/reference/agents/generate.mdx +55 -6
- package/.docs/raw/reference/agents/generateLegacy.mdx +2 -2
- package/.docs/raw/reference/agents/getLLM.mdx +1 -1
- package/.docs/raw/reference/agents/network.mdx +46 -3
- package/.docs/raw/reference/cli/mastra.mdx +2 -1
- package/.docs/raw/reference/client-js/agents.mdx +3 -3
- package/.docs/raw/reference/client-js/memory.mdx +43 -0
- package/.docs/raw/reference/client-js/workflows.mdx +92 -63
- package/.docs/raw/reference/core/getLogger.mdx +1 -1
- package/.docs/raw/reference/core/listLogs.mdx +1 -1
- package/.docs/raw/reference/core/listLogsByRunId.mdx +1 -1
- package/.docs/raw/reference/core/mastra-model-gateway.mdx +5 -19
- package/.docs/raw/reference/core/setLogger.mdx +1 -1
- package/.docs/raw/reference/core/setTelemetry.mdx +1 -1
- package/.docs/raw/reference/deployer/netlify.mdx +1 -2
- package/.docs/raw/reference/evals/answer-relevancy.mdx +28 -98
- package/.docs/raw/reference/evals/answer-similarity.mdx +12 -258
- package/.docs/raw/reference/evals/bias.mdx +29 -87
- package/.docs/raw/reference/evals/completeness.mdx +31 -90
- package/.docs/raw/reference/evals/content-similarity.mdx +28 -88
- package/.docs/raw/reference/evals/context-precision.mdx +28 -130
- package/.docs/raw/reference/evals/context-relevance.mdx +11 -11
- package/.docs/raw/reference/evals/faithfulness.mdx +28 -101
- package/.docs/raw/reference/evals/hallucination.mdx +28 -103
- package/.docs/raw/reference/evals/keyword-coverage.mdx +28 -107
- package/.docs/raw/reference/evals/noise-sensitivity.mdx +11 -11
- package/.docs/raw/reference/evals/prompt-alignment.mdx +15 -15
- package/.docs/raw/reference/evals/scorer-utils.mdx +362 -0
- package/.docs/raw/reference/evals/textual-difference.mdx +27 -100
- package/.docs/raw/reference/evals/tone-consistency.mdx +25 -98
- package/.docs/raw/reference/evals/tool-call-accuracy.mdx +7 -7
- package/.docs/raw/reference/evals/toxicity.mdx +29 -92
- package/.docs/raw/reference/index.mdx +1 -0
- package/.docs/raw/reference/memory/memory-class.mdx +5 -7
- package/.docs/raw/reference/observability/tracing/bridges/otel.mdx +150 -0
- package/.docs/raw/reference/observability/tracing/configuration.mdx +0 -4
- package/.docs/raw/reference/observability/tracing/exporters/arize.mdx +4 -0
- package/.docs/raw/reference/observability/tracing/exporters/langsmith.mdx +17 -1
- package/.docs/raw/reference/observability/tracing/exporters/otel.mdx +6 -0
- package/.docs/raw/reference/observability/tracing/exporters/posthog.mdx +132 -0
- package/.docs/raw/reference/observability/tracing/instances.mdx +0 -4
- package/.docs/raw/reference/observability/tracing/interfaces.mdx +29 -4
- package/.docs/raw/reference/observability/tracing/spans.mdx +0 -4
- package/.docs/raw/reference/processors/batch-parts-processor.mdx +1 -1
- package/.docs/raw/reference/processors/language-detector.mdx +10 -3
- package/.docs/raw/reference/processors/message-history-processor.mdx +131 -0
- package/.docs/raw/reference/processors/moderation-processor.mdx +12 -5
- package/.docs/raw/reference/processors/pii-detector.mdx +12 -5
- package/.docs/raw/reference/processors/processor-interface.mdx +502 -0
- package/.docs/raw/reference/processors/prompt-injection-detector.mdx +10 -3
- package/.docs/raw/reference/processors/semantic-recall-processor.mdx +197 -0
- package/.docs/raw/reference/processors/system-prompt-scrubber.mdx +3 -4
- package/.docs/raw/reference/processors/token-limiter-processor.mdx +2 -2
- package/.docs/raw/reference/processors/tool-call-filter.mdx +125 -0
- package/.docs/raw/reference/processors/unicode-normalizer.mdx +1 -1
- package/.docs/raw/reference/processors/working-memory-processor.mdx +221 -0
- package/.docs/raw/reference/rag/embeddings.mdx +5 -5
- package/.docs/raw/reference/rag/rerank.mdx +1 -2
- package/.docs/raw/reference/rag/rerankWithScorer.mdx +0 -1
- package/.docs/raw/reference/storage/cloudflare-d1.mdx +37 -0
- package/.docs/raw/reference/storage/convex.mdx +164 -0
- package/.docs/raw/reference/storage/lance.mdx +33 -0
- package/.docs/raw/reference/storage/libsql.mdx +37 -0
- package/.docs/raw/reference/storage/mongodb.mdx +39 -0
- package/.docs/raw/reference/storage/mssql.mdx +37 -0
- package/.docs/raw/reference/storage/postgresql.mdx +37 -0
- package/.docs/raw/reference/streaming/ChunkType.mdx +1 -1
- package/.docs/raw/reference/streaming/agents/stream.mdx +64 -2
- package/.docs/raw/reference/streaming/workflows/observeStream.mdx +7 -9
- package/.docs/raw/reference/streaming/workflows/{resumeStreamVNext.mdx → resumeStream.mdx} +51 -11
- package/.docs/raw/reference/streaming/workflows/stream.mdx +83 -24
- package/.docs/raw/reference/templates/overview.mdx +1 -4
- package/.docs/raw/reference/tools/client.mdx +1 -2
- package/.docs/raw/reference/tools/create-tool.mdx +132 -0
- package/.docs/raw/reference/tools/graph-rag-tool.mdx +5 -5
- package/.docs/raw/reference/tools/mcp-client.mdx +76 -21
- package/.docs/raw/reference/tools/mcp-server.mdx +1 -2
- package/.docs/raw/reference/tools/vector-query-tool.mdx +14 -15
- package/.docs/raw/reference/vectors/chroma.mdx +81 -1
- package/.docs/raw/reference/vectors/convex.mdx +429 -0
- package/.docs/raw/reference/vectors/couchbase.mdx +24 -17
- package/.docs/raw/reference/vectors/duckdb.mdx +462 -0
- package/.docs/raw/reference/vectors/elasticsearch.mdx +310 -0
- package/.docs/raw/reference/vectors/lance.mdx +38 -22
- package/.docs/raw/reference/vectors/libsql.mdx +35 -2
- package/.docs/raw/reference/vectors/mongodb.mdx +35 -2
- package/.docs/raw/reference/vectors/opensearch.mdx +37 -16
- package/.docs/raw/reference/vectors/pg.mdx +43 -36
- package/.docs/raw/reference/vectors/pinecone.mdx +48 -1
- package/.docs/raw/reference/vectors/qdrant.mdx +36 -1
- package/.docs/raw/reference/vectors/turbopuffer.mdx +74 -0
- package/.docs/raw/reference/voice/google.mdx +159 -20
- package/.docs/raw/reference/voice/openai-realtime.mdx +2 -2
- package/.docs/raw/reference/voice/voice.addInstructions.mdx +2 -3
- package/.docs/raw/reference/voice/voice.addTools.mdx +1 -1
- package/.docs/raw/reference/voice/voice.answer.mdx +1 -1
- package/.docs/raw/reference/voice/voice.close.mdx +1 -1
- package/.docs/raw/reference/voice/voice.connect.mdx +1 -1
- package/.docs/raw/reference/voice/voice.off.mdx +1 -1
- package/.docs/raw/reference/voice/voice.on.mdx +1 -1
- package/.docs/raw/reference/voice/voice.send.mdx +1 -1
- package/.docs/raw/reference/voice/voice.updateConfig.mdx +1 -1
- package/.docs/raw/reference/workflows/run-methods/restart.mdx +142 -0
- package/.docs/raw/reference/workflows/run-methods/resume.mdx +44 -0
- package/.docs/raw/reference/workflows/run-methods/start.mdx +44 -0
- package/.docs/raw/reference/workflows/run.mdx +13 -5
- package/.docs/raw/reference/workflows/step.mdx +13 -0
- package/.docs/raw/reference/workflows/workflow.mdx +19 -0
- package/.docs/raw/server-db/mastra-client.mdx +1 -2
- package/.docs/raw/server-db/mastra-server.mdx +30 -1
- package/.docs/raw/server-db/request-context.mdx +0 -1
- package/.docs/raw/server-db/storage.mdx +11 -0
- package/.docs/raw/streaming/overview.mdx +26 -15
- package/.docs/raw/streaming/tool-streaming.mdx +48 -5
- package/.docs/raw/streaming/workflow-streaming.mdx +5 -11
- package/.docs/raw/tools-mcp/advanced-usage.mdx +1 -2
- package/.docs/raw/tools-mcp/mcp-overview.mdx +3 -5
- package/.docs/raw/voice/overview.mdx +21 -41
- package/.docs/raw/voice/speech-to-speech.mdx +4 -4
- package/.docs/raw/voice/speech-to-text.mdx +1 -2
- package/.docs/raw/voice/text-to-speech.mdx +1 -2
- package/.docs/raw/workflows/control-flow.mdx +180 -0
- package/.docs/raw/workflows/error-handling.mdx +1 -0
- package/.docs/raw/workflows/human-in-the-loop.mdx +4 -4
- package/.docs/raw/workflows/overview.mdx +56 -44
- package/.docs/raw/workflows/snapshots.mdx +1 -0
- package/.docs/raw/workflows/suspend-and-resume.mdx +85 -16
- package/.docs/raw/workflows/time-travel.mdx +313 -0
- package/.docs/raw/workflows/workflow-state.mdx +191 -0
- package/CHANGELOG.md +18 -0
- package/dist/{chunk-5NJC7NRO.js → chunk-4CM2BQNP.js} +24 -4
- package/dist/prepare-docs/package-changes.d.ts.map +1 -1
- package/dist/prepare-docs/prepare.js +1 -1
- package/dist/stdio.js +1 -1
- package/package.json +7 -7
- package/.docs/raw/agents/human-in-the-loop-with-tools.mdx +0 -90
- package/.docs/raw/frameworks/agentic-uis/cedar-os.mdx +0 -102
- package/.docs/raw/frameworks/agentic-uis/openrouter.mdx +0 -179
- package/.docs/raw/frameworks/web-frameworks/next-js.mdx +0 -379
- package/.docs/raw/getting-started/quickstart.mdx +0 -27
- package/.docs/raw/getting-started/templates.mdx +0 -73
- package/.docs/raw/reference/streaming/workflows/observeStreamVNext.mdx +0 -47
- package/.docs/raw/reference/streaming/workflows/streamVNext.mdx +0 -153
- /package/.docs/raw/{frameworks/agentic-uis → guides/build-your-ui}/assistant-ui.mdx +0 -0
- /package/.docs/raw/{frameworks/agentic-uis → guides/build-your-ui}/copilotkit.mdx +0 -0
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
### package.json
|
|
2
|
+
```json
|
|
3
|
+
{
|
|
4
|
+
"name": "examples-mcp-server-adapters",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@mastra/core": "latest",
|
|
7
|
+
"@mastra/mcp": "latest",
|
|
8
|
+
"@mastra/hono": "latest",
|
|
9
|
+
"@mastra/express": "latest",
|
|
10
|
+
"@mastra/auth": "latest",
|
|
11
|
+
"@mastra/auth-supabase": "latest",
|
|
12
|
+
"@mastra/auth-firebase": "latest",
|
|
13
|
+
"@mastra/auth-auth0": "latest",
|
|
14
|
+
"@mastra/auth-workos": "latest",
|
|
15
|
+
"@mastra/auth-clerk": "latest",
|
|
16
|
+
"hono": "^4.10.4",
|
|
17
|
+
"@hono/node-server": "^1.19.6",
|
|
18
|
+
"express": "^5.1.0",
|
|
19
|
+
"mastra": "latest",
|
|
20
|
+
"zod": "^3.25.76"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/express": "^5.0.5",
|
|
24
|
+
"@types/node": "22.13.17",
|
|
25
|
+
"tsx": "^4.19.3",
|
|
26
|
+
"typescript": "^5.8.3"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### express-server.ts
|
|
32
|
+
```typescript
|
|
33
|
+
import { MastraServer } from '@mastra/express';
|
|
34
|
+
import express from 'express';
|
|
35
|
+
|
|
36
|
+
import { mastra } from './mastra';
|
|
37
|
+
|
|
38
|
+
const PORT = 3002;
|
|
39
|
+
|
|
40
|
+
// Create Express app
|
|
41
|
+
const app = express();
|
|
42
|
+
|
|
43
|
+
// Add JSON body parser middleware
|
|
44
|
+
// This tests that MCP endpoints work correctly with express.json() middleware
|
|
45
|
+
app.use(express.json());
|
|
46
|
+
|
|
47
|
+
// Add a simple health check endpoint
|
|
48
|
+
app.get('/', (req, res) => {
|
|
49
|
+
res.json({ status: 'ok', server: 'express', message: 'Express MCP Server is running' });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Create Mastra server adapter
|
|
53
|
+
const adapter = new MastraServer({
|
|
54
|
+
app,
|
|
55
|
+
mastra,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Initialize all routes including MCP endpoints
|
|
59
|
+
adapter.init();
|
|
60
|
+
|
|
61
|
+
// Start the server
|
|
62
|
+
app.listen(PORT, () => {
|
|
63
|
+
console.log(`Express MCP Server running on port ${PORT}`);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### hono-server.ts
|
|
69
|
+
```typescript
|
|
70
|
+
import { serve } from '@hono/node-server';
|
|
71
|
+
import { MastraServer } from '@mastra/hono';
|
|
72
|
+
import { Hono } from 'hono';
|
|
73
|
+
|
|
74
|
+
import { mastra } from './mastra';
|
|
75
|
+
|
|
76
|
+
const PORT = 3001;
|
|
77
|
+
|
|
78
|
+
// Create Hono app
|
|
79
|
+
const app = new Hono();
|
|
80
|
+
|
|
81
|
+
// Add a simple health check endpoint
|
|
82
|
+
app.get('/', c => c.json({ status: 'ok', server: 'hono', message: 'Hono MCP Server is running' }));
|
|
83
|
+
|
|
84
|
+
// Create Mastra server adapter
|
|
85
|
+
// Note: Type assertion needed due to Hono version differences between example and @mastra/hono
|
|
86
|
+
const adapter = new MastraServer({
|
|
87
|
+
app: app as any,
|
|
88
|
+
mastra,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Initialize all routes including MCP endpoints
|
|
92
|
+
adapter.init();
|
|
93
|
+
|
|
94
|
+
// Start the server
|
|
95
|
+
console.log(`Hono MCP Server running on port ${PORT}`);
|
|
96
|
+
serve({
|
|
97
|
+
fetch: app.fetch,
|
|
98
|
+
port: PORT,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### mastra/auth/index.ts
|
|
104
|
+
```typescript
|
|
105
|
+
// Import auth providers
|
|
106
|
+
import { MastraAuthFirebase } from '@mastra/auth-firebase';
|
|
107
|
+
import { MastraAuthSupabase } from '@mastra/auth-supabase';
|
|
108
|
+
import { MastraAuthAuth0 } from '@mastra/auth-auth0';
|
|
109
|
+
import { MastraAuthWorkos } from '@mastra/auth-workos';
|
|
110
|
+
import { MastraAuthClerk } from '@mastra/auth-clerk';
|
|
111
|
+
import { MastraJwtAuth } from '@mastra/auth';
|
|
112
|
+
|
|
113
|
+
// Get the configured auth provider based on environment
|
|
114
|
+
export function getAuthProvider() {
|
|
115
|
+
const provider = process.env.AUTH_PROVIDER?.toLowerCase();
|
|
116
|
+
|
|
117
|
+
switch (provider) {
|
|
118
|
+
case 'auth0':
|
|
119
|
+
return new MastraAuthAuth0();
|
|
120
|
+
case 'firebase':
|
|
121
|
+
return new MastraAuthFirebase();
|
|
122
|
+
case 'supabase':
|
|
123
|
+
return new MastraAuthSupabase();
|
|
124
|
+
case 'workos':
|
|
125
|
+
return new MastraAuthWorkos();
|
|
126
|
+
case 'clerk':
|
|
127
|
+
return new MastraAuthClerk();
|
|
128
|
+
case 'jwt':
|
|
129
|
+
default:
|
|
130
|
+
return new MastraJwtAuth();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const authConfig = getAuthProvider();
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### mastra/index.ts
|
|
139
|
+
```typescript
|
|
140
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
141
|
+
|
|
142
|
+
import { mainMcpServer, secondaryMcpServer } from './mcp-servers';
|
|
143
|
+
import { authConfig } from './auth';
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Create Mastra instance with MCP servers
|
|
147
|
+
*/
|
|
148
|
+
export const mastra = new Mastra({
|
|
149
|
+
mcpServers: {
|
|
150
|
+
'main-mcp': mainMcpServer,
|
|
151
|
+
'secondary-mcp': secondaryMcpServer,
|
|
152
|
+
},
|
|
153
|
+
server: {
|
|
154
|
+
auth: authConfig,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### mastra/mcp-servers/index.ts
|
|
161
|
+
```typescript
|
|
162
|
+
import { MCPServer } from '@mastra/mcp';
|
|
163
|
+
|
|
164
|
+
import { calculatorTool, echoTool, weatherTool } from '../tools';
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Main MCP server with all tools
|
|
168
|
+
*/
|
|
169
|
+
export const mainMcpServer = new MCPServer({
|
|
170
|
+
name: 'main-server',
|
|
171
|
+
version: '1.0.0',
|
|
172
|
+
description: 'Main MCP server with weather, calculator, and echo tools',
|
|
173
|
+
tools: {
|
|
174
|
+
getWeather: weatherTool,
|
|
175
|
+
calculate: calculatorTool,
|
|
176
|
+
echo: echoTool,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Secondary MCP server with a subset of tools
|
|
182
|
+
*/
|
|
183
|
+
export const secondaryMcpServer = new MCPServer({
|
|
184
|
+
name: 'secondary-server',
|
|
185
|
+
version: '1.0.0',
|
|
186
|
+
description: 'Secondary MCP server with calculator only',
|
|
187
|
+
tools: {
|
|
188
|
+
calculate: calculatorTool,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### mastra/tools/index.ts
|
|
195
|
+
```typescript
|
|
196
|
+
import { createTool } from '@mastra/core/tools';
|
|
197
|
+
import { z } from 'zod';
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Weather tool - simulates getting weather for a location
|
|
201
|
+
*/
|
|
202
|
+
export const weatherTool = createTool({
|
|
203
|
+
id: 'getWeather',
|
|
204
|
+
description: 'Gets the current weather for a location',
|
|
205
|
+
inputSchema: z.object({
|
|
206
|
+
location: z.string().describe('The location to get weather for'),
|
|
207
|
+
}),
|
|
208
|
+
execute: async ({ location }) => {
|
|
209
|
+
// Simulated weather data
|
|
210
|
+
return {
|
|
211
|
+
temperature: 72,
|
|
212
|
+
condition: `Sunny in ${location}`,
|
|
213
|
+
humidity: 45,
|
|
214
|
+
windSpeed: 10,
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Calculator tool - performs basic math operations
|
|
221
|
+
*/
|
|
222
|
+
export const calculatorTool = createTool({
|
|
223
|
+
id: 'calculate',
|
|
224
|
+
description: 'Performs basic calculations',
|
|
225
|
+
inputSchema: z.object({
|
|
226
|
+
operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
|
|
227
|
+
a: z.number(),
|
|
228
|
+
b: z.number(),
|
|
229
|
+
}),
|
|
230
|
+
execute: async ({ operation, a, b }) => {
|
|
231
|
+
if (operation === 'divide' && b === 0) {
|
|
232
|
+
throw new Error('Cannot divide by zero');
|
|
233
|
+
}
|
|
234
|
+
let result = 0;
|
|
235
|
+
switch (operation) {
|
|
236
|
+
case 'add':
|
|
237
|
+
result = a + b;
|
|
238
|
+
break;
|
|
239
|
+
case 'subtract':
|
|
240
|
+
result = a - b;
|
|
241
|
+
break;
|
|
242
|
+
case 'multiply':
|
|
243
|
+
result = a * b;
|
|
244
|
+
break;
|
|
245
|
+
case 'divide':
|
|
246
|
+
result = a / b;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
return { result, operation, operands: { a, b } };
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Echo tool - simple tool that echoes back input
|
|
255
|
+
*/
|
|
256
|
+
export const echoTool = createTool({
|
|
257
|
+
id: 'echo',
|
|
258
|
+
description: 'Echoes back the provided message',
|
|
259
|
+
inputSchema: z.object({
|
|
260
|
+
message: z.string().describe('The message to echo'),
|
|
261
|
+
}),
|
|
262
|
+
execute: async ({ message }) => {
|
|
263
|
+
return { echo: message, timestamp: new Date().toISOString() };
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### test-mcp.ts
|
|
270
|
+
```typescript
|
|
271
|
+
import * as fs from 'node:fs';
|
|
272
|
+
import * as path from 'node:path';
|
|
273
|
+
import { MCPClient } from '@mastra/mcp';
|
|
274
|
+
|
|
275
|
+
// MCP server IDs as registered with Mastra (keys from mcpServers config)
|
|
276
|
+
const mainServerId = 'main-mcp';
|
|
277
|
+
const secondaryServerId = 'secondary-mcp';
|
|
278
|
+
|
|
279
|
+
// Parse command line arguments
|
|
280
|
+
const args = process.argv.slice(2);
|
|
281
|
+
const portIndex = args.indexOf('--port');
|
|
282
|
+
const PORT = portIndex !== -1 && args[portIndex + 1] ? parseInt(args[portIndex + 1]) : 3001;
|
|
283
|
+
|
|
284
|
+
const BASE_URL = `http://localhost:${PORT}`;
|
|
285
|
+
|
|
286
|
+
// Auth token for protected endpoints
|
|
287
|
+
const AUTH_TOKEN = process.env.TEST_AUTH_TOKEN || '';
|
|
288
|
+
const authHeaders: Record<string, string> = AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {};
|
|
289
|
+
|
|
290
|
+
// Output file setup
|
|
291
|
+
const OUTPUT_DIR = path.join(import.meta.dirname, '..', 'output');
|
|
292
|
+
const serverType = PORT === 3001 ? 'hono' : PORT === 3002 ? 'express' : `port-${PORT}`;
|
|
293
|
+
const OUTPUT_FILE = path.join(OUTPUT_DIR, `test-results-${serverType}.txt`);
|
|
294
|
+
|
|
295
|
+
// Ensure output directory exists
|
|
296
|
+
if (!fs.existsSync(OUTPUT_DIR)) {
|
|
297
|
+
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Log buffer for writing to file
|
|
301
|
+
const logBuffer: string[] = [];
|
|
302
|
+
|
|
303
|
+
interface TestResult {
|
|
304
|
+
name: string;
|
|
305
|
+
passed: boolean;
|
|
306
|
+
error?: string;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const results: TestResult[] = [];
|
|
310
|
+
|
|
311
|
+
function log(message: string) {
|
|
312
|
+
console.log(message);
|
|
313
|
+
logBuffer.push(message);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function success(testName: string) {
|
|
317
|
+
results.push({ name: testName, passed: true });
|
|
318
|
+
log(` ✓ ${testName}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function fail(testName: string, error: unknown) {
|
|
322
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
323
|
+
results.push({ name: testName, passed: false, error: errorMessage });
|
|
324
|
+
log(` ✗ ${testName}: ${errorMessage}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function writeOutput() {
|
|
328
|
+
const content = logBuffer.join('\n');
|
|
329
|
+
fs.writeFileSync(OUTPUT_FILE, content, 'utf-8');
|
|
330
|
+
console.log(`\nTest output written to: ${OUTPUT_FILE}`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function testHealthCheck() {
|
|
334
|
+
log('\n--- Testing Health Check ---');
|
|
335
|
+
try {
|
|
336
|
+
const res = await fetch(BASE_URL);
|
|
337
|
+
const data = (await res.json()) as { status?: string };
|
|
338
|
+
if (data.status === 'ok') {
|
|
339
|
+
success('Health check returns ok');
|
|
340
|
+
} else {
|
|
341
|
+
fail('Health check returns ok', `Expected status 'ok', got '${data.status}'`);
|
|
342
|
+
}
|
|
343
|
+
} catch (error) {
|
|
344
|
+
fail('Health check returns ok', error);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function testHttpTransport() {
|
|
349
|
+
log('\n--- Testing HTTP Transport ---');
|
|
350
|
+
|
|
351
|
+
// Test with MCPClient for HTTP transport
|
|
352
|
+
const httpClient = new MCPClient({
|
|
353
|
+
servers: {
|
|
354
|
+
main: {
|
|
355
|
+
url: new URL(`${BASE_URL}/api/mcp/${mainServerId}/mcp`),
|
|
356
|
+
requestInit: { headers: authHeaders },
|
|
357
|
+
},
|
|
358
|
+
secondary: {
|
|
359
|
+
url: new URL(`${BASE_URL}/api/mcp/${secondaryServerId}/mcp`),
|
|
360
|
+
requestInit: { headers: authHeaders },
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
// Test listing tools from main server
|
|
367
|
+
const tools = await httpClient.listTools();
|
|
368
|
+
const mainTools = Object.keys(tools).filter(k => k.startsWith('main_'));
|
|
369
|
+
if (mainTools.length === 3) {
|
|
370
|
+
success('HTTP: List tools from main server (3 tools)');
|
|
371
|
+
} else {
|
|
372
|
+
fail('HTTP: List tools from main server (3 tools)', `Expected 3 tools, got ${mainTools.length}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Test listing tools from secondary server
|
|
376
|
+
const secondaryTools = Object.keys(tools).filter(k => k.startsWith('secondary_'));
|
|
377
|
+
if (secondaryTools.length === 1) {
|
|
378
|
+
success('HTTP: List tools from secondary server (1 tool)');
|
|
379
|
+
} else {
|
|
380
|
+
fail('HTTP: List tools from secondary server (1 tool)', `Expected 1 tool, got ${secondaryTools.length}`);
|
|
381
|
+
}
|
|
382
|
+
} catch (error) {
|
|
383
|
+
fail('HTTP: List tools', error);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
// Test executing calculator tool
|
|
388
|
+
const tools = await httpClient.listTools();
|
|
389
|
+
const calculateTool = tools['main_calculate'];
|
|
390
|
+
if (!calculateTool || !calculateTool.execute) {
|
|
391
|
+
throw new Error('Calculator tool not found');
|
|
392
|
+
}
|
|
393
|
+
const result = await calculateTool.execute({ operation: 'multiply', a: 6, b: 7 });
|
|
394
|
+
const output = JSON.parse(result.content[0].text);
|
|
395
|
+
if (output.result === 42) {
|
|
396
|
+
success('HTTP: Execute calculator tool (6 * 7 = 42)');
|
|
397
|
+
} else {
|
|
398
|
+
fail('HTTP: Execute calculator tool (6 * 7 = 42)', `Expected 42, got ${output.result}`);
|
|
399
|
+
}
|
|
400
|
+
} catch (error) {
|
|
401
|
+
fail('HTTP: Execute calculator tool', error);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
try {
|
|
405
|
+
// Test executing weather tool
|
|
406
|
+
const tools = await httpClient.listTools();
|
|
407
|
+
const weatherTool = tools['main_getWeather'];
|
|
408
|
+
if (!weatherTool || !weatherTool.execute) {
|
|
409
|
+
throw new Error('Weather tool not found');
|
|
410
|
+
}
|
|
411
|
+
const result = await weatherTool.execute({ location: 'San Francisco' });
|
|
412
|
+
const output = JSON.parse(result.content[0].text);
|
|
413
|
+
if (output.condition === 'Sunny in San Francisco') {
|
|
414
|
+
success('HTTP: Execute weather tool (San Francisco)');
|
|
415
|
+
} else {
|
|
416
|
+
fail('HTTP: Execute weather tool (San Francisco)', `Unexpected condition: ${output.condition}`);
|
|
417
|
+
}
|
|
418
|
+
} catch (error) {
|
|
419
|
+
fail('HTTP: Execute weather tool', error);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
// Test executing echo tool
|
|
424
|
+
const tools = await httpClient.listTools();
|
|
425
|
+
const echoTool = tools['main_echo'];
|
|
426
|
+
if (!echoTool || !echoTool.execute) {
|
|
427
|
+
throw new Error('Echo tool not found');
|
|
428
|
+
}
|
|
429
|
+
const result = await echoTool.execute({ message: 'Hello MCP!' });
|
|
430
|
+
const output = JSON.parse(result.content[0].text);
|
|
431
|
+
if (output.echo === 'Hello MCP!') {
|
|
432
|
+
success('HTTP: Execute echo tool');
|
|
433
|
+
} else {
|
|
434
|
+
fail('HTTP: Execute echo tool', `Expected 'Hello MCP!', got '${output.echo}'`);
|
|
435
|
+
}
|
|
436
|
+
} catch (error) {
|
|
437
|
+
fail('HTTP: Execute echo tool', error);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Test secondary server's calculator tool
|
|
441
|
+
try {
|
|
442
|
+
const tools = await httpClient.listTools();
|
|
443
|
+
const secondaryCalculateTool = tools['secondary_calculate'];
|
|
444
|
+
if (!secondaryCalculateTool || !secondaryCalculateTool.execute) {
|
|
445
|
+
throw new Error('Secondary calculator tool not found');
|
|
446
|
+
}
|
|
447
|
+
const result = await secondaryCalculateTool.execute({ operation: 'divide', a: 100, b: 4 });
|
|
448
|
+
const output = JSON.parse(result.content[0].text);
|
|
449
|
+
if (output.result === 25) {
|
|
450
|
+
success('HTTP: Execute secondary server calculator tool (100 / 4 = 25)');
|
|
451
|
+
} else {
|
|
452
|
+
fail('HTTP: Execute secondary server calculator tool (100 / 4 = 25)', `Expected 25, got ${output.result}`);
|
|
453
|
+
}
|
|
454
|
+
} catch (error) {
|
|
455
|
+
fail('HTTP: Execute secondary server calculator tool', error);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
await httpClient.disconnect();
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async function testSseTransport() {
|
|
462
|
+
log('\n--- Testing SSE Transport ---');
|
|
463
|
+
|
|
464
|
+
// Test with MCPClient for SSE transport
|
|
465
|
+
const sseClient = new MCPClient({
|
|
466
|
+
servers: {
|
|
467
|
+
main: {
|
|
468
|
+
url: new URL(`${BASE_URL}/api/mcp/${mainServerId}/sse`),
|
|
469
|
+
requestInit: { headers: authHeaders },
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
try {
|
|
475
|
+
// Test listing tools via SSE
|
|
476
|
+
const tools = await sseClient.listTools();
|
|
477
|
+
const mainTools = Object.keys(tools).filter(k => k.startsWith('main_'));
|
|
478
|
+
if (mainTools.length === 3) {
|
|
479
|
+
success('SSE: List tools from main server (3 tools)');
|
|
480
|
+
} else {
|
|
481
|
+
fail('SSE: List tools from main server (3 tools)', `Expected 3 tools, got ${mainTools.length}`);
|
|
482
|
+
}
|
|
483
|
+
} catch (error) {
|
|
484
|
+
fail('SSE: List tools', error);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
try {
|
|
488
|
+
// Test executing calculator tool via SSE
|
|
489
|
+
const tools = await sseClient.listTools();
|
|
490
|
+
const calculateTool = tools['main_calculate'];
|
|
491
|
+
if (!calculateTool || !calculateTool.execute) {
|
|
492
|
+
throw new Error('Calculator tool not found');
|
|
493
|
+
}
|
|
494
|
+
const result = await calculateTool.execute({ operation: 'add', a: 100, b: 23 });
|
|
495
|
+
const output = JSON.parse(result.content[0].text);
|
|
496
|
+
if (output.result === 123) {
|
|
497
|
+
success('SSE: Execute calculator tool (100 + 23 = 123)');
|
|
498
|
+
} else {
|
|
499
|
+
fail('SSE: Execute calculator tool (100 + 23 = 123)', `Expected 123, got ${output.result}`);
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
fail('SSE: Execute calculator tool', error);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
try {
|
|
506
|
+
// Test executing weather tool via SSE
|
|
507
|
+
const tools = await sseClient.listTools();
|
|
508
|
+
const weatherTool = tools['main_getWeather'];
|
|
509
|
+
if (!weatherTool || !weatherTool.execute) {
|
|
510
|
+
throw new Error('Weather tool not found');
|
|
511
|
+
}
|
|
512
|
+
const result = await weatherTool.execute({ location: 'New York' });
|
|
513
|
+
const output = JSON.parse(result.content[0].text);
|
|
514
|
+
if (output.condition === 'Sunny in New York') {
|
|
515
|
+
success('SSE: Execute weather tool (New York)');
|
|
516
|
+
} else {
|
|
517
|
+
fail('SSE: Execute weather tool (New York)', `Unexpected condition: ${output.condition}`);
|
|
518
|
+
}
|
|
519
|
+
} catch (error) {
|
|
520
|
+
fail('SSE: Execute weather tool', error);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
await sseClient.disconnect();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async function testSseConnectionLifecycle() {
|
|
527
|
+
log('\n--- Testing SSE Connection Lifecycle ---');
|
|
528
|
+
|
|
529
|
+
// Test multiple connect/disconnect cycles
|
|
530
|
+
for (let i = 1; i <= 3; i++) {
|
|
531
|
+
const client = new MCPClient({
|
|
532
|
+
servers: {
|
|
533
|
+
main: {
|
|
534
|
+
url: new URL(`${BASE_URL}/api/mcp/${mainServerId}/sse`),
|
|
535
|
+
requestInit: { headers: authHeaders },
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
const tools = await client.listTools();
|
|
542
|
+
const toolCount = Object.keys(tools).filter(k => k.startsWith('main_')).length;
|
|
543
|
+
if (toolCount === 3) {
|
|
544
|
+
success(`SSE: Connection cycle ${i} - connect and list tools`);
|
|
545
|
+
} else {
|
|
546
|
+
fail(`SSE: Connection cycle ${i} - connect and list tools`, `Expected 3 tools, got ${toolCount}`);
|
|
547
|
+
}
|
|
548
|
+
await client.disconnect();
|
|
549
|
+
success(`SSE: Connection cycle ${i} - disconnect`);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
fail(`SSE: Connection cycle ${i}`, error);
|
|
552
|
+
try {
|
|
553
|
+
await client.disconnect();
|
|
554
|
+
} catch {
|
|
555
|
+
// Ignore disconnect errors
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
async function testToolResponseFormat() {
|
|
562
|
+
log('\n--- Testing Tool Response Format ---');
|
|
563
|
+
|
|
564
|
+
const httpClient = new MCPClient({
|
|
565
|
+
servers: {
|
|
566
|
+
main: {
|
|
567
|
+
url: new URL(`${BASE_URL}/api/mcp/${mainServerId}/mcp`),
|
|
568
|
+
requestInit: { headers: authHeaders },
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
try {
|
|
574
|
+
// Verify tool response has expected MCP format
|
|
575
|
+
const tools = await httpClient.listTools();
|
|
576
|
+
const calculateTool = tools['main_calculate'];
|
|
577
|
+
if (!calculateTool || !calculateTool.execute) {
|
|
578
|
+
throw new Error('Calculator tool not found');
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const result = await calculateTool.execute({ operation: 'subtract', a: 50, b: 8 });
|
|
582
|
+
|
|
583
|
+
// Verify response structure
|
|
584
|
+
if (result && result.content && Array.isArray(result.content) && result.content[0]?.text) {
|
|
585
|
+
const output = JSON.parse(result.content[0].text);
|
|
586
|
+
if (output.result === 42 && output.operation === 'subtract' && output.operands) {
|
|
587
|
+
success('HTTP: Tool response has correct MCP format');
|
|
588
|
+
} else {
|
|
589
|
+
fail('HTTP: Tool response has correct MCP format', `Unexpected output: ${JSON.stringify(output)}`);
|
|
590
|
+
}
|
|
591
|
+
} else {
|
|
592
|
+
fail('HTTP: Tool response has correct MCP format', 'Response missing expected structure');
|
|
593
|
+
}
|
|
594
|
+
} catch (error) {
|
|
595
|
+
fail('HTTP: Tool response format test', error);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
// Verify echo tool response includes timestamp
|
|
600
|
+
const tools = await httpClient.listTools();
|
|
601
|
+
const echoTool = tools['main_echo'];
|
|
602
|
+
if (!echoTool || !echoTool.execute) {
|
|
603
|
+
throw new Error('Echo tool not found');
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const result = await echoTool.execute({ message: 'test timestamp' });
|
|
607
|
+
const output = JSON.parse(result.content[0].text);
|
|
608
|
+
|
|
609
|
+
if (output.echo === 'test timestamp' && output.timestamp) {
|
|
610
|
+
// Verify timestamp is a valid ISO date
|
|
611
|
+
const date = new Date(output.timestamp);
|
|
612
|
+
if (!isNaN(date.getTime())) {
|
|
613
|
+
success('HTTP: Echo tool includes valid timestamp');
|
|
614
|
+
} else {
|
|
615
|
+
fail('HTTP: Echo tool includes valid timestamp', `Invalid timestamp: ${output.timestamp}`);
|
|
616
|
+
}
|
|
617
|
+
} else {
|
|
618
|
+
fail('HTTP: Echo tool includes valid timestamp', 'Missing echo or timestamp in response');
|
|
619
|
+
}
|
|
620
|
+
} catch (error) {
|
|
621
|
+
fail('HTTP: Echo tool timestamp test', error);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
await httpClient.disconnect();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
async function testErrorHandling() {
|
|
628
|
+
log('\n--- Testing Error Handling ---');
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
// Test 404 for non-existent server
|
|
632
|
+
const res = await fetch(`${BASE_URL}/api/mcp/non-existent-server/mcp`, {
|
|
633
|
+
method: 'POST',
|
|
634
|
+
headers: {
|
|
635
|
+
'Content-Type': 'application/json',
|
|
636
|
+
Accept: 'application/json, text/event-stream',
|
|
637
|
+
...authHeaders,
|
|
638
|
+
},
|
|
639
|
+
body: JSON.stringify({
|
|
640
|
+
jsonrpc: '2.0',
|
|
641
|
+
method: 'initialize',
|
|
642
|
+
params: {
|
|
643
|
+
protocolVersion: '2024-11-05',
|
|
644
|
+
capabilities: {},
|
|
645
|
+
clientInfo: { name: 'test-client', version: '1.0.0' },
|
|
646
|
+
},
|
|
647
|
+
id: 1,
|
|
648
|
+
}),
|
|
649
|
+
});
|
|
650
|
+
if (res.status === 404) {
|
|
651
|
+
success('HTTP: Returns 404 for non-existent server');
|
|
652
|
+
} else {
|
|
653
|
+
fail('HTTP: Returns 404 for non-existent server', `Expected 404, got ${res.status}`);
|
|
654
|
+
}
|
|
655
|
+
} catch (error) {
|
|
656
|
+
fail('HTTP: Returns 404 for non-existent server', error);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
try {
|
|
660
|
+
// Test 404 for non-existent SSE server
|
|
661
|
+
const res = await fetch(`${BASE_URL}/api/mcp/non-existent-server/sse`, {
|
|
662
|
+
headers: authHeaders,
|
|
663
|
+
});
|
|
664
|
+
if (res.status === 404) {
|
|
665
|
+
success('SSE: Returns 404 for non-existent server');
|
|
666
|
+
} else {
|
|
667
|
+
fail('SSE: Returns 404 for non-existent server', `Expected 404, got ${res.status}`);
|
|
668
|
+
}
|
|
669
|
+
} catch (error) {
|
|
670
|
+
fail('SSE: Returns 404 for non-existent server', error);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
async function runTests() {
|
|
675
|
+
log(`\n========================================`);
|
|
676
|
+
log(` MCP Server Adapter Tests`);
|
|
677
|
+
log(` Testing against: ${BASE_URL}`);
|
|
678
|
+
log(` Server type: ${serverType}`);
|
|
679
|
+
log(` Timestamp: ${new Date().toISOString()}`);
|
|
680
|
+
log(`========================================`);
|
|
681
|
+
|
|
682
|
+
await testHealthCheck();
|
|
683
|
+
await testHttpTransport();
|
|
684
|
+
await testSseTransport();
|
|
685
|
+
await testSseConnectionLifecycle();
|
|
686
|
+
await testToolResponseFormat();
|
|
687
|
+
await testErrorHandling();
|
|
688
|
+
|
|
689
|
+
// Summary
|
|
690
|
+
const passed = results.filter(r => r.passed).length;
|
|
691
|
+
const failed = results.filter(r => !r.passed).length;
|
|
692
|
+
|
|
693
|
+
log(`\n========================================`);
|
|
694
|
+
log(` Summary: ${passed} passed, ${failed} failed`);
|
|
695
|
+
log(`========================================\n`);
|
|
696
|
+
|
|
697
|
+
if (failed > 0) {
|
|
698
|
+
log('Failed tests:');
|
|
699
|
+
results
|
|
700
|
+
.filter(r => !r.passed)
|
|
701
|
+
.forEach(r => {
|
|
702
|
+
log(` - ${r.name}: ${r.error}`);
|
|
703
|
+
});
|
|
704
|
+
log('');
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Write output to file
|
|
708
|
+
writeOutput();
|
|
709
|
+
|
|
710
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Run tests
|
|
714
|
+
runTests().catch(error => {
|
|
715
|
+
console.error('Test runner failed:', error);
|
|
716
|
+
log(`\nTest runner failed: ${error}`);
|
|
717
|
+
writeOutput();
|
|
718
|
+
process.exit(1);
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
```
|