Summary
site_insert_html with an element the importer has no module for (<link>) does not
return a validation error. It hangs, and it leaves the MCP bridge permanently wedged.
After that single call, every browser-routed MCP tool fails with:
AI chat stream ended before tool result arrived.
This is not scoped to the tool or the document that triggered it. It takes down the
Site editor and the Content workspace together, and it survives every recovery I could
attempt from the client side.
Found while pushing a 7-page static site into a hosted Instatic instance over the MCP
connector. The rest of that session surfaced several smaller issues, listed at the
bottom; happy to split any of them into separate issues if you prefer.
Steps to reproduce
- Connect the MCP connector with the Site editor open.
- Confirm editor-routed tools work (
site_get_node_html on any node returns HTML).
- Call
site_insert_html with an unsupported element:
{ "parentId": "<any page rootNodeId>", "index": 0,
"html": "<link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />" }
- The call never returns a result.
- Every subsequent browser-routed call fails with the stream error above.
Expected behavior
An unsupported element is rejected with a validation error naming the element, the way
an invalid site_apply_css selector would be. A malformed import must not be able to
wedge the bridge.
Actual behavior
The bridge stops servicing browser-routed requests for the remainder of the session.
Confirmed still broken after each of these:
- reloading the Site editor browser tab
/mcp reconnect of the connector (twice)
- reconnect first, then reload the tab
- opening the Content workspace instead (a different workspace, same failure)
Tools verified failing after the hang: site_get_node_html, site_read_document,
site_list_code_assets (including type=style, which returns one small asset, so
payload size is not the cause), site_inspect_code_runtime,
content_set_active_document, content_set_document_fields.
Headless tools kept working normally throughout: get_context,
site_list_documents, site_publish, content_get_collection_schema,
content_list_documents, content_get_document. So the server and the data layer are
fine; it is specifically the browser bridge that is stuck. That split is also what made
it recoverable enough to finish the work: I could still publish.
One detail that may help localise it. Immediately after a /mcp reconnect, the first
editor call returned a clean, correct error:
This tool runs in the Instatic Site editor. Open the Site editor in a browser ...
and the very next call was wedged again. That looks like the stale client re-registering
onto the fresh bridge and re-poisoning it, rather than the bridge itself being
unrecoverable.
Version or commit
Hosted Railway deployment, tested 2026-09-05. Connector over HTTP MCP.
Deployment mode
Hosted (Railway)
Secondary: get_context reports a connection that services nothing
Throughout the wedge, get_context kept returning:
{"editor":{"siteConnected":true,"contentConnected":false}}
siteConnected: true while every editor call times out. It appears to reflect a
registration record rather than a live ping. This cost several diagnostic cycles,
because the obvious reading is "connected, so the problem is my call". A liveness check,
or a lastSeen timestamp, would make this self-diagnosing.
Other findings from the same session
Separate from the hang. All verified on the same deployment.
1. Routes resolve at both /path and /path/ with no canonicalisation
/web-ops and /web-ops/ both return 200 and neither redirects to the other. Because
relative hrefs resolve against the current URL, every relative link on a page breaks
when the visitor arrives at the unslashed form:
from /web-ops |
from /web-ops/ |
assessment/ -> /assessment/ (404) |
-> /web-ops/assessment/ (200) |
why/ -> /why/ (404) |
-> /web-ops/why/ (200) |
Any site authored with relative links is half-broken depending on entry URL, and both
forms are independently indexable. Worked around by rewriting all 78 internal links to
root-absolute. A 301 to one canonical form, or a <link rel="canonical">, would fix it.
2. site_replace_node_html silently drops <script>
Body HTML containing a <script> imports without it. No warning, no error; the returned
nodeIds simply omit it. Distinct from #411 (attributes) in that the whole element
disappears. Scripts do have a legitimate home in the code-asset layer, so the fix may
just be to say so in the tool description and/or return a notice.
3. site_apply_css can silently no-op
site_apply_css merge ".compare-head .is-us { color: var(--fg); }"
-> {"cssRulesCreated": 0, "cssRulesUpdated": 0}
No error, no rule written. An existing .compare-head span rule ties it on specificity.
Raising specificity to .compare-head span.is-us created it. A zero/zero result with
supplied CSS should report why.
4. CMS form: honeypotName injects a duplicate field
Setting honeypotName to a field name that already exists in the page markup makes
Instatic inject a second input with that name. The value then submits as an array:
"values": { "company_website_url": ["", ""], ... }
and the endpoint rejects it with {"error":"Invalid form submission"}. Every submission
fails. Deleting the authored field fixed it. Worth either detecting the collision or
saying in the prop description that the honeypot is generated and must not exist in
markup.
5. honeypotName defaults to company
base.form defaults honeypotName to "company". That is an extremely common real
field name; our lead form had a required company field. Left at the default, every
genuine submission is silently classified as spam. A default that cannot collide
(_instatic_hp, say) would be safer.
6. Re-importing a page's HTML resets form node props
site_replace_node_html recreates the node tree, so a form configured via
site_update_node_props (mode: cms, targetTableId, honeypotName, redirectUrl)
silently reverts to importer defaults, including back to mode: custom. On a live lead
form that means submissions stop being stored with no visible change. Possibly related
to #466.
7. No favicon support
Published <head> contains no <link rel="icon">. /favicon.svg serves a placeholder
that nothing references, and browsers only auto-probe /favicon.ico, which 404s. So a
site cannot have a favicon at all, and there is no MCP surface or <head> extension
point to add one.
8. #411 still reproduces
#411 (image alt dropped, published
alt sourced only from Media Library metadata) is closed, but reproduces on this
deployment as of 2026-09-05: 8 images pushed with descriptive alt all published as
alt="", giving 0 of 14 images site-wide any alt text. Combined with #416 (no media
metadata write in MCP), alt text is currently unreachable end to end for an
agent-driven workflow.
Related existing issues
Not re-reporting these, listing them so the SEO picture is in one place:
#219 (seoTitle/seoDescription unreachable for Pages), #425 (root-level
sitemap.xml/robots.txt), #416 (MCP media metadata lifecycle), #411 (image alt),
#380 (honeypot rejections unobservable).
Summary
site_insert_htmlwith an element the importer has no module for (<link>) does notreturn a validation error. It hangs, and it leaves the MCP bridge permanently wedged.
After that single call, every browser-routed MCP tool fails with:
This is not scoped to the tool or the document that triggered it. It takes down the
Site editor and the Content workspace together, and it survives every recovery I could
attempt from the client side.
Found while pushing a 7-page static site into a hosted Instatic instance over the MCP
connector. The rest of that session surfaced several smaller issues, listed at the
bottom; happy to split any of them into separate issues if you prefer.
Steps to reproduce
site_get_node_htmlon any node returns HTML).site_insert_htmlwith an unsupported element:{ "parentId": "<any page rootNodeId>", "index": 0, "html": "<link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />" }Expected behavior
An unsupported element is rejected with a validation error naming the element, the way
an invalid
site_apply_cssselector would be. A malformed import must not be able towedge the bridge.
Actual behavior
The bridge stops servicing browser-routed requests for the remainder of the session.
Confirmed still broken after each of these:
/mcpreconnect of the connector (twice)Tools verified failing after the hang:
site_get_node_html,site_read_document,site_list_code_assets(includingtype=style, which returns one small asset, sopayload size is not the cause),
site_inspect_code_runtime,content_set_active_document,content_set_document_fields.Headless tools kept working normally throughout:
get_context,site_list_documents,site_publish,content_get_collection_schema,content_list_documents,content_get_document. So the server and the data layer arefine; it is specifically the browser bridge that is stuck. That split is also what made
it recoverable enough to finish the work: I could still publish.
One detail that may help localise it. Immediately after a
/mcpreconnect, the firsteditor call returned a clean, correct error:
and the very next call was wedged again. That looks like the stale client re-registering
onto the fresh bridge and re-poisoning it, rather than the bridge itself being
unrecoverable.
Version or commit
Hosted Railway deployment, tested 2026-09-05. Connector over HTTP MCP.
Deployment mode
Hosted (Railway)
Secondary:
get_contextreports a connection that services nothingThroughout the wedge,
get_contextkept returning:{"editor":{"siteConnected":true,"contentConnected":false}}siteConnected: truewhile every editor call times out. It appears to reflect aregistration record rather than a live ping. This cost several diagnostic cycles,
because the obvious reading is "connected, so the problem is my call". A liveness check,
or a
lastSeentimestamp, would make this self-diagnosing.Other findings from the same session
Separate from the hang. All verified on the same deployment.
1. Routes resolve at both
/pathand/path/with no canonicalisation/web-opsand/web-ops/both return 200 and neither redirects to the other. Becauserelative hrefs resolve against the current URL, every relative link on a page breaks
when the visitor arrives at the unslashed form:
/web-ops/web-ops/assessment/->/assessment/(404)/web-ops/assessment/(200)why/->/why/(404)/web-ops/why/(200)Any site authored with relative links is half-broken depending on entry URL, and both
forms are independently indexable. Worked around by rewriting all 78 internal links to
root-absolute. A 301 to one canonical form, or a
<link rel="canonical">, would fix it.2.
site_replace_node_htmlsilently drops<script>Body HTML containing a
<script>imports without it. No warning, no error; the returnednodeIdssimply omit it. Distinct from #411 (attributes) in that the whole elementdisappears. Scripts do have a legitimate home in the code-asset layer, so the fix may
just be to say so in the tool description and/or return a notice.
3.
site_apply_csscan silently no-opNo error, no rule written. An existing
.compare-head spanrule ties it on specificity.Raising specificity to
.compare-head span.is-uscreated it. A zero/zero result withsupplied CSS should report why.
4. CMS form:
honeypotNameinjects a duplicate fieldSetting
honeypotNameto a field name that already exists in the page markup makesInstatic inject a second input with that name. The value then submits as an array:
and the endpoint rejects it with
{"error":"Invalid form submission"}. Every submissionfails. Deleting the authored field fixed it. Worth either detecting the collision or
saying in the prop description that the honeypot is generated and must not exist in
markup.
5.
honeypotNamedefaults tocompanybase.formdefaultshoneypotNameto"company". That is an extremely common realfield name; our lead form had a required
companyfield. Left at the default, everygenuine submission is silently classified as spam. A default that cannot collide
(
_instatic_hp, say) would be safer.6. Re-importing a page's HTML resets form node props
site_replace_node_htmlrecreates the node tree, so a form configured viasite_update_node_props(mode: cms,targetTableId,honeypotName,redirectUrl)silently reverts to importer defaults, including back to
mode: custom. On a live leadform that means submissions stop being stored with no visible change. Possibly related
to #466.
7. No favicon support
Published
<head>contains no<link rel="icon">./favicon.svgserves a placeholderthat nothing references, and browsers only auto-probe
/favicon.ico, which 404s. So asite cannot have a favicon at all, and there is no MCP surface or
<head>extensionpoint to add one.
8. #411 still reproduces
#411 (image
altdropped, publishedaltsourced only from Media Library metadata) is closed, but reproduces on thisdeployment as of 2026-09-05: 8 images pushed with descriptive
altall published asalt="", giving 0 of 14 images site-wide any alt text. Combined with #416 (no mediametadata write in MCP), alt text is currently unreachable end to end for an
agent-driven workflow.
Related existing issues
Not re-reporting these, listing them so the SEO picture is in one place:
#219 (
seoTitle/seoDescriptionunreachable for Pages), #425 (root-levelsitemap.xml/robots.txt), #416 (MCP media metadata lifecycle), #411 (imagealt),#380 (honeypot rejections unobservable).