@agent-native/core 0.128.4 → 0.129.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +84 -0
- package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
- package/corpus/core/package.json +6 -3
- package/corpus/core/src/a2a/client.ts +18 -4
- package/corpus/core/src/a2a/server.ts +19 -3
- package/corpus/core/src/a2a/types.ts +7 -0
- package/corpus/core/src/action.ts +43 -16
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +14 -10
- package/corpus/core/src/agent/production-agent.ts +41 -3
- package/corpus/core/src/agent/thread-data-builder.ts +5 -0
- package/corpus/core/src/chat-threads/migrations.ts +53 -0
- package/corpus/core/src/cli/create.ts +4 -0
- package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
- package/corpus/core/src/cli/skills.ts +16 -0
- package/corpus/core/src/client/AgentPanel.tsx +9 -5
- package/corpus/core/src/client/AssistantChat.tsx +138 -46
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +16 -10
- package/corpus/core/src/client/agent-chat-adapter.ts +21 -3
- package/corpus/core/src/client/analytics.ts +159 -102
- package/corpus/core/src/client/chat/message-components.tsx +12 -5
- package/corpus/core/src/client/chat/runtime.ts +2 -1
- package/corpus/core/src/client/chat/tool-call-display.tsx +25 -2
- package/corpus/core/src/client/chat-model-groups.ts +3 -0
- package/corpus/core/src/client/client-status-requests.ts +161 -0
- package/corpus/core/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
- package/corpus/core/src/client/sse-event-processor.ts +15 -3
- package/corpus/core/src/client/use-agent-engine-configured.ts +54 -50
- package/corpus/core/src/client/use-chat-models.ts +16 -11
- package/corpus/core/src/client/use-chat-threads.ts +32 -9
- package/corpus/core/src/client/use-session.ts +4 -5
- package/corpus/core/src/db/client.ts +83 -8
- package/corpus/core/src/db/ensure-additive-columns.ts +31 -20
- package/corpus/core/src/db/migrations.ts +22 -2
- package/corpus/core/src/mcp/approval-store.ts +99 -0
- package/corpus/core/src/mcp/build-server.ts +579 -303
- package/corpus/core/src/mcp/embed-app.ts +1 -1
- package/corpus/core/src/mcp/oauth-client-metadata.ts +380 -0
- package/corpus/core/src/mcp/oauth-route.ts +57 -52
- package/corpus/core/src/mcp/screen-memory-stdio.ts +400 -378
- package/corpus/core/src/mcp/server.ts +29 -145
- package/corpus/core/src/mcp/stdio.ts +72 -80
- package/corpus/core/src/mcp-client/manager.ts +6 -10
- package/corpus/core/src/mcp-client/oauth-client.ts +127 -36
- package/corpus/core/src/mcp-client/oauth-routes.ts +16 -6
- package/corpus/core/src/mcp-client/routes.ts +6 -5
- package/corpus/core/src/server/agent-capabilities.ts +20 -0
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +27 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +18 -0
- package/corpus/core/src/server/transcribe-voice.ts +14 -5
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +13 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +1 -10
- package/corpus/templates/analytics/app/global.css +0 -31
- package/corpus/templates/analytics/app/lib/sql-query.ts +46 -20
- package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboard-loading-states-now-use-a-simpler-standar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-28-analytics-dashboards-now-load-first-party-charts-reliably-in.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-cache.ts +42 -16
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +4 -2
- package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/chat/README.md +0 -2
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -6
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -2
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -1
- package/corpus/templates/clips/changelog/2026-07-28-copied-share-links-no-longer-leave-an-unnecessary-confirmati.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-playback-skip-controls-no-longer-show-overlapping-numbers.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-public-clips-share-buttons-now-use-a-clean-text-only-label.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +14 -17
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +3 -1
- package/corpus/templates/clips/desktop/src/styles.css +13 -10
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +36 -0
- package/corpus/templates/content/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +155 -34
- package/corpus/templates/content/actions/_builder-docs-client.ts +151 -30
- package/corpus/templates/content/actions/stage-builder-source-bulk-update.ts +5 -2
- package/corpus/templates/content/app/root.tsx +35 -14
- package/corpus/templates/content/changelog/2026-07-28-builder-backed-files-media-fields-now-accept-direct-file-url.md +6 -0
- package/corpus/templates/content/changelog/2026-07-28-builder-content-reads-now-negotiate-the-newest-mcp-protocol-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-28-public-content-pages-load-faster-before-the-optional-ask-sid.md +6 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +36 -16
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +42 -3
- package/corpus/templates/design/actions/open-visual-edit.ts +2 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +14 -15
- package/corpus/templates/design/app/components/design/ResponsiveInteractBar.tsx +314 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +88 -3
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +7 -6
- package/corpus/templates/design/app/i18n-data.ts +56 -11
- package/corpus/templates/design/app/i18n-responsive-interact.ts +183 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +60 -0
- package/corpus/templates/design/app/pages/design-editor/responsive-interact.ts +89 -0
- package/corpus/templates/design/changelog/2026-07-28-design-edits-can-be-applied-through-the-host-coding-agent-fr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-28-interact-mode-can-preview-designs-in-responsive-device-sizes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-28-interact-mode-now-opens-a-full-screen-responsive-preview-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +2 -2
- package/corpus/templates/design/changelog/2026-07-28-visual-edit-now-always-shows-the-live-running-app-in-the-can.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +13 -2
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +13 -2
- package/corpus/toolkit/CHANGELOG.md +13 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/chat-history.css +1 -2
- package/corpus/toolkit/src/composer/TiptapComposer.tsx +45 -0
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +8 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +18 -3
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/types.d.ts +7 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +15 -1
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +39 -16
- package/dist/action.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +14 -10
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +35 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +2 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +3 -0
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/chat-threads/migrations.d.ts +21 -0
- package/dist/chat-threads/migrations.d.ts.map +1 -0
- package/dist/chat-threads/migrations.js +45 -0
- package/dist/chat-threads/migrations.js.map +1 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +4 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +36 -16
- package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +15 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -5
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +37 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +41 -8
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +11 -10
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +19 -3
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +150 -101
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +11 -4
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/runtime.d.ts.map +1 -1
- package/dist/client/chat/runtime.js +2 -1
- package/dist/client/chat/runtime.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +4 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +14 -8
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +3 -0
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/client-status-requests.d.ts +14 -0
- package/dist/client/client-status-requests.d.ts.map +1 -0
- package/dist/client/client-status-requests.js +126 -0
- package/dist/client/client-status-requests.js.map +1 -0
- package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +7 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +8 -3
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +29 -43
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +11 -11
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +23 -7
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-session.d.ts.map +1 -1
- package/dist/client/use-session.js +4 -4
- package/dist/client/use-session.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +48 -4
- package/dist/db/client.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts.map +1 -1
- package/dist/db/ensure-additive-columns.js +32 -21
- package/dist/db/ensure-additive-columns.js.map +1 -1
- package/dist/db/migrations.d.ts +9 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +14 -3
- package/dist/db/migrations.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/approval-store.d.ts +16 -0
- package/dist/mcp/approval-store.d.ts.map +1 -0
- package/dist/mcp/approval-store.js +85 -0
- package/dist/mcp/approval-store.js.map +1 -0
- package/dist/mcp/build-server.d.ts +1 -34
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +220 -23
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.js +1 -1
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/oauth-client-metadata.d.ts +15 -0
- package/dist/mcp/oauth-client-metadata.d.ts.map +1 -0
- package/dist/mcp/oauth-client-metadata.js +297 -0
- package/dist/mcp/oauth-client-metadata.js.map +1 -0
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +39 -53
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp/screen-memory-stdio.js +304 -296
- package/dist/mcp/screen-memory-stdio.js.map +1 -1
- package/dist/mcp/server.d.ts +12 -25
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +24 -133
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts.map +1 -1
- package/dist/mcp/stdio.js +36 -35
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +6 -6
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/oauth-client.d.ts +13 -17
- package/dist/mcp-client/oauth-client.d.ts.map +1 -1
- package/dist/mcp-client/oauth-client.js +74 -16
- package/dist/mcp-client/oauth-client.js.map +1 -1
- package/dist/mcp-client/oauth-routes.d.ts +2 -2
- package/dist/mcp-client/oauth-routes.d.ts.map +1 -1
- package/dist/mcp-client/oauth-routes.js +16 -6
- package/dist/mcp-client/oauth-routes.js.map +1 -1
- package/dist/mcp-client/routes.js +5 -5
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-capabilities.d.ts.map +1 -1
- package/dist/server/agent-capabilities.js +21 -0
- package/dist/server/agent-capabilities.js.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +14 -0
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +16 -0
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +11 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/transcribe-voice.js +12 -6
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/templates/chat/.agents/skills/security/SKILL.md +13 -2
- package/dist/templates/chat/README.md +0 -2
- package/dist/templates/default/.agents/skills/security/SKILL.md +13 -2
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
- package/docs/content/template-design-collaboration-and-full-apps.mdx +3 -1
- package/package.json +7 -4
- package/src/a2a/client.ts +18 -4
- package/src/a2a/server.ts +19 -3
- package/src/a2a/types.ts +7 -0
- package/src/action.ts +43 -16
- package/src/agent/engine/ai-sdk-engine.ts +14 -10
- package/src/agent/production-agent.ts +41 -3
- package/src/agent/thread-data-builder.ts +5 -0
- package/src/chat-threads/migrations.ts +53 -0
- package/src/cli/create.ts +4 -0
- package/src/cli/skills-content/design-visual-edit-skill.ts +36 -16
- package/src/cli/skills.ts +16 -0
- package/src/client/AgentPanel.tsx +9 -5
- package/src/client/AssistantChat.tsx +138 -46
- package/src/client/MultiTabAssistantChat.tsx +16 -10
- package/src/client/agent-chat-adapter.ts +21 -3
- package/src/client/analytics.ts +159 -102
- package/src/client/chat/message-components.tsx +12 -5
- package/src/client/chat/runtime.ts +2 -1
- package/src/client/chat/tool-call-display.tsx +25 -2
- package/src/client/chat-model-groups.ts +3 -0
- package/src/client/client-status-requests.ts +161 -0
- package/src/client/settings/VoiceTranscriptionSection.tsx +2 -2
- package/src/client/sse-event-processor.ts +15 -3
- package/src/client/use-agent-engine-configured.ts +54 -50
- package/src/client/use-chat-models.ts +16 -11
- package/src/client/use-chat-threads.ts +32 -9
- package/src/client/use-session.ts +4 -5
- package/src/db/client.ts +83 -8
- package/src/db/ensure-additive-columns.ts +31 -20
- package/src/db/migrations.ts +22 -2
- package/src/mcp/approval-store.ts +99 -0
- package/src/mcp/build-server.ts +579 -303
- package/src/mcp/embed-app.ts +1 -1
- package/src/mcp/oauth-client-metadata.ts +380 -0
- package/src/mcp/oauth-route.ts +57 -52
- package/src/mcp/screen-memory-stdio.ts +400 -378
- package/src/mcp/server.ts +29 -145
- package/src/mcp/stdio.ts +72 -80
- package/src/mcp-client/manager.ts +6 -10
- package/src/mcp-client/oauth-client.ts +127 -36
- package/src/mcp-client/oauth-routes.ts +16 -6
- package/src/mcp-client/routes.ts +6 -5
- package/src/server/agent-capabilities.ts +20 -0
- package/src/server/agent-chat/action-filters-a2a.ts +27 -0
- package/src/server/agent-chat-plugin.ts +18 -0
- package/src/server/transcribe-voice.ts +14 -5
- package/src/templates/chat/.agents/skills/security/SKILL.md +13 -2
- package/src/templates/chat/README.md +0 -2
- package/src/templates/default/.agents/skills/security/SKILL.md +13 -2
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +5 -2
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +18 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +13 -2
package/dist/mcp/server.js
CHANGED
|
@@ -10,28 +10,6 @@ import { MCP_PUBLIC_ROUTE_PREFIX, MCP_ROUTE_PREFIXES, joinMcpRoute, } from "./ro
|
|
|
10
10
|
// any (future) external importer of `@agent-native/core/mcp` keep resolving
|
|
11
11
|
// against `./server.js` exactly as before this refactor.
|
|
12
12
|
export { createMCPServerForRequest, verifyAuth, getAccessTokens, resolveOrgIdFromDomain, buildLinkArtifacts, };
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Runtime detection — Node fast-path vs. web-standard fallback
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
/**
|
|
17
|
-
* Resolve the underlying Node `http` req/res pair if (and only if) we're
|
|
18
|
-
* running on a real Node HTTP server (local dev, `node` Nitro preset). On the
|
|
19
|
-
* web-standard runtime (Nitro 3 / Netlify web runtime, Cloudflare, Deno, Bun)
|
|
20
|
-
* BOTH of these are undefined — that's the signal to take the web fallback
|
|
21
|
-
* instead of returning 501.
|
|
22
|
-
*/
|
|
23
|
-
function getNodeReqRes(event) {
|
|
24
|
-
const e = event;
|
|
25
|
-
const nodeReq = e.node?.req ?? e.req?.runtime?.node?.req;
|
|
26
|
-
const nodeRes = e.node?.res ?? e.req?.runtime?.node?.res;
|
|
27
|
-
return { nodeReq, nodeRes };
|
|
28
|
-
}
|
|
29
|
-
function shouldUseNodeFastPath(event) {
|
|
30
|
-
if (process.env.AGENT_NATIVE_MCP_NODE_FAST_PATH !== "1")
|
|
31
|
-
return false;
|
|
32
|
-
const { nodeReq, nodeRes } = getNodeReqRes(event);
|
|
33
|
-
return Boolean(nodeReq && nodeRes);
|
|
34
|
-
}
|
|
35
13
|
/**
|
|
36
14
|
* Derive the request origin + the markdown deep-link target from the inbound
|
|
37
15
|
* headers. Identical logic for both the Node and web paths so the absolute
|
|
@@ -177,29 +155,20 @@ function buildUnauthorizedBody(event) {
|
|
|
177
155
|
/**
|
|
178
156
|
* Handle a single `{routePrefix}/mcp` request on either runtime.
|
|
179
157
|
*
|
|
180
|
-
* -
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* `Response` as a normal h3 return value. This is used for Nitro local dev
|
|
185
|
-
* too; the direct Node writer can otherwise race h3 and double-write.
|
|
186
|
-
* - **Opt-in Node fast-path:** set `AGENT_NATIVE_MCP_NODE_FAST_PATH=1` to
|
|
187
|
-
* delegate directly to the SDK's `StreamableHTTPServerTransport`.
|
|
158
|
+
* Builds one request-scoped MCP `Server` from the verified caller identity and
|
|
159
|
+
* drives it through the SDK's v2 `createMcpHandler`. That entry serves native
|
|
160
|
+
* 2026-07-28 envelopes and stateless 2025-era traffic from the same factory,
|
|
161
|
+
* so protocol generations cannot drift apart.
|
|
188
162
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* via `createMCPServerForRequest` and both transports funnel into the same
|
|
193
|
-
* `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {
|
|
194
|
-
* parsedBody })` with the same options.
|
|
163
|
+
* The handler is Web Standard on every runtime. H3 owns the Node response when
|
|
164
|
+
* one exists, avoiding the double-write race from a transport writing directly
|
|
165
|
+
* to `node.res`.
|
|
195
166
|
*
|
|
196
167
|
* Returns:
|
|
197
168
|
* - `undefined` when the request targets a sub-route (so management/status
|
|
198
169
|
* routes mounted under `/_agent-native/mcp/*` handle it themselves) — the
|
|
199
170
|
* h3 mount falls through to the next handler.
|
|
200
|
-
* - a Web `Response`
|
|
201
|
-
* auth-error path) otherwise. The Node path also sets `_handled` so h3
|
|
202
|
-
* doesn't double-write.
|
|
171
|
+
* - a Web `Response` or an auth-error object otherwise.
|
|
203
172
|
*/
|
|
204
173
|
export async function handleMcpRequest(event, config) {
|
|
205
174
|
const pathname = event.url?.pathname || "/";
|
|
@@ -241,24 +210,9 @@ export async function handleMcpRequest(event, config) {
|
|
|
241
210
|
setResponseHeader(event, "WWW-Authenticate", buildMcpOAuthChallenge(event));
|
|
242
211
|
return buildUnauthorizedBody(event);
|
|
243
212
|
}
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
// that stream dies and the client reports "session expired" / "not
|
|
248
|
-
// connected". The spec lets a server that offers no GET stream answer 405, so
|
|
249
|
-
// the client falls back to plain POST request/response. Reject GET here
|
|
250
|
-
// instead of letting the SDK open a doomed stream.
|
|
251
|
-
if (method === "DELETE") {
|
|
252
|
-
setResponseStatus(event, 204);
|
|
253
|
-
return "";
|
|
254
|
-
}
|
|
255
|
-
if (method !== "POST") {
|
|
256
|
-
setResponseStatus(event, 405);
|
|
257
|
-
return { error: "Method not allowed" };
|
|
258
|
-
}
|
|
259
|
-
// Read body for POST (GET has no body). Read it via the h3 helper exactly
|
|
260
|
-
// once; both transports accept it as a pre-parsed body so the request
|
|
261
|
-
// stream is never consumed twice.
|
|
213
|
+
// Read POST bodies through h3 exactly once. `createMcpHandler` accepts the
|
|
214
|
+
// parsed value, so neither its modern classifier nor its legacy fallback
|
|
215
|
+
// consumes the request stream a second time.
|
|
262
216
|
const body = method === "POST" ? await readBody(event) : undefined;
|
|
263
217
|
// Optional diagnostics for host capability negotiation. Keep disabled by
|
|
264
218
|
// default because initialize payloads can include client-specific metadata.
|
|
@@ -271,13 +225,7 @@ export async function handleMcpRequest(event, config) {
|
|
|
271
225
|
console.error("[MCP_DEBUG_INIT] clientInfo=", JSON.stringify(init.params?.clientInfo), "capabilities=", JSON.stringify(init.params?.capabilities));
|
|
272
226
|
}
|
|
273
227
|
}
|
|
274
|
-
|
|
275
|
-
// server from the SAME config + verified identity + request meta, so
|
|
276
|
-
// tools/list, tools/call, and the deep-link `_meta` are identical. A
|
|
277
|
-
// connected real caller (connect-minted token / `mcp install` /
|
|
278
|
-
// ACCESS_TOKEN / production) gets the full action surface even in local
|
|
279
|
-
// dev; unauthenticated dev probes stay sparse. See `external-agents` skill.
|
|
280
|
-
const server = await createMCPServerForRequest(config, authResult.identity, {
|
|
228
|
+
const serverRequestMeta = {
|
|
281
229
|
...requestMeta,
|
|
282
230
|
fullSurface: authResult.fullSurface === true,
|
|
283
231
|
inlineMcpApps: requestMeta.inlineMcpApps === true &&
|
|
@@ -287,69 +235,16 @@ export async function handleMcpRequest(event, config) {
|
|
|
287
235
|
// When the caller minted their token with --full-catalog (catalog_scope:
|
|
288
236
|
// "full" JWT claim), bypass the connector-catalog tier filter.
|
|
289
237
|
...(authResult.fullCatalog === true ? { fullCatalog: true } : {}),
|
|
238
|
+
};
|
|
239
|
+
const { createMcpHandler } = await import("@modelcontextprotocol/server");
|
|
240
|
+
const handler = createMcpHandler(() => createMCPServerForRequest(config, authResult.identity, serverRequestMeta), {
|
|
241
|
+
legacy: "stateless",
|
|
242
|
+
// Ordinary calls stay single-body JSON unless a handler emits a related
|
|
243
|
+
// message before its result. Subscription/listen remains SSE.
|
|
244
|
+
responseMode: "auto",
|
|
290
245
|
});
|
|
291
|
-
if (shouldUseNodeFastPath(event)) {
|
|
292
|
-
const { nodeReq, nodeRes } = getNodeReqRes(event);
|
|
293
|
-
// ---- Opt-in Node fast-path ---------------------------------------------
|
|
294
|
-
const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
295
|
-
const transport = new StreamableHTTPServerTransport({
|
|
296
|
-
sessionIdGenerator: undefined, // stateless
|
|
297
|
-
// Return JSON request/response instead of SSE. A stateless serverless
|
|
298
|
-
// instance can freeze right after returning a streaming Response, before
|
|
299
|
-
// the deferred SSE result event is flushed — the client then never gets
|
|
300
|
-
// the tools/call result and reports "session expired". JSON mode awaits
|
|
301
|
-
// the result inside the request lifecycle and returns it as one body.
|
|
302
|
-
enableJsonResponse: true,
|
|
303
|
-
});
|
|
304
|
-
await server.connect(transport);
|
|
305
|
-
try {
|
|
306
|
-
// The SDK transport writes directly to the Node response. Node-only by
|
|
307
|
-
// construction; we only reach here when real Node req/res exist.
|
|
308
|
-
await transport.handleRequest(nodeReq, nodeRes, body);
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
// The SDK transport writes directly to the Node response. If the socket
|
|
312
|
-
// is already closed/ended (client disconnected, or the host stream
|
|
313
|
-
// layer also flushed), Node throws ERR_STREAM_WRITE_AFTER_END *after*
|
|
314
|
-
// the MCP payload was already delivered correctly. Swallow that benign
|
|
315
|
-
// post-flush write so an external agent disconnecting mid-stream can
|
|
316
|
-
// never take down the server process; rethrow anything else.
|
|
317
|
-
if (err?.code !== "ERR_STREAM_WRITE_AFTER_END")
|
|
318
|
-
throw err;
|
|
319
|
-
if (process.env.DEBUG)
|
|
320
|
-
console.log("[mcp] ignored post-flush ERR_STREAM_WRITE_AFTER_END (client disconnected)");
|
|
321
|
-
}
|
|
322
|
-
// Prevent H3 from double-writing the response
|
|
323
|
-
event._handled = true;
|
|
324
|
-
return undefined;
|
|
325
|
-
}
|
|
326
|
-
// ---- Web-standard response path (Nitro local dev, Netlify web runtime, CF,
|
|
327
|
-
// Deno, Bun) ---------------------------------------------------------------
|
|
328
|
-
//
|
|
329
|
-
// `StreamableHTTPServerTransport` is itself just a thin wrapper that
|
|
330
|
-
// converts the Node req/res to a web Request/Response and delegates to
|
|
331
|
-
// `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {
|
|
332
|
-
// parsedBody })`. Using the web transport directly with the SAME options +
|
|
333
|
-
// the same pre-read `parsedBody` produces byte-identical protocol output
|
|
334
|
-
// (including the deep-link `_meta` built inside createMCPServerForRequest),
|
|
335
|
-
// and works on every web runtime because it returns a Web `Response`
|
|
336
|
-
// (JSON for request/response, or an SSE `ReadableStream` body which h3
|
|
337
|
-
// streams natively).
|
|
338
|
-
const { WebStandardStreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
|
|
339
|
-
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
340
|
-
sessionIdGenerator: undefined, // stateless — same as the Node path
|
|
341
|
-
// JSON request/response (not SSE) — see the Node fast-path note above.
|
|
342
|
-
// This is the serverless-safe framing: the result is computed and returned
|
|
343
|
-
// within the request, never pushed onto a stream after the instance froze.
|
|
344
|
-
enableJsonResponse: true,
|
|
345
|
-
});
|
|
346
|
-
await server.connect(transport);
|
|
347
246
|
const webRequest = buildWebRequest(event, method);
|
|
348
|
-
|
|
349
|
-
// synthesized request has no body, so only pass the option for POST (where
|
|
350
|
-
// we actually have a parsed body). For GET the transport reads no body.
|
|
351
|
-
const response = await transport.handleRequest(webRequest, method === "POST" ? { parsedBody: body } : undefined);
|
|
352
|
-
return response;
|
|
247
|
+
return handler.fetch(webRequest, method === "POST" ? { parsedBody: body } : undefined);
|
|
353
248
|
}
|
|
354
249
|
// ---------------------------------------------------------------------------
|
|
355
250
|
// mountMCP — register MCP Streamable HTTP endpoint on H3/Nitro
|
|
@@ -360,14 +255,10 @@ export async function handleMcpRequest(event, config) {
|
|
|
360
255
|
* Endpoints: `/mcp` (public) and `/_agent-native/mcp` (compatibility).
|
|
361
256
|
* A custom route prefix only mounts that custom endpoint.
|
|
362
257
|
*
|
|
363
|
-
* Uses
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
* server uses the SDK's Node transport; the web-standard runtime (Nitro 3 /
|
|
368
|
-
* Netlify web runtime, Cloudflare, Deno, Bun) uses the SDK's web-standard
|
|
369
|
-
* transport. Both build the same server and produce identical JSON-RPC
|
|
370
|
-
* output.
|
|
258
|
+
* Uses the v2 Web Standard per-request handler with native 2026-07-28 serving
|
|
259
|
+
* and stateless 2025-era fallback. It carries no in-memory protocol session
|
|
260
|
+
* across invocations and works unchanged on Node, Nitro/Netlify web runtimes,
|
|
261
|
+
* Cloudflare, Deno, and Bun.
|
|
371
262
|
*
|
|
372
263
|
* Auth: Bearer token matching ACCESS_TOKEN/ACCESS_TOKENS or JWT via A2A_SECRET.
|
|
373
264
|
* No auth required when neither is configured (dev mode).
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getRequestHeader,\n} from \"h3\";\n\nimport { getConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { isLoopbackRequest } from \"../server/auth.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n type MCPConfig,\n type MCPCallerIdentity,\n type MCPRequestMeta,\n} from \"./build-server.js\";\nimport {\n buildMcpOAuthChallenge,\n getMcpOAuthAudiences,\n getMcpOAuthIssuer,\n getMcpOAuthProtectedResourceMetadataUrl,\n getMcpOAuthResource,\n} from \"./oauth-route.js\";\nimport {\n MCP_PUBLIC_ROUTE_PREFIX,\n MCP_ROUTE_PREFIXES,\n joinMcpRoute,\n} from \"./route-paths.js\";\n\n// Re-export the shared MCP server builder + types so the stdio transport and\n// any (future) external importer of `@agent-native/core/mcp` keep resolving\n// against `./server.js` exactly as before this refactor.\nexport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n};\nexport type { MCPConfig, MCPCallerIdentity, MCPRequestMeta };\n\n// ---------------------------------------------------------------------------\n// Runtime detection — Node fast-path vs. web-standard fallback\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the underlying Node `http` req/res pair if (and only if) we're\n * running on a real Node HTTP server (local dev, `node` Nitro preset). On the\n * web-standard runtime (Nitro 3 / Netlify web runtime, Cloudflare, Deno, Bun)\n * BOTH of these are undefined — that's the signal to take the web fallback\n * instead of returning 501.\n */\nfunction getNodeReqRes(event: H3Event): {\n nodeReq: any | undefined;\n nodeRes: any | undefined;\n} {\n const e = event as any;\n const nodeReq = e.node?.req ?? e.req?.runtime?.node?.req;\n const nodeRes = e.node?.res ?? e.req?.runtime?.node?.res;\n return { nodeReq, nodeRes };\n}\n\nfunction shouldUseNodeFastPath(event: H3Event): boolean {\n if (process.env.AGENT_NATIVE_MCP_NODE_FAST_PATH !== \"1\") return false;\n const { nodeReq, nodeRes } = getNodeReqRes(event);\n return Boolean(nodeReq && nodeRes);\n}\n\n/**\n * Derive the request origin + the markdown deep-link target from the inbound\n * headers. Identical logic for both the Node and web paths so the absolute\n * deep-link URLs in tool results are computed the same way regardless of\n * runtime.\n */\nfunction deriveRequestMeta(event: H3Event): MCPRequestMeta {\n const forwardedProto = getRequestHeader(event, \"x-forwarded-proto\");\n const host =\n getRequestHeader(event, \"x-forwarded-host\") ||\n getRequestHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const origin = host ? `${proto}://${host}` : undefined;\n const targetHeader = getRequestHeader(\n event,\n \"x-agent-native-open-target\",\n )?.toLowerCase();\n const target =\n targetHeader === \"desktop\" ||\n targetHeader === \"terminal\" ||\n targetHeader === \"browser\"\n ? (targetHeader as MCPRequestMeta[\"target\"])\n : undefined;\n const clientName = getRequestHeader(event, \"user-agent\")?.trim() || undefined;\n const clientHint =\n getRequestHeader(event, \"x-agent-native-mcp-client\")?.trim() || undefined;\n const fullCatalogHeader = getRequestHeader(\n event,\n \"x-agent-native-mcp-full-catalog\",\n )?.toLowerCase();\n const fullCatalog =\n fullCatalogHeader === \"1\" ||\n fullCatalogHeader === \"true\" ||\n fullCatalogHeader === \"yes\";\n const inlineAppsHeader = getRequestHeader(\n event,\n \"x-agent-native-mcp-inline-apps\",\n )?.toLowerCase();\n const inlineAppsRequested =\n inlineAppsHeader === \"1\" ||\n inlineAppsHeader === \"true\" ||\n inlineAppsHeader === \"yes\";\n const basePath = getConfiguredAppBasePath();\n return {\n origin,\n ...(basePath ? { basePath } : {}),\n target,\n clientName,\n clientHint,\n ...(fullCatalog ? { fullCatalog } : {}),\n ...(inlineAppsRequested ? { inlineMcpApps: true } : {}),\n };\n}\n\nfunction isLoopbackOrigin(origin: string | undefined): boolean {\n if (!origin) return false;\n try {\n const hostname = new URL(origin).hostname;\n return (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname === \"[::1]\" ||\n hostname.startsWith(\"127.\")\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Reconstruct a Web Standard `Request` for the web-standard MCP transport.\n *\n * On the web runtime h3 v2 exposes the real web `Request` as `event.req`; we\n * prefer it (its `method` / `headers` are exactly what the client sent). But\n * the framework middleware rewrites `event.req.url` when it strips a mount\n * prefix, and the transport reads `req.method` + `req.headers` (never the\n * body — we pass that via `parsedBody`), so we always synthesize a clean\n * `Request` with the verified method + a fresh `Headers` copy. The URL is\n * cosmetic for the SDK (it only does `new URL(req.url)` for `requestInfo`),\n * so a best-effort absolute URL derived from the inbound host is sufficient\n * and never throws.\n */\nfunction buildWebRequest(event: H3Event, method: string): Request {\n const src = (event as any).req as Request | undefined;\n\n const headers = new Headers();\n if (src?.headers && typeof src.headers.forEach === \"function\") {\n src.headers.forEach((value, key) => headers.set(key, value));\n } else {\n const rawHeaders = (event as any).node?.req?.headers as\n | Record<string, string | string[] | undefined>\n | undefined;\n if (rawHeaders) {\n for (const [key, value] of Object.entries(rawHeaders)) {\n if (value == null) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n }\n }\n\n // The SDK requires Accept + Content-Type to advertise both JSON and SSE on\n // a POST. Real MCP clients (Claude Code, `agent-native connect`) always\n // send these; we never inject/alter them — if they're absent the SDK\n // returns its spec-mandated 406/415, identical to the Node path.\n\n const host =\n headers.get(\"x-forwarded-host\") || headers.get(\"host\") || \"localhost\";\n const forwardedProto = headers.get(\"x-forwarded-proto\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (/^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const basePath = getConfiguredAppBasePath();\n const url = `${proto}://${host}${basePath}${MCP_PUBLIC_ROUTE_PREFIX}`;\n\n // No body here on purpose: the JSON-RPC payload is forwarded via the\n // transport's `parsedBody` option (the same mechanism the Node transport\n // uses), so the request stream is never read twice.\n return new Request(url, { method, headers });\n}\n\n/**\n * Build an actionable JSON body for the 401 response. OAuth-capable clients\n * follow the `WWW-Authenticate` header automatically, but the JSON body is what\n * a human or a coding agent reads when a tool call comes back unauthorized — so\n * spell out the exact remediation: the `agent-native connect <url>` command and\n * the authorize/metadata URL. Keeping the legacy `error: \"Unauthorized\"` field\n * means existing clients that only check that field still work.\n */\nfunction buildUnauthorizedBody(event: H3Event): {\n error: string;\n message: string;\n authenticate: {\n command?: string;\n firstTimeCommand?: string;\n authorizeUrl?: string;\n resourceMetadataUrl?: string;\n mcpUrl?: string;\n };\n} {\n const issuer = getMcpOAuthIssuer(event);\n const mcpUrl = getMcpOAuthResource(event);\n const resourceMetadataUrl = getMcpOAuthProtectedResourceMetadataUrl(event);\n const command = issuer\n ? `npx -y @agent-native/core@latest reconnect ${issuer}`\n : undefined;\n const firstTimeCommand = issuer\n ? `npx @agent-native/core@latest connect ${issuer}`\n : undefined;\n const authorizeUrl = issuer\n ? `${issuer}${MCP_PUBLIC_ROUTE_PREFIX}/oauth/authorize`\n : undefined;\n const message = command\n ? `Authentication required. Run \\`${command}\\` to re-authenticate this ` +\n `MCP connector without reinstalling it (or, in a Claude Code host, ` +\n `run /mcp and choose Authenticate), then retry. For first-time ` +\n `setup, run \\`${firstTimeCommand}\\`.`\n : \"Authentication required. Authenticate the MCP connector in your host, \" +\n \"then retry.\";\n return {\n error: \"Unauthorized\",\n message,\n authenticate: {\n ...(command ? { command } : {}),\n ...(firstTimeCommand ? { firstTimeCommand } : {}),\n ...(authorizeUrl ? { authorizeUrl } : {}),\n ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}),\n ...(mcpUrl ? { mcpUrl } : {}),\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// handleMcpRequest — runtime-agnostic MCP request handler\n// ---------------------------------------------------------------------------\n\n/**\n * Handle a single `{routePrefix}/mcp` request on either runtime.\n *\n * - **Default path:** build the SAME MCP `Server`\n * from the SAME config + identity, drive it through the SDK's\n * `WebStandardStreamableHTTPServerTransport` (which the Node transport is\n * itself just a thin wrapper around), and return the resulting Web\n * `Response` as a normal h3 return value. This is used for Nitro local dev\n * too; the direct Node writer can otherwise race h3 and double-write.\n * - **Opt-in Node fast-path:** set `AGENT_NATIVE_MCP_NODE_FAST_PATH=1` to\n * delegate directly to the SDK's `StreamableHTTPServerTransport`.\n *\n * Auth, the `runWithRequestContext` identity wrap, the deep-link `_meta` /\n * markdown append, `requestMeta` origin/target derivation and the stateless\n * semantics are IDENTICAL on both paths because both build the same server\n * via `createMCPServerForRequest` and both transports funnel into the same\n * `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n * parsedBody })` with the same options.\n *\n * Returns:\n * - `undefined` when the request targets a sub-route (so management/status\n * routes mounted under `/_agent-native/mcp/*` handle it themselves) — the\n * h3 mount falls through to the next handler.\n * - a Web `Response` (web fallback) or a string/object (Node path /\n * auth-error path) otherwise. The Node path also sets `_handled` so h3\n * doesn't double-write.\n */\nexport async function handleMcpRequest(\n event: H3Event,\n config: MCPConfig,\n): Promise<\n Response | string | { error: string } | Record<string, unknown> | undefined\n> {\n const pathname = event.url?.pathname || \"/\";\n const subpath = pathname.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (subpath) {\n // Let management/status routes mounted under /_agent-native/mcp/* handle\n // their own requests instead of treating them as MCP protocol traffic.\n return undefined;\n }\n\n const method = getMethod(event);\n\n // Auth check — extracts the caller's identity from the JWT (`sub`), or, on\n // the static-token / dev-open path, from the forwarded\n // `X-Agent-Native-Owner-Email` hint the stdio proxy sends (the\n // `agent-native mcp install` flow). Without this the install flow would run\n // every tool unscoped (userEmail === undefined).\n const authHeader = getRequestHeader(event, \"authorization\");\n const ownerEmailHeader = getRequestHeader(\n event,\n \"x-agent-native-owner-email\",\n );\n // Gate header-only dev-open on the REAL socket peer, never a parsed\n // `Host` header (client-controlled — an attacker could send\n // `Host: localhost`). A deployed app missing A2A_SECRET / ACCESS_TOKEN\n // must fail closed rather than trust a spoofable owner-email header that\n // `fullSurface` would otherwise escalate to the full mutating surface.\n const requestMeta = deriveRequestMeta(event);\n const hasLocalOwnerHint = Boolean(ownerEmailHeader?.trim());\n const authResult = await verifyAuth(authHeader, ownerEmailHeader, {\n // A bare localhost URL is still a protected MCP resource. This lets\n // OAuth-native hosts (Kiro, Claude Code, etc.) receive the standard 401\n // challenge and open browser approval instead of silently getting the\n // sparse anonymous dev surface. The stdio proxy remains zero-config for\n // local installs because it forwards an owner hint; an explicit opt-in is\n // available for local diagnostics.\n allowDevOpen:\n isLoopbackRequest(event) &&\n isLoopbackOrigin(requestMeta.origin) &&\n (hasLocalOwnerHint || process.env.AGENT_NATIVE_MCP_DEV_OPEN === \"1\"),\n resourceUrl: getMcpOAuthAudiences(event),\n });\n if (!authResult.authed) {\n setResponseStatus(event, 401);\n setResponseHeader(event, \"WWW-Authenticate\", buildMcpOAuthChallenge(event));\n return buildUnauthorizedBody(event);\n }\n\n // Stateless mode: only POST is meaningful. A stateless, per-request transport\n // on serverless cannot keep the standalone GET SSE stream (server->client\n // channel) alive across invocations — once the function returns and freezes,\n // that stream dies and the client reports \"session expired\" / \"not\n // connected\". The spec lets a server that offers no GET stream answer 405, so\n // the client falls back to plain POST request/response. Reject GET here\n // instead of letting the SDK open a doomed stream.\n if (method === \"DELETE\") {\n setResponseStatus(event, 204);\n return \"\";\n }\n\n if (method !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // Read body for POST (GET has no body). Read it via the h3 helper exactly\n // once; both transports accept it as a pre-parsed body so the request\n // stream is never consumed twice.\n const body = method === \"POST\" ? await readBody(event) : undefined;\n\n // Optional diagnostics for host capability negotiation. Keep disabled by\n // default because initialize payloads can include client-specific metadata.\n if (process.env.MCP_DEBUG_INIT && body) {\n const msgs = Array.isArray(body) ? body : [body];\n const init = msgs.find(\n (m): m is { params?: { capabilities?: unknown; clientInfo?: unknown } } =>\n typeof m === \"object\" &&\n m !== null &&\n (m as { method?: unknown }).method === \"initialize\",\n );\n if (init) {\n console.error(\n \"[MCP_DEBUG_INIT] clientInfo=\",\n JSON.stringify(init.params?.clientInfo),\n \"capabilities=\",\n JSON.stringify(init.params?.capabilities),\n );\n }\n }\n\n // Per-request stateless transport + server. Both runtimes build the SAME\n // server from the SAME config + verified identity + request meta, so\n // tools/list, tools/call, and the deep-link `_meta` are identical. A\n // connected real caller (connect-minted token / `mcp install` /\n // ACCESS_TOKEN / production) gets the full action surface even in local\n // dev; unauthenticated dev probes stay sparse. See `external-agents` skill.\n const server = await createMCPServerForRequest(config, authResult.identity, {\n ...requestMeta,\n fullSurface: authResult.fullSurface === true,\n inlineMcpApps:\n requestMeta.inlineMcpApps === true &&\n authResult.identity?.firstPartyMcp === true\n ? true\n : undefined,\n // When the caller minted their token with --full-catalog (catalog_scope:\n // \"full\" JWT claim), bypass the connector-catalog tier filter.\n ...(authResult.fullCatalog === true ? { fullCatalog: true } : {}),\n });\n\n if (shouldUseNodeFastPath(event)) {\n const { nodeReq, nodeRes } = getNodeReqRes(event);\n // ---- Opt-in Node fast-path ---------------------------------------------\n const { StreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/streamableHttp.js\");\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless\n // Return JSON request/response instead of SSE. A stateless serverless\n // instance can freeze right after returning a streaming Response, before\n // the deferred SSE result event is flushed — the client then never gets\n // the tools/call result and reports \"session expired\". JSON mode awaits\n // the result inside the request lifecycle and returns it as one body.\n enableJsonResponse: true,\n });\n await server.connect(transport);\n try {\n // The SDK transport writes directly to the Node response. Node-only by\n // construction; we only reach here when real Node req/res exist.\n await transport.handleRequest(nodeReq, nodeRes, body);\n } catch (err: any) {\n // The SDK transport writes directly to the Node response. If the socket\n // is already closed/ended (client disconnected, or the host stream\n // layer also flushed), Node throws ERR_STREAM_WRITE_AFTER_END *after*\n // the MCP payload was already delivered correctly. Swallow that benign\n // post-flush write so an external agent disconnecting mid-stream can\n // never take down the server process; rethrow anything else.\n if (err?.code !== \"ERR_STREAM_WRITE_AFTER_END\") throw err;\n if (process.env.DEBUG)\n console.log(\n \"[mcp] ignored post-flush ERR_STREAM_WRITE_AFTER_END (client disconnected)\",\n );\n }\n // Prevent H3 from double-writing the response\n (event as any)._handled = true;\n return undefined;\n }\n\n // ---- Web-standard response path (Nitro local dev, Netlify web runtime, CF,\n // Deno, Bun) ---------------------------------------------------------------\n //\n // `StreamableHTTPServerTransport` is itself just a thin wrapper that\n // converts the Node req/res to a web Request/Response and delegates to\n // `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n // parsedBody })`. Using the web transport directly with the SAME options +\n // the same pre-read `parsedBody` produces byte-identical protocol output\n // (including the deep-link `_meta` built inside createMCPServerForRequest),\n // and works on every web runtime because it returns a Web `Response`\n // (JSON for request/response, or an SSE `ReadableStream` body which h3\n // streams natively).\n const { WebStandardStreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\");\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless — same as the Node path\n // JSON request/response (not SSE) — see the Node fast-path note above.\n // This is the serverless-safe framing: the result is computed and returned\n // within the request, never pushed onto a stream after the instance froze.\n enableJsonResponse: true,\n });\n await server.connect(transport);\n const webRequest = buildWebRequest(event, method);\n // `parsedBody: undefined` would make the SDK try to read `req.json()`; our\n // synthesized request has no body, so only pass the option for POST (where\n // we actually have a parsed body). For GET the transport reads no body.\n const response = await transport.handleRequest(\n webRequest,\n method === \"POST\" ? { parsedBody: body } : undefined,\n );\n return response;\n}\n\n// ---------------------------------------------------------------------------\n// mountMCP — register MCP Streamable HTTP endpoint on H3/Nitro\n// ---------------------------------------------------------------------------\n\n/**\n * Mount an MCP remote server on an H3/Nitro app.\n *\n * Endpoints: `/mcp` (public) and `/_agent-native/mcp` (compatibility).\n * A custom route prefix only mounts that custom endpoint.\n *\n * Uses stateless Streamable HTTP transport — no in-memory sessions, JSON\n * request/response (no SSE), and no standalone GET stream, so it survives\n * serverless instances that freeze between invocations (SSE framing there\n * drops the result and clients report \"session expired\"). Runtime-agnostic: a real Node\n * server uses the SDK's Node transport; the web-standard runtime (Nitro 3 /\n * Netlify web runtime, Cloudflare, Deno, Bun) uses the SDK's web-standard\n * transport. Both build the same server and produce identical JSON-RPC\n * output.\n *\n * Auth: Bearer token matching ACCESS_TOKEN/ACCESS_TOKENS or JWT via A2A_SECRET.\n * No auth required when neither is configured (dev mode).\n */\nexport function mountMCP(\n nitroApp: any,\n config: MCPConfig,\n routePrefix = \"/_agent-native\",\n): void {\n const routePaths =\n routePrefix === \"/_agent-native\"\n ? [...MCP_ROUTE_PREFIXES]\n : [joinMcpRoute(routePrefix, \"/mcp\")];\n const handler = defineEventHandler(async (event) => {\n return handleMcpRequest(event as H3Event, config);\n });\n\n for (const routePath of routePaths) {\n getH3App(nitroApp).use(routePath, handler);\n }\n\n if (process.env.DEBUG)\n console.log(\n `[mcp] Mounted MCP server at ${routePaths.join(\" and \")} (${Object.keys(config.actions).length} tools${config.askAgent ? \" + ask-agent\" : \"\"})`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getRequestHeader,\n} from \"h3\";\n\nimport { getConfiguredAppBasePath } from \"../server/app-base-path.js\";\nimport { isLoopbackRequest } from \"../server/auth.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n type MCPConfig,\n type MCPCallerIdentity,\n type MCPRequestMeta,\n} from \"./build-server.js\";\nimport {\n buildMcpOAuthChallenge,\n getMcpOAuthAudiences,\n getMcpOAuthIssuer,\n getMcpOAuthProtectedResourceMetadataUrl,\n getMcpOAuthResource,\n} from \"./oauth-route.js\";\nimport {\n MCP_PUBLIC_ROUTE_PREFIX,\n MCP_ROUTE_PREFIXES,\n joinMcpRoute,\n} from \"./route-paths.js\";\n\n// Re-export the shared MCP server builder + types so the stdio transport and\n// any (future) external importer of `@agent-native/core/mcp` keep resolving\n// against `./server.js` exactly as before this refactor.\nexport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n};\nexport type { MCPConfig, MCPCallerIdentity, MCPRequestMeta };\n\n/**\n * Derive the request origin + the markdown deep-link target from the inbound\n * headers. Identical logic for both the Node and web paths so the absolute\n * deep-link URLs in tool results are computed the same way regardless of\n * runtime.\n */\nfunction deriveRequestMeta(event: H3Event): MCPRequestMeta {\n const forwardedProto = getRequestHeader(event, \"x-forwarded-proto\");\n const host =\n getRequestHeader(event, \"x-forwarded-host\") ||\n getRequestHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const origin = host ? `${proto}://${host}` : undefined;\n const targetHeader = getRequestHeader(\n event,\n \"x-agent-native-open-target\",\n )?.toLowerCase();\n const target =\n targetHeader === \"desktop\" ||\n targetHeader === \"terminal\" ||\n targetHeader === \"browser\"\n ? (targetHeader as MCPRequestMeta[\"target\"])\n : undefined;\n const clientName = getRequestHeader(event, \"user-agent\")?.trim() || undefined;\n const clientHint =\n getRequestHeader(event, \"x-agent-native-mcp-client\")?.trim() || undefined;\n const fullCatalogHeader = getRequestHeader(\n event,\n \"x-agent-native-mcp-full-catalog\",\n )?.toLowerCase();\n const fullCatalog =\n fullCatalogHeader === \"1\" ||\n fullCatalogHeader === \"true\" ||\n fullCatalogHeader === \"yes\";\n const inlineAppsHeader = getRequestHeader(\n event,\n \"x-agent-native-mcp-inline-apps\",\n )?.toLowerCase();\n const inlineAppsRequested =\n inlineAppsHeader === \"1\" ||\n inlineAppsHeader === \"true\" ||\n inlineAppsHeader === \"yes\";\n const basePath = getConfiguredAppBasePath();\n return {\n origin,\n ...(basePath ? { basePath } : {}),\n target,\n clientName,\n clientHint,\n ...(fullCatalog ? { fullCatalog } : {}),\n ...(inlineAppsRequested ? { inlineMcpApps: true } : {}),\n };\n}\n\nfunction isLoopbackOrigin(origin: string | undefined): boolean {\n if (!origin) return false;\n try {\n const hostname = new URL(origin).hostname;\n return (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname === \"[::1]\" ||\n hostname.startsWith(\"127.\")\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Reconstruct a Web Standard `Request` for the web-standard MCP transport.\n *\n * On the web runtime h3 v2 exposes the real web `Request` as `event.req`; we\n * prefer it (its `method` / `headers` are exactly what the client sent). But\n * the framework middleware rewrites `event.req.url` when it strips a mount\n * prefix, and the transport reads `req.method` + `req.headers` (never the\n * body — we pass that via `parsedBody`), so we always synthesize a clean\n * `Request` with the verified method + a fresh `Headers` copy. The URL is\n * cosmetic for the SDK (it only does `new URL(req.url)` for `requestInfo`),\n * so a best-effort absolute URL derived from the inbound host is sufficient\n * and never throws.\n */\nfunction buildWebRequest(event: H3Event, method: string): Request {\n const src = (event as any).req as Request | undefined;\n\n const headers = new Headers();\n if (src?.headers && typeof src.headers.forEach === \"function\") {\n src.headers.forEach((value, key) => headers.set(key, value));\n } else {\n const rawHeaders = (event as any).node?.req?.headers as\n | Record<string, string | string[] | undefined>\n | undefined;\n if (rawHeaders) {\n for (const [key, value] of Object.entries(rawHeaders)) {\n if (value == null) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n }\n }\n\n // The SDK requires Accept + Content-Type to advertise both JSON and SSE on\n // a POST. Real MCP clients (Claude Code, `agent-native connect`) always\n // send these; we never inject/alter them — if they're absent the SDK\n // returns its spec-mandated 406/415, identical to the Node path.\n\n const host =\n headers.get(\"x-forwarded-host\") || headers.get(\"host\") || \"localhost\";\n const forwardedProto = headers.get(\"x-forwarded-proto\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (/^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const basePath = getConfiguredAppBasePath();\n const url = `${proto}://${host}${basePath}${MCP_PUBLIC_ROUTE_PREFIX}`;\n\n // No body here on purpose: the JSON-RPC payload is forwarded via the\n // transport's `parsedBody` option (the same mechanism the Node transport\n // uses), so the request stream is never read twice.\n return new Request(url, { method, headers });\n}\n\n/**\n * Build an actionable JSON body for the 401 response. OAuth-capable clients\n * follow the `WWW-Authenticate` header automatically, but the JSON body is what\n * a human or a coding agent reads when a tool call comes back unauthorized — so\n * spell out the exact remediation: the `agent-native connect <url>` command and\n * the authorize/metadata URL. Keeping the legacy `error: \"Unauthorized\"` field\n * means existing clients that only check that field still work.\n */\nfunction buildUnauthorizedBody(event: H3Event): {\n error: string;\n message: string;\n authenticate: {\n command?: string;\n firstTimeCommand?: string;\n authorizeUrl?: string;\n resourceMetadataUrl?: string;\n mcpUrl?: string;\n };\n} {\n const issuer = getMcpOAuthIssuer(event);\n const mcpUrl = getMcpOAuthResource(event);\n const resourceMetadataUrl = getMcpOAuthProtectedResourceMetadataUrl(event);\n const command = issuer\n ? `npx -y @agent-native/core@latest reconnect ${issuer}`\n : undefined;\n const firstTimeCommand = issuer\n ? `npx @agent-native/core@latest connect ${issuer}`\n : undefined;\n const authorizeUrl = issuer\n ? `${issuer}${MCP_PUBLIC_ROUTE_PREFIX}/oauth/authorize`\n : undefined;\n const message = command\n ? `Authentication required. Run \\`${command}\\` to re-authenticate this ` +\n `MCP connector without reinstalling it (or, in a Claude Code host, ` +\n `run /mcp and choose Authenticate), then retry. For first-time ` +\n `setup, run \\`${firstTimeCommand}\\`.`\n : \"Authentication required. Authenticate the MCP connector in your host, \" +\n \"then retry.\";\n return {\n error: \"Unauthorized\",\n message,\n authenticate: {\n ...(command ? { command } : {}),\n ...(firstTimeCommand ? { firstTimeCommand } : {}),\n ...(authorizeUrl ? { authorizeUrl } : {}),\n ...(resourceMetadataUrl ? { resourceMetadataUrl } : {}),\n ...(mcpUrl ? { mcpUrl } : {}),\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// handleMcpRequest — runtime-agnostic MCP request handler\n// ---------------------------------------------------------------------------\n\n/**\n * Handle a single `{routePrefix}/mcp` request on either runtime.\n *\n * Builds one request-scoped MCP `Server` from the verified caller identity and\n * drives it through the SDK's v2 `createMcpHandler`. That entry serves native\n * 2026-07-28 envelopes and stateless 2025-era traffic from the same factory,\n * so protocol generations cannot drift apart.\n *\n * The handler is Web Standard on every runtime. H3 owns the Node response when\n * one exists, avoiding the double-write race from a transport writing directly\n * to `node.res`.\n *\n * Returns:\n * - `undefined` when the request targets a sub-route (so management/status\n * routes mounted under `/_agent-native/mcp/*` handle it themselves) — the\n * h3 mount falls through to the next handler.\n * - a Web `Response` or an auth-error object otherwise.\n */\nexport async function handleMcpRequest(\n event: H3Event,\n config: MCPConfig,\n): Promise<\n Response | string | { error: string } | Record<string, unknown> | undefined\n> {\n const pathname = event.url?.pathname || \"/\";\n const subpath = pathname.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (subpath) {\n // Let management/status routes mounted under /_agent-native/mcp/* handle\n // their own requests instead of treating them as MCP protocol traffic.\n return undefined;\n }\n\n const method = getMethod(event);\n\n // Auth check — extracts the caller's identity from the JWT (`sub`), or, on\n // the static-token / dev-open path, from the forwarded\n // `X-Agent-Native-Owner-Email` hint the stdio proxy sends (the\n // `agent-native mcp install` flow). Without this the install flow would run\n // every tool unscoped (userEmail === undefined).\n const authHeader = getRequestHeader(event, \"authorization\");\n const ownerEmailHeader = getRequestHeader(\n event,\n \"x-agent-native-owner-email\",\n );\n // Gate header-only dev-open on the REAL socket peer, never a parsed\n // `Host` header (client-controlled — an attacker could send\n // `Host: localhost`). A deployed app missing A2A_SECRET / ACCESS_TOKEN\n // must fail closed rather than trust a spoofable owner-email header that\n // `fullSurface` would otherwise escalate to the full mutating surface.\n const requestMeta = deriveRequestMeta(event);\n const hasLocalOwnerHint = Boolean(ownerEmailHeader?.trim());\n const authResult = await verifyAuth(authHeader, ownerEmailHeader, {\n // A bare localhost URL is still a protected MCP resource. This lets\n // OAuth-native hosts (Kiro, Claude Code, etc.) receive the standard 401\n // challenge and open browser approval instead of silently getting the\n // sparse anonymous dev surface. The stdio proxy remains zero-config for\n // local installs because it forwards an owner hint; an explicit opt-in is\n // available for local diagnostics.\n allowDevOpen:\n isLoopbackRequest(event) &&\n isLoopbackOrigin(requestMeta.origin) &&\n (hasLocalOwnerHint || process.env.AGENT_NATIVE_MCP_DEV_OPEN === \"1\"),\n resourceUrl: getMcpOAuthAudiences(event),\n });\n if (!authResult.authed) {\n setResponseStatus(event, 401);\n setResponseHeader(event, \"WWW-Authenticate\", buildMcpOAuthChallenge(event));\n return buildUnauthorizedBody(event);\n }\n\n // Read POST bodies through h3 exactly once. `createMcpHandler` accepts the\n // parsed value, so neither its modern classifier nor its legacy fallback\n // consumes the request stream a second time.\n const body = method === \"POST\" ? await readBody(event) : undefined;\n\n // Optional diagnostics for host capability negotiation. Keep disabled by\n // default because initialize payloads can include client-specific metadata.\n if (process.env.MCP_DEBUG_INIT && body) {\n const msgs = Array.isArray(body) ? body : [body];\n const init = msgs.find(\n (m): m is { params?: { capabilities?: unknown; clientInfo?: unknown } } =>\n typeof m === \"object\" &&\n m !== null &&\n (m as { method?: unknown }).method === \"initialize\",\n );\n if (init) {\n console.error(\n \"[MCP_DEBUG_INIT] clientInfo=\",\n JSON.stringify(init.params?.clientInfo),\n \"capabilities=\",\n JSON.stringify(init.params?.capabilities),\n );\n }\n }\n\n const serverRequestMeta: MCPRequestMeta = {\n ...requestMeta,\n fullSurface: authResult.fullSurface === true,\n inlineMcpApps:\n requestMeta.inlineMcpApps === true &&\n authResult.identity?.firstPartyMcp === true\n ? true\n : undefined,\n // When the caller minted their token with --full-catalog (catalog_scope:\n // \"full\" JWT claim), bypass the connector-catalog tier filter.\n ...(authResult.fullCatalog === true ? { fullCatalog: true } : {}),\n };\n const { createMcpHandler } = await import(\"@modelcontextprotocol/server\");\n const handler = createMcpHandler(\n () =>\n createMCPServerForRequest(config, authResult.identity, serverRequestMeta),\n {\n legacy: \"stateless\",\n // Ordinary calls stay single-body JSON unless a handler emits a related\n // message before its result. Subscription/listen remains SSE.\n responseMode: \"auto\",\n },\n );\n const webRequest = buildWebRequest(event, method);\n return handler.fetch(\n webRequest,\n method === \"POST\" ? { parsedBody: body } : undefined,\n );\n}\n\n// ---------------------------------------------------------------------------\n// mountMCP — register MCP Streamable HTTP endpoint on H3/Nitro\n// ---------------------------------------------------------------------------\n\n/**\n * Mount an MCP remote server on an H3/Nitro app.\n *\n * Endpoints: `/mcp` (public) and `/_agent-native/mcp` (compatibility).\n * A custom route prefix only mounts that custom endpoint.\n *\n * Uses the v2 Web Standard per-request handler with native 2026-07-28 serving\n * and stateless 2025-era fallback. It carries no in-memory protocol session\n * across invocations and works unchanged on Node, Nitro/Netlify web runtimes,\n * Cloudflare, Deno, and Bun.\n *\n * Auth: Bearer token matching ACCESS_TOKEN/ACCESS_TOKENS or JWT via A2A_SECRET.\n * No auth required when neither is configured (dev mode).\n */\nexport function mountMCP(\n nitroApp: any,\n config: MCPConfig,\n routePrefix = \"/_agent-native\",\n): void {\n const routePaths =\n routePrefix === \"/_agent-native\"\n ? [...MCP_ROUTE_PREFIXES]\n : [joinMcpRoute(routePrefix, \"/mcp\")];\n const handler = defineEventHandler(async (event) => {\n return handleMcpRequest(event as H3Event, config);\n });\n\n for (const routePath of routePaths) {\n getH3App(nitroApp).use(routePath, handler);\n }\n\n if (process.env.DEBUG)\n console.log(\n `[mcp] Mounted MCP server at ${routePaths.join(\" and \")} (${Object.keys(config.actions).length} tools${config.askAgent ? \" + ask-agent\" : \"\"})`,\n );\n}\n"]}
|
package/dist/mcp/stdio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAQH,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA6PD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAef"}
|
package/dist/mcp/stdio.js
CHANGED
|
@@ -113,16 +113,17 @@ async function runProxy(opts) {
|
|
|
113
113
|
`\`agent-native mcp serve --standalone\` to build the server from disk.`);
|
|
114
114
|
}
|
|
115
115
|
const target = `${origin}${mcpSubpath}`;
|
|
116
|
-
const { Client } = await import("@modelcontextprotocol/
|
|
117
|
-
const {
|
|
118
|
-
const {
|
|
119
|
-
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
120
|
-
const { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, } = await import("@modelcontextprotocol/sdk/types.js");
|
|
116
|
+
const { Client, StreamableHTTPClientTransport } = await import("@modelcontextprotocol/client");
|
|
117
|
+
const { Server } = await import("@modelcontextprotocol/server");
|
|
118
|
+
const { serveStdio } = await import("@modelcontextprotocol/server/stdio");
|
|
121
119
|
// --- Upstream HTTP client -------------------------------------------------
|
|
122
120
|
const clientTransport = new StreamableHTTPClientTransport(new URL(target), {
|
|
123
121
|
requestInit: { headers: authHeaders(env) },
|
|
124
122
|
});
|
|
125
|
-
const client = new Client({ name: "agent-native-mcp-proxy", version: "1.0.0" }, {
|
|
123
|
+
const client = new Client({ name: "agent-native-mcp-proxy", version: "1.0.0" }, {
|
|
124
|
+
capabilities: {},
|
|
125
|
+
versionNegotiation: { mode: "auto" },
|
|
126
|
+
});
|
|
126
127
|
await client.connect(clientTransport);
|
|
127
128
|
log(`Proxying stdio ⇄ ${target} (app: ${appId})`);
|
|
128
129
|
// --- Downstream stdio server ---------------------------------------------
|
|
@@ -133,36 +134,38 @@ async function runProxy(opts) {
|
|
|
133
134
|
if (upstreamCapabilities?.extensions) {
|
|
134
135
|
capabilities.extensions = upstreamCapabilities.extensions;
|
|
135
136
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
141
|
-
// Forward the call verbatim; the upstream appends the deep-link block.
|
|
142
|
-
return client.callTool(request.params);
|
|
143
|
-
});
|
|
144
|
-
if (upstreamCapabilities?.resources) {
|
|
145
|
-
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
|
|
146
|
-
return client.listResources(request.params);
|
|
137
|
+
const stdio = serveStdio(() => {
|
|
138
|
+
const server = new Server({ name: `agent-native-${appId}`, version: "1.0.0" }, { capabilities });
|
|
139
|
+
server.setRequestHandler("tools/list", async (request) => {
|
|
140
|
+
return client.listTools(request.params);
|
|
147
141
|
});
|
|
148
|
-
server.setRequestHandler(
|
|
149
|
-
|
|
142
|
+
server.setRequestHandler("tools/call", async (request) => {
|
|
143
|
+
// Forward the call verbatim; the upstream appends the deep-link block.
|
|
144
|
+
return client.callTool(request.params);
|
|
150
145
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
146
|
+
if (upstreamCapabilities?.resources) {
|
|
147
|
+
server.setRequestHandler("resources/list", async (request) => {
|
|
148
|
+
return client.listResources(request.params);
|
|
149
|
+
});
|
|
150
|
+
server.setRequestHandler("resources/templates/list", async (request) => {
|
|
151
|
+
return client.listResourceTemplates(request.params);
|
|
152
|
+
});
|
|
153
|
+
server.setRequestHandler("resources/read", async (request) => {
|
|
154
|
+
return client.readResource(request.params);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return server;
|
|
158
|
+
}, { legacy: "serve" });
|
|
157
159
|
// Keep the proxy alive until the client/transport closes.
|
|
158
160
|
await new Promise((resolve) => {
|
|
159
161
|
const done = () => resolve();
|
|
160
|
-
stdioTransport.onclose = done;
|
|
161
162
|
clientTransport.onclose = done;
|
|
163
|
+
process.stdin.once("end", done);
|
|
162
164
|
process.once("SIGINT", done);
|
|
163
165
|
process.once("SIGTERM", done);
|
|
164
166
|
});
|
|
165
167
|
try {
|
|
168
|
+
await stdio.close();
|
|
166
169
|
await client.close();
|
|
167
170
|
}
|
|
168
171
|
catch {
|
|
@@ -200,10 +203,10 @@ async function runStandalone(opts) {
|
|
|
200
203
|
}
|
|
201
204
|
const { autoDiscoverActions } = await import("../server/action-discovery.js");
|
|
202
205
|
const { createMCPServerForRequest } = await import("./build-server.js");
|
|
203
|
-
const {
|
|
206
|
+
const { serveStdio } = await import("@modelcontextprotocol/server/stdio");
|
|
204
207
|
const actions = await autoDiscoverActions(cwd);
|
|
205
208
|
log(`Standalone: discovered ${Object.keys(actions).length} action(s) in ${cwd}`);
|
|
206
|
-
const
|
|
209
|
+
const stdio = serveStdio(() => createMCPServerForRequest({
|
|
207
210
|
name: appId.charAt(0).toUpperCase() + appId.slice(1),
|
|
208
211
|
appId,
|
|
209
212
|
description: `Agent-native ${appId} app (standalone MCP)`,
|
|
@@ -219,15 +222,13 @@ async function runStandalone(opts) {
|
|
|
219
222
|
clientName: "agent-native-mcp-standalone",
|
|
220
223
|
// Compact by default; opt into the full catalog with the env flag.
|
|
221
224
|
fullCatalog: process.env.AGENT_NATIVE_MCP_FULL_CATALOG === "1",
|
|
222
|
-
});
|
|
223
|
-
const transport = new StdioServerTransport();
|
|
224
|
-
await server.connect(transport);
|
|
225
|
+
}), { legacy: "serve" });
|
|
225
226
|
await new Promise((resolve) => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
process.once("
|
|
229
|
-
process.once("SIGTERM", done);
|
|
227
|
+
process.stdin.once("end", resolve);
|
|
228
|
+
process.once("SIGINT", resolve);
|
|
229
|
+
process.once("SIGTERM", resolve);
|
|
230
230
|
});
|
|
231
|
+
await stdio.close();
|
|
231
232
|
}
|
|
232
233
|
/**
|
|
233
234
|
* Entry point for `agent-native mcp serve`. Defaults to proxy mode; pass
|
package/dist/mcp/stdio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP **stdio** transport for the `agent-native mcp serve` command.\n *\n * This is the binary external coding agents (Claude Code, Claude Cowork,\n * Codex) actually launch — they speak MCP over a child process's stdio, not\n * HTTP. We expose the agent-native app's MCP surface over stdio in two modes:\n *\n * - **proxy (default)** — connect an MCP `Client` over\n * `StreamableHTTPClientTransport` to the *already-running* local app's\n * `http://127.0.0.1:<port>/mcp` (falling back to the legacy\n * `/_agent-native/mcp` path), and run a stdio `Server` that forwards tools\n * and optional MCP App resources to it. The live app is the single source\n * of truth: HMR'd actions, the real registry, correct per-request deep\n * links, and tenant scoping all come for free. If the app isn't running,\n * we wait briefly for it (the workspace gateway boots it lazily on first\n * request).\n *\n * - **standalone (`--standalone`)** — no running server, no HMR. Build the\n * MCP server in-process from `autoDiscoverActions(cwd)` +\n * `createMCPServerForRequest`, connected straight to a\n * `StdioServerTransport`. Useful in CI / when nothing is serving.\n *\n * Node-only: imports `node:*` and the SDK stdio/http transports. Never part\n * of the serverless bundle.\n */\n\nimport type { ServerCapabilities } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport {\n MCP_LEGACY_ROUTE_PREFIX,\n MCP_PUBLIC_ROUTE_PREFIX,\n} from \"./route-paths.js\";\nimport { resolveLocalAppOrigin } from \"./workspace-resolve.js\";\n\nexport interface RunMCPStdioOptions {\n /** App id to bridge to (workspace). Optional in a single-app project. */\n appId?: string;\n /** Explicit port of the running app's dev server. Overrides discovery. */\n port?: number;\n /** Skip the HTTP proxy and build the server in-process from disk. */\n standalone?: boolean;\n /** Working directory (defaults to process.cwd()). */\n cwd?: string;\n /** Env (defaults to process.env). */\n env?: NodeJS.ProcessEnv;\n /** Max ms to wait for the running app before failing (proxy mode). */\n waitForAppMs?: number;\n}\n\nconst MCP_SUBPATHS = [\n MCP_PUBLIC_ROUTE_PREFIX,\n MCP_LEGACY_ROUTE_PREFIX,\n] as const;\n\nfunction log(msg: string): void {\n // stderr only — stdout is the MCP protocol channel and must stay clean.\n process.stderr.write(`[mcp] ${msg}\\n`);\n}\n\n/**\n * Owner identity the installer wrote into the client config's env. Passed\n * through to the HTTP MCP endpoint as a JWT/identity bearer (when present)\n * so tool runs stay tenant-scoped. For local dev with a static ACCESS_TOKEN\n * the email is informational; for hosted JWT auth the token already carries\n * `sub`, so we only add an `X-Agent-Native-Owner-Email` hint header.\n */\nfunction authHeaders(env: NodeJS.ProcessEnv): Record<string, string> {\n const headers: Record<string, string> = {\n \"X-Agent-Native-MCP-Client\": \"agent-native-mcp-proxy\",\n };\n // Default to the compact/connector catalog + tool-search like every other\n // client. The local CLI no longer auto-pulls the full ~105-tool catalog;\n // opt in explicitly with AGENT_NATIVE_MCP_FULL_CATALOG=1 when you really want\n // every tool schema loaded up front.\n if (env.AGENT_NATIVE_MCP_FULL_CATALOG === \"1\") {\n headers[\"X-Agent-Native-MCP-Full-Catalog\"] = \"1\";\n }\n const token = env.ACCESS_TOKEN || env.AGENT_NATIVE_MCP_TOKEN;\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n const owner = env.AGENT_NATIVE_OWNER_EMAIL;\n if (owner) headers[\"X-Agent-Native-Owner-Email\"] = owner;\n return headers;\n}\n\nasync function probeOrigin(\n origin: string,\n subpath: string,\n timeoutMs = 800,\n): Promise<boolean> {\n try {\n const res = await fetch(`${origin}${subpath}`, {\n method: \"GET\",\n signal: AbortSignal.timeout(timeoutMs),\n });\n // Any HTTP response (even 401/405/406) means the server is up.\n return res.status > 0;\n } catch {\n return false;\n }\n}\n\nasync function resolveMcpSubpath(origin: string): Promise<string | null> {\n for (const subpath of MCP_SUBPATHS) {\n if (await probeOrigin(origin, subpath)) return subpath;\n }\n return null;\n}\n\n/**\n * Proxy mode: stdio Server ⇄ HTTP Client to the running app.\n *\n * We register the standard handlers on the stdio server and forward them\n * verbatim to the upstream HTTP MCP server via the SDK `Client`. The upstream\n * owns tool definitions, results, MCP App resources, and the appended\n * deep-link block / `_meta`, so nothing is duplicated here.\n */\nasync function runProxy(opts: RunMCPStdioOptions): Promise<void> {\n const { origin, appId } = await resolveLocalAppOrigin({\n cwd: opts.cwd,\n env: opts.env,\n appId: opts.appId,\n port: opts.port,\n });\n const env = opts.env ?? process.env;\n // Wait for the app to come up. The workspace gateway lazily boots an app's\n // dev server on first request, so a fresh `mcp serve` may briefly race the\n // boot. Hit the gateway path too so the lazy start is triggered.\n const deadline = Date.now() + (opts.waitForAppMs ?? 60_000);\n let mcpSubpath = await resolveMcpSubpath(origin);\n if (!mcpSubpath) {\n log(`Waiting for ${appId} at ${origin} …`);\n while (!mcpSubpath && Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 750));\n mcpSubpath = await resolveMcpSubpath(origin);\n }\n }\n if (!mcpSubpath) {\n throw new Error(\n `Timed out waiting for the local app at ${origin}. Start it with ` +\n `\\`agent-native dev\\` (or \\`agent-native workspace-dev\\`), or run ` +\n `\\`agent-native mcp serve --standalone\\` to build the server from disk.`,\n );\n }\n const target = `${origin}${mcpSubpath}`;\n\n const { Client } = await import(\"@modelcontextprotocol/sdk/client/index.js\");\n const { StreamableHTTPClientTransport } =\n await import(\"@modelcontextprotocol/sdk/client/streamableHttp.js\");\n const { Server } = await import(\"@modelcontextprotocol/sdk/server/index.js\");\n const { StdioServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/stdio.js\");\n const {\n ListToolsRequestSchema,\n CallToolRequestSchema,\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n ListResourceTemplatesRequestSchema,\n } = await import(\"@modelcontextprotocol/sdk/types.js\");\n\n // --- Upstream HTTP client -------------------------------------------------\n const clientTransport = new StreamableHTTPClientTransport(new URL(target), {\n requestInit: { headers: authHeaders(env) },\n });\n const client = new Client(\n { name: \"agent-native-mcp-proxy\", version: \"1.0.0\" },\n { capabilities: {} },\n );\n await client.connect(clientTransport);\n log(`Proxying stdio ⇄ ${target} (app: ${appId})`);\n\n // --- Downstream stdio server ---------------------------------------------\n const upstreamCapabilities = client.getServerCapabilities();\n const capabilities: ServerCapabilities = { tools: {} };\n if (upstreamCapabilities?.resources) capabilities.resources = {};\n if (upstreamCapabilities?.extensions) {\n capabilities.extensions = upstreamCapabilities.extensions;\n }\n\n const server = new Server(\n { name: `agent-native-${appId}`, version: \"1.0.0\" },\n { capabilities },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async (request: any) => {\n return client.listTools(request.params);\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request: any) => {\n // Forward the call verbatim; the upstream appends the deep-link block.\n return client.callTool(request.params);\n });\n\n if (upstreamCapabilities?.resources) {\n server.setRequestHandler(\n ListResourcesRequestSchema,\n async (request: any) => {\n return client.listResources(request.params);\n },\n );\n\n server.setRequestHandler(\n ListResourceTemplatesRequestSchema,\n async (request: any) => {\n return client.listResourceTemplates(request.params);\n },\n );\n\n server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request: any) => {\n return client.readResource(request.params);\n },\n );\n }\n\n const stdioTransport = new StdioServerTransport();\n await server.connect(stdioTransport);\n\n // Keep the proxy alive until the client/transport closes.\n await new Promise<void>((resolve) => {\n const done = () => resolve();\n stdioTransport.onclose = done;\n clientTransport.onclose = done;\n process.once(\"SIGINT\", done);\n process.once(\"SIGTERM\", done);\n });\n\n try {\n await client.close();\n } catch {\n // best-effort\n }\n}\n\n/**\n * Standalone mode: build the MCP server in-process from disk.\n *\n * No running server, no HMR — actions are discovered via\n * `autoDiscoverActions(cwd)` and the shared `createMCPServerForRequest`\n * builder is reused so behavior (tools, deep links, builtin cross-app tools)\n * matches the HTTP mount exactly.\n */\nasync function runStandalone(opts: RunMCPStdioOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const env = opts.env ?? process.env;\n\n const { resolveLocalAppOrigin } = await import(\"./workspace-resolve.js\");\n let appId = opts.appId ?? \"app\";\n let origin: string | undefined;\n try {\n const resolved = await resolveLocalAppOrigin({\n cwd,\n env,\n appId: opts.appId,\n port: opts.port,\n });\n appId = resolved.appId;\n // Origin is best-effort here (server may not be running) — still useful\n // so a `link` builder's relative deep link becomes an absolute URL.\n origin = resolved.origin;\n } catch {\n // No workspace / can't resolve — fall back to a bare app id.\n }\n\n const { autoDiscoverActions } = await import(\"../server/action-discovery.js\");\n const { createMCPServerForRequest } = await import(\"./build-server.js\");\n const { StdioServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/stdio.js\");\n\n const actions = await autoDiscoverActions(cwd);\n log(\n `Standalone: discovered ${Object.keys(actions).length} action(s) in ${cwd}`,\n );\n\n const server = await createMCPServerForRequest(\n {\n name: appId.charAt(0).toUpperCase() + appId.slice(1),\n appId,\n description: `Agent-native ${appId} app (standalone MCP)`,\n actions,\n // No askAgent in standalone — there is no running engine/runtime here.\n // builtin cross-app tools stay on so `list_apps` / `open_app` /\n // `create_workspace_app` / `list_templates` still work from disk.\n },\n // No verified identity in standalone (no inbound auth header). Runs with\n // platform-default scope, same as a tokenless local HTTP mount.\n undefined,\n {\n origin,\n clientName: \"agent-native-mcp-standalone\",\n // Compact by default; opt into the full catalog with the env flag.\n fullCatalog: process.env.AGENT_NATIVE_MCP_FULL_CATALOG === \"1\",\n },\n );\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n await new Promise<void>((resolve) => {\n const done = () => resolve();\n transport.onclose = done;\n process.once(\"SIGINT\", done);\n process.once(\"SIGTERM\", done);\n });\n}\n\n/**\n * Entry point for `agent-native mcp serve`. Defaults to proxy mode; pass\n * `standalone: true` to build the server from disk with no running app.\n */\nexport async function runMCPStdio(\n opts: RunMCPStdioOptions = {},\n): Promise<void> {\n if (opts.standalone) {\n await runStandalone(opts);\n return;\n }\n try {\n await runProxy(opts);\n } catch (err: any) {\n // Proxy couldn't reach a running app — surface a clear, actionable\n // message on stderr. We do NOT silently fall back to standalone: the\n // caller asked for the live registry; auto-falling-back would hide a\n // broken dev server and serve stale tools.\n log(`Proxy mode failed: ${err?.message ?? err}`);\n throw err;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP **stdio** transport for the `agent-native mcp serve` command.\n *\n * This is the binary external coding agents (Claude Code, Claude Cowork,\n * Codex) actually launch — they speak MCP over a child process's stdio, not\n * HTTP. We expose the agent-native app's MCP surface over stdio in two modes:\n *\n * - **proxy (default)** — connect an MCP `Client` over\n * `StreamableHTTPClientTransport` to the *already-running* local app's\n * `http://127.0.0.1:<port>/mcp` (falling back to the legacy\n * `/_agent-native/mcp` path), and run a stdio `Server` that forwards tools\n * and optional MCP App resources to it. The live app is the single source\n * of truth: HMR'd actions, the real registry, correct per-request deep\n * links, and tenant scoping all come for free. If the app isn't running,\n * we wait briefly for it (the workspace gateway boots it lazily on first\n * request).\n *\n * - **standalone (`--standalone`)** — no running server, no HMR. Build the\n * MCP server in-process from `autoDiscoverActions(cwd)` +\n * `createMCPServerForRequest`, connected straight to a\n * `StdioServerTransport`. Useful in CI / when nothing is serving.\n *\n * Node-only: imports `node:*` and the SDK stdio/http transports. Never part\n * of the serverless bundle.\n */\n\nimport {\n MCP_LEGACY_ROUTE_PREFIX,\n MCP_PUBLIC_ROUTE_PREFIX,\n} from \"./route-paths.js\";\nimport { resolveLocalAppOrigin } from \"./workspace-resolve.js\";\n\nexport interface RunMCPStdioOptions {\n /** App id to bridge to (workspace). Optional in a single-app project. */\n appId?: string;\n /** Explicit port of the running app's dev server. Overrides discovery. */\n port?: number;\n /** Skip the HTTP proxy and build the server in-process from disk. */\n standalone?: boolean;\n /** Working directory (defaults to process.cwd()). */\n cwd?: string;\n /** Env (defaults to process.env). */\n env?: NodeJS.ProcessEnv;\n /** Max ms to wait for the running app before failing (proxy mode). */\n waitForAppMs?: number;\n}\n\nconst MCP_SUBPATHS = [\n MCP_PUBLIC_ROUTE_PREFIX,\n MCP_LEGACY_ROUTE_PREFIX,\n] as const;\n\nfunction log(msg: string): void {\n // stderr only — stdout is the MCP protocol channel and must stay clean.\n process.stderr.write(`[mcp] ${msg}\\n`);\n}\n\n/**\n * Owner identity the installer wrote into the client config's env. Passed\n * through to the HTTP MCP endpoint as a JWT/identity bearer (when present)\n * so tool runs stay tenant-scoped. For local dev with a static ACCESS_TOKEN\n * the email is informational; for hosted JWT auth the token already carries\n * `sub`, so we only add an `X-Agent-Native-Owner-Email` hint header.\n */\nfunction authHeaders(env: NodeJS.ProcessEnv): Record<string, string> {\n const headers: Record<string, string> = {\n \"X-Agent-Native-MCP-Client\": \"agent-native-mcp-proxy\",\n };\n // Default to the compact/connector catalog + tool-search like every other\n // client. The local CLI no longer auto-pulls the full ~105-tool catalog;\n // opt in explicitly with AGENT_NATIVE_MCP_FULL_CATALOG=1 when you really want\n // every tool schema loaded up front.\n if (env.AGENT_NATIVE_MCP_FULL_CATALOG === \"1\") {\n headers[\"X-Agent-Native-MCP-Full-Catalog\"] = \"1\";\n }\n const token = env.ACCESS_TOKEN || env.AGENT_NATIVE_MCP_TOKEN;\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n const owner = env.AGENT_NATIVE_OWNER_EMAIL;\n if (owner) headers[\"X-Agent-Native-Owner-Email\"] = owner;\n return headers;\n}\n\nasync function probeOrigin(\n origin: string,\n subpath: string,\n timeoutMs = 800,\n): Promise<boolean> {\n try {\n const res = await fetch(`${origin}${subpath}`, {\n method: \"GET\",\n signal: AbortSignal.timeout(timeoutMs),\n });\n // Any HTTP response (even 401/405/406) means the server is up.\n return res.status > 0;\n } catch {\n return false;\n }\n}\n\nasync function resolveMcpSubpath(origin: string): Promise<string | null> {\n for (const subpath of MCP_SUBPATHS) {\n if (await probeOrigin(origin, subpath)) return subpath;\n }\n return null;\n}\n\n/**\n * Proxy mode: stdio Server ⇄ HTTP Client to the running app.\n *\n * We register the standard handlers on the stdio server and forward them\n * verbatim to the upstream HTTP MCP server via the SDK `Client`. The upstream\n * owns tool definitions, results, MCP App resources, and the appended\n * deep-link block / `_meta`, so nothing is duplicated here.\n */\nasync function runProxy(opts: RunMCPStdioOptions): Promise<void> {\n const { origin, appId } = await resolveLocalAppOrigin({\n cwd: opts.cwd,\n env: opts.env,\n appId: opts.appId,\n port: opts.port,\n });\n const env = opts.env ?? process.env;\n // Wait for the app to come up. The workspace gateway lazily boots an app's\n // dev server on first request, so a fresh `mcp serve` may briefly race the\n // boot. Hit the gateway path too so the lazy start is triggered.\n const deadline = Date.now() + (opts.waitForAppMs ?? 60_000);\n let mcpSubpath = await resolveMcpSubpath(origin);\n if (!mcpSubpath) {\n log(`Waiting for ${appId} at ${origin} …`);\n while (!mcpSubpath && Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 750));\n mcpSubpath = await resolveMcpSubpath(origin);\n }\n }\n if (!mcpSubpath) {\n throw new Error(\n `Timed out waiting for the local app at ${origin}. Start it with ` +\n `\\`agent-native dev\\` (or \\`agent-native workspace-dev\\`), or run ` +\n `\\`agent-native mcp serve --standalone\\` to build the server from disk.`,\n );\n }\n const target = `${origin}${mcpSubpath}`;\n\n const { Client, StreamableHTTPClientTransport } =\n await import(\"@modelcontextprotocol/client\");\n const { Server } = await import(\"@modelcontextprotocol/server\");\n const { serveStdio } = await import(\"@modelcontextprotocol/server/stdio\");\n\n // --- Upstream HTTP client -------------------------------------------------\n const clientTransport = new StreamableHTTPClientTransport(new URL(target), {\n requestInit: { headers: authHeaders(env) },\n });\n const client = new Client(\n { name: \"agent-native-mcp-proxy\", version: \"1.0.0\" },\n {\n capabilities: {},\n versionNegotiation: { mode: \"auto\" },\n },\n );\n await client.connect(clientTransport);\n log(`Proxying stdio ⇄ ${target} (app: ${appId})`);\n\n // --- Downstream stdio server ---------------------------------------------\n const upstreamCapabilities = client.getServerCapabilities();\n const capabilities: NonNullable<\n ReturnType<typeof client.getServerCapabilities>\n > = { tools: {} };\n if (upstreamCapabilities?.resources) capabilities.resources = {};\n if (upstreamCapabilities?.extensions) {\n capabilities.extensions = upstreamCapabilities.extensions;\n }\n\n const stdio = serveStdio(\n () => {\n const server = new Server(\n { name: `agent-native-${appId}`, version: \"1.0.0\" },\n { capabilities },\n );\n\n server.setRequestHandler(\"tools/list\", async (request: any) => {\n return client.listTools(request.params);\n });\n\n server.setRequestHandler(\"tools/call\", async (request: any) => {\n // Forward the call verbatim; the upstream appends the deep-link block.\n return client.callTool(request.params);\n });\n\n if (upstreamCapabilities?.resources) {\n server.setRequestHandler(\"resources/list\", async (request: any) => {\n return client.listResources(request.params);\n });\n\n server.setRequestHandler(\n \"resources/templates/list\",\n async (request: any) => {\n return client.listResourceTemplates(request.params);\n },\n );\n\n server.setRequestHandler(\"resources/read\", async (request: any) => {\n return client.readResource(request.params);\n });\n }\n return server;\n },\n { legacy: \"serve\" },\n );\n\n // Keep the proxy alive until the client/transport closes.\n await new Promise<void>((resolve) => {\n const done = () => resolve();\n clientTransport.onclose = done;\n process.stdin.once(\"end\", done);\n process.once(\"SIGINT\", done);\n process.once(\"SIGTERM\", done);\n });\n\n try {\n await stdio.close();\n await client.close();\n } catch {\n // best-effort\n }\n}\n\n/**\n * Standalone mode: build the MCP server in-process from disk.\n *\n * No running server, no HMR — actions are discovered via\n * `autoDiscoverActions(cwd)` and the shared `createMCPServerForRequest`\n * builder is reused so behavior (tools, deep links, builtin cross-app tools)\n * matches the HTTP mount exactly.\n */\nasync function runStandalone(opts: RunMCPStdioOptions): Promise<void> {\n const cwd = opts.cwd ?? process.cwd();\n const env = opts.env ?? process.env;\n\n const { resolveLocalAppOrigin } = await import(\"./workspace-resolve.js\");\n let appId = opts.appId ?? \"app\";\n let origin: string | undefined;\n try {\n const resolved = await resolveLocalAppOrigin({\n cwd,\n env,\n appId: opts.appId,\n port: opts.port,\n });\n appId = resolved.appId;\n // Origin is best-effort here (server may not be running) — still useful\n // so a `link` builder's relative deep link becomes an absolute URL.\n origin = resolved.origin;\n } catch {\n // No workspace / can't resolve — fall back to a bare app id.\n }\n\n const { autoDiscoverActions } = await import(\"../server/action-discovery.js\");\n const { createMCPServerForRequest } = await import(\"./build-server.js\");\n const { serveStdio } = await import(\"@modelcontextprotocol/server/stdio\");\n\n const actions = await autoDiscoverActions(cwd);\n log(\n `Standalone: discovered ${Object.keys(actions).length} action(s) in ${cwd}`,\n );\n\n const stdio = serveStdio(\n () =>\n createMCPServerForRequest(\n {\n name: appId.charAt(0).toUpperCase() + appId.slice(1),\n appId,\n description: `Agent-native ${appId} app (standalone MCP)`,\n actions,\n // No askAgent in standalone — there is no running engine/runtime here.\n // builtin cross-app tools stay on so `list_apps` / `open_app` /\n // `create_workspace_app` / `list_templates` still work from disk.\n },\n // No verified identity in standalone (no inbound auth header). Runs with\n // platform-default scope, same as a tokenless local HTTP mount.\n undefined,\n {\n origin,\n clientName: \"agent-native-mcp-standalone\",\n // Compact by default; opt into the full catalog with the env flag.\n fullCatalog: process.env.AGENT_NATIVE_MCP_FULL_CATALOG === \"1\",\n },\n ),\n { legacy: \"serve\" },\n );\n\n await new Promise<void>((resolve) => {\n process.stdin.once(\"end\", resolve);\n process.once(\"SIGINT\", resolve);\n process.once(\"SIGTERM\", resolve);\n });\n await stdio.close();\n}\n\n/**\n * Entry point for `agent-native mcp serve`. Defaults to proxy mode; pass\n * `standalone: true` to build the server from disk with no running app.\n */\nexport async function runMCPStdio(\n opts: RunMCPStdioOptions = {},\n): Promise<void> {\n if (opts.standalone) {\n await runStandalone(opts);\n return;\n }\n try {\n await runProxy(opts);\n } catch (err: any) {\n // Proxy couldn't reach a running app — surface a clear, actionable\n // message on stderr. We do NOT silently fall back to standalone: the\n // caller asked for the live registry; auto-falling-back would hide a\n // broken dev server and serve stale tools.\n log(`Proxy mode failed: ${err?.message ?? err}`);\n throw err;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/mcp-client/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAO9D,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC,MAAM,WAAW,OAAO;IACtB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAyBD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS/C;AAED,MAAM,WAAW,uBAAuB;IACtC,iCAAiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA2FD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,GAAG,CAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD;6EACyE;IACzE,OAAO,CAAC,gBAAgB,CAAuC;IAE/D,YAAY,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,OAAO,GAAE,uBAA4B,EAG1E;IAED,wDAAwD;IACxD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;+EAC2E;IAC3E,SAAS,IAAI,SAAS,GAAG,IAAI,CAE5B;IAED,wEAAwE;IACxE,IAAI,iBAAiB,IAAI,MAAM,EAAE,CAGhC;IAED,2EAA2E;IAC3E,IAAI,gBAAgB,IAAI,MAAM,EAAE,CAI/B;IAED;;;OAGG;YACW,OAAO;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/mcp-client/manager.ts"],"names":[],"mappings":"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"}
|