Skip to content

MCP server

For every verified site, Sill runs a per-site Model Context Protocol (MCP) server at its edge, over Streamable-HTTP transport. MCP clients can connect to the site’s MCP endpoint to discover and invoke the site’s exposed skills.

POST https://edge.sill.so/v1/mcp/{site_key}

The transport is Streamable-HTTP, as defined in the MCP specification.

  • initialize — the MCP handshake. Returns the server’s protocol version and capabilities.
  • tools/list — returns the site’s exposed skills as MCP tools. The tool set is backing-filtered — only skills the site actually exposes through a wired backing appear here (the same set the agent card advertises).
  • tools/call invocations are recorded in the site’s signed audit envelope.

A minimal MCP initialize request, posted to a verified site’s MCP endpoint:

POST /v1/mcp/SITE_KEY HTTP/1.1
Host: edge.sill.so
Content-Type: application/json
Accept: application/json, text/event-stream
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "example-client", "version": "0.0.0" }
}
}

Replace SITE_KEY with the site key issued for the verified domain.

An agent can narrow the tools returned by tools/list to a declared subset by including an optional params._meta.sill_scope array of skill_id strings in the request. The server returns the intersection of (a) the site’s enabled, backed skills and (b) the declared scope. This lets an agent operating at least-privilege — for example a research-only client that never intends to check out — avoid learning the identifiers of skills it does not plan to call.

Scope filtering is a discovery-only signal. It does not gate tools/call. The mandate + policy pipeline remains the authorization surface for every invocation; an agent that calls a skill outside its declared scope hits that pipeline unchanged.

// tools/list with declared scope
const request = {
jsonrpc: '2.0',
id: 42,
method: 'tools/list',
params: {
_meta: {
sill_scope: ['browse_catalog', 'check_availability'],
},
},
};

On a site with the seven default skills enabled, this request returns two tools (browse_catalog, check_availability) instead of all seven. _meta is the MCP-reserved extension namespace; the sill_ prefix on sill_scope marks it as Sill-defined so it will not collide with other server extensions.

The response is a standard MCP tools/list result. The tools[] array is a subset of what an unscoped request would return; no new fields are added.

{
jsonrpc: '2.0',
id: 42,
result: {
tools: [
{ name: 'browse_catalog', description: '...', inputSchema: { /* ... */ } },
{ name: 'check_availability', description: '...', inputSchema: { /* ... */ } },
],
nextCursor: null,
},
}

The filter is fail-open. Any of the following returns the site’s full enabled-skill list, byte-identical to the unscoped behavior:

  • params absent, or not an object.
  • _meta absent, or not an object.
  • sill_scope absent, or not an array.
  • sill_scope present but every entry is invalid (all dropped by validation — see below).

Each entry in sill_scope is validated independently. Entries that fail validation are silently dropped; the request is never rejected on the basis of an invalid scope entry.

RuleBehavior
Element type must be stringNon-strings dropped.
skill_id shape: /^[a-z][a-z0-9_]*$/Non-matching entries dropped.
Maximum length: 64 characters per entryLonger entries dropped.
Maximum array length: 32 entriesEntries beyond the first 32 truncated.

The silent-drop discipline is deliberate. Surfacing a per-entry diagnostic would give a probing client a shape-fuzzing oracle for the skill_id validator; the operator-side signal is a structured log line, not a client-visible field.

Skills in sill_scope that are not in the site’s enabled set are silently ignored. The response does not distinguish “this skill exists but is disabled” from “this skill does not exist” — the same anti-fingerprinting posture the edge applies elsewhere.

  • initialize is unchanged. No scope is captured at handshake time. The server does not persist per-session scope state; declarations are per-request.
  • tools/call is unchanged. The declared scope has no effect on invocation. Merchant policy remains the authority on what a request is allowed to do.
  • No feature flag. The filter is additive and fail-open; clients that never send _meta.sill_scope see today’s behavior byte-for-byte.
  • Connector-wired skills (e.g. catalog browse against a wired commerce backend) dispatch through Sill’s connector layer.
  • Skills without a wired backing fall back to discovery / observe-only.
  • Money-movement skills require a signed mandate and dispatch only when payments are enabled. See the Transactional overview.
  • MCP server responses are not signed. The signed surface is the agent card pointer to the MCP endpoint, not the MCP responses themselves. (See the agent card.)
  • The verified surface is live MCP discovery (initialize + tools/list) and the audited tools/call record. Full MCP skill execution is conditional on the skill’s backing, and money-movement skills additionally require the signed-mandate path.