@akira-tl/forgerelay 1.1.0 → 1.1.2
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/CHANGELOG.md +26 -0
- package/README.md +4 -2
- package/dist/activity/runtime/mcp-query-tools.js +16 -10
- package/dist/cli/mcp/external-mcp.js +481 -0
- package/dist/cli/mcp/status.js +295 -0
- package/dist/cli.js +14 -1
- package/dist/lsp/test-support/server-fixture.js +1 -2
- package/dist/mcp/oauth/auth-protocol.js +375 -0
- package/dist/mcp/oauth/oauth-provider.js +11 -12
- package/dist/mcp/oauth/oauth-store.js +2 -2
- package/dist/mcp/oauth/router.js +2 -6
- package/dist/mcp/operations/batch/executor.js +1 -1
- package/dist/mcp/operations/external-mcp/external-mcp-oauth.js +387 -0
- package/dist/mcp/operations/external-mcp/external-mcp-runtime.js +23 -6
- package/dist/mcp/operations/external-mcp/external-mcp.js +178 -23
- package/dist/mcp/operations/native-bulk-mutations.js +1 -1
- package/dist/mcp/process/tools.js +19 -15
- package/dist/mcp/request-context.js +18 -0
- package/dist/mcp/request-meta.js +28 -3
- package/dist/mcp/server/core/capabilities.js +1 -4
- package/dist/mcp/server/operations/runtime/filesystem-tools.js +35 -28
- package/dist/mcp/server/operations/runtime/operation-runtime.js +7 -7
- package/dist/mcp/server/transport/http-server.js +41 -20
- package/dist/mcp/server/workspace/runtime/workspace-open-presentation.js +2 -0
- package/dist/mcp/server/workspace/runtime/workspace-open.js +13 -9
- package/dist/mcp/server/workspace/runtime/workspace-tools.js +31 -27
- package/dist/runtime/config/external-mcp-auth-store.js +225 -0
- package/dist/runtime/config/external-mcp-config.js +76 -22
- package/dist/runtime/config/external-mcp-registry.js +165 -0
- package/dist/runtime/testing/server-fixture.js +4 -4
- package/dist/server.js +15 -9
- package/dist/ui/.vite/manifest.json +297 -298
- package/dist/ui/activity-panel-app.html +1 -1
- package/dist/ui/assets/activity-panel-app-Bw7ZFX2g.js +114 -0
- package/dist/ui/assets/angular-html-DeUNP12X.js +1 -0
- package/dist/ui/assets/{angular-ts-BearSZDb.js → angular-ts-B3v8FKi_.js} +1 -1
- package/dist/ui/assets/{apl-CYQtr-y6.js → apl-Bs3iQm4P.js} +1 -1
- package/dist/ui/assets/{astro-DDzqKIjK.js → astro-D6GHecBY.js} +1 -1
- package/dist/ui/assets/{blade-DkwEyHvQ.js → blade-BMNbVOHv.js} +1 -1
- package/dist/ui/assets/c-BquuA6bv.js +1 -0
- package/dist/ui/assets/{cobol-xBn5JxHE.js → cobol-BuZ6kfps.js} +1 -1
- package/dist/ui/assets/{coffee-BaXXvoJw.js → coffee-DgC5uBzL.js} +1 -1
- package/dist/ui/assets/cpp-BdvWqCaB.js +1 -0
- package/dist/ui/assets/{crystal-DjOpXVU1.js → crystal-0Q5qBvNI.js} +1 -1
- package/dist/ui/assets/css-Be_T8idh.js +1 -0
- package/dist/ui/assets/{edge-DNaRizoR.js → edge-DaGLdgh_.js} +1 -1
- package/dist/ui/assets/{elixir-CwBMwZmy.js → elixir-CMgiFIzB.js} +1 -1
- package/dist/ui/assets/{elm-gOUD2CW3.js → elm-B-ufMlMC.js} +1 -1
- package/dist/ui/assets/{erb-BcR-fjUp.js → erb-CaGiOZM-.js} +1 -1
- package/dist/ui/assets/{git-rebase-BAQPKHF6.js → git-rebase-CpwUWCzK.js} +1 -1
- package/dist/ui/assets/{glimmer-js-P_wOfSz_.js → glimmer-js-BRxccvnE.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-B44aY1fZ.js → glimmer-ts-CgQbPzlT.js} +1 -1
- package/dist/ui/assets/glsl-D7JmHFr0.js +1 -0
- package/dist/ui/assets/graphql-C8n0eUBK.js +1 -0
- package/dist/ui/assets/{hack-ddU2k0nt.js → hack-lVN7KVQv.js} +1 -1
- package/dist/ui/assets/haml-h18lG0pS.js +1 -0
- package/dist/ui/assets/{handlebars-BpzaUpmz.js → handlebars-lRFjRPfj.js} +1 -1
- package/dist/ui/assets/heavy-payload-Cqx9MOkH.js +290 -0
- package/dist/ui/assets/html-DtILqTE1.js +1 -0
- package/dist/ui/assets/{html-derivative-B2beVdmA.js → html-derivative-CSTSmPup.js} +1 -1
- package/dist/ui/assets/{http-iEskZy8U.js → http-DNI8fsbY.js} +1 -1
- package/dist/ui/assets/{hurl-BuUsLSKv.js → hurl-DgRi60JG.js} +1 -1
- package/dist/ui/assets/java-CW9pZ5bh.js +1 -0
- package/dist/ui/assets/javascript-Cvg2UrWL.js +1 -0
- package/dist/ui/assets/{jinja-CRpkWwrH.js → jinja-CZw_S1FB.js} +1 -1
- package/dist/ui/assets/{jison-BYfSnuHj.js → jison-C56u_FZv.js} +1 -1
- package/dist/ui/assets/json-DW2UTv1q.js +1 -0
- package/dist/ui/assets/jsx-Zj5gobdD.js +1 -0
- package/dist/ui/assets/{julia-B8Rxy7vD.js → julia-Cvcrre-L.js} +1 -1
- package/dist/ui/assets/{just-DzhIWpFP.js → just-8CZ2u6Tj.js} +1 -1
- package/dist/ui/assets/{latex-CUNjUUL-.js → latex-D289AXWG.js} +1 -1
- package/dist/ui/assets/{liquid-hUg7nC61.js → liquid-CFEX3SkZ.js} +1 -1
- package/dist/ui/assets/lua-BKpJ0ybO.js +1 -0
- package/dist/ui/assets/{marko-CQmIkwMF.js → marko-D9maZ0a6.js} +1 -1
- package/dist/ui/assets/{mdc-CB-6dHYa.js → mdc-rM9l0qWR.js} +1 -1
- package/dist/ui/assets/{nginx-CQORo_Bt.js → nginx-C9w6p2C9.js} +1 -1
- package/dist/ui/assets/{nim-BNwBNzdn.js → nim-BRePHk0J.js} +1 -1
- package/dist/ui/assets/{perl-Cnz14fAJ.js → perl-CskTmiPQ.js} +1 -1
- package/dist/ui/assets/{php-YywDo63b.js → php-DCU_FvNI.js} +1 -1
- package/dist/ui/assets/{pug-BwbJp4cM.js → pug-XLaVxTvv.js} +1 -1
- package/dist/ui/assets/{qml-D2DY6dMH.js → qml-CaONKSl-.js} +1 -1
- package/dist/ui/assets/r-BCVR0ZE3.js +1 -0
- package/dist/ui/assets/{razor-pMTG7k41.js → razor-DDnGXxnU.js} +1 -1
- package/dist/ui/assets/regexp-DWGTYYVx.js +1 -0
- package/dist/ui/assets/{rst-CO_ndDm4.js → rst-Dz3GWvQm.js} +1 -1
- package/dist/ui/assets/{ruby-xzRn9gTh.js → ruby-DC3jGtMY.js} +1 -1
- package/dist/ui/assets/{sas-CBdtFKLA.js → sas-7mNpvsjZ.js} +1 -1
- package/dist/ui/assets/scss-uBsoCJVy.js +1 -0
- package/dist/ui/assets/shellscript-BCN9N_Jf.js +1 -0
- package/dist/ui/assets/{shellsession-BaZnm5rZ.js → shellsession-Hsw46VXV.js} +1 -1
- package/dist/ui/assets/{soy-IouG3xdB.js → soy-D6KV69HU.js} +1 -1
- package/dist/ui/assets/sql-CVzVQkJh.js +1 -0
- package/dist/ui/assets/{stata-dgbkIZHP.js → stata-BwUjXNhI.js} +1 -1
- package/dist/ui/assets/{surrealql-CBROnw_p.js → surrealql-CgloWqRa.js} +1 -1
- package/dist/ui/assets/{svelte-6r6BpX4-.js → svelte-DcC3n6IC.js} +1 -1
- package/dist/ui/assets/{templ-BKD_PsbL.js → templ-DOFfnWTJ.js} +1 -1
- package/dist/ui/assets/{tex-CKY1bwHb.js → tex-ln89VPaX.js} +1 -1
- package/dist/ui/assets/{ts-tags-BiYP5N_C.js → ts-tags-CWMzCstH.js} +1 -1
- package/dist/ui/assets/tsx-DgzfiGeK.js +1 -0
- package/dist/ui/assets/{twig-BTe1oPFW.js → twig-Bi2itZL9.js} +1 -1
- package/dist/ui/assets/typescript-CQ24f4zW.js +1 -0
- package/dist/ui/assets/{vue-CT0IiySh.js → vue-BS8jE5u6.js} +1 -1
- package/dist/ui/assets/{vue-html-B-tXcbat.js → vue-html-o38xqhyB.js} +1 -1
- package/dist/ui/assets/{vue-vine-C5ZyDCrs.js → vue-vine-D2NvKv50.js} +1 -1
- package/dist/ui/assets/xml-_44rx9_2.js +1 -0
- package/dist/ui/assets/{xsl-DvDSndNI.js → xsl-B5QWQPoi.js} +1 -1
- package/dist/ui/assets/yaml-CKL2pEWe.js +1 -0
- package/dist/workspaces/relay/auth/remote-auth.js +3 -5
- package/dist/workspaces/relay/tests/test-support.js +7 -4
- package/dist/workspaces/relay/workspace-relay.js +14 -8
- package/dist/workspaces/resources/skills.js +1 -1
- package/docs/chatgpt-coding-workflow.md +12 -6
- package/docs/configuration.md +158 -6
- package/docs/debugging.md +8 -5
- package/docs/roadmap.md +64 -3
- package/docs/security.md +18 -0
- package/package.json +11 -4
- package/scripts/debug/accept/bootstrap.mjs +2 -0
- package/scripts/debug/accept/harness.mjs +9 -2
- package/scripts/debug/accept/modern-http.mjs +169 -0
- package/scripts/debug/accept/support.mjs +10 -6
- package/scripts/debug/accept.mjs +1 -0
- package/scripts/debug/runtime.mjs +4 -1
- package/scripts/debug/runtime.test.mjs +9 -0
- package/scripts/release/parity-sandbox.mjs +35 -0
- package/scripts/release/release-gate.test.mjs +42 -1
- package/scripts/release-parity.mjs +3 -22
- package/scripts/release-proof.mjs +24 -4
- package/scripts/release-proof.test.mjs +12 -4
- package/dist/ui/assets/activity-panel-app-XlqSanXT.js +0 -115
- package/dist/ui/assets/angular-html-tB9EchbM.js +0 -1
- package/dist/ui/assets/c-Dv-N5hjn.js +0 -1
- package/dist/ui/assets/cpp-C3unXX-3.js +0 -1
- package/dist/ui/assets/css-8Xr4kNNH.js +0 -1
- package/dist/ui/assets/glsl-BvCQg9MI.js +0 -1
- package/dist/ui/assets/graphql-C9S90gn_.js +0 -1
- package/dist/ui/assets/haml-Bb1w9rMG.js +0 -1
- package/dist/ui/assets/heavy-payload-CJKqi8Ac.js +0 -290
- package/dist/ui/assets/html-dUOs5pA9.js +0 -1
- package/dist/ui/assets/java-BFZCrORY.js +0 -1
- package/dist/ui/assets/javascript-DaIQ0Zqj.js +0 -1
- package/dist/ui/assets/json-BQC_Yp48.js +0 -1
- package/dist/ui/assets/jsx-Dd-CJRf9.js +0 -1
- package/dist/ui/assets/lua-BoZTiL2I.js +0 -1
- package/dist/ui/assets/r-B5nYsy-M.js +0 -1
- package/dist/ui/assets/regexp-oP0lbks_.js +0 -1
- package/dist/ui/assets/scss-CEqgKQNf.js +0 -1
- package/dist/ui/assets/shellscript-DzJJiWQC.js +0 -1
- package/dist/ui/assets/sql-DC2rdTzV.js +0 -1
- package/dist/ui/assets/tsx-D2OMiPNF.js +0 -1
- package/dist/ui/assets/typescript-BGIABksB.js +0 -1
- package/dist/ui/assets/xml-CfeBNlMP.js +0 -1
- package/dist/ui/assets/yaml-umbj2r1g.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./java-CW9pZ5bh.js";import{t}from"./heavy-payload-Cqx9MOkH.js";var n=t({default:()=>i}),r=Object.freeze(JSON.parse(`{"displayName":"XML","name":"xml","patterns":[{"begin":"(<\\\\?)\\\\s*([-0-9A-Z_a-z]+)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.xml"}},"end":"(\\\\?>)","name":"meta.tag.preprocessor.xml","patterns":[{"match":" ([-A-Za-z]+)","name":"entity.other.attribute-name.xml"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"begin":"(<!)(DOCTYPE)\\\\s+([:A-Z_a-z][-.0-:A-Z_a-z]*)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"keyword.other.doctype.xml"},"3":{"name":"variable.language.documentroot.xml"}},"end":"\\\\s*(>)","name":"meta.tag.sgml.doctype.xml","patterns":[{"include":"#internalSubset"}]},{"include":"#comments"},{"begin":"(<)((?:([-0-9A-Z_a-z]+)(:))?([-0-:A-Z_a-z]+))(?=(\\\\s[^>]*)?></\\\\2>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.xml"},"3":{"name":"entity.name.tag.namespace.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)(</)((?:([-0-9A-Z_a-z]+)(:))?([-0-:A-Z_a-z]+))(>)","endCaptures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"punctuation.definition.tag.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"entity.name.tag.namespace.xml"},"5":{"name":"punctuation.separator.namespace.xml"},"6":{"name":"entity.name.tag.localname.xml"},"7":{"name":"punctuation.definition.tag.xml"}},"name":"meta.tag.no-content.xml","patterns":[{"include":"#tagStuff"}]},{"begin":"(</?)(?:([-.\\\\w]+)((:)))?([-.:\\\\w]+)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(/?>)","name":"meta.tag.xml","patterns":[{"include":"#tagStuff"}]},{"include":"#entity"},{"include":"#bare-ampersand"},{"begin":"<%@","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.xml"}},"end":"%>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.xml"}},"name":"source.java-props.embedded.xml","patterns":[{"match":"page|include|taglib","name":"keyword.other.page-props.xml"}]},{"begin":"<%[!=]?(?!--)","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.xml"}},"end":"(?!--)%>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.xml"}},"name":"source.java.embedded.xml","patterns":[{"include":"source.java"}]},{"begin":"<!\\\\[CDATA\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"]]>","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.unquoted.cdata.xml"}],"repository":{"EntityDecl":{"begin":"(<!)(ENTITY)\\\\s+(%\\\\s+)?([:A-Z_a-z][-.0-:A-Z_a-z]*)(\\\\s+(?:SYSTEM|PUBLIC)\\\\s+)?","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"keyword.other.entity.xml"},"3":{"name":"punctuation.definition.entity.xml"},"4":{"name":"variable.language.entity.xml"},"5":{"name":"keyword.other.entitytype.xml"}},"end":"(>)","patterns":[{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},"bare-ampersand":{"match":"&","name":"invalid.illegal.bad-ampersand.xml"},"comments":{"patterns":[{"begin":"<%--","captures":{"0":{"name":"punctuation.definition.comment.xml"},"end":"--%>","name":"comment.block.xml"}},{"begin":"<!--","captures":{"0":{"name":"punctuation.definition.comment.xml"}},"end":"-->","name":"comment.block.xml","patterns":[{"begin":"--(?!>)","captures":{"0":{"name":"invalid.illegal.bad-comments-or-CDATA.xml"}}}]}]},"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml","patterns":[{"include":"#entity"},{"include":"#bare-ampersand"}]},"entity":{"captures":{"1":{"name":"punctuation.definition.constant.xml"},"3":{"name":"punctuation.definition.constant.xml"}},"match":"(&)([:A-Z_a-z][-.0-:A-Z_a-z]*|#[0-9]+|#x\\\\h+)(;)","name":"constant.character.entity.xml"},"internalSubset":{"begin":"(\\\\[)","captures":{"1":{"name":"punctuation.definition.constant.xml"}},"end":"(])","name":"meta.internalsubset.xml","patterns":[{"include":"#EntityDecl"},{"include":"#parameterEntity"},{"include":"#comments"}]},"parameterEntity":{"captures":{"1":{"name":"punctuation.definition.constant.xml"},"3":{"name":"punctuation.definition.constant.xml"}},"match":"(%)([:A-Z_a-z][-.0-:A-Z_a-z]*)(;)","name":"constant.character.parameter-entity.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml","patterns":[{"include":"#entity"},{"include":"#bare-ampersand"}]},"tagStuff":{"patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":"(?:^|\\\\s+)(?:([-.\\\\w]+)((:)))?([-.:\\\\w]+)\\\\s*="},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]}},"scopeName":"text.xml","embeddedLangs":["java"]}`)),i=[...e,r];export{n,i as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./xml-
|
|
1
|
+
import{t as e}from"./xml-_44rx9_2.js";var t=Object.freeze(JSON.parse(`{"displayName":"XSL","name":"xsl","patterns":[{"begin":"(<)(xsl)((:))(template)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)","name":"meta.tag.xml.template","patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":" (?:([-0-9A-Z_a-z]+)((:)))?([-A-Za-z]+)"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"include":"text.xml"}],"repository":{"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml"}},"scopeName":"text.xml.xsl","embeddedLangs":["xml"]}`)),n=[...e,t];export{n as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./heavy-payload-Cqx9MOkH.js";var t=e({default:()=>n}),n=[Object.freeze(JSON.parse(`{"displayName":"YAML","fileTypes":["yaml","yml","rviz","reek","clang-format","yaml-tmlanguage","syntax","sublime-syntax"],"firstLineMatch":"^%YAML( ?1.\\\\d+)?","name":"yaml","patterns":[{"include":"#comment"},{"include":"#property"},{"include":"#directive"},{"match":"^---","name":"entity.other.document.begin.yaml"},{"match":"^\\\\.{3}","name":"entity.other.document.end.yaml"},{"include":"#node"}],"repository":{"block-collection":{"patterns":[{"include":"#block-sequence"},{"include":"#block-mapping"}]},"block-mapping":{"patterns":[{"include":"#block-pair"}]},"block-node":{"patterns":[{"include":"#prototype"},{"include":"#block-scalar"},{"include":"#block-collection"},{"include":"#flow-scalar-plain-out"},{"include":"#flow-node"}]},"block-pair":{"patterns":[{"begin":"\\\\?","beginCaptures":{"1":{"name":"punctuation.definition.key-value.begin.yaml"}},"end":"(?=\\\\?)|^ *(:)|(:)","endCaptures":{"1":{"name":"punctuation.separator.key-value.mapping.yaml"},"2":{"name":"invalid.illegal.expected-newline.yaml"}},"name":"meta.block-mapping.yaml","patterns":[{"include":"#block-node"}]},{"begin":"(?=(?:[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S)([^:\\\\s]|:\\\\S|\\\\s+(?![#\\\\s]))*\\\\s*:(\\\\s|$))","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","patterns":[{"include":"#flow-scalar-plain-out-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S","beginCaptures":{"0":{"name":"entity.name.tag.yaml"}},"contentName":"entity.name.tag.yaml","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","name":"string.unquoted.plain.out.yaml"}]},{"match":":(?=\\\\s|$)","name":"punctuation.separator.key-value.mapping.yaml"}]},"block-scalar":{"begin":"(?:(\\\\|)|(>))([1-9])?([-+])?(.*\\\\n?)","beginCaptures":{"1":{"name":"keyword.control.flow.block-scalar.literal.yaml"},"2":{"name":"keyword.control.flow.block-scalar.folded.yaml"},"3":{"name":"constant.numeric.indentation-indicator.yaml"},"4":{"name":"storage.modifier.chomping-indicator.yaml"},"5":{"patterns":[{"include":"#comment"},{"match":".+","name":"invalid.illegal.expected-comment-or-newline.yaml"}]}},"end":"^(?=\\\\S)|(?!\\\\G)","patterns":[{"begin":"^( +)(?! )","end":"^(?!\\\\1|\\\\s*$)","name":"string.unquoted.block.yaml"}]},"block-sequence":{"match":"(-)(?!\\\\S)","name":"punctuation.definition.block.sequence.item.yaml"},"comment":{"begin":"(?:^([\\\\t ]*)|[\\\\t ]+)(?=#\\\\p{print}*$)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.yaml"}},"end":"(?!\\\\G)","patterns":[{"begin":"#","beginCaptures":{"0":{"name":"punctuation.definition.comment.yaml"}},"end":"\\\\n","name":"comment.line.number-sign.yaml"}]},"directive":{"begin":"^%","beginCaptures":{"0":{"name":"punctuation.definition.directive.begin.yaml"}},"end":"(?=$|[\\\\t ]+($|#))","name":"meta.directive.yaml","patterns":[{"captures":{"1":{"name":"keyword.other.directive.yaml.yaml"},"2":{"name":"constant.numeric.yaml-version.yaml"}},"match":"\\\\G(YAML)[\\\\t ]+(\\\\d+\\\\.\\\\d+)"},{"captures":{"1":{"name":"keyword.other.directive.tag.yaml"},"2":{"name":"storage.type.tag-handle.yaml"},"3":{"name":"support.type.tag-prefix.yaml"}},"match":"\\\\G(TAG)(?:[\\\\t ]+(!(?:[-0-9A-Za-z]*!)?)(?:[\\\\t ]+(!(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])*|(?![]!,\\\\[{}])(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])+))?)?"},{"captures":{"1":{"name":"support.other.directive.reserved.yaml"},"2":{"name":"string.unquoted.directive-name.yaml"},"3":{"name":"string.unquoted.directive-parameter.yaml"}},"match":"\\\\G(\\\\w+)(?:[\\\\t ]+(\\\\w+)(?:[\\\\t ]+(\\\\w+))?)?"},{"match":"\\\\S+","name":"invalid.illegal.unrecognized.yaml"}]},"flow-alias":{"captures":{"1":{"name":"keyword.control.flow.alias.yaml"},"2":{"name":"punctuation.definition.alias.yaml"},"3":{"name":"variable.other.alias.yaml"},"4":{"name":"invalid.illegal.character.anchor.yaml"}},"match":"((\\\\*))([^],/\\\\[{}\\\\s]+)([^],}\\\\s]\\\\S*)?"},"flow-collection":{"patterns":[{"include":"#flow-sequence"},{"include":"#flow-mapping"}]},"flow-mapping":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.mapping.begin.yaml"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.mapping.end.yaml"}},"name":"meta.flow-mapping.yaml","patterns":[{"include":"#prototype"},{"match":",","name":"punctuation.separator.mapping.yaml"},{"include":"#flow-pair"}]},"flow-node":{"patterns":[{"include":"#prototype"},{"include":"#flow-alias"},{"include":"#flow-collection"},{"include":"#flow-scalar"}]},"flow-pair":{"patterns":[{"begin":"\\\\?","beginCaptures":{"0":{"name":"punctuation.definition.key-value.begin.yaml"}},"end":"(?=[],}])","name":"meta.flow-pair.explicit.yaml","patterns":[{"include":"#prototype"},{"include":"#flow-pair"},{"include":"#flow-node"},{"begin":":(?=\\\\s|$|[],\\\\[{}])","beginCaptures":{"0":{"name":"punctuation.separator.key-value.mapping.yaml"}},"end":"(?=[],}])","patterns":[{"include":"#flow-value"}]}]},{"begin":"(?=(?:[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s])([^],:\\\\[{}\\\\s]|:[^],\\\\[{}\\\\s]|\\\\s+(?![#\\\\s]))*\\\\s*:(\\\\s|$))","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"meta.flow-pair.key.yaml","patterns":[{"include":"#flow-scalar-plain-in-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s]","beginCaptures":{"0":{"name":"entity.name.tag.yaml"}},"contentName":"entity.name.tag.yaml","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"string.unquoted.plain.in.yaml"}]},{"include":"#flow-node"},{"begin":":(?=\\\\s|$|[],\\\\[{}])","captures":{"0":{"name":"punctuation.separator.key-value.mapping.yaml"}},"end":"(?=[],}])","name":"meta.flow-pair.yaml","patterns":[{"include":"#flow-value"}]}]},"flow-scalar":{"patterns":[{"include":"#flow-scalar-double-quoted"},{"include":"#flow-scalar-single-quoted"},{"include":"#flow-scalar-plain-in"}]},"flow-scalar-double-quoted":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.yaml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.yaml"}},"name":"string.quoted.double.yaml","patterns":[{"match":"\\\\\\\\([ \\"/0LN\\\\\\\\_abefnprtv]|x\\\\d\\\\d|u\\\\d{4}|U\\\\d{8})","name":"constant.character.escape.yaml"},{"match":"\\\\\\\\\\\\n","name":"constant.character.escape.double-quoted.newline.yaml"}]},"flow-scalar-plain-in":{"patterns":[{"include":"#flow-scalar-plain-in-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s]","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"string.unquoted.plain.in.yaml"}]},"flow-scalar-plain-in-implicit-type":{"patterns":[{"captures":{"1":{"name":"constant.language.null.yaml"},"2":{"name":"constant.language.boolean.yaml"},"3":{"name":"constant.numeric.integer.yaml"},"4":{"name":"constant.numeric.float.yaml"},"5":{"name":"constant.other.timestamp.yaml"},"6":{"name":"constant.language.value.yaml"},"7":{"name":"constant.language.merge.yaml"}},"match":"(?:(null|Null|NULL|~)|([Yy]|yes|Yes|YES|[Nn]|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)|([-+]?0b[01_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[_\\\\h]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)|([-+]?(?:[0-9][0-9_]*)?\\\\.[.0-9]*(?:[Ee][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))|(\\\\d{4}-\\\\d{2}-\\\\d{2}|\\\\d{4}-\\\\d{1,2}-\\\\d{1,2}(?:[Tt]|[\\\\t ]+)\\\\d{1,2}:\\\\d{2}:\\\\d{2}(?:\\\\.\\\\d*)?(?:[\\\\t ]*Z|[-+]\\\\d{1,2}(?::\\\\d{1,2})?)?)|(=)|(<<))(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])"}]},"flow-scalar-plain-out":{"patterns":[{"include":"#flow-scalar-plain-out-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","name":"string.unquoted.plain.out.yaml"}]},"flow-scalar-plain-out-implicit-type":{"patterns":[{"captures":{"1":{"name":"constant.language.null.yaml"},"2":{"name":"constant.language.boolean.yaml"},"3":{"name":"constant.numeric.integer.yaml"},"4":{"name":"constant.numeric.float.yaml"},"5":{"name":"constant.other.timestamp.yaml"},"6":{"name":"constant.language.value.yaml"},"7":{"name":"constant.language.merge.yaml"}},"match":"(?:(null|Null|NULL|~)|([Yy]|yes|Yes|YES|[Nn]|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)|([-+]?0b[01_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[_\\\\h]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)|([-+]?(?:[0-9][0-9_]*)?\\\\.[.0-9]*(?:[Ee][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))|(\\\\d{4}-\\\\d{2}-\\\\d{2}|\\\\d{4}-\\\\d{1,2}-\\\\d{1,2}(?:[Tt]|[\\\\t ]+)\\\\d{1,2}:\\\\d{2}:\\\\d{2}(?:\\\\.\\\\d*)?(?:[\\\\t ]*Z|[-+]\\\\d{1,2}(?::\\\\d{1,2})?)?)|(=)|(<<))(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))"}]},"flow-scalar-single-quoted":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.yaml"}},"end":"'(?!')","endCaptures":{"0":{"name":"punctuation.definition.string.end.yaml"}},"name":"string.quoted.single.yaml","patterns":[{"match":"''","name":"constant.character.escape.single-quoted.yaml"}]},"flow-sequence":{"begin":"\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.sequence.begin.yaml"}},"end":"]","endCaptures":{"0":{"name":"punctuation.definition.sequence.end.yaml"}},"name":"meta.flow-sequence.yaml","patterns":[{"include":"#prototype"},{"match":",","name":"punctuation.separator.sequence.yaml"},{"include":"#flow-pair"},{"include":"#flow-node"}]},"flow-value":{"patterns":[{"begin":"\\\\G(?![],}])","end":"(?=[],}])","name":"meta.flow-pair.value.yaml","patterns":[{"include":"#flow-node"}]}]},"node":{"patterns":[{"include":"#block-node"}]},"property":{"begin":"(?=[!\\\\&])","end":"(?!\\\\G)","name":"meta.property.yaml","patterns":[{"captures":{"1":{"name":"keyword.control.property.anchor.yaml"},"2":{"name":"punctuation.definition.anchor.yaml"},"3":{"name":"entity.name.type.anchor.yaml"},"4":{"name":"invalid.illegal.character.anchor.yaml"}},"match":"\\\\G((&))([^],/\\\\[{}\\\\s]+)(\\\\S+)?"},{"match":"\\\\G!(?:<(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])+>|(?:[-0-9A-Za-z]*!)?(?:%\\\\h{2}|[#$\\\\&-+\\\\--;=?-Z_a-z~])+|)(?=[\\\\t ]|$)","name":"storage.type.tag-handle.yaml"},{"match":"\\\\S+","name":"invalid.illegal.tag-handle.yaml"}]},"prototype":{"patterns":[{"include":"#comment"},{"include":"#property"}]}},"scopeName":"source.yaml","aliases":["yml"]}`))];export{t as n,n as t};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import { UnauthorizedError } from "@modelcontextprotocol/
|
|
3
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
|
-
import { StreamableHTTPClientTransport, StreamableHTTPError, } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2
|
+
import { Client, SdkHttpError, StreamableHTTPClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
|
|
5
3
|
import { publicEndpointUrl } from "../../../mcp/oauth/public-url.js";
|
|
6
4
|
const REMOTE_AUTH_TIMEOUT_MS = 15_000;
|
|
7
5
|
const packageVersion = readForgeRelayVersion();
|
|
@@ -45,11 +43,11 @@ export async function refreshRemoteAuthentication(remote, endpointInput = remote
|
|
|
45
43
|
}
|
|
46
44
|
export function isRemoteMcpUnauthorized(error) {
|
|
47
45
|
return error instanceof UnauthorizedError ||
|
|
48
|
-
(error instanceof
|
|
46
|
+
(error instanceof SdkHttpError && error.status === 401);
|
|
49
47
|
}
|
|
50
48
|
export async function connectRemoteMcpClient(remote, endpointInput) {
|
|
51
49
|
const endpoint = normalizeRemoteServiceTarget(endpointInput);
|
|
52
|
-
const client = new Client({ name: "forgerelay-cli", version: packageVersion });
|
|
50
|
+
const client = new Client({ name: "forgerelay-cli", version: packageVersion }, { versionNegotiation: { mode: "legacy" } });
|
|
53
51
|
const transport = new StreamableHTTPClientTransport(publicEndpointUrl(endpoint, "mcp"), {
|
|
54
52
|
requestInit: {
|
|
55
53
|
headers: { Authorization: `Bearer ${remote.accessToken}` },
|
|
@@ -3,9 +3,8 @@ import { execFileSync } from "node:child_process";
|
|
|
3
3
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { createRequire, syncBuiltinESMExports } from "node:module";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
|
-
import { Client } from "@modelcontextprotocol/
|
|
7
|
-
import {
|
|
8
|
-
import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
|
|
7
|
+
import { CompatibilityCallToolResultSchema } from "@modelcontextprotocol/core";
|
|
9
8
|
import { ActivityAuditStore } from "../../../activity/history/audit-store.js";
|
|
10
9
|
import { BashOutputStore } from "../../../activity/history/bash-output-store.js";
|
|
11
10
|
import { HostTurnStore } from "../../../activity/history/host-turn-store.js";
|
|
@@ -224,5 +223,9 @@ export function resultText(result) {
|
|
|
224
223
|
.join("\n");
|
|
225
224
|
}
|
|
226
225
|
function parseToolResult(result) {
|
|
227
|
-
|
|
226
|
+
const parsed = CompatibilityCallToolResultSchema.parse(result);
|
|
227
|
+
if (!Array.isArray(parsed.content)) {
|
|
228
|
+
throw new Error("Expected a content-based compatibility tool result.");
|
|
229
|
+
}
|
|
230
|
+
return parsed;
|
|
228
231
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { CompatibilityCallToolResultSchema } from "@modelcontextprotocol/core";
|
|
5
5
|
import { isRemoteMcpUnauthorized, refreshRemoteAuthentication, } from "./auth/remote-auth.js";
|
|
6
6
|
import { RemoteMcpConnectionPool } from "./transport/remote-mcp-connection-pool.js";
|
|
7
7
|
import { withFileLock } from "../../runtime/state/lock/file-lock.js";
|
|
@@ -465,13 +465,19 @@ export class RemoteWorkspaceRelay {
|
|
|
465
465
|
throw new Error(`Remote ForgeRelay ${alias} request failed: ${errorMessage(error)}`, { cause: error });
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
|
-
const invoke = async (active) =>
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
468
|
+
const invoke = async (active) => {
|
|
469
|
+
const parsed = CompatibilityCallToolResultSchema.parse(await active.client.callTool({
|
|
470
|
+
name,
|
|
471
|
+
arguments: args,
|
|
472
|
+
...(conversationScopeId
|
|
473
|
+
? { _meta: { "openai/session": conversationScopeId } }
|
|
474
|
+
: {}),
|
|
475
|
+
}));
|
|
476
|
+
if (!Array.isArray(parsed.content)) {
|
|
477
|
+
throw new Error("Remote ForgeRelay returned a modern-only tool result on the legacy Relay protocol path.");
|
|
478
|
+
}
|
|
479
|
+
return parsed;
|
|
480
|
+
};
|
|
475
481
|
try {
|
|
476
482
|
return await invoke(connection);
|
|
477
483
|
}
|
|
@@ -7,8 +7,8 @@ import { expandHomePath, isPathInsideRoot } from "../../mcp/filesystem/roots.js"
|
|
|
7
7
|
const FRONTMATTER_DELIMITER = "---";
|
|
8
8
|
export function effectiveSkillPaths(config, cwd) {
|
|
9
9
|
const defaultPathCandidates = [
|
|
10
|
-
join(homedir(), ".agents", "skills"),
|
|
11
10
|
resolve(cwd, ".agents", "skills"),
|
|
11
|
+
join(homedir(), ".agents", "skills"),
|
|
12
12
|
config.configSkillsDir,
|
|
13
13
|
join(config.agentDir, "skills"),
|
|
14
14
|
];
|
|
@@ -201,12 +201,16 @@ gateway rather than each receiving another top-level tool schema.
|
|
|
201
201
|
`open_workspace` adds lightweight discovery surfaces:
|
|
202
202
|
|
|
203
203
|
- `capabilityFingerprint` is returned on every open/resume and includes the
|
|
204
|
-
ForgeRelay version, active tool mode, and stable semantic capability names
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
ForgeRelay version, active tool mode, and stable semantic capability names. It
|
|
205
|
+
is a feature fingerprint, not a callable registry;
|
|
206
|
+
- `capabilityCatalog` is the callable registry for the `capability` gateway and
|
|
207
|
+
lists currently available registered actions such as `hooks.check`, with
|
|
208
|
+
compact guide metadata. Only names present here are valid for
|
|
209
|
+
`capability(action="describe"|"run")`;
|
|
207
210
|
- `capabilityGuides` is returned with bootstrap context and contains compact
|
|
208
211
|
descriptors for ForgeRelay-owned, versioned guides that can be loaded with
|
|
209
|
-
the normal `read` tool.
|
|
212
|
+
the normal `read` tool. Guide names are documentation descriptors, not
|
|
213
|
+
callable capability names.
|
|
210
214
|
|
|
211
215
|
Do not preload every capability guide. Read a guide only when the current task
|
|
212
216
|
needs that domain. Built-in guides cover lifecycle Hooks, advanced managed
|
|
@@ -228,14 +232,16 @@ force the Host to discard a cached tool schema.
|
|
|
228
232
|
|
|
229
233
|
## Agent Skills
|
|
230
234
|
|
|
231
|
-
ForgeRelay discovers standard Agent Skills from:
|
|
235
|
+
ForgeRelay discovers standard Agent Skills in precedence order from:
|
|
232
236
|
|
|
233
|
-
- `~/.agents/skills`
|
|
234
237
|
- project `.agents/skills`
|
|
238
|
+
- `~/.agents/skills`
|
|
235
239
|
- the active ForgeRelay config directory's `skills` folder
|
|
236
240
|
- `FORGERELAY_AGENT_DIR/skills` (defaults to `~/.codex/skills`)
|
|
237
241
|
- paths from `FORGERELAY_SKILL_PATHS`
|
|
238
242
|
|
|
243
|
+
Same-named collisions use the first source, so project Skills override global Skills.
|
|
244
|
+
|
|
239
245
|
When a task matches an advertised skill, read its `SKILL.md` before using other
|
|
240
246
|
files in the skill directory.
|
|
241
247
|
|
package/docs/configuration.md
CHANGED
|
@@ -10,8 +10,18 @@ New installations use:
|
|
|
10
10
|
```text
|
|
11
11
|
~/.forgerelay/config.json
|
|
12
12
|
~/.forgerelay/auth.json
|
|
13
|
+
~/.forgerelay/mcp.json # optional External MCP registry
|
|
14
|
+
~/.forgerelay/mcp-auth.json # created only when External MCP OAuth state exists
|
|
13
15
|
```
|
|
14
16
|
|
|
17
|
+
A Workspace may also define project-scoped External MCP servers in:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
<workspace>/.forgerelay/mcp.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`mcp-auth.json` is ForgeRelay-private credential state and must not be copied into a project.
|
|
24
|
+
|
|
15
25
|
Override the directory with:
|
|
16
26
|
|
|
17
27
|
```bash
|
|
@@ -26,6 +36,10 @@ npx @akira-tl/forgerelay serve
|
|
|
26
36
|
npx @akira-tl/forgerelay doctor
|
|
27
37
|
npx @akira-tl/forgerelay config get
|
|
28
38
|
npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com/forgerelay/main,https://forge-alt.example.com/relay
|
|
39
|
+
npx @akira-tl/forgerelay mcp list
|
|
40
|
+
npx @akira-tl/forgerelay mcp test <server>
|
|
41
|
+
npx @akira-tl/forgerelay mcp auth <server>
|
|
42
|
+
npx @akira-tl/forgerelay mcp logout <server>
|
|
29
43
|
npx @akira-tl/forgerelay maintenance inspect
|
|
30
44
|
```
|
|
31
45
|
|
|
@@ -160,11 +174,27 @@ The same value may be persisted as `mediaMaxBytes` in `config.json`. The budget
|
|
|
160
174
|
|
|
161
175
|
Media content is transient. Image base64 is present only in the live MCP result delivered to the Host; Activity/Audit, structured output, UI state, Workspace state, and logs keep bounded metadata such as MIME type and decoded byte size. Reading or forwarding an image does **not** create an Artifact. Artifact download/materialization remains a separate explicit workflow.
|
|
162
176
|
|
|
163
|
-
User-configured MCP servers are
|
|
177
|
+
User-configured MCP servers are exposed through the workspace-scoped `mcp.external` Capability rather than becoming new top-level MCP tools. The capability remains discoverable even when the effective server registry is empty, so servers added later by hot reload become usable without reconnecting the Host.
|
|
178
|
+
|
|
179
|
+
### External MCP configuration files
|
|
180
|
+
|
|
181
|
+
New configuration uses a dedicated `mcp.json` file. The machine-wide registry is:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
~/.forgerelay/mcp.json
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
or the equivalent path below `FORGERELAY_CONFIG_DIR`. A Workspace may add or override servers in:
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
<workspace>/.forgerelay/mcp.json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Both files use this shape:
|
|
164
194
|
|
|
165
195
|
```json
|
|
166
196
|
{
|
|
167
|
-
"
|
|
197
|
+
"servers": {
|
|
168
198
|
"renderer": {
|
|
169
199
|
"transport": "stdio",
|
|
170
200
|
"command": "node",
|
|
@@ -172,15 +202,135 @@ User-configured MCP servers are registered in `config.json` under `mcpServers` a
|
|
|
172
202
|
},
|
|
173
203
|
"remote-renderer": {
|
|
174
204
|
"transport": "streamable-http",
|
|
175
|
-
"url": "https://renderer.example.com/mcp"
|
|
205
|
+
"url": "https://renderer.example.com/mcp"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Server names are stable lowercase identifiers matching `^[a-z][a-z0-9._-]{0,63}$`; one source may contain at most 32 servers.
|
|
212
|
+
|
|
213
|
+
Effective configuration is merged by server name in this order:
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
Project mcp.json > global mcp.json > legacy config.json.mcpServers
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
A Project entry may explicitly hide an inherited server:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"servers": {
|
|
224
|
+
"remote-renderer": {
|
|
225
|
+
"disabled": true
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`disabled` defaults to `false` and normally does not need to be written. Removing the Project entry exposes the lower-precedence global/legacy server again. A complete server entry may also contain `"disabled": true`; ForgeRelay validates the entry but does not activate it.
|
|
232
|
+
|
|
233
|
+
The historical `config.json -> mcpServers` object remains a deprecated read-compatible source. New configuration and documentation use `mcp.json`; the legacy source is retained for at least the next two feature-release compatibility windows and should not be used for new setups.
|
|
234
|
+
|
|
235
|
+
ForgeRelay reloads global and Project `mcp.json` on demand before External MCP operations. A valid changed file becomes visible to the next `servers`, `tools`, or `call` operation without restarting ForgeRelay. Each operation uses one immutable snapshot, so an in-flight call is not switched underneath itself. If a previously valid source becomes invalid, that running ForgeRelay process keeps the whole previous valid source as last-known-good and reports a bounded diagnostic; no partially parsed subset is activated. A fresh CLI process cannot reconstruct another process's in-memory last-known-good snapshot, so it reports the invalid source while noting that an existing runtime may still be using its prior valid snapshot.
|
|
236
|
+
|
|
237
|
+
### External MCP transports and authentication
|
|
238
|
+
|
|
239
|
+
A stdio server supports `command`, optional `args`, `env`, and `cwd`. It is launched directly, not through a shell. Its process still runs with the operating-system authority of the user running ForgeRelay. A Project `.forgerelay/mcp.json` can therefore introduce executable project configuration; opening an allowed project is the trust boundary, and ForgeRelay does not add a second per-server approval prompt.
|
|
240
|
+
|
|
241
|
+
A Streamable HTTP server supports `url` and optional static `headers`:
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"servers": {
|
|
246
|
+
"private-api": {
|
|
247
|
+
"transport": "streamable-http",
|
|
248
|
+
"url": "https://mcp.example.com/mcp",
|
|
176
249
|
"headers": {
|
|
177
|
-
"Authorization": "Bearer <
|
|
250
|
+
"Authorization": "Bearer <user-managed-secret>"
|
|
178
251
|
}
|
|
179
252
|
}
|
|
180
253
|
}
|
|
181
254
|
}
|
|
182
255
|
```
|
|
183
256
|
|
|
257
|
+
ForgeRelay does not require every HTTP MCP server to use OAuth. The effective models are:
|
|
258
|
+
|
|
259
|
+
- no authentication: connect directly;
|
|
260
|
+
- static credentials: user-managed `headers` for HTTP or `env` for stdio;
|
|
261
|
+
- interactive OAuth: explicitly initiated by a human through the CLI.
|
|
262
|
+
|
|
263
|
+
Do not commit static secrets in Project `mcp.json`. ForgeRelay does not move project-defined header/env secrets into a separate secret manager in v1.1.1.
|
|
264
|
+
|
|
265
|
+
Interactive OAuth state is stored only in the machine-private:
|
|
266
|
+
|
|
267
|
+
```text
|
|
268
|
+
~/.forgerelay/mcp-auth.json
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
(or the configured ForgeRelay config directory). Project OAuth credentials are still stored there, keyed to the canonical Project root and server; they are not written into the project. Global/legacy servers use a global credential identity. Project credentials are not reused across Projects merely because the server name or URL matches.
|
|
272
|
+
|
|
273
|
+
Authenticate explicitly:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
forgerelay mcp auth <server>
|
|
277
|
+
forgerelay mcp auth <server> --project /path/to/project
|
|
278
|
+
forgerelay mcp auth <server> --global
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The CLI performs OAuth discovery, PKCE and the browser/callback exchange, then atomically commits the credential. The running ForgeRelay server is not an OAuth callback broker; it simply reads the updated credential store on later External MCP calls. On a desktop the CLI opens the authorization URL and listens on a short-lived loopback callback. On SSH/headless systems it prints the authorization URL and asks for the final callback URL to be pasted; pasted input is displayed only as `*` mask characters.
|
|
282
|
+
|
|
283
|
+
Normal token refresh is non-interactive and may be performed by the runtime. If refresh fails, the resource/issuer binding changes, or the server requires additional scope, the runtime does not open a browser: it returns `mcp.auth_required` or `mcp.reauthorization_required`, and the human reruns `forgerelay mcp auth <server>`. Multiple ForgeRelay processes coordinate refresh through the shared credential store so refresh-token rotation does not turn a successful refresh in one process into a false reauthorization failure in another.
|
|
284
|
+
|
|
285
|
+
ForgeRelay uses Dynamic Client Registration when the authorization server supports the compatible flow. For CIMD-only authorization servers, configure a stable public HTTPS client metadata document and the exact loopback callback port it advertises:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"servers": {
|
|
290
|
+
"modern": {
|
|
291
|
+
"transport": "streamable-http",
|
|
292
|
+
"url": "https://mcp.example.com/mcp",
|
|
293
|
+
"oauth": {
|
|
294
|
+
"clientMetadataUrl": "https://client.example.com/forgerelay.json",
|
|
295
|
+
"callbackPort": 49152
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`clientMetadataUrl` must use HTTPS with a non-root path; `callbackPort` must be `1024..65535`. ForgeRelay does not operate a hosted CIMD service, so this advanced configuration is supplied by the operator when a server requires it.
|
|
303
|
+
|
|
304
|
+
Remove local OAuth state with:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
forgerelay mcp logout <server>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
ForgeRelay removes the local credential even when remote token revocation is unsupported or fails, and reports that distinction.
|
|
311
|
+
|
|
312
|
+
### External MCP diagnostics
|
|
313
|
+
|
|
314
|
+
Use the CLI before editing runtime state by guesswork:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
forgerelay mcp list
|
|
318
|
+
forgerelay mcp test <server>
|
|
319
|
+
forgerelay doctor
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`mcp list` is passive: it reports the resolved Project/global/legacy sources, disabled entries, authentication state, credential-store health, and invalid/last-known-good configuration diagnostics. With no explicit scope it uses the active Workspace root when supplied by ForgeRelay, otherwise walks upward from the current directory for the nearest `.forgerelay/mcp.json`; `--project` selects a Project explicitly and `--global` excludes Project configuration.
|
|
323
|
+
|
|
324
|
+
`mcp test` is the active probe. It connects to the selected server and performs tool discovery, reporting source, transport, auth state, negotiated MCP era/version, tool count, and actionable failures such as authentication required, unreachable transport, or tool discovery failure.
|
|
325
|
+
|
|
326
|
+
`doctor` remains passive. Its External MCP section reads configuration and credential metadata only; it does not launch configured stdio servers or make HTTP MCP requests. Use `mcp test` when an active connectivity check is intended.
|
|
327
|
+
|
|
328
|
+
### External MCP protocol compatibility and Relay
|
|
329
|
+
|
|
330
|
+
ForgeRelay's External MCP client negotiates modern MCP 2026-07-28 when available and falls back to supported legacy MCP servers. Host-facing HTTP similarly supports the modern stateless protocol while retaining the legacy sessionful path for compatible Hosts.
|
|
331
|
+
|
|
332
|
+
For a relayed Workspace, External MCP configuration, credentials, process launches, OAuth refreshes, and upstream MCP calls belong to the **Execution ForgeRelay**. The Gateway does not copy or forward External MCP credentials. Run `forgerelay mcp auth` on the machine/configuration that owns execution when a relayed Workspace needs OAuth.
|
|
333
|
+
|
|
184
334
|
The Agent explicitly selects the configured server, advertised tool, and arguments through `capability(name="mcp.external", action="run", ...)`. Direct upstream PNG/JPEG/WebP/GIF `ImageContent` is validated and forwarded without decode/re-encode. Text, paths, URLs, `resource_link` values, and other references remain exactly that by default: ForgeRelay does not automatically fetch them, call `read`, infer that they refer to an image, or create an Artifact.
|
|
185
335
|
|
|
186
336
|
A known server/tool may opt into explicit request/result adaptation with `ExternalMcpBeforeForward` or `ExternalMcpAfterForward` project/global Hooks. These transforms use the structured versioned stdin/stdout protocol described under [Lifecycle hooks](#lifecycle-hooks); ordinary Hook stdout never rewrites MCP data. For example, a project can match one renderer tool whose normal result is a path and deliberately convert that result into `ImageContent`. The Hook command performs any file/network access with its normal local-user authority, and the transformed result still passes through the same MCP shape, MIME/base64, and `mediaMaxBytes` validation before Host delivery.
|
|
@@ -710,14 +860,16 @@ select a global instruction file; its `skills` child is an additional Agent Skil
|
|
|
710
860
|
| `FORGERELAY_AGENT_DIR` | Defaults to `~/.codex`; its `skills` child is included as an additional Skill source. |
|
|
711
861
|
| `FORGERELAY_SKILL_PATHS` | Optional comma-separated additional skill directories. |
|
|
712
862
|
|
|
713
|
-
Standard Agent Skills are discovered from:
|
|
863
|
+
Standard Agent Skills are discovered in precedence order from:
|
|
714
864
|
|
|
715
|
-
- `~/.agents/skills`
|
|
716
865
|
- project `.agents/skills`
|
|
866
|
+
- `~/.agents/skills`
|
|
717
867
|
- the active ForgeRelay config directory's `skills` folder
|
|
718
868
|
- `FORGERELAY_AGENT_DIR/skills`
|
|
719
869
|
- paths from `FORGERELAY_SKILL_PATHS`
|
|
720
870
|
|
|
871
|
+
When the same Skill name appears in more than one source, the first source wins. Project Skills therefore override same-named global `~/.agents/skills` entries, matching ForgeRelay's project-over-global configuration model.
|
|
872
|
+
|
|
721
873
|
When subagents are enabled, profiles are discovered from:
|
|
722
874
|
|
|
723
875
|
- the active ForgeRelay config directory's `agents/*.md`;
|
package/docs/debugging.md
CHANGED
|
@@ -54,7 +54,7 @@ The selected debug config is authoritative for its own `host` and `port`; the
|
|
|
54
54
|
launcher reports endpoints derived from that file instead of assuming `7677`.
|
|
55
55
|
This makes parallel isolated instances straightforward: give each instance its
|
|
56
56
|
own config, state, and worktree directories and configure different ports (for
|
|
57
|
-
example `7677` for a Gateway and `
|
|
57
|
+
example `7677` for a Gateway and `7678` for an Execution ForgeRelay), then launch
|
|
58
58
|
each with its own `FORGERELAY_DEBUG_CONFIG_DIR`.
|
|
59
59
|
|
|
60
60
|
## Run a local MCP Apps Host
|
|
@@ -107,12 +107,15 @@ behavior.
|
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
109
|
npm run debug:accept
|
|
110
|
+
npm run debug:accept:modern
|
|
111
|
+
npm run debug:accept:relay
|
|
110
112
|
```
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
`127.0.0.1:7677
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
`debug:accept` starts its own fully isolated legacy/sessionful ForgeRelay fixture on
|
|
115
|
+
`127.0.0.1:7677`. `debug:accept:modern` exercises the MCP 2026-07-28 stateless Host
|
|
116
|
+
path on isolated `7678`, and `debug:accept:relay` exercises an isolated
|
|
117
|
+
7677 Gateway → 7678 Execution topology. Each runner owns its temporary config/state,
|
|
118
|
+
generates its own authentication material, and shuts down what it started.
|
|
116
119
|
It refuses to start when port `7677` is already occupied so it cannot
|
|
117
120
|
accidentally validate an older debug process.
|
|
118
121
|
|
package/docs/roadmap.md
CHANGED
|
@@ -348,9 +348,70 @@ recovery, checkpoint, and retention facts; the Gateway only routes and presents
|
|
|
348
348
|
results. Development acceptance remains on isolated 7677/7678 instances and never uses
|
|
349
349
|
the normal 7676 installation.
|
|
350
350
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
351
|
+
## 0.10 — Command Shell Runtime P3
|
|
352
|
+
|
|
353
|
+
0.10 把 ForgeRelay 的命令执行从“默认假设 Bash”提升为显式、可观察、跨平台的
|
|
354
|
+
Command Shell Runtime,同时保持公开 Core tool 名称 `bash` 不变,避免因为 Windows
|
|
355
|
+
支持而扩大 Host 的常驻 MCP surface。
|
|
356
|
+
|
|
357
|
+
- **0.10.0** — 建立 server-lifetime Command Shell Runtime identity 与选择优先级;
|
|
358
|
+
`forgerelay init` 管理可编辑 shell Instructions;系统级高权限启动默认拒绝,只有
|
|
359
|
+
显式 `--allow-elevated` 才允许继续;
|
|
360
|
+
- **0.10.1** — 将 PowerShell 7(`pwsh`)作为 Windows 上的一等 Agent/Hook/PTY
|
|
361
|
+
runtime,并补齐真实 packaged npm acceptance;
|
|
362
|
+
- **0.10.2** — 加入 Windows PowerShell 5.1,完成 ConPTY、Unicode、进程树清理和
|
|
363
|
+
packaged launcher 路径;
|
|
364
|
+
- **0.10.3** — 将 `cmd.exe` 提升为一等 runtime,覆盖其独立 quoting、escaping、
|
|
365
|
+
`%ERRORLEVEL%`、pipe/PTY 与 `.cmd` launcher contract;
|
|
366
|
+
- **0.10.4** — 让 shell identity 跟随实际 Execution ForgeRelay,并贯通 Workspace
|
|
367
|
+
Relay、Composite Workspace、doctor、UI、Instructions 与公开 tool description;
|
|
368
|
+
- **0.10.5** — 移除 ForgeRelay 对 legacy `disable-model-invocation` Skill frontmatter
|
|
369
|
+
的过滤,保持 Skill discovery 由 Agent 侧匹配决定。
|
|
370
|
+
|
|
371
|
+
P3 的发布验收以真实 Windows shell matrix 与 packed artifact 为核心,同时继续保留
|
|
372
|
+
Linux/macOS 回归验证。开发与运行时验收只使用隔离的 7677/7678 实例,不触碰 7676。
|
|
373
|
+
|
|
374
|
+
## 1.0 — Stable product baseline
|
|
375
|
+
|
|
376
|
+
1.0 将已经完成的 Workspace、Capability Gateway、Hooks、LSP、Activity/Audit、Tasks、
|
|
377
|
+
Recovery/Checkpoint、Relay/Composite 与跨平台 shell contract 提升为稳定的 1.x 产品
|
|
378
|
+
基线,而不是重新设计一套运行时模型。
|
|
379
|
+
|
|
380
|
+
- **1.0.0** — 固化当前 MCP Core tool surface、CLI、Workspace 生命周期、managed
|
|
381
|
+
worktree finalize 与 Capability Gateway,现有 0.10.5 配置和持久化状态无需迁移;
|
|
382
|
+
- **1.0.1** — 修复 Capability 与 Workspace lifecycle pretty logging,使日志保留
|
|
383
|
+
semantic operation identity,并补齐 Composite capability attribution。
|
|
384
|
+
|
|
385
|
+
1.x 继续遵守现有发布规则:稳定版本只有在本地 release gate 与真实 7677/7678 路径
|
|
386
|
+
验收通过后才创建 tag;tag-triggered Linux/macOS/Windows workflow 成功后才形成正式
|
|
387
|
+
npm/GitHub Release。
|
|
388
|
+
|
|
389
|
+
## 1.1 — First-class image transport
|
|
390
|
+
|
|
391
|
+
1.1 把 image-bearing MCP result 纳入 ForgeRelay 的一等、受预算约束的传输路径,
|
|
392
|
+
同时保持“ForgeRelay 不是图片仓库,也不自动解引用外部引用”的边界。
|
|
393
|
+
|
|
394
|
+
- `read` 依据文件签名把 PNG、JPEG、WebP、GIF 返回为标准 MCP `ImageContent`,bulk
|
|
395
|
+
Read 保留 text/image 输入顺序;
|
|
396
|
+
- Workspace Relay 在 Execution ForgeRelay → Gateway ForgeRelay 路径中原样保留
|
|
397
|
+
image content,并在 Gateway 侧再次执行 media budget;
|
|
398
|
+
- 用户显式配置的外部 MCP server 通过 `mcp.external` Capability 调用,原生
|
|
399
|
+
`ImageContent` 可直接转发,但 path/URL/resource reference 默认仍只是 reference;
|
|
400
|
+
- `ExternalMcpBeforeForward` / `ExternalMcpAfterForward` Transform Hook 为特定
|
|
401
|
+
server/tool 提供显式结构化适配 seam,但不能改写已选择的 server/tool;
|
|
402
|
+
- Media content 保持瞬时 MCP payload,不自动成为 Artifact;Activity/Audit、日志、
|
|
403
|
+
structured output 与 Workspace state 只持久化受限 metadata,不保存 image base64;
|
|
404
|
+
- 每个 tool result 默认采用 20 MiB decoded-media budget,超限显式失败,不静默截断、
|
|
405
|
+
resize 或转码。
|
|
406
|
+
|
|
407
|
+
1.1.0 已完成真实 7677 HTTP/OAuth/MCP、7677 → 7678 Relay、external MCP、Transform
|
|
408
|
+
Hook、packed artifact 和 ChatGPT Host 图像呈现验收,并作为正式稳定版本发布。
|
|
409
|
+
|
|
410
|
+
## 1.x forward planning
|
|
411
|
+
|
|
412
|
+
当前 roadmap 没有承诺 1.1 之后的下一条 minor feature line。新的 1.x 产品工作应从
|
|
413
|
+
明确的用户目标、架构问题或外部 issue 出发,先形成可验证的 spec/tickets,再进入实现;
|
|
414
|
+
不要仅根据历史版本号顺序推断或虚构 1.2 功能范围。
|
|
354
415
|
|
|
355
416
|
## Workspace Task Lists
|
|
356
417
|
|
package/docs/security.md
CHANGED
|
@@ -147,6 +147,24 @@ Workspace from another conversation intentionally shares the same completion sco
|
|
|
147
147
|
as well. Hook handlers keep their separate bounded timeout
|
|
148
148
|
policy because they are lifecycle gates rather than user-command execution.
|
|
149
149
|
|
|
150
|
+
## External MCP configuration and credentials
|
|
151
|
+
|
|
152
|
+
External MCP extends the same local-authority model rather than creating a sandbox. Machine-wide servers live in the ForgeRelay config directory's `mcp.json`; Project servers may live in `<workspace>/.forgerelay/mcp.json`. A Project stdio entry can launch a configured executable with the same operating-system user authority as ForgeRelay, so Project MCP configuration is executable project configuration. ForgeRelay does not add a second per-server approval prompt after the operator has allowed and opened that project root.
|
|
153
|
+
|
|
154
|
+
Static HTTP headers and stdio environment values are user-managed configuration. Do not commit secrets in Project `mcp.json`; v1.1.1 does not automatically extract project-defined secrets into a secret manager.
|
|
155
|
+
|
|
156
|
+
Interactive External MCP OAuth credentials are different. They are kept in the machine-private ForgeRelay config directory:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
~/.forgerelay/mcp-auth.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Project OAuth credentials are keyed to the Project root but still stay in this private machine file; ForgeRelay does not write access tokens, refresh tokens, authorization codes, PKCE verifiers, or client secrets into the project. Callback URLs pasted in headless mode are masked in the terminal. Runtime token refresh is non-interactive; any fresh consent/authorization requires an explicit human `forgerelay mcp auth <server>` invocation.
|
|
163
|
+
|
|
164
|
+
External MCP configuration and OAuth state belong to the Execution ForgeRelay for relayed Workspaces. The Gateway does not receive or replicate those credentials merely because it forwards the Workspace operation.
|
|
165
|
+
|
|
166
|
+
External MCP result references are not implicitly dereferenced. Paths, URLs and MCP resource references returned by an upstream server remain references unless the Agent explicitly reads them or an explicitly configured External MCP transform Hook changes the result.
|
|
167
|
+
|
|
150
168
|
## Lifecycle hooks
|
|
151
169
|
|
|
152
170
|
Hook command 是本地代码执行,使用与 ForgeRelay 相同的操作系统用户权限并继承进程环境。
|