Skip to content

WebMCP: publish full skill-lib catalogue and invoke live MCP tools - #87

Merged
erinepshovel-code merged 14 commits into
mainfrom
feat/full-skill-catalog-mcp-invocation
Oct 17, 2026
Merged

erinepshovel-code merged 14 commits into
mainfrom
feat/full-skill-catalog-mcp-invocation

Conversation

@erinepshovel-code

Copy link
Copy Markdown
Contributor

FROM → TO

From a curated WebMCP subset and five registry-only MCP tools → to the entire verified skill-lib catalogue (all 45 currently registered skills) plus explicit browser-side Streamable HTTP tool discovery and invocation.

Changes

  • Publish both metadata-block and procedural skills from the same commit-pinned registry projection; keep repository-first action selection, dependency closure and static no-JS reading.
  • Add a direct JSON-mode MCP client with endpoint validation, explicit calls, optional transient bearer credential, no redirects or ambient cookies, and actual server response/failure readouts.
  • Enable Enact selected skill via MCP only when the connected endpoint advertises tiw_execute_skill; require repository head, selected skill, human outcome and explicit approval. A server reply is not reported as a verified completed job.
  • Retain the public MCP server as five read-only registry operations; add client tests including a real loopback read-only server roundtrip and negative transport/security cases.
  • Document executor envelope and receipt/authority obligations; append builder journal entry.

Contract

DONE WHEN: every skill in the source registry can be inspected in the human page and read-only tool registry; a user can invoke an advertised MCP tool with actual response and explicit failure; no operational execution is implied without the advertised tiw_execute_skill tool.

PROVEN BY: npm run test:mcp, WebMCP tests, site build gates, builder-history gate, and explicit loopback tool invocation.

FAILS IF: any skills are hidden, write privileges are granted by selection, credentials persist, a fabricated runner result is shown, or an unavailable executor is represented as working.

hmmm: The deployed public endpoint provides no executor. Connecting and verifying an independently authorized skill runner remains a separate operational dependency; no public-site changes should install VM-shell authority in the registry server.

@erinepshovel-code
erinepshovel-code marked this pull request as ready for review October 17, 2026 22:26
@erinepshovel-code
erinepshovel-code merged commit c955f2f into main Oct 17, 2026
5 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T22:31:27.555952Z b23b73b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b23b73b73a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/assets/js/webmcp.js
setText(toolsStatus, `Calling ${tool.name}…`, 'hmmm');
try {
const result = await invokeMcpTool(boundEndpoint, tool.name, args, { token: tokenInput?.value || '' });
if (requestRevision !== revision) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve in-flight execution receipts after context edits

If the repository, skill, outcome, endpoint, or credential changes while a tools/call request is in flight, the associated listeners increment revision, so this early return discards the executor's eventual success or failure. An effectful call may already have changed the remote repository, leaving the user without its only receipt and potentially prompting a duplicate retry; retain the response with the invocation's original context rather than silently dropping it.

Useful? React with 👍 / 👎.

Comment on lines +55 to +58
if (body.length > MAX_ARGUMENT_CHARS) throw new Error('MCP arguments exceed the request limit');

let response;
try {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Time out stalled MCP requests

When an endpoint accepts the connection but never completes the response or stalls while sending its body, this fetch has no timeout unless an external caller supplies a signal, and the page binding supplies none. The surrounding busy state therefore never clears, leaving discovery and invocation controls disabled even after the endpoint is edited; create a bounded abort signal for browser requests.

Useful? React with 👍 / 👎.

Comment on lines +71 to +72
}
const size = Number(response.headers.get('content-length') || 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the response limit while reading the body

For a chunked response or any response without a trustworthy Content-Length, response.text() buffers the entire payload before the character limit is checked. A misconfigured or compromised endpoint can therefore consume unbounded browser memory despite MAX_RESPONSE_CHARS; stream the body and abort as soon as the limit is exceeded.

Useful? React with 👍 / 👎.

export async function discoverMcpTools(endpoint, options = {}) {
const result = await mcpRequest(endpoint, 'tools/list', {}, options);
if (!Array.isArray(result.tools)) throw new Error('MCP tools/list returned no tool catalogue');
const names = new Set();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Follow pagination when discovering tools

When tools/list returns a nextCursor, this reads only the initial page and silently ignores every later tool. An executor located on a later page is consequently absent from the selector and leaves skill enactment disabled even though the endpoint advertises it; the official MCP SDK pagination documentation specifies that clients follow nextCursor until it is omitted.

Useful? React with 👍 / 👎.

});
} catch {
throw new Error('MCP request failed: check endpoint availability, HTTPS, CORS, and network access');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse modern JSON-RPC errors before rejecting HTTP 400

For a 2026-era request, a conforming server can return HTTP 400 with a matching JSON-RPC error body, such as a header-mismatch or missing-capability error; the official TypeScript SDK documentation treats these as in-band protocol errors. Rejecting on response.ok before reading that body replaces the actionable MCP error with only MCP HTTP 400, so the page cannot display the endpoint's actual failure as promised.

Useful? React with 👍 / 👎.

Comment thread src/assets/js/webmcp.js
setResult(`hmmm: Invalid tool arguments: ${error.message}`);
return;
}
await execute(tool, args);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reserve the execution tool for guarded enactment

When the discovered dropdown contains tiw_execute_skill, the generic Call button reaches this path with arbitrary hand-entered arguments, bypassing the dedicated enactment checks for a repository head, selected skill, outcome, and canonical envelope. It also skips the forced confirmation when the server advertises readOnlyHint: true, so the same execution tool that the guarded button treats as effectful can be invoked without those human-in-loop protections; exclude this tool from the generic path or route it through the guarded enactment flow.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant