Skip to content

Commit 76c9875

Browse files
poitaclaude
andcommitted
feat(schema): add Remote.extensions for server-level extension information
Gives MCP extensions a place on each remote to publish information a client needs before connecting (e.g. webhook signing keys for SEP-3415 Events). Entries are not a declaration of extension support; support is negotiated via server/discover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzSw9zenmbDjJXgmtp94Pv
1 parent 526201b commit 76c9875

6 files changed

Lines changed: 125 additions & 1 deletion

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A prior attempt to land these types directly in the core spec ([modelcontextprot
1313
A **Server Card** is a JSON document — hosted at any unreserved URI, with `GET <streamable-http-url>/server-card` reserved as the recommended location (see [discovery.md](docs/discovery.md)) — describing:
1414

1515
- The server's identity (`name`, `version`, `description`, optional `title` / `icons` / `repository` / `websiteUrl`)
16-
- Its remote transport endpoints (URLs, headers, variable templates, supported protocol versions)
16+
- Its remote transport endpoints (URLs, headers, variable templates, supported protocol versions, server-level extension information)
1717
- Optional registry-style extension metadata (`_meta`)
1818

1919
Clients can automatically discover Server Cards through [AI Catalog](https://github.com/Agent-Card/ai-catalog) entries advertised on domains present in agentic sessions.

‎docs/discovery.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ the transport served at each `remotes[]` endpoint, and descriptive fields (`titl
153153
`description`, `icons`) — SHOULD NOT contradict the equivalent values declared in the Server
154154
Card.
155155

156+
A remote's `extensions` map carries server-level information defined by each extension; it
157+
is not a declaration of extension support. Clients MUST NOT infer from the presence or
158+
absence of an entry whether the server supports that extension — support is negotiated via
159+
`capabilities.extensions` in `server/discover`, which may vary per user and need not match
160+
the Server Card.
161+
156162
As with the deliberately omitted primitives (tools, resources, prompts), a static manifest
157163
can drift from runtime, so even the fields a Server Card does declare are advisory rather
158164
than binding. Accordingly:
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
3+
"name": "example-org/bad-extension",
4+
"version": "1.0.0",
5+
"description": "Extension information must be an object, not a boolean.",
6+
"remotes": [
7+
{
8+
"type": "streamable-http",
9+
"url": "https://mcp.example.com/mcp",
10+
"extensions": {
11+
"io.modelcontextprotocol/tasks": true
12+
}
13+
}
14+
]
15+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
3+
"name": "example-org/with-extensions",
4+
"version": "1.0.0",
5+
"description": "Server Card whose remote publishes extension information.",
6+
"remotes": [
7+
{
8+
"type": "streamable-http",
9+
"url": "https://mcp.example.com/mcp",
10+
"supportedProtocolVersions": ["2025-11-25"],
11+
"extensions": {
12+
"io.modelcontextprotocol/events": {
13+
"webhooks": {
14+
"signingKeys": {
15+
"keys": [
16+
{
17+
"kty": "OKP",
18+
"crv": "Ed25519",
19+
"kid": "2026-10",
20+
"x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
21+
}
22+
]
23+
},
24+
"egressIpRanges": ["203.0.113.0/24", "2001:db8::/32"]
25+
}
26+
}
27+
}
28+
}
29+
]
30+
}

‎schema.json‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@
7171
},
7272
"type": "object"
7373
},
74+
"JSONArray": {
75+
"items": {
76+
"$ref": "#/$defs/JSONValue"
77+
},
78+
"type": "array"
79+
},
80+
"JSONObject": {
81+
"additionalProperties": {
82+
"$ref": "#/$defs/JSONValue"
83+
},
84+
"type": "object"
85+
},
86+
"JSONValue": {
87+
"anyOf": [
88+
{
89+
"$ref": "#/$defs/JSONObject"
90+
},
91+
{
92+
"items": {
93+
"$ref": "#/$defs/JSONValue"
94+
},
95+
"type": "array"
96+
},
97+
{
98+
"type": ["string", "integer", "boolean"]
99+
}
100+
]
101+
},
74102
"KeyValueInput": {
75103
"description": "A named {@link Input} — used for HTTP headers — whose `value` may reference\nvariables for substitution.",
76104
"properties": {
@@ -133,6 +161,13 @@
133161
"Remote": {
134162
"description": "Metadata for connecting to a remote (HTTP-based) MCP server endpoint.",
135163
"properties": {
164+
"extensions": {
165+
"additionalProperties": {
166+
"$ref": "#/$defs/JSONObject"
167+
},
168+
"description": "Optional server-level information about MCP extensions for this remote\nendpoint. Keys are extension identifiers (e.g.,\n`\"io.modelcontextprotocol/events\"`), and values are objects whose contents\nare defined by the respective extension — typically information a client\nneeds before connecting, such as keys for verifying webhook signatures.\n\nThe presence or absence of an entry does not indicate whether the server\nsupports that extension, and an entry need not match the server's\n`capabilities.extensions`. Extension support is negotiated at runtime via\n`server/discover` and may vary per user.\n\nKeys MUST follow the {@link MetaObject`_meta` key naming rules}, with a\nmandatory prefix.",
169+
"type": "object"
170+
},
136171
"headers": {
137172
"description": "HTTP headers required or accepted when connecting to this remote\nendpoint. Each header is described as a {@link KeyValueInput} so that\nclients can prompt users for required values, mark secrets, surface\ndefaults, and constrain to a list of choices.",
138173
"items": {

‎schema.ts‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,23 @@ export interface Remote {
200200
* clients to select a compatible protocol version before connecting.
201201
*/
202202
supportedProtocolVersions?: string[];
203+
204+
/**
205+
* Optional server-level information about MCP extensions for this remote
206+
* endpoint. Keys are extension identifiers (e.g.,
207+
* `"io.modelcontextprotocol/events"`), and values are objects whose contents
208+
* are defined by the respective extension — typically information a client
209+
* needs before connecting, such as keys for verifying webhook signatures.
210+
*
211+
* The presence or absence of an entry does not indicate whether the server
212+
* supports that extension, and an entry need not match the server's
213+
* `capabilities.extensions`. Extension support is negotiated at runtime via
214+
* `server/discover` and may vary per user.
215+
*
216+
* Keys MUST follow the {@link MetaObject | `_meta` key naming rules}, with a
217+
* mandatory prefix.
218+
*/
219+
extensions?: { [key: string]: JSONObject };
203220
}
204221

205222
/**
@@ -279,6 +296,27 @@ export interface KeyValueInput extends Input {
279296

280297
/* ---------- Inlined dependencies from the main MCP spec ---------- */
281298

299+
/**
300+
* @category Common Types
301+
*/
302+
export type JSONValue =
303+
| string
304+
| number
305+
| boolean
306+
| null
307+
| JSONObject
308+
| JSONArray;
309+
310+
/**
311+
* @category Common Types
312+
*/
313+
export type JSONObject = { [key: string]: JSONValue };
314+
315+
/**
316+
* @category Common Types
317+
*/
318+
export type JSONArray = JSONValue[];
319+
282320
/**
283321
* Represents the contents of a `_meta` field, which clients and servers use to attach additional metadata to their interactions.
284322
*

0 commit comments

Comments
 (0)