Find the URL
/sse suffix — mcp list returns the Streamable HTTP URL directly.
The older
/mcp/<version-id>/sse route still works, and existing clients on it keep running. It is transitional compatibility rather than the current transport, so point new clients at the Streamable HTTP URL above.Open a session
POST a JSON-RPCinitialize request with your token:
Mcp-Session-Id and the negotiated MCP-Protocol-Version. Before listing or calling tools, complete the MCP lifecycle with a notification in a second POST carrying both returned headers:
execute arguments. The execute tool declares that session.get, session.set, and session.page are already attached inside its script and share state only across calls on the same MCP connection. Reinitializing creates fresh state; old result_ref values cannot cross into it.
If a connection is unavailable, the Engine returns HTTP 404 with MCP_SESSION_UNAVAILABLE and a compact recovery contract:
execute script that does not use prior session state can keep its arguments. Rebuild a script that uses session.get, session.page, or an earlier result_ref, because those values do not cross the reset.
A partial provider dispatch, timeout, or lost runtime response instead returns MCP_EXECUTION_OUTCOME_UNKNOWN with execute_request: do_not_replay and provider_execution: unknown. Reconnect, inspect current state, and do not automatically replay execute, because a provider mutation may already have been accepted. Recovery fields never contain the opaque session ID or token. Detailed transport diagnostics remain internal OTEL attributes.
The execute_request field tells the agent whether formatting must change. correct_arguments means reformat the current execute arguments and is paired with provider_execution: not_started. adjust_projection means provider work is complete; change only the session-local result projection. use_next_request means run the supplied request exactly. unchanged requires no script change, while do_not_replay prohibits resubmission until the external outcome has been inspected.
DELETE ends that session and nothing more. It is not revocation — use mcp token revoke for that.
The two tools
The agent-facing surface is deliberately small. A large tool catalogue is what fills a model’s context before it has done anything useful; two tools plus just-in-time discovery does not.search_docs
Ranks operations and returns calling detail, with exact lookup when pagination bounds or omitted schema sections require it.
execute
Runs a single approved call, or TypeScript chaining several, away from credentials, the filesystem, and open network access.
search_docs response is bounded to 64 KiB of UTF-8 JSON. Check schema_status.complete before writing the call. When it is false, compare included_sections with available_sections and request only the missing section with the exact operationId and section. Physical operations expose parameters, request, and response:<status> sections. Unified operations expose input, targets, and output. You can add an RFC 6901 schemaPath to retrieve one smaller subtree when a section is still too large. Sections are returned whole or omitted, so never infer fields from an incomplete result.
A ranked physical result that may support Engine pagination returns pagination.supported: true and pagination.exact_lookup_required: true. Its usage offers only an exact operationId lookup for full guidance or the safe two-argument call(operationId, params). It deliberately omits caller_bound_supported and engine_max_pages, and neither mentions nor authorizes a numeric bound or third argument. Resolve exact detail before adding a pagination option, but not solely to make the safe two-argument call. Exact physical detail returns the authoritative supported, caller_bound_supported, optional engine_max_pages, and usage fields. A ranked result may instead establish supported: false and provide the exact two-argument form without another lookup solely for pagination, but it also omits caller_bound_supported. Exact mode alone exposes caller_bound_supported and engine_max_pages.
Pagination guidance belongs only to the operation ID in the same result. Evaluate every physical call separately: guidance for gmail.users.messages.list never authorizes a third argument for gmail.users.messages.get. Do not infer pagination from GET or from parameter names such as page, cursor, offset, or Gmail maxResults.
Call search_docs without a query only when you need to browse. That mode returns a bounded, schema-free catalogue with total and truncated metadata. If you already know the public operation ID, use exact operationId lookup instead of intent search.
Chaining several operations inside one execute does not bundle them into a single approval. The Engine authorizes each underlying operation on its own merits, and anything outside the token’s allowlist is refused even mid-script.
Execution deadlines and delays
Eachexecute has a 30-second total budget and allows at most ten call() invocations. Provider calls, delays, and result serialization share that budget. A 15-second delay leaves roughly 15 seconds for everything else. You receive the result after the script finishes, not after each underlying call.
Use await sleep(milliseconds) for a delay. Existing await new Promise(resolve => setTimeout(resolve, milliseconds)) scripts also work. Timers return numeric handles for clearTimeout, accept finite delays from 0 to 2,147,483,647 milliseconds, and allow at most 1,000 pending timers per invocation. They do not survive the invocation’s deadline.
Await every operation. On completion, failure, cancellation, or timeout, Fused clears pending timers, aborts outstanding bridge HTTP requests, and blocks further calls from that invocation. Detached timers are not a background workflow mechanism. A timeout returns MCP_EXECUTE_TIMEOUT; a client cancellation observed by the runtime uses MCP_EXECUTE_CANCELLED.
Decode encoded provider data
Use these helpers inside the existingexecute tool; they do not add MCP tools or make provider calls:
decodeBase64(text)returns UTF-8 text from standard base64 or base64url, with or without padding.encodeBase64(text, urlSafe = false)encodes UTF-8 text. Passtruefor unpadded base64url.atob(text)returns a binary string from standard base64. It is not a UTF-8 decoder and does not accept the URL-safe alphabet.
decodeBase64 also rejects invalid UTF-8; use atob when you need binary byte values. The unrestricted Node Buffer API is not exposed.
Decoding a Gmail message does not parse its MIME or RFC822 structure. Decode the needed content, select or parse the fields your task requires, and return only those fields under the normal output budget. These helpers do not remove the existing result-size limits.
Retrieve large results without repeating the operation
execute returns results directly when they fit its output budget: 16 KiB of UTF-8 JSON by default. Set the optional outputBudgetBytes tool argument from 1,024 to 65,536 bytes when your client needs a different limit. This is a byte budget, not a token count; token usage depends on your model and data.
For larger admitted results, Fused keeps a snapshot in the current session and returns a small MCP_RESULT_STORED envelope. It includes result_ref, expiry, byte size, the effective output budget, explicit same-session state, a directly executable next_request, and an explicitly incomplete structural preview. Run next_request through execute to begin a session-only read without reconstructing a call or repeating the provider operation. Its collections list advertises array paths, row counts, and observed immediate field names, so you can choose a different projection without another discovery call. Automatic previews and collection metadata do not include scalar values, such as message text or file contents.
For example, a transaction collection can advertise this metadata:
session.page inside the existing execute tool to retrieve as many complete projected rows as fit. This reads the stored snapshot without repeating any provider calls:
path is an RFC 6901 JSON Pointer; omit it or use "" for a root array. fields contains literal immediate object keys, not dotted paths. Omit fields to return whole rows, including primitive or mixed-type rows. Selected sparse fields stay absent where missing; a field absent from every row is rejected. An empty collection returns an empty complete page.
Each page contains items, offset, total, returned, nextOffset, and complete. Continue with the same reference, path, fields, and output budget using the returned nextOffset. A null nextOffset and complete: true mean no rows remain after this page; they do not mean earlier pages are included. Return the page directly instead of collecting all pages into another oversized result. Fused counts the serialized page envelope, JSON escaping, and UTF-8 bytes when choosing the row count.
Discovery is bounded: at most eight collections, 256 traversal nodes, eight levels, 32 children per node, 512 inspected rows per collection, and 32 field names of at most 128 UTF-8 bytes. fields_complete: false means some field information was omitted; collections_complete: false means some collection paths were omitted. A small output budget may reduce metadata further. You can select advertised fields immediately even when discovery is incomplete. Use session.get(result_ref) followed by ordinary JavaScript property access, Object.keys(...), or string slicing to inspect additional stored values. session.get accepts exactly one string key; use session.page for an RFC 6901 array path. Extra session.get arguments fail explicitly instead of being ignored. Never infer that an unlisted field does not exist.
If one selected row cannot fit, MCP_RESULT_ROW_TOO_LARGE asks you to choose fewer fields or use session.get to inspect a field or string slice. Fused never silently cuts a row or returns a non-progressing empty page. Do not repeat the original operation to recover from a paging error. If you only need a total or other aggregate, calculate it inside execute and return the answer rather than every transaction.
Each session retains at most 16 snapshots and 4 MiB, evicting the oldest first. References expire five minutes after creation; reads do not extend their lifetime. Closing the session releases its snapshots, and another session cannot retrieve them. If you receive MCP_RESULT_UNAVAILABLE, the result is no longer available: decide explicitly whether repeating the operation is safe. Never automatically retry an operation with side effects.
The existing 1 MiB limit for each physical result and final execution value still applies. Model-facing execution JSON is capped at 64 KiB. Error text uses the smaller of your output budget and 8 KiB. Retention is temporary navigation, not persistent storage or a way to bypass execution limits.
Unified operations
search_docs returns token-authorized Unified operations beside physical operations under their exact authored names. Call one through the same execute tool:
targets is always required. It names the exact binding steps to run, must include every declared dependency of those steps, and never defaults to all bindings. A Unified call may also include target-keyed selectors, pagination, and an idempotencyKey. Physical-target pagination inside a Unified operation must use that target-keyed Unified pagination parameter, never the separate third argument used for a direct physical call. See call a unified operation for the complete contract.
What tools never accept
Neither the tool schema nor itscall() function accepts a provider token, API key, client secret, or other provider credential.
Physical calls use the session’s connected-user routing. Unified calls mirror the SDK and may carry non-secret service selectors such as endUserRef, authType, authName, and resourceId; Engine middleware still resolves the actual credential before dispatch. A fixed-binding token remains authoritative and ignores a conflicting caller user or resource selector. See tokens for OAuth services.
Provider arguments
Arguments come from the imported canonical request schema. Two behaviours are worth expecting:- Map-valued objects keep their
additional_propertiesvalue schema. Validate each entry rather than treating the object as untyped. - Resource-name path values are passed normally. Where the contract marks slash-preserving expansion, the Engine keeps embedded
/separators and still escapes unsafe segment characters. Do not pre-encode.
Pagination
Pagination is derived from the selected endpoint and its current effective service-version policy. Do not add pagination fields to the MCP config or to physical provider schemas. Rankedpagination.supported: true guidance safely authorizes an ordinary call(operationId, params), which completes the reviewed provider pagination loop inside Engine and returns one aggregate before MCP result retention runs.
Provider page-size parameters such as Gmail maxResults do not bound total Engine traversal. Only when exact detail for that same operationId reports caller_bound_supported: true and a goal intentionally needs the first N provider pages may you pass the canonical caller bound as call(operationId, params, { pagination: { maxPages: N } }), using a positive N strictly lower than engine_max_pages. Never derive a numeric bound or third argument from a ranked result, including one with supported: true. A supported one-page policy has caller_bound_supported: false because no positive lower bound exists.
When available guidance reports supported: false, or exact detail reports caller_bound_supported: false, use the two-argument form and omit the pagination option. Engine makes one provider request for an unsupported call and does not traverse pages. Manually repeat a paged GET only when its documentation explicitly supplies the page input, continuation output, and stop condition: pass the page input in params, await the two-argument call(), read the continuation from the result, and repeat until that stop condition. Every page remains subject to the same ten-call and 30-second execute limits. Never guess those semantics from field names. A Unified call keeps its target-keyed pagination inside the documented Unified invocation object.
Invalid physical pagination intent is rejected before that operation reaches its provider. This includes a missing or invalid maxPages, pagination on an unsupported operation, and a bound that does not strictly lower the Engine limit. When no earlier or concurrent call in the same execute may have dispatched, this isolated failure returns execute_request: correct_arguments, provider_execution: not_started, and automatic_replay: false; correct the current arguments using exact operation guidance. Invalid target-keyed physical pagination on a Unified call is also a pre-provider correction when isolated.
If an earlier or concurrent call may have dispatched, the outer execute instead returns execute_request: do_not_replay with provider_execution: unknown, because the script may already have provider side effects. Inspect external state before issuing new work; do not replay the whole script merely because the pagination validation itself preceded its provider call.
If automatic traversal reaches an Engine pagination limit before the provider terminates, narrow the provider query or deliberately choose a smaller caller bound. Do not suppress the provider’s continuation field through a partial-response selector to make an unfinished collection appear complete.
Useful commands
Create a token for an agent
The token from your first apply allows everything and never expires. Narrow it before an agent uses it.