@eclipse-glsp/protocol
Version:
The protocol definition for client-server communication in GLSP
225 lines • 10.8 kB
TypeScript
/********************************************************************************
* Copyright (c) 2025-2026 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { InitializeParameters, InitializeResult } from './types';
/** Wire-protocol naming for the data-handler exposure mode (see {@link McpServerInitOptions.dataMode}). */
export type McpDataMode = 'resources' | 'tools';
/**
* Behavioral and tuning options that an MCP-aware GLSP client may pass through the
* `initialize` request. Every field here is safe for the IDE to control per-init: changing
* any of them cannot widen the network attack surface or relax the DNS-rebinding mitigation.
*
* Contrast with {@link McpServerDeployOptions}, which lists fields the adopter sets at
* deploy time and that are intentionally *not* exposed to init for security reasons. The
* split limits blast radius: behavioural fields like `port` may be negotiated by the IDE
* over the wire, while security-sensitive bind/policy fields stay adopter-controlled and
* cannot be widened by an MCP `initialize` payload.
*
* @experimental
*/
export interface McpServerInitOptions {
/**
* How the data handlers are exposed to the MCP client. `'tools'` registers them as tools
* (default — most MCP clients support tools more reliably). `'resources'` registers them
* as URI-addressable Resources, the spec-aligned form, when the client is known to
* support it.
*
* @default 'tools'
*/
dataMode?: McpDataMode;
/**
* The personality injected into MCP clients by reading the MCP server's instructions.
*/
agentPersona?: string;
/**
* Maximum number of historical SSE events the in-memory event store retains per session.
* Older events are evicted (LRU by insert order) so memory stays bounded under long-running
* deployments. Must exceed the worst-case in-flight event count or a client reconnecting
* with a stale `Last-Event-ID` will find its resume point already evicted.
*
* @default 10000
*/
eventStoreLimit?: number;
}
/**
* Security-sensitive bind/policy fields the adopter sets at deploy time on the server
* module. These fields are deliberately *not* part of the wire-protocol init schema — they
* are not reachable from {@link McpServerConfiguration.options}, and the launcher reads
* them only from the adopter-supplied defaults. The server-side runtime view that consumers
* `@inject` (the holder named {@link McpServerOptions}) carries the merged combined shape
* {@link McpServerOptions} = init ∩ deploy.
*
* Why these are deploy-only: an MCP client driven by an LLM should not be able to widen the
* server's network exposure or weaken its DNS-rebinding mitigation through an `initialize`
* payload.
*
* @experimental
*/
export interface McpServerDeployOptions {
/**
* Host/interface the MCP HTTP server binds to. The launcher pins this to loopback by
* default; an adopter overrides via the server module's `McpServerDefaults` binding when
* they need a non-loopback bind.
*
* @default '127.0.0.1'
*/
host?: string;
/**
* Allowed `Host` header values for the MCP HTTP endpoint. Requests whose `Host` header is
* not in this list are rejected with `403 Forbidden`. Spec MUST per the Streamable HTTP
* transport's DNS-rebinding mitigation.
*
* @default ['127.0.0.1', 'localhost']
*/
allowedHosts?: string[];
/**
* Allowed `Origin` header values. When set, browser-originating requests with an `Origin`
* not in this list are rejected with `403 Forbidden`. Leave undefined to skip Origin
* checking (typical for desktop-IDE MCP clients which omit `Origin`); set explicitly when
* the deployment is fronted by a browser-based MCP client.
*/
allowedOrigins?: string[];
/**
* Explicit acknowledgement that the operator accepts running an unauthenticated MCP
* endpoint on a non-loopback bind. The MCP server ships with NO built-in authentication;
* the default `host: '127.0.0.1'` is the only safe configuration without external
* fronting. Setting a non-loopback `host` (e.g., `'0.0.0.0'` for "easier dev access")
* WITHOUT setting this flag causes the launcher to refuse to start with an actionable
* error.
*
* Set to `true` only when an external mechanism (reverse proxy, mTLS, network ACL, etc.)
* authenticates traffic before it reaches the MCP endpoint. Deploy-only — like the other
* fields in this type, it is unreachable from the wire.
*
* @default false
*/
acknowledgedNoAuth?: boolean;
}
/**
* Combined view of MCP server options as seen by the server-side runtime (defaults merged
* with the init-time overrides). Adopters supplying defaults via the server module's
* `McpServerDefaults` binding use this shape; per-init overrides use the narrower
* {@link McpServerInitOptions}.
*
* @experimental
*/
export type McpServerOptions = McpServerInitOptions & McpServerDeployOptions;
/** @experimental */
export interface McpServerConfiguration {
/**
* The port on which the MCP server should be started. Defaults to `0` (a random available
* port). The resolved URL is reported in {@link McpInitializeResult.mcpServer.url} and as a
* tagged log line on the GLSP server's stdout (`[GLSP-MCP-Server]:Ready. ...`) so that
* IDE integrations can pick it up automatically (mirroring how the GLSP server itself
* reports its port).
*
* Why `port` lives here but `host` lives on {@link McpServerDeployOptions}: an IDE has a
* legitimate operational reason to pin a specific port (matching its MCP client config),
* and the security blast radius of port choice is local. `host`, by contrast, controls
* the bind interface — letting an init payload widen it from loopback would re-open the
* DNS-rebinding attack pattern that the Host/Origin checks mitigate.
*/
port?: number;
/**
* The route on which the MCP server should be started.
*/
route?: string;
/**
* The name of the MCP server.
*/
name?: string;
/**
* Behavioral and tuning options the IDE may set per init. Security-sensitive bind/policy
* fields ({@link McpServerDeployOptions}) are intentionally not part of this shape.
*/
options?: McpServerInitOptions;
}
/** @experimental */
export interface McpInitializeParameters extends InitializeParameters {
/**
* MCP server configuration parameters.
*
* **Presence is the opt-in signal.** The MCP server is started if and only if this key is
* defined in the initialize parameters; the value's content controls *how* it is configured.
* Omitting the key entirely disables MCP. Setting it to an empty object (`{ mcpServer: {} }`)
* enables MCP with all defaults. A populated object overrides specific fields.
*
* @example
* // Disable MCP (the default for most clients)
* { applicationId: '...', protocolVersion: '...' }
*
* @example
* // Enable MCP with all defaults
* { applicationId: '...', protocolVersion: '...', mcpServer: {} }
*
* @example
* // Enable MCP with a custom port
* { applicationId: '...', protocolVersion: '...', mcpServer: { port: 12345 } }
*/
mcpServer?: McpServerConfiguration;
}
export declare namespace McpInitializeParameters {
/**
* Type guard that also doubles as the **opt-in check**: returns `true` iff `params.mcpServer`
* is defined (regardless of its content). Server-side code uses this to decide whether to
* start the MCP HTTP server at all. See {@link McpInitializeParameters.mcpServer} for the
* opt-in semantics.
*/
function is(params?: InitializeParameters): params is McpInitializeParameters;
/**
* Returns the {@link McpServerConfiguration} from the given initialize parameters, or
* `undefined` if MCP is not opted in (i.e., `mcpServer` is missing). A return value of `{}`
* (an empty object) means "MCP is enabled, use all defaults" — distinct from `undefined`
* which means "MCP is not enabled."
*/
function getServerConfig(params?: InitializeParameters): McpServerConfiguration | undefined;
}
/** @experimental */
export interface McpServerResult {
/** The name of the MCP server. */
name: string;
/** The URL at which the MCP server is accessible. */
url: string;
/** Optional headers AI clients should include when connecting. */
headers?: Record<string, string>;
}
export declare namespace McpServerResult {
/** True when the candidate is shaped like {@link McpServerResult}. */
function is(candidate: unknown): candidate is McpServerResult;
}
/**
* Initialize-result extension carrying the MCP server's announced URL. Returned by the
* GLSP server's `initialize` handshake when (and only when) MCP was opted into via
* {@link McpInitializeParameters.mcpServer}; otherwise the server returns a plain
* {@link InitializeResult} and callers should narrow with {@link McpInitializeResult.is}.
*
* @experimental
*/
export interface McpInitializeResult extends InitializeResult {
mcpServer: McpServerResult;
}
export declare namespace McpInitializeResult {
/** Narrows to `McpInitializeResult` (i.e., asserts `mcpServer` is populated and well-shaped). */
function is(result?: InitializeResult): result is McpInitializeResult;
/** Returns the {@link McpServerResult} from the given initialize result, or `undefined` if MCP is not announced. */
function getServer(result?: InitializeResult): McpServerResult | undefined;
/**
* Attaches an {@link McpServerResult} announcement to a base {@link InitializeResult},
* returning the augmented {@link McpInitializeResult}. Server-side handshake code uses this
* instead of an in-place cast to keep the mutation typed.
*/
function attachServer(result: InitializeResult, server: McpServerResult): McpInitializeResult;
}
//# sourceMappingURL=mcp.d.ts.map