@cursor/july 0.1.96 → 0.1.99
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/AGENTS.md +1 -1
- package/README.md +3 -2
- package/dist/bin/agent-serve.js +13 -3
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +16 -0
- package/dist/channels/origin/api.d.ts +15 -4
- package/dist/channels/origin/api.d.ts.map +1 -1
- package/dist/channels/origin/api.js +19 -3
- package/dist/channels/origin/binding.d.ts +11 -0
- package/dist/channels/origin/binding.d.ts.map +1 -1
- package/dist/channels/origin/binding.js +41 -25
- package/dist/channels/origin/index.d.ts +1 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +1 -0
- package/dist/channels/origin/origin-channel.d.ts +2 -0
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +40 -4
- package/dist/channels/origin/reactions.d.ts +56 -0
- package/dist/channels/origin/reactions.d.ts.map +1 -0
- package/dist/channels/origin/reactions.js +67 -0
- package/dist/channels/origin/types.d.ts +11 -0
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/approvals.d.ts +16 -0
- package/dist/channels/slack/approvals.d.ts.map +1 -1
- package/dist/channels/slack/approvals.js +86 -0
- package/dist/channels/slack/cli-project.d.ts +19 -0
- package/dist/channels/slack/cli-project.d.ts.map +1 -0
- package/dist/channels/slack/cli-project.js +234 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +142 -63
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +1 -1
- package/dist/channels/slack/init.d.ts +3 -2
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +5 -5
- package/dist/channels/slack/interactive.d.ts +2 -1
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +15 -4
- package/dist/channels/slack/live-delivery.d.ts +1 -1
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +4 -2
- package/dist/channels/slack/manifest.d.ts +1 -1
- package/dist/channels/slack/manifest.js +1 -1
- package/dist/channels/slack/progress-delivery.d.ts +28 -0
- package/dist/channels/slack/progress-delivery.d.ts.map +1 -0
- package/dist/channels/slack/progress-delivery.js +115 -0
- package/dist/channels/slack/setup.d.ts +1 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +10 -6
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +1 -0
- package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
- package/dist/channels/slack/tool-approval-events.js +91 -1
- package/dist/channels/slack/types.d.ts +9 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.jXleCmOc.js → app.BplEAZ3S.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.8LhyglIT.js → VPLocalSearchBox.CHXyv4wP.js} +1 -1
- package/dist/docs/assets/chunks/{theme.9ged-pr2.js → theme.BTcsZmjQ.js} +2 -2
- package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
- package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
- package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.js → reference_cli.md.DfoeyvL0.js} +9 -6
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.lean.js → reference_cli.md.DfoeyvL0.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
- package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.BEJx9XVj.js} +2 -2
- package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
- package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.CvAHsdSp.js} +10 -2
- package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.CvAHsdSp.lean.js} +1 -1
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/deployment.md +5 -4
- package/dist/docs/design/runtime-abstraction.md +1757 -0
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +8 -8
- package/dist/docs/guides/mcp-oauth.md +26 -8
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +17 -33
- package/dist/docs/guides/slack.md +92 -201
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +5 -3
- package/dist/docs/llms-full.txt +2065 -637
- package/dist/docs/llms.txt +3 -2
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/agent-config.md +2 -2
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +13 -10
- package/dist/docs/reference/cli.md +32 -16
- package/dist/docs/reference/connections.html +9 -8
- package/dist/docs/reference/connections.md +6 -3
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +7 -7
- package/dist/docs/reference/http-api.md +3 -1
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/sessions.md +4 -2
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +15 -7
- package/dist/docs/reference/tools.md +34 -2
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +28 -0
- package/dist/docs/templates/agents-md.md +105 -0
- package/dist/docs/templates/code-wiki.html +5 -5
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +5 -5
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +2 -2
- package/dist/evals/run-facts.d.ts.map +1 -1
- package/dist/evals/run-facts.js +27 -0
- package/dist/files-backends/cursor-hosted.d.ts +3 -2
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +15 -9
- package/dist/internal/approval-gate.d.ts +12 -13
- package/dist/internal/approval-gate.d.ts.map +1 -1
- package/dist/internal/approval-gate.js +16 -21
- package/dist/internal/as-of.d.ts +19 -0
- package/dist/internal/as-of.d.ts.map +1 -0
- package/dist/internal/as-of.js +82 -0
- package/dist/internal/chat-client.js +10 -0
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +149 -21
- package/dist/internal/cli-mcp-oauth.js +8 -18
- package/dist/internal/cli-slack-manual.d.ts +24 -2
- package/dist/internal/cli-slack-manual.d.ts.map +1 -1
- package/dist/internal/cli-slack-manual.js +251 -20
- package/dist/internal/cli-slack.d.ts +9 -2
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +29 -82
- package/dist/internal/cursor/account-mcp.d.ts +1 -0
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +17 -0
- package/dist/internal/cursor-agent-template.d.ts +1 -1
- package/dist/internal/cursor-agent-template.d.ts.map +1 -1
- package/dist/internal/cursor-agent-template.js +1 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +5 -6
- package/dist/internal/deploy-client.d.ts +17 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +31 -10
- package/dist/internal/env-file.d.ts +19 -0
- package/dist/internal/env-file.d.ts.map +1 -0
- package/dist/internal/env-file.js +90 -0
- package/dist/internal/framework-file-storage.d.ts +11 -17
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +17 -40
- package/dist/internal/framework-storage-selection.d.ts +13 -11
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +37 -26
- package/dist/internal/hosted-admission-adapter.d.ts +28 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -0
- package/dist/internal/hosted-admission-adapter.js +7 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +13 -1
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +8 -1
- package/dist/internal/hosted-delivery.d.ts +21 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +101 -34
- package/dist/internal/hosted-execution-diag.d.ts +59 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
- package/dist/internal/hosted-execution-diag.js +187 -0
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +85 -2
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +2 -0
- package/dist/internal/logs-client.d.ts +5 -0
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +5 -0
- package/dist/internal/mcp-endpoint.js +2 -3
- package/dist/internal/mcp-host.d.ts +10 -0
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +57 -8
- package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
- package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-on-demand.js +287 -0
- package/dist/internal/mcp-oauth-persist.d.ts +42 -0
- package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-persist.js +92 -0
- package/dist/internal/mcp-oauth.d.ts +1 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +10 -2
- package/dist/internal/null-kv-storage.d.ts +48 -0
- package/dist/internal/null-kv-storage.d.ts.map +1 -0
- package/dist/internal/null-kv-storage.js +58 -0
- package/dist/internal/otel/collector.d.ts.map +1 -1
- package/dist/internal/otel/collector.js +22 -9
- package/dist/internal/server.d.ts +6 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +123 -33
- package/dist/internal/session-engine.d.ts +88 -3
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +538 -46
- package/dist/internal/session-run-log.d.ts +120 -0
- package/dist/internal/session-run-log.d.ts.map +1 -0
- package/dist/internal/session-run-log.js +359 -0
- package/dist/internal/sessions-client.d.ts +9 -7
- package/dist/internal/sessions-client.d.ts.map +1 -1
- package/dist/internal/sessions-client.js +3 -1
- package/dist/internal/storage-coordinator.d.ts +13 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +37 -6
- package/dist/internal/storage-roles.d.ts +5 -0
- package/dist/internal/storage-roles.d.ts.map +1 -1
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +10 -0
- package/dist/internal/tool-policy.d.ts +29 -9
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +24 -0
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +10 -0
- package/dist/internal/turn-outbox.d.ts +24 -0
- package/dist/internal/turn-outbox.d.ts.map +1 -0
- package/dist/internal/turn-outbox.js +80 -0
- package/dist/playground/assets/index-D7rGZNjy.css +1 -0
- package/dist/playground/assets/index-jzNbJENa.js +69 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +1 -1
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +12 -0
- package/dist/storage-protocol.d.ts +8 -0
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +8 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/tools.d.ts +12 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +88 -7
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +5 -3
- package/docs/deployment.md +5 -4
- package/docs/design/runtime-abstraction.md +1757 -0
- package/docs/guides/mcp-oauth.md +26 -8
- package/docs/guides/slack.md +93 -202
- package/docs/reference/agent-config.md +2 -2
- package/docs/reference/cli.md +32 -16
- package/docs/reference/connections.md +6 -3
- package/docs/reference/http-api.md +3 -1
- package/docs/reference/sessions.md +4 -2
- package/docs/reference/tools.md +34 -2
- package/docs/templates/agents-md.md +110 -0
- package/docs/troubleshooting.md +2 -2
- package/package.json +1 -1
- package/skills/create-agent/SKILL.md +2 -1
- package/skills/mcp-auth/SKILL.md +6 -3
- package/skills/setup-slack/SKILL.md +23 -13
- package/src/bin/agent-serve.ts +12 -1
- package/src/channels/github/github-channel.ts +17 -0
- package/src/channels/origin/api.ts +24 -5
- package/src/channels/origin/binding.ts +55 -26
- package/src/channels/origin/index.ts +1 -0
- package/src/channels/origin/origin-channel.ts +78 -10
- package/src/channels/origin/reactions.ts +82 -0
- package/src/channels/origin/types.ts +11 -0
- package/src/channels/slack/approvals.ts +105 -0
- package/src/channels/slack/cli-project.ts +267 -0
- package/src/channels/slack/defaults.ts +165 -74
- package/src/channels/slack/dispatch.ts +2 -0
- package/src/channels/slack/init.ts +10 -5
- package/src/channels/slack/interactive.ts +35 -9
- package/src/channels/slack/live-delivery.ts +5 -3
- package/src/channels/slack/manifest.ts +1 -1
- package/src/channels/slack/progress-delivery.ts +133 -0
- package/src/channels/slack/setup.ts +10 -6
- package/src/channels/slack/slack-channel.ts +1 -0
- package/src/channels/slack/tool-approval-events.ts +93 -0
- package/src/channels/slack/types.ts +9 -1
- package/src/evals/run-facts.ts +32 -0
- package/src/files-backends/cursor-hosted.ts +3 -2
- package/src/index.ts +4 -0
- package/src/internal/advertise-tools.ts +31 -10
- package/src/internal/approval-gate.ts +20 -29
- package/src/internal/as-of.ts +107 -0
- package/src/internal/chat-client.ts +19 -0
- package/src/internal/cli-deploy.ts +203 -13
- package/src/internal/cli-mcp-oauth.ts +7 -21
- package/src/internal/cli-slack-manual.ts +350 -18
- package/src/internal/cli-slack.ts +40 -84
- package/src/internal/cursor/account-mcp.ts +21 -0
- package/src/internal/cursor-agent-template.ts +1 -0
- package/src/internal/cursor-event-relay.ts +5 -6
- package/src/internal/deploy-client.ts +43 -0
- package/src/internal/env-file.ts +84 -0
- package/src/internal/framework-file-storage.ts +18 -46
- package/src/internal/framework-storage-selection.ts +41 -25
- package/src/internal/hosted-admission-adapter.ts +42 -0
- package/src/internal/hosted-delivery-protocol.ts +14 -2
- package/src/internal/hosted-delivery.ts +169 -44
- package/src/internal/hosted-execution-diag.ts +252 -0
- package/src/internal/http-channel.ts +107 -0
- package/src/internal/init-project.ts +2 -0
- package/src/internal/logs-client.ts +5 -0
- package/src/internal/mcp-endpoint.ts +13 -4
- package/src/internal/mcp-host.ts +77 -11
- package/src/internal/mcp-oauth-on-demand.ts +352 -0
- package/src/internal/mcp-oauth-persist.ts +127 -0
- package/src/internal/mcp-oauth.ts +17 -1
- package/src/internal/null-kv-storage.ts +74 -0
- package/src/internal/otel/collector.ts +30 -0
- package/src/internal/server.ts +159 -11
- package/src/internal/session-engine.ts +691 -57
- package/src/internal/session-run-log.ts +584 -0
- package/src/internal/sessions-client.ts +17 -8
- package/src/internal/storage-coordinator.ts +49 -9
- package/src/internal/storage-roles.ts +7 -0
- package/src/internal/stream-progress.ts +19 -0
- package/src/internal/tool-policy.ts +49 -9
- package/src/internal/trajectory.ts +10 -0
- package/src/internal/turn-outbox.ts +85 -0
- package/src/storage-backends/cursor-hosted.ts +13 -1
- package/src/storage-protocol.ts +10 -0
- package/src/storage.ts +12 -0
- package/src/tools.ts +12 -2
- package/src/types.ts +93 -8
- package/templates/agents-md/README.md +39 -0
- package/templates/agents-md/agent/agent.ts +8 -0
- package/templates/agents-md/agent/channels/github.ts +10 -0
- package/templates/agents-md/agent/channels/queue.ts +28 -0
- package/templates/agents-md/agent/channels/slack.ts +9 -0
- package/templates/agents-md/agent/instructions.md +39 -0
- package/templates/agents-md/agent/lib/collect.ts +439 -0
- package/templates/agents-md/agent/lib/config.ts +8 -0
- package/templates/agents-md/agent/lib/paths.ts +51 -0
- package/templates/agents-md/agent/schedules/weekly.ts +17 -0
- package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
- package/templates/agents-md/evals/agents.eval.ts +135 -0
- package/templates/agents-md/evals/evals.config.ts +5 -0
- package/templates/agents-md/init.json +38 -0
- package/templates/agents-md/package.json +18 -0
- package/templates/agents-md/tsconfig.json +12 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +0 -1
- package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
- package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
- package/dist/docs/assets/index.md.CI93Ltlb.js +0 -5
- package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
- package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
- package/dist/docs/design/agsh.md +0 -406
- package/dist/playground/assets/index-B1DDvBeC.css +0 -1
- package/dist/playground/assets/index-Cx9CclK_.js +0 -88
- package/docs/design/agsh.md +0 -406
- /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.CI93Ltlb.lean.js → index.md.CVeRUOeZ.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.BEJx9XVj.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
|
@@ -74,6 +74,7 @@ type TemplateEntry = {
|
|
|
74
74
|
|
|
75
75
|
const TEMPLATES: Readonly<Record<TemplateName, TemplateEntry>> = {
|
|
76
76
|
"agentic-owners": { dir: "agentic-owners" },
|
|
77
|
+
"agents-md": { dir: "agents-md" },
|
|
77
78
|
"code-wiki": { dir: "code-wiki" },
|
|
78
79
|
demo: { dir: "demo" },
|
|
79
80
|
"pr-autofixer": { dir: "pr-autofixer" },
|
|
@@ -711,6 +712,7 @@ Scaffold a project, then open the playground:
|
|
|
711
712
|
npx ${PACKAGE_NAME} init ./my-agent # installs deps + links agent-sdk onto PATH
|
|
712
713
|
npx ${PACKAGE_NAME} init ./my-demo --template demo # record a PR walkthrough
|
|
713
714
|
npx ${PACKAGE_NAME} init ./code-wiki --template code-wiki # keep wiki pages current after merge
|
|
715
|
+
npx ${PACKAGE_NAME} init ./agents-md --template agents-md # keep AGENTS.md current from last week's PRs and Slack
|
|
714
716
|
npx ${PACKAGE_NAME} init ./my-reviewer --template security-reviewer # review PRs for security bugs
|
|
715
717
|
npx ${PACKAGE_NAME} init ./security-help --template security-help # answer security questions in Slack
|
|
716
718
|
npx ${PACKAGE_NAME} init ./my-triage --template triage-linear # comment on Linear issues
|
|
@@ -114,6 +114,11 @@ export function sanitizeCustomerError(message: string): string {
|
|
|
114
114
|
/**
|
|
115
115
|
* One-line label for `agent-sdk deploy` polling (TTY spinner / non-TTY
|
|
116
116
|
* transitions). Uses statusMessage → progress → raw status.
|
|
117
|
+
*
|
|
118
|
+
* Deliberately does NOT include `lastError`. The spinner redraws with
|
|
119
|
+
* `\r\x1b[2K`, which clears one physical row, so a reason long enough to
|
|
120
|
+
* soft-wrap would leave the earlier rows on screen. Callers print the
|
|
121
|
+
* reason once on the final line instead.
|
|
117
122
|
*/
|
|
118
123
|
export function deployProgressLabel(detail: {
|
|
119
124
|
status: string;
|
|
@@ -293,7 +293,11 @@ function buildConnectionBridgeMcpServer(
|
|
|
293
293
|
if (reason !== undefined) {
|
|
294
294
|
throw new Error(reason);
|
|
295
295
|
}
|
|
296
|
-
const tools = await engine.
|
|
296
|
+
const tools = await engine.runWithMcpPark(
|
|
297
|
+
sessionId ?? "",
|
|
298
|
+
"tools/list",
|
|
299
|
+
() => engine.host.mcp.listTools(connectionName)
|
|
300
|
+
);
|
|
297
301
|
return {
|
|
298
302
|
tools: tools.map((tool) => ({
|
|
299
303
|
name: tool.name,
|
|
@@ -327,10 +331,15 @@ function buildConnectionBridgeMcpServer(
|
|
|
327
331
|
return sdkResultToMcpResult(answer.result);
|
|
328
332
|
}
|
|
329
333
|
try {
|
|
330
|
-
const result = await engine.
|
|
331
|
-
|
|
334
|
+
const result = await engine.runWithMcpPark(
|
|
335
|
+
sessionId ?? "",
|
|
332
336
|
request.params.name,
|
|
333
|
-
|
|
337
|
+
() =>
|
|
338
|
+
engine.host.mcp.callTool(
|
|
339
|
+
connectionName,
|
|
340
|
+
request.params.name,
|
|
341
|
+
request.params.arguments ?? {}
|
|
342
|
+
)
|
|
334
343
|
);
|
|
335
344
|
return {
|
|
336
345
|
// The host client already speaks MCP, so the content array is valid
|
package/src/internal/mcp-host.ts
CHANGED
|
@@ -26,6 +26,47 @@ import type {
|
|
|
26
26
|
import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
|
|
27
27
|
import { createHostMcpOAuthProvider } from "./mcp-oauth.js";
|
|
28
28
|
|
|
29
|
+
export class McpNeedsAuthError extends Error {
|
|
30
|
+
readonly connection: string;
|
|
31
|
+
|
|
32
|
+
constructor(connection: string, cause?: unknown) {
|
|
33
|
+
super(
|
|
34
|
+
`MCP connection "${connection}" needs authorization. Run \`${CLI} mcp oauth ${connection}\`.`
|
|
35
|
+
);
|
|
36
|
+
this.name = "McpNeedsAuthError";
|
|
37
|
+
this.connection = connection;
|
|
38
|
+
if (cause !== undefined) {
|
|
39
|
+
this.cause = cause;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isMcpNeedsAuthError(
|
|
45
|
+
error: unknown
|
|
46
|
+
): error is McpNeedsAuthError {
|
|
47
|
+
return error instanceof McpNeedsAuthError;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function hostMcpCallNeedsAuth(result: HostMcpCallResult): boolean {
|
|
51
|
+
if (result.isError !== true) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const text = result.content
|
|
55
|
+
.map((part) => (part.type === "text" ? part.text : ""))
|
|
56
|
+
.join("\n");
|
|
57
|
+
return text.includes("needsAuth") || text.includes("needs authorization");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function throwIfCallNeedsAuth(
|
|
61
|
+
connection: string,
|
|
62
|
+
result: HostMcpCallResult
|
|
63
|
+
): HostMcpCallResult {
|
|
64
|
+
if (hostMcpCallNeedsAuth(result)) {
|
|
65
|
+
throw new McpNeedsAuthError(connection);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
29
70
|
interface OpenedConnection {
|
|
30
71
|
client: Client;
|
|
31
72
|
close: () => Promise<void>;
|
|
@@ -46,6 +87,7 @@ export interface HostMcpOneOff {
|
|
|
46
87
|
export class McpHost implements HostMcpRegistry {
|
|
47
88
|
private readonly byName = new Map<string, DiscoveredConnection>();
|
|
48
89
|
private readonly clients = new Map<string, Promise<OpenedConnection>>();
|
|
90
|
+
private oauthRedirectUrl: string | undefined;
|
|
49
91
|
|
|
50
92
|
constructor(connections: DiscoveredConnection[]) {
|
|
51
93
|
for (const connection of connections) {
|
|
@@ -53,6 +95,11 @@ export class McpHost implements HostMcpRegistry {
|
|
|
53
95
|
}
|
|
54
96
|
}
|
|
55
97
|
|
|
98
|
+
/** Public serve callback for host OAuth (not the CLI loopback port on pods). */
|
|
99
|
+
setOAuthRedirectUrl(url: string): void {
|
|
100
|
+
this.oauthRedirectUrl = url;
|
|
101
|
+
}
|
|
102
|
+
|
|
56
103
|
/**
|
|
57
104
|
* Register a connection after construction (serve-time resolved peers).
|
|
58
105
|
* Clients open lazily on first use, so adding before first call is safe.
|
|
@@ -82,10 +129,11 @@ export class McpHost implements HostMcpRegistry {
|
|
|
82
129
|
* mapping as registry calls.
|
|
83
130
|
*/
|
|
84
131
|
oneOff(connection: DiscoveredConnection): HostMcpOneOff {
|
|
132
|
+
const redirectUrl = this.oauthRedirectUrl;
|
|
85
133
|
const withFreshClient = async <T>(
|
|
86
134
|
run: (client: Client) => Promise<T>
|
|
87
135
|
): Promise<T> => {
|
|
88
|
-
const opened = await openConnection(connection);
|
|
136
|
+
const opened = await openConnection(connection, redirectUrl);
|
|
89
137
|
try {
|
|
90
138
|
return await run(opened.client);
|
|
91
139
|
} finally {
|
|
@@ -104,7 +152,10 @@ export class McpHost implements HostMcpRegistry {
|
|
|
104
152
|
name: toolName,
|
|
105
153
|
arguments: args,
|
|
106
154
|
});
|
|
107
|
-
return
|
|
155
|
+
return throwIfCallNeedsAuth(
|
|
156
|
+
connection.name,
|
|
157
|
+
normalizeCallResult(result)
|
|
158
|
+
);
|
|
108
159
|
}),
|
|
109
160
|
};
|
|
110
161
|
}
|
|
@@ -119,10 +170,23 @@ export class McpHost implements HostMcpRegistry {
|
|
|
119
170
|
name: toolName,
|
|
120
171
|
arguments: args,
|
|
121
172
|
});
|
|
122
|
-
return normalizeCallResult(result);
|
|
173
|
+
return throwIfCallNeedsAuth(connectionName, normalizeCallResult(result));
|
|
123
174
|
});
|
|
124
175
|
}
|
|
125
176
|
|
|
177
|
+
async dropClient(name: string): Promise<void> {
|
|
178
|
+
const pending = this.clients.get(name);
|
|
179
|
+
this.clients.delete(name);
|
|
180
|
+
if (pending === undefined) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
await (await pending).close();
|
|
185
|
+
} catch {
|
|
186
|
+
// Best-effort teardown.
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
126
190
|
async close(): Promise<void> {
|
|
127
191
|
const opened = await Promise.allSettled([...this.clients.values()]);
|
|
128
192
|
this.clients.clear();
|
|
@@ -198,7 +262,7 @@ export class McpHost implements HostMcpRegistry {
|
|
|
198
262
|
`Unknown MCP connection "${name}". Authored MCP connections: ${known}.`
|
|
199
263
|
);
|
|
200
264
|
}
|
|
201
|
-
return openConnection(connection);
|
|
265
|
+
return openConnection(connection, this.oauthRedirectUrl);
|
|
202
266
|
}
|
|
203
267
|
}
|
|
204
268
|
|
|
@@ -283,13 +347,14 @@ function toToolInfo(tool: {
|
|
|
283
347
|
}
|
|
284
348
|
|
|
285
349
|
async function openConnection(
|
|
286
|
-
connection: DiscoveredConnection
|
|
350
|
+
connection: DiscoveredConnection,
|
|
351
|
+
oauthRedirectUrl?: string
|
|
287
352
|
): Promise<OpenedConnection> {
|
|
288
353
|
const client = new Client({
|
|
289
354
|
name: "agent-serve",
|
|
290
355
|
version: "0.1.0",
|
|
291
356
|
});
|
|
292
|
-
const transport = await createTransport(connection);
|
|
357
|
+
const transport = await createTransport(connection, oauthRedirectUrl);
|
|
293
358
|
try {
|
|
294
359
|
await client.connect(transport);
|
|
295
360
|
} catch (error) {
|
|
@@ -297,10 +362,7 @@ async function openConnection(
|
|
|
297
362
|
error instanceof UnauthorizedError &&
|
|
298
363
|
isOauthHttpTransport(connection.transport)
|
|
299
364
|
) {
|
|
300
|
-
throw new
|
|
301
|
-
`MCP connection "${connection.name}" needs authorization. Run \`${CLI} mcp oauth ${connection.name}\`.`,
|
|
302
|
-
{ cause: error }
|
|
303
|
-
);
|
|
365
|
+
throw new McpNeedsAuthError(connection.name, error);
|
|
304
366
|
}
|
|
305
367
|
throw error;
|
|
306
368
|
}
|
|
@@ -322,7 +384,10 @@ async function openConnection(
|
|
|
322
384
|
};
|
|
323
385
|
}
|
|
324
386
|
|
|
325
|
-
async function createTransport(
|
|
387
|
+
async function createTransport(
|
|
388
|
+
connection: DiscoveredConnection,
|
|
389
|
+
oauthRedirectUrl?: string
|
|
390
|
+
) {
|
|
326
391
|
const transport = connection.transport;
|
|
327
392
|
if ("agent" in transport) {
|
|
328
393
|
// Peers are resolved to concrete URLs by the serve host before any call
|
|
@@ -365,6 +430,7 @@ async function createTransport(connection: DiscoveredConnection) {
|
|
|
365
430
|
? await createHostMcpOAuthProvider({
|
|
366
431
|
identifier: connection.name,
|
|
367
432
|
resourceUrl: transport.url,
|
|
433
|
+
redirectUrl: oauthRedirectUrl,
|
|
368
434
|
})
|
|
369
435
|
: undefined;
|
|
370
436
|
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mid-run host MCP OAuth: mint an authUrl, finish on the public serve
|
|
3
|
+
* callback (file tokens). Deployment secrets persist from the
|
|
4
|
+
* authenticated park, not from that callback.
|
|
5
|
+
*
|
|
6
|
+
* CLI `mcp oauth` still uses the loopback callback. This path is recovery
|
|
7
|
+
* and first-use without a separate `--store` step.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
11
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
12
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
13
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
14
|
+
import { describeError } from "./describe-error.js";
|
|
15
|
+
import { LOG_PREFIX } from "./distribution.js";
|
|
16
|
+
import {
|
|
17
|
+
createHostMcpOAuthProvider,
|
|
18
|
+
FileMcpOAuthStore,
|
|
19
|
+
MCP_OAUTH_CALLBACK_URL,
|
|
20
|
+
} from "./mcp-oauth.js";
|
|
21
|
+
import {
|
|
22
|
+
type McpOauthSecretsTarget,
|
|
23
|
+
type ResolveHostedMcpOauthSecretsArgs,
|
|
24
|
+
resolveHostedMcpOauthSecretsTarget,
|
|
25
|
+
upsertHostMcpOauthSecrets,
|
|
26
|
+
} from "./mcp-oauth-persist.js";
|
|
27
|
+
|
|
28
|
+
export function mcpOauthServeCallbackPath(basePath = ""): string {
|
|
29
|
+
return `${basePath}/v1/mcp-oauth/callback`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function mcpOauthServeCallbackUrl(
|
|
33
|
+
origin: string,
|
|
34
|
+
basePath = ""
|
|
35
|
+
): string {
|
|
36
|
+
return `${origin.replace(/\/$/, "")}${mcpOauthServeCallbackPath(basePath)}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type BeginHostMcpOauthResult =
|
|
40
|
+
| { status: "authorized" }
|
|
41
|
+
| {
|
|
42
|
+
status: "needs_auth";
|
|
43
|
+
authUrl: string;
|
|
44
|
+
state: string;
|
|
45
|
+
finish: (code: string) => Promise<void>;
|
|
46
|
+
abort: () => Promise<void>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export async function beginHostMcpOauth(args: {
|
|
50
|
+
connection: string;
|
|
51
|
+
url: string;
|
|
52
|
+
type?: "http" | "sse";
|
|
53
|
+
headers?: Record<string, string>;
|
|
54
|
+
redirectUrl: string;
|
|
55
|
+
store?: FileMcpOAuthStore;
|
|
56
|
+
}): Promise<BeginHostMcpOauthResult> {
|
|
57
|
+
let authorizationUrl: URL | undefined;
|
|
58
|
+
const provider = await createHostMcpOAuthProvider({
|
|
59
|
+
identifier: args.connection,
|
|
60
|
+
resourceUrl: args.url,
|
|
61
|
+
store: args.store,
|
|
62
|
+
redirectUrl: args.redirectUrl,
|
|
63
|
+
onRedirect: (url) => {
|
|
64
|
+
authorizationUrl = url;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const client = new Client({ name: "agent-sdk-mcp-oauth", version: "0.1.0" });
|
|
69
|
+
const url = new URL(args.url);
|
|
70
|
+
const requestInit =
|
|
71
|
+
args.headers === undefined ? undefined : { headers: args.headers };
|
|
72
|
+
|
|
73
|
+
const makeTransport = ():
|
|
74
|
+
| StreamableHTTPClientTransport
|
|
75
|
+
| SSEClientTransport => {
|
|
76
|
+
if (args.type === "sse") {
|
|
77
|
+
return new SSEClientTransport(url, {
|
|
78
|
+
authProvider: provider,
|
|
79
|
+
requestInit,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return new StreamableHTTPClientTransport(url, {
|
|
83
|
+
authProvider: provider,
|
|
84
|
+
requestInit,
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const transport = makeTransport();
|
|
89
|
+
try {
|
|
90
|
+
await client.connect(transport);
|
|
91
|
+
await client.close().catch(() => undefined);
|
|
92
|
+
return { status: "authorized" };
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (!(error instanceof UnauthorizedError)) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const redirect = authorizationUrl ?? provider.lastRedirectUrl;
|
|
100
|
+
if (redirect === undefined) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Auth required for "${args.connection}" but no authorization URL was provided.`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const state = redirect.searchParams.get("state") ?? "";
|
|
106
|
+
if (state === "") {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Auth required for "${args.connection}" but the authorization URL had no state.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
status: "needs_auth",
|
|
114
|
+
authUrl: redirect.toString(),
|
|
115
|
+
state,
|
|
116
|
+
finish: async (code: string) => {
|
|
117
|
+
await transport.finishAuth(code);
|
|
118
|
+
await transport.close?.().catch(() => undefined);
|
|
119
|
+
},
|
|
120
|
+
abort: async () => {
|
|
121
|
+
await transport.close?.().catch(() => undefined);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
type BoundAttempt = {
|
|
127
|
+
connection: string;
|
|
128
|
+
resourceUrl: string;
|
|
129
|
+
finish: (code: string) => Promise<void>;
|
|
130
|
+
abort: () => Promise<void>;
|
|
131
|
+
sessionId?: string;
|
|
132
|
+
callId?: string;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export type McpOauthCompleteResult = {
|
|
136
|
+
connection: string;
|
|
137
|
+
sessionId?: string;
|
|
138
|
+
callId?: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export class McpOauthOnDemandHub {
|
|
142
|
+
private readonly attempts = new Map<string, BoundAttempt>();
|
|
143
|
+
private readonly completed = new Map<string, BoundAttempt>();
|
|
144
|
+
private readonly finishing = new Map<
|
|
145
|
+
string,
|
|
146
|
+
Promise<McpOauthCompleteResult>
|
|
147
|
+
>();
|
|
148
|
+
private readonly aborted = new Set<string>();
|
|
149
|
+
callbackUrl: string | undefined;
|
|
150
|
+
secrets?: McpOauthSecretsTarget;
|
|
151
|
+
// Identity only — resolve the key at persist, after freeze bind.
|
|
152
|
+
secretsBind?: ResolveHostedMcpOauthSecretsArgs;
|
|
153
|
+
logger?: (line: string) => void;
|
|
154
|
+
private store?: FileMcpOAuthStore;
|
|
155
|
+
|
|
156
|
+
async mint(args: {
|
|
157
|
+
connection: string;
|
|
158
|
+
url: string;
|
|
159
|
+
type?: "http" | "sse";
|
|
160
|
+
headers?: Record<string, string>;
|
|
161
|
+
sessionId?: string;
|
|
162
|
+
}): Promise<{ authUrl: string; state: string } | { authorized: true }> {
|
|
163
|
+
const redirectUrl = this.callbackUrl ?? MCP_OAUTH_CALLBACK_URL;
|
|
164
|
+
const store = this.fileStore();
|
|
165
|
+
const started = await beginHostMcpOauth({
|
|
166
|
+
connection: args.connection,
|
|
167
|
+
url: args.url,
|
|
168
|
+
type: args.type,
|
|
169
|
+
headers: args.headers,
|
|
170
|
+
redirectUrl,
|
|
171
|
+
store,
|
|
172
|
+
});
|
|
173
|
+
if (started.status === "authorized") {
|
|
174
|
+
return { authorized: true };
|
|
175
|
+
}
|
|
176
|
+
this.attempts.set(started.state, {
|
|
177
|
+
connection: args.connection,
|
|
178
|
+
resourceUrl: args.url,
|
|
179
|
+
finish: started.finish,
|
|
180
|
+
abort: started.abort,
|
|
181
|
+
sessionId: args.sessionId,
|
|
182
|
+
});
|
|
183
|
+
return { authUrl: started.authUrl, state: started.state };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async abortCall(sessionId: string, callId: string): Promise<void> {
|
|
187
|
+
await this.dropWhere(
|
|
188
|
+
(attempt) => attempt.sessionId === sessionId && attempt.callId === callId,
|
|
189
|
+
true
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async abortSession(sessionId: string): Promise<void> {
|
|
194
|
+
await this.dropWhere((attempt) => attempt.sessionId === sessionId, false);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async close(): Promise<void> {
|
|
198
|
+
await this.dropWhere(() => true, true);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private async dropWhere(
|
|
202
|
+
match: (attempt: BoundAttempt) => boolean,
|
|
203
|
+
includeCompleted: boolean
|
|
204
|
+
): Promise<void> {
|
|
205
|
+
const jobs: Array<Promise<void>> = [];
|
|
206
|
+
for (const [state, attempt] of this.attempts) {
|
|
207
|
+
if (!match(attempt)) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
this.aborted.add(state);
|
|
211
|
+
this.attempts.delete(state);
|
|
212
|
+
jobs.push(attempt.abort().catch(() => undefined));
|
|
213
|
+
}
|
|
214
|
+
if (includeCompleted) {
|
|
215
|
+
for (const [state, attempt] of this.completed) {
|
|
216
|
+
if (!match(attempt)) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
this.aborted.add(state);
|
|
220
|
+
this.completed.delete(state);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
await Promise.all(jobs);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
bind(
|
|
227
|
+
state: string,
|
|
228
|
+
sessionId: string,
|
|
229
|
+
callId: string
|
|
230
|
+
): "pending" | "already_done" | "unknown" {
|
|
231
|
+
const live = this.attempts.get(state);
|
|
232
|
+
if (live !== undefined) {
|
|
233
|
+
live.sessionId = sessionId;
|
|
234
|
+
live.callId = callId;
|
|
235
|
+
return "pending";
|
|
236
|
+
}
|
|
237
|
+
const done = this.completed.get(state);
|
|
238
|
+
if (done !== undefined) {
|
|
239
|
+
done.sessionId = sessionId;
|
|
240
|
+
done.callId = callId;
|
|
241
|
+
return "already_done";
|
|
242
|
+
}
|
|
243
|
+
return "unknown";
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async complete(state: string, code: string): Promise<McpOauthCompleteResult> {
|
|
247
|
+
if (this.aborted.has(state)) {
|
|
248
|
+
throw new Error("Unknown OAuth state.");
|
|
249
|
+
}
|
|
250
|
+
const pending = this.finishing.get(state);
|
|
251
|
+
if (pending !== undefined) {
|
|
252
|
+
return await pending;
|
|
253
|
+
}
|
|
254
|
+
const attempt = this.attempts.get(state);
|
|
255
|
+
if (attempt === undefined) {
|
|
256
|
+
throw new Error("Unknown OAuth state.");
|
|
257
|
+
}
|
|
258
|
+
const run = this.finishAttempt(state, attempt, code);
|
|
259
|
+
this.finishing.set(state, run);
|
|
260
|
+
return await run;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private async finishAttempt(
|
|
264
|
+
state: string,
|
|
265
|
+
attempt: BoundAttempt,
|
|
266
|
+
code: string
|
|
267
|
+
): Promise<McpOauthCompleteResult> {
|
|
268
|
+
try {
|
|
269
|
+
await attempt.finish(code);
|
|
270
|
+
this.attempts.delete(state);
|
|
271
|
+
if (!this.aborted.has(state)) {
|
|
272
|
+
this.completed.set(state, attempt);
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
connection: attempt.connection,
|
|
276
|
+
sessionId: attempt.sessionId,
|
|
277
|
+
callId: attempt.callId,
|
|
278
|
+
};
|
|
279
|
+
} finally {
|
|
280
|
+
this.finishing.delete(state);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private fileStore(): FileMcpOAuthStore {
|
|
285
|
+
this.store ??= new FileMcpOAuthStore();
|
|
286
|
+
return this.store;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async persistFor(connection: string, resourceUrl: string): Promise<void> {
|
|
290
|
+
const target =
|
|
291
|
+
this.secrets ??
|
|
292
|
+
resolveHostedMcpOauthSecretsTarget(this.secretsBind ?? {});
|
|
293
|
+
if (target === undefined) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const store = this.fileStore();
|
|
297
|
+
const tokens = await store.loadTokens(connection, resourceUrl);
|
|
298
|
+
if (tokens === undefined || tokens.access_token.trim() === "") {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const client = await store.loadClientInformation(connection, resourceUrl);
|
|
302
|
+
try {
|
|
303
|
+
const names = await upsertHostMcpOauthSecrets({
|
|
304
|
+
connection,
|
|
305
|
+
tokens,
|
|
306
|
+
clientId: client?.client_id,
|
|
307
|
+
target,
|
|
308
|
+
});
|
|
309
|
+
this.logger?.(
|
|
310
|
+
`${LOG_PREFIX} MCP OAuth tokens stored on the deployment (${names.join(", ")}).`
|
|
311
|
+
);
|
|
312
|
+
} catch (error) {
|
|
313
|
+
this.logger?.(
|
|
314
|
+
`${LOG_PREFIX} MCP OAuth persist failed for "${connection}": ${describeError(error)}`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async handleCallback(request: Request): Promise<Response> {
|
|
320
|
+
const url = new URL(request.url);
|
|
321
|
+
const code = url.searchParams.get("code");
|
|
322
|
+
const state = url.searchParams.get("state") ?? "";
|
|
323
|
+
if (this.aborted.has(state)) {
|
|
324
|
+
return oauthHtml(404, "<h1>Not found</h1>");
|
|
325
|
+
}
|
|
326
|
+
if (this.completed.has(state)) {
|
|
327
|
+
return oauthHtml(200, "<h1>Authorized</h1><p>Return to the agent.</p>");
|
|
328
|
+
}
|
|
329
|
+
if (!this.attempts.has(state)) {
|
|
330
|
+
return oauthHtml(404, "<h1>Not found</h1>");
|
|
331
|
+
}
|
|
332
|
+
if (code !== null && code !== "") {
|
|
333
|
+
try {
|
|
334
|
+
await this.complete(state, code);
|
|
335
|
+
} catch {
|
|
336
|
+
return oauthHtml(400, "<h1>Authorization failed</h1>");
|
|
337
|
+
}
|
|
338
|
+
if (this.aborted.has(state)) {
|
|
339
|
+
return oauthHtml(404, "<h1>Not found</h1>");
|
|
340
|
+
}
|
|
341
|
+
return oauthHtml(200, "<h1>Authorized</h1><p>Return to the agent.</p>");
|
|
342
|
+
}
|
|
343
|
+
return oauthHtml(400, "<h1>Authorization failed</h1>");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function oauthHtml(status: number, body: string): Response {
|
|
348
|
+
return new Response(`<!doctype html><html><body>${body}</body></html>`, {
|
|
349
|
+
status,
|
|
350
|
+
headers: { "content-type": "text/html; charset=utf-8" },
|
|
351
|
+
});
|
|
352
|
+
}
|