@illuma-ai/agents 1.3.1 → 1.4.0-alpha.0
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/dist/cjs/graphs/Graph.cjs +3 -18
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +3 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +58 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs +288 -0
- package/dist/cjs/providers/a2a/A2ACapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/a2a/client.cjs +92 -0
- package/dist/cjs/providers/a2a/client.cjs.map +1 -0
- package/dist/cjs/providers/a2a/config.cjs +38 -0
- package/dist/cjs/providers/a2a/config.cjs.map +1 -0
- package/dist/cjs/providers/capabilityNaming.cjs +43 -0
- package/dist/cjs/providers/capabilityNaming.cjs.map +1 -0
- package/dist/cjs/providers/composite/CompositeCapabilityProvider.cjs +80 -0
- package/dist/cjs/providers/composite/CompositeCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs +244 -0
- package/dist/cjs/providers/mcp/MCPCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/mcp/config.cjs +42 -0
- package/dist/cjs/providers/mcp/config.cjs.map +1 -0
- package/dist/cjs/providers/mcp/transport.cjs +65 -0
- package/dist/cjs/providers/mcp/transport.cjs.map +1 -0
- package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs +121 -0
- package/dist/cjs/providers/tools-server/ToolsServerCapabilityProvider.cjs.map +1 -0
- package/dist/cjs/providers/types.cjs +51 -0
- package/dist/cjs/providers/types.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +3 -0
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/proxyTool.cjs +100 -0
- package/dist/cjs/tools/proxyTool.cjs.map +1 -0
- package/dist/cjs/utils/credentials.cjs +142 -0
- package/dist/cjs/utils/credentials.cjs.map +1 -0
- package/dist/cjs/utils/httpClient.cjs +74 -0
- package/dist/cjs/utils/httpClient.cjs.map +1 -0
- package/dist/cjs/utils/toolManifest.cjs +100 -0
- package/dist/cjs/utils/toolManifest.cjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +3 -18
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +3 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +14 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs +281 -0
- package/dist/esm/providers/a2a/A2ACapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/a2a/client.mjs +88 -0
- package/dist/esm/providers/a2a/client.mjs.map +1 -0
- package/dist/esm/providers/a2a/config.mjs +35 -0
- package/dist/esm/providers/a2a/config.mjs.map +1 -0
- package/dist/esm/providers/capabilityNaming.mjs +39 -0
- package/dist/esm/providers/capabilityNaming.mjs.map +1 -0
- package/dist/esm/providers/composite/CompositeCapabilityProvider.mjs +78 -0
- package/dist/esm/providers/composite/CompositeCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs +240 -0
- package/dist/esm/providers/mcp/MCPCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/mcp/config.mjs +39 -0
- package/dist/esm/providers/mcp/config.mjs.map +1 -0
- package/dist/esm/providers/mcp/transport.mjs +63 -0
- package/dist/esm/providers/mcp/transport.mjs.map +1 -0
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs +119 -0
- package/dist/esm/providers/tools-server/ToolsServerCapabilityProvider.mjs.map +1 -0
- package/dist/esm/providers/types.mjs +51 -0
- package/dist/esm/providers/types.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +3 -0
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/proxyTool.mjs +98 -0
- package/dist/esm/tools/proxyTool.mjs.map +1 -0
- package/dist/esm/utils/credentials.mjs +135 -0
- package/dist/esm/utils/credentials.mjs.map +1 -0
- package/dist/esm/utils/httpClient.mjs +70 -0
- package/dist/esm/utils/httpClient.mjs.map +1 -0
- package/dist/esm/utils/toolManifest.mjs +96 -0
- package/dist/esm/utils/toolManifest.mjs.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/providers/a2a/A2ACapabilityProvider.d.ts +89 -0
- package/dist/types/providers/a2a/client.d.ts +47 -0
- package/dist/types/providers/a2a/config.d.ts +18 -0
- package/dist/types/providers/a2a/index.d.ts +6 -0
- package/dist/types/providers/a2a/types.d.ts +173 -0
- package/dist/types/providers/capabilityNaming.d.ts +25 -0
- package/dist/types/providers/composite/CompositeCapabilityProvider.d.ts +22 -0
- package/dist/types/providers/composite/index.d.ts +1 -0
- package/dist/types/providers/index.d.ts +13 -0
- package/dist/types/providers/mcp/MCPCapabilityProvider.d.ts +54 -0
- package/dist/types/providers/mcp/config.d.ts +20 -0
- package/dist/types/providers/mcp/index.d.ts +5 -0
- package/dist/types/providers/mcp/transport.d.ts +18 -0
- package/dist/types/providers/mcp/types.d.ts +112 -0
- package/dist/types/providers/tools-server/ToolsServerCapabilityProvider.d.ts +45 -0
- package/dist/types/providers/tools-server/index.d.ts +1 -0
- package/dist/types/providers/types.d.ts +170 -0
- package/dist/types/tools/proxyTool.d.ts +55 -0
- package/dist/types/types/stream.d.ts +10 -0
- package/dist/types/utils/credentials.d.ts +77 -0
- package/dist/types/utils/httpClient.d.ts +46 -0
- package/dist/types/utils/index.d.ts +3 -0
- package/dist/types/utils/toolManifest.d.ts +49 -0
- package/package.json +21 -1
- package/src/graphs/Graph.ts +0 -23
- package/src/index.ts +4 -0
- package/src/providers/__tests__/CompositeCapabilityProvider.test.ts +93 -0
- package/src/providers/__tests__/ToolsServerCapabilityProvider.integration.spec.ts +79 -0
- package/src/providers/__tests__/ToolsServerCapabilityProvider.test.ts +206 -0
- package/src/providers/__tests__/types.test.ts +64 -0
- package/src/providers/a2a/A2ACapabilityProvider.ts +384 -0
- package/src/providers/a2a/__tests__/A2ACapabilityProvider.integration.spec.ts +345 -0
- package/src/providers/a2a/__tests__/A2ACapabilityProvider.test.ts +460 -0
- package/src/providers/a2a/client.ts +115 -0
- package/src/providers/a2a/config.ts +40 -0
- package/src/providers/a2a/index.ts +29 -0
- package/src/providers/a2a/types.ts +191 -0
- package/src/providers/capabilityNaming.ts +42 -0
- package/src/providers/composite/CompositeCapabilityProvider.ts +112 -0
- package/src/providers/composite/index.ts +1 -0
- package/src/providers/index.ts +65 -0
- package/src/providers/mcp/MCPCapabilityProvider.ts +345 -0
- package/src/providers/mcp/__tests__/MCPCapabilityProvider.integration.spec.ts +386 -0
- package/src/providers/mcp/__tests__/MCPCapabilityProvider.test.ts +371 -0
- package/src/providers/mcp/config.ts +45 -0
- package/src/providers/mcp/index.ts +21 -0
- package/src/providers/mcp/transport.ts +76 -0
- package/src/providers/mcp/types.ts +139 -0
- package/src/providers/tools-server/ToolsServerCapabilityProvider.ts +220 -0
- package/src/providers/tools-server/index.ts +1 -0
- package/src/providers/types.ts +187 -0
- package/src/tools/proxyTool.ts +146 -0
- package/src/types/stream.ts +10 -0
- package/src/utils/__tests__/credentials.test.ts +130 -0
- package/src/utils/__tests__/errors.test.ts +6 -4
- package/src/utils/__tests__/httpClient.test.ts +75 -0
- package/src/utils/__tests__/toolManifest.test.ts +116 -0
- package/src/utils/credentials.ts +157 -0
- package/src/utils/httpClient.ts +92 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/toolManifest.ts +109 -0
- package/src/agents/AgentContext.js.map +0 -1
- package/src/agents/AgentContext.test.js.map +0 -1
- package/src/agents/__tests__/AgentContext.test.js.map +0 -1
- package/src/agents/__tests__/resolveStructuredOutputMode.test.js.map +0 -1
- package/src/common/enum.js.map +0 -1
- package/src/common/index.js.map +0 -1
- package/src/events.js.map +0 -1
- package/src/graphs/Graph.js.map +0 -1
- package/src/graphs/MultiAgentGraph.js.map +0 -1
- package/src/graphs/__tests__/structured-output.integration.test.js.map +0 -1
- package/src/graphs/__tests__/structured-output.test.js.map +0 -1
- package/src/graphs/contextManagement.e2e.test.js.map +0 -1
- package/src/graphs/contextManagement.test.js.map +0 -1
- package/src/graphs/handoffValidation.test.js.map +0 -1
- package/src/graphs/index.js.map +0 -1
- package/src/index.js.map +0 -1
- package/src/instrumentation.js.map +0 -1
- package/src/llm/anthropic/index.js.map +0 -1
- package/src/llm/anthropic/types.js.map +0 -1
- package/src/llm/anthropic/utils/message_inputs.js.map +0 -1
- package/src/llm/anthropic/utils/message_outputs.js.map +0 -1
- package/src/llm/anthropic/utils/output_parsers.js.map +0 -1
- package/src/llm/anthropic/utils/tools.js.map +0 -1
- package/src/llm/bedrock/__tests__/bedrock-caching.test.js.map +0 -1
- package/src/llm/bedrock/index.js.map +0 -1
- package/src/llm/bedrock/types.js.map +0 -1
- package/src/llm/bedrock/utils/index.js.map +0 -1
- package/src/llm/bedrock/utils/message_inputs.js.map +0 -1
- package/src/llm/bedrock/utils/message_outputs.js.map +0 -1
- package/src/llm/fake.js.map +0 -1
- package/src/llm/google/index.js.map +0 -1
- package/src/llm/google/types.js.map +0 -1
- package/src/llm/google/utils/common.js.map +0 -1
- package/src/llm/google/utils/tools.js.map +0 -1
- package/src/llm/google/utils/zod_to_genai_parameters.js.map +0 -1
- package/src/llm/openai/index.js.map +0 -1
- package/src/llm/openai/types.js.map +0 -1
- package/src/llm/openai/utils/index.js.map +0 -1
- package/src/llm/openai/utils/isReasoningModel.test.js.map +0 -1
- package/src/llm/openrouter/index.js.map +0 -1
- package/src/llm/openrouter/reasoning.test.js.map +0 -1
- package/src/llm/providers.js.map +0 -1
- package/src/llm/text.js.map +0 -1
- package/src/llm/vertexai/index.js.map +0 -1
- package/src/messages/__tests__/tools.test.js.map +0 -1
- package/src/messages/cache.js.map +0 -1
- package/src/messages/cache.test.js.map +0 -1
- package/src/messages/content.js.map +0 -1
- package/src/messages/content.test.js.map +0 -1
- package/src/messages/core.js.map +0 -1
- package/src/messages/ensureThinkingBlock.test.js.map +0 -1
- package/src/messages/format.js.map +0 -1
- package/src/messages/formatAgentMessages.test.js.map +0 -1
- package/src/messages/formatAgentMessages.tools.test.js.map +0 -1
- package/src/messages/formatMessage.test.js.map +0 -1
- package/src/messages/ids.js.map +0 -1
- package/src/messages/index.js.map +0 -1
- package/src/messages/labelContentByAgent.test.js.map +0 -1
- package/src/messages/prune.js.map +0 -1
- package/src/messages/reducer.js.map +0 -1
- package/src/messages/shiftIndexTokenCountMap.test.js.map +0 -1
- package/src/messages/summarize.js.map +0 -1
- package/src/messages/summarize.test.js.map +0 -1
- package/src/messages/tools.js.map +0 -1
- package/src/mockStream.js.map +0 -1
- package/src/prompts/collab.js.map +0 -1
- package/src/prompts/index.js.map +0 -1
- package/src/prompts/taskmanager.js.map +0 -1
- package/src/run.js.map +0 -1
- package/src/schemas/index.js.map +0 -1
- package/src/schemas/schema-preparation.test.js.map +0 -1
- package/src/schemas/validate.js.map +0 -1
- package/src/schemas/validate.test.js.map +0 -1
- package/src/scripts/abort.js.map +0 -1
- package/src/scripts/ant_web_search.js.map +0 -1
- package/src/scripts/ant_web_search_edge_case.js.map +0 -1
- package/src/scripts/ant_web_search_error_edge_case.js.map +0 -1
- package/src/scripts/args.js.map +0 -1
- package/src/scripts/bedrock-cache-debug.js.map +0 -1
- package/src/scripts/bedrock-content-aggregation-test.js.map +0 -1
- package/src/scripts/bedrock-merge-test.js.map +0 -1
- package/src/scripts/bedrock-parallel-tools-test.js.map +0 -1
- package/src/scripts/caching.js.map +0 -1
- package/src/scripts/cli.js.map +0 -1
- package/src/scripts/cli2.js.map +0 -1
- package/src/scripts/cli3.js.map +0 -1
- package/src/scripts/cli4.js.map +0 -1
- package/src/scripts/cli5.js.map +0 -1
- package/src/scripts/code_exec.js.map +0 -1
- package/src/scripts/code_exec_files.js.map +0 -1
- package/src/scripts/code_exec_multi_session.js.map +0 -1
- package/src/scripts/code_exec_ptc.js.map +0 -1
- package/src/scripts/code_exec_session.js.map +0 -1
- package/src/scripts/code_exec_simple.js.map +0 -1
- package/src/scripts/content.js.map +0 -1
- package/src/scripts/empty_input.js.map +0 -1
- package/src/scripts/handoff-test.js.map +0 -1
- package/src/scripts/image.js.map +0 -1
- package/src/scripts/memory.js.map +0 -1
- package/src/scripts/multi-agent-chain.js.map +0 -1
- package/src/scripts/multi-agent-conditional.js.map +0 -1
- package/src/scripts/multi-agent-document-review-chain.js.map +0 -1
- package/src/scripts/multi-agent-hybrid-flow.js.map +0 -1
- package/src/scripts/multi-agent-parallel-start.js.map +0 -1
- package/src/scripts/multi-agent-parallel.js.map +0 -1
- package/src/scripts/multi-agent-sequence.js.map +0 -1
- package/src/scripts/multi-agent-supervisor.js.map +0 -1
- package/src/scripts/multi-agent-test.js.map +0 -1
- package/src/scripts/parallel-asymmetric-tools-test.js.map +0 -1
- package/src/scripts/parallel-full-metadata-test.js.map +0 -1
- package/src/scripts/parallel-tools-test.js.map +0 -1
- package/src/scripts/programmatic_exec.js.map +0 -1
- package/src/scripts/programmatic_exec_agent.js.map +0 -1
- package/src/scripts/search.js.map +0 -1
- package/src/scripts/sequential-full-metadata-test.js.map +0 -1
- package/src/scripts/simple.js.map +0 -1
- package/src/scripts/single-agent-metadata-test.js.map +0 -1
- package/src/scripts/stream.js.map +0 -1
- package/src/scripts/test-custom-prompt-key.js.map +0 -1
- package/src/scripts/test-handoff-input.js.map +0 -1
- package/src/scripts/test-handoff-preamble.js.map +0 -1
- package/src/scripts/test-handoff-steering.js.map +0 -1
- package/src/scripts/test-multi-agent-list-handoff.js.map +0 -1
- package/src/scripts/test-parallel-agent-labeling.js.map +0 -1
- package/src/scripts/test-parallel-handoffs.js.map +0 -1
- package/src/scripts/test-thinking-handoff-bedrock.js.map +0 -1
- package/src/scripts/test-thinking-handoff.js.map +0 -1
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js.map +0 -1
- package/src/scripts/test-tool-before-handoff-role-order.js.map +0 -1
- package/src/scripts/test-tools-before-handoff.js.map +0 -1
- package/src/scripts/test_code_api.js.map +0 -1
- package/src/scripts/thinking-bedrock.js.map +0 -1
- package/src/scripts/thinking-vertexai.js.map +0 -1
- package/src/scripts/thinking.js.map +0 -1
- package/src/scripts/tool_search.js.map +0 -1
- package/src/scripts/tools.js.map +0 -1
- package/src/specs/agent-handoffs-bedrock.integration.test.js.map +0 -1
- package/src/specs/agent-handoffs.test.js.map +0 -1
- package/src/specs/anthropic.simple.test.js.map +0 -1
- package/src/specs/azure.simple.test.js.map +0 -1
- package/src/specs/cache.simple.test.js.map +0 -1
- package/src/specs/custom-event-await.test.js.map +0 -1
- package/src/specs/deepseek.simple.test.js.map +0 -1
- package/src/specs/emergency-prune.test.js.map +0 -1
- package/src/specs/moonshot.simple.test.js.map +0 -1
- package/src/specs/observability.integration.test.js.map +0 -1
- package/src/specs/openai.simple.test.js.map +0 -1
- package/src/specs/openrouter.simple.test.js.map +0 -1
- package/src/specs/prune.test.js.map +0 -1
- package/src/specs/reasoning.test.js.map +0 -1
- package/src/specs/spec.utils.js.map +0 -1
- package/src/specs/thinking-handoff.test.js.map +0 -1
- package/src/specs/thinking-prune.test.js.map +0 -1
- package/src/specs/token-distribution-edge-case.test.js.map +0 -1
- package/src/specs/token-memoization.test.js.map +0 -1
- package/src/specs/tokens.test.js.map +0 -1
- package/src/specs/tool-error.test.js.map +0 -1
- package/src/splitStream.js.map +0 -1
- package/src/splitStream.test.js.map +0 -1
- package/src/stream.js.map +0 -1
- package/src/stream.test.js.map +0 -1
- package/src/test/mockTools.js.map +0 -1
- package/src/tools/BrowserTools.js.map +0 -1
- package/src/tools/Calculator.js.map +0 -1
- package/src/tools/Calculator.test.js.map +0 -1
- package/src/tools/CodeExecutor.js.map +0 -1
- package/src/tools/ProgrammaticToolCalling.js.map +0 -1
- package/src/tools/StreamingToolCallBuffer.js.map +0 -1
- package/src/tools/ToolNode.js.map +0 -1
- package/src/tools/ToolSearch.js.map +0 -1
- package/src/tools/__tests__/BrowserTools.test.js.map +0 -1
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js.map +0 -1
- package/src/tools/__tests__/ProgrammaticToolCalling.test.js.map +0 -1
- package/src/tools/__tests__/StreamingToolCallBuffer.test.js.map +0 -1
- package/src/tools/__tests__/ToolApproval.test.js.map +0 -1
- package/src/tools/__tests__/ToolNode.recovery.test.js.map +0 -1
- package/src/tools/__tests__/ToolNode.session.test.js.map +0 -1
- package/src/tools/__tests__/ToolSearch.integration.test.js.map +0 -1
- package/src/tools/__tests__/ToolSearch.test.js.map +0 -1
- package/src/tools/__tests__/handlers.test.js.map +0 -1
- package/src/tools/__tests__/truncation-recovery.integration.test.js.map +0 -1
- package/src/tools/handlers.js.map +0 -1
- package/src/tools/schema.js.map +0 -1
- package/src/tools/search/anthropic.js.map +0 -1
- package/src/tools/search/content.js.map +0 -1
- package/src/tools/search/content.test.js.map +0 -1
- package/src/tools/search/firecrawl.js.map +0 -1
- package/src/tools/search/format.js.map +0 -1
- package/src/tools/search/highlights.js.map +0 -1
- package/src/tools/search/index.js.map +0 -1
- package/src/tools/search/jina-reranker.test.js.map +0 -1
- package/src/tools/search/rerankers.js.map +0 -1
- package/src/tools/search/schema.js.map +0 -1
- package/src/tools/search/search.js.map +0 -1
- package/src/tools/search/serper-scraper.js.map +0 -1
- package/src/tools/search/test.js.map +0 -1
- package/src/tools/search/tool.js.map +0 -1
- package/src/tools/search/types.js.map +0 -1
- package/src/tools/search/utils.js.map +0 -1
- package/src/types/graph.js.map +0 -1
- package/src/types/graph.test.js.map +0 -1
- package/src/types/index.js.map +0 -1
- package/src/types/llm.js.map +0 -1
- package/src/types/messages.js.map +0 -1
- package/src/types/run.js.map +0 -1
- package/src/types/stream.js.map +0 -1
- package/src/types/tools.js.map +0 -1
- package/src/utils/contextAnalytics.js.map +0 -1
- package/src/utils/contextAnalytics.test.js.map +0 -1
- package/src/utils/events.js.map +0 -1
- package/src/utils/graph.js.map +0 -1
- package/src/utils/handlers.js.map +0 -1
- package/src/utils/index.js.map +0 -1
- package/src/utils/llm.js.map +0 -1
- package/src/utils/llmConfig.js.map +0 -1
- package/src/utils/logging.js.map +0 -1
- package/src/utils/misc.js.map +0 -1
- package/src/utils/run.js.map +0 -1
- package/src/utils/schema.js.map +0 -1
- package/src/utils/title.js.map +0 -1
- package/src/utils/tokens.js.map +0 -1
- package/src/utils/toonFormat.js.map +0 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test — exercises MCPCapabilityProvider against a local HTTP
|
|
3
|
+
* server that speaks the MCP Streamable HTTP protocol.
|
|
4
|
+
*
|
|
5
|
+
* The server is a minimal pure-http harness implementing just the subset of
|
|
6
|
+
* JSON-RPC methods the test needs (`initialize`, `tools/list`, `tools/call`).
|
|
7
|
+
* We deliberately avoid importing the MCP SDK's server module here because
|
|
8
|
+
* (a) the SDK's server-side depends on ajv validation which clashes with
|
|
9
|
+
* the project-wide ajv@6 override, and (b) the integration surface we care
|
|
10
|
+
* about is the CLIENT path — connecting, listing, invoking. The client
|
|
11
|
+
* doesn't know whether the server is built on the SDK or not.
|
|
12
|
+
*
|
|
13
|
+
* This exercises:
|
|
14
|
+
* - transport selection (streamable-http)
|
|
15
|
+
* - initialize → listTools → callTool flow through our provider
|
|
16
|
+
* - auth header forwarding from getAuthHeaders
|
|
17
|
+
* - the three config-source patterns (direct / YAML-derived / marketplace)
|
|
18
|
+
* producing equivalent capability behavior
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { createServer, type Server as HttpServer } from 'node:http';
|
|
22
|
+
import type { AddressInfo } from 'node:net';
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
MCPCapabilityProvider,
|
|
26
|
+
formatCapabilityName,
|
|
27
|
+
} from '../MCPCapabilityProvider';
|
|
28
|
+
import { CapabilityKind } from '../../types';
|
|
29
|
+
import type { MCPServerSpec } from '../types';
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Minimal MCP HTTP harness — dispatches JSON-RPC requests synchronously.
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
interface Harness {
|
|
36
|
+
url: string;
|
|
37
|
+
httpServer: HttpServer;
|
|
38
|
+
lastHeaders: Record<string, string>;
|
|
39
|
+
close: () => Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface JsonRpcRequest {
|
|
43
|
+
jsonrpc: '2.0';
|
|
44
|
+
id: string | number;
|
|
45
|
+
method: string;
|
|
46
|
+
params?: unknown;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface JsonRpcResponse {
|
|
50
|
+
jsonrpc: '2.0';
|
|
51
|
+
id: string | number | null;
|
|
52
|
+
result?: unknown;
|
|
53
|
+
error?: { code: number; message: string };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const TOOLS_FIXTURE = [
|
|
57
|
+
{
|
|
58
|
+
name: 'echo',
|
|
59
|
+
description: 'Return the input string back.',
|
|
60
|
+
inputSchema: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: { message: { type: 'string' } },
|
|
63
|
+
required: ['message'],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'fail',
|
|
68
|
+
description: 'Always returns an error result.',
|
|
69
|
+
inputSchema: { type: 'object', properties: {} },
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
function handleRpc(req: JsonRpcRequest): JsonRpcResponse {
|
|
74
|
+
const base = { jsonrpc: '2.0' as const, id: req.id };
|
|
75
|
+
|
|
76
|
+
switch (req.method) {
|
|
77
|
+
case 'initialize':
|
|
78
|
+
return {
|
|
79
|
+
...base,
|
|
80
|
+
result: {
|
|
81
|
+
protocolVersion: '2024-11-05',
|
|
82
|
+
capabilities: { tools: {} },
|
|
83
|
+
serverInfo: { name: 'test-server', version: '0.0.1' },
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
case 'tools/list':
|
|
88
|
+
return { ...base, result: { tools: TOOLS_FIXTURE } };
|
|
89
|
+
|
|
90
|
+
case 'tools/call': {
|
|
91
|
+
const params = req.params as {
|
|
92
|
+
name: string;
|
|
93
|
+
arguments?: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
if (params.name === 'echo') {
|
|
96
|
+
const message = (params.arguments?.message as string) ?? '';
|
|
97
|
+
return {
|
|
98
|
+
...base,
|
|
99
|
+
result: { content: [{ type: 'text', text: message }] },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (params.name === 'fail') {
|
|
103
|
+
return {
|
|
104
|
+
...base,
|
|
105
|
+
result: {
|
|
106
|
+
content: [{ type: 'text', text: 'intentional failure' }],
|
|
107
|
+
isError: true,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
error: { code: -32601, message: `Unknown tool: ${params.name}` },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
default:
|
|
118
|
+
// Notifications (e.g., notifications/initialized) have no `id`;
|
|
119
|
+
// per JSON-RPC we return no response for those. Here we always have
|
|
120
|
+
// an id because we only dispatch regular requests.
|
|
121
|
+
return {
|
|
122
|
+
...base,
|
|
123
|
+
error: { code: -32601, message: `Method not found: ${req.method}` },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function startLocalMCPServer(
|
|
129
|
+
opts: { requireAuth?: boolean } = {}
|
|
130
|
+
): Promise<Harness> {
|
|
131
|
+
const lastHeaders: Record<string, string> = {};
|
|
132
|
+
|
|
133
|
+
const httpServer = createServer(async (req, res) => {
|
|
134
|
+
// Capture headers for auth-forwarding assertions.
|
|
135
|
+
for (const [k, v] of Object.entries(req.headers)) {
|
|
136
|
+
if (typeof v === 'string') lastHeaders[k.toLowerCase()] = v;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (req.method !== 'POST') {
|
|
140
|
+
res.writeHead(405);
|
|
141
|
+
res.end();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (opts.requireAuth) {
|
|
146
|
+
const auth = req.headers['authorization'];
|
|
147
|
+
if (typeof auth !== 'string' || !auth.startsWith('Bearer ')) {
|
|
148
|
+
res.writeHead(401, { 'content-type': 'application/json' });
|
|
149
|
+
res.end(JSON.stringify({ error: 'unauthorized' }));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const chunks: Buffer[] = [];
|
|
155
|
+
for await (const chunk of req) chunks.push(chunk as Buffer);
|
|
156
|
+
const body = Buffer.concat(chunks).toString('utf8');
|
|
157
|
+
|
|
158
|
+
let parsed: unknown;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(body);
|
|
161
|
+
} catch {
|
|
162
|
+
res.writeHead(400, { 'content-type': 'application/json' });
|
|
163
|
+
res.end(JSON.stringify({ error: 'invalid JSON' }));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Handle either a single request or a batch (always a single for our client).
|
|
168
|
+
const reqs = Array.isArray(parsed)
|
|
169
|
+
? (parsed as JsonRpcRequest[])
|
|
170
|
+
: [parsed as JsonRpcRequest];
|
|
171
|
+
|
|
172
|
+
// Notifications (no id) get no response
|
|
173
|
+
const responses: JsonRpcResponse[] = [];
|
|
174
|
+
for (const r of reqs) {
|
|
175
|
+
if (r.id === undefined) continue;
|
|
176
|
+
responses.push(handleRpc(r));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (responses.length === 0) {
|
|
180
|
+
res.writeHead(202);
|
|
181
|
+
res.end();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const payload = Array.isArray(parsed) ? responses : responses[0];
|
|
186
|
+
res.writeHead(200, {
|
|
187
|
+
'content-type': 'application/json',
|
|
188
|
+
// Streamable HTTP transport requires a session id header.
|
|
189
|
+
'mcp-session-id': 'test-session',
|
|
190
|
+
});
|
|
191
|
+
res.end(JSON.stringify(payload));
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
await new Promise<void>((resolve) =>
|
|
195
|
+
httpServer.listen(0, '127.0.0.1', resolve)
|
|
196
|
+
);
|
|
197
|
+
const port = (httpServer.address() as AddressInfo).port;
|
|
198
|
+
const url = `http://127.0.0.1:${port}/mcp`;
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
url,
|
|
202
|
+
httpServer,
|
|
203
|
+
lastHeaders,
|
|
204
|
+
close: () =>
|
|
205
|
+
new Promise<void>((resolve, reject) => {
|
|
206
|
+
httpServer.close((err) => (err ? reject(err) : resolve()));
|
|
207
|
+
}),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// Tests
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
describe('MCPCapabilityProvider (live streamable-http)', () => {
|
|
216
|
+
let harness: Harness;
|
|
217
|
+
let provider: MCPCapabilityProvider;
|
|
218
|
+
|
|
219
|
+
beforeAll(async () => {
|
|
220
|
+
harness = await startLocalMCPServer();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
afterAll(async () => {
|
|
224
|
+
await provider?.close();
|
|
225
|
+
await harness.close();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('connects and discovers tools from a live server', async () => {
|
|
229
|
+
const spec: MCPServerSpec = {
|
|
230
|
+
type: 'streamable-http',
|
|
231
|
+
url: harness.url,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
provider = new MCPCapabilityProvider({
|
|
235
|
+
servers: { test: spec },
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const capabilities = await provider.fetchManifest();
|
|
239
|
+
const names = capabilities.map((c) => c.name).sort();
|
|
240
|
+
expect(names).toEqual([
|
|
241
|
+
formatCapabilityName('test', 'echo'),
|
|
242
|
+
formatCapabilityName('test', 'fail'),
|
|
243
|
+
]);
|
|
244
|
+
expect(capabilities[0].kind).toBe(CapabilityKind.MCP);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('invokes a tool end-to-end and returns text', async () => {
|
|
248
|
+
const caps = await provider.fetchManifest({
|
|
249
|
+
names: [formatCapabilityName('test', 'echo')],
|
|
250
|
+
});
|
|
251
|
+
expect(caps).toHaveLength(1);
|
|
252
|
+
|
|
253
|
+
const [runnable] = await provider.createRunnables(caps, {});
|
|
254
|
+
const result = await runnable.invoke({ message: 'hello world' });
|
|
255
|
+
expect(result).toBe('hello world');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('surfaces isError from the server as a thrown error', async () => {
|
|
259
|
+
const caps = await provider.fetchManifest({
|
|
260
|
+
names: [formatCapabilityName('test', 'fail')],
|
|
261
|
+
});
|
|
262
|
+
const [runnable] = await provider.createRunnables(caps, {});
|
|
263
|
+
await expect(runnable.invoke({})).rejects.toThrow(
|
|
264
|
+
/test:fail.*intentional failure/
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe('MCPCapabilityProvider — auth header forwarding', () => {
|
|
270
|
+
let harness: Harness;
|
|
271
|
+
let provider: MCPCapabilityProvider;
|
|
272
|
+
|
|
273
|
+
beforeAll(async () => {
|
|
274
|
+
harness = await startLocalMCPServer({ requireAuth: true });
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
afterAll(async () => {
|
|
278
|
+
await provider?.close();
|
|
279
|
+
await harness.close();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('rejects without auth (server returns 401 → empty manifest)', async () => {
|
|
283
|
+
provider = new MCPCapabilityProvider({
|
|
284
|
+
servers: { secure: { type: 'streamable-http', url: harness.url } },
|
|
285
|
+
});
|
|
286
|
+
const caps = await provider.fetchManifest();
|
|
287
|
+
expect(caps).toEqual([]);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('succeeds when getAuthHeaders supplies a Bearer token', async () => {
|
|
291
|
+
provider = new MCPCapabilityProvider({
|
|
292
|
+
servers: { secure: { type: 'streamable-http', url: harness.url } },
|
|
293
|
+
getAuthHeaders: () => ({ Authorization: 'Bearer test-token-123' }),
|
|
294
|
+
});
|
|
295
|
+
const caps = await provider.fetchManifest();
|
|
296
|
+
expect(caps.length).toBeGreaterThan(0);
|
|
297
|
+
expect(harness.lastHeaders['authorization']).toBe('Bearer test-token-123');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('MCPCapabilityProvider — config-source patterns', () => {
|
|
302
|
+
let harness: Harness;
|
|
303
|
+
|
|
304
|
+
beforeAll(async () => {
|
|
305
|
+
harness = await startLocalMCPServer();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
afterAll(async () => {
|
|
309
|
+
await harness.close();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const verifyProviderWorks = async (
|
|
313
|
+
p: MCPCapabilityProvider
|
|
314
|
+
): Promise<void> => {
|
|
315
|
+
const caps = await p.fetchManifest();
|
|
316
|
+
expect(caps.length).toBeGreaterThan(0);
|
|
317
|
+
const echoCap = caps.find((c) => c.name.endsWith('echo'));
|
|
318
|
+
expect(echoCap).toBeDefined();
|
|
319
|
+
const [runnable] = await p.createRunnables([echoCap!], {});
|
|
320
|
+
const result = await runnable.invoke({ message: 'ok' });
|
|
321
|
+
expect(result).toBe('ok');
|
|
322
|
+
await p.close();
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
it('direct programmatic spec', async () => {
|
|
326
|
+
const p = new MCPCapabilityProvider({
|
|
327
|
+
servers: {
|
|
328
|
+
mine: { type: 'streamable-http', url: harness.url },
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
await verifyProviderWorks(p);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('YAML-derived spec (simulated)', async () => {
|
|
335
|
+
// The host parses YAML and normalizes entries into the spec shape
|
|
336
|
+
// before constructing the provider.
|
|
337
|
+
const yamlLike = {
|
|
338
|
+
mcp_servers: [
|
|
339
|
+
{
|
|
340
|
+
name: 'from-yaml',
|
|
341
|
+
type: 'streamable-http',
|
|
342
|
+
url: harness.url,
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const servers: Record<string, MCPServerSpec> = {};
|
|
348
|
+
for (const entry of yamlLike.mcp_servers) {
|
|
349
|
+
servers[entry.name] = {
|
|
350
|
+
type: entry.type as 'streamable-http',
|
|
351
|
+
url: entry.url,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const p = new MCPCapabilityProvider({ servers });
|
|
356
|
+
await verifyProviderWorks(p);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('marketplace-catalog-derived spec (simulated)', async () => {
|
|
360
|
+
// The host fetched a catalog entry, populated auth via its own token
|
|
361
|
+
// store, and assembled the spec.
|
|
362
|
+
const marketplaceEntry = {
|
|
363
|
+
id: 'market-echo',
|
|
364
|
+
name: 'Market Echo',
|
|
365
|
+
transport: 'streamable-http' as const,
|
|
366
|
+
url: harness.url,
|
|
367
|
+
authConfig: [{ authField: 'MCP_MARKET_TOKEN', required: true }],
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const servers: Record<string, MCPServerSpec> = {
|
|
371
|
+
[marketplaceEntry.id]: {
|
|
372
|
+
type: marketplaceEntry.transport,
|
|
373
|
+
url: marketplaceEntry.url,
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const p = new MCPCapabilityProvider({
|
|
378
|
+
servers,
|
|
379
|
+
getAuthHeaders: () => ({
|
|
380
|
+
// Host injected from its credential store — the library doesn't know.
|
|
381
|
+
'x-market-token': 'resolved-by-host',
|
|
382
|
+
}),
|
|
383
|
+
});
|
|
384
|
+
await verifyProviderWorks(p);
|
|
385
|
+
});
|
|
386
|
+
});
|