Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions app/mcp/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,29 @@ function acceptedMcpRequestNeedsNormalization(request: Request) {
return null
}

function normalizedMcpRequest(request: Request) {
async function normalizedMcpRequest(request: Request) {
const needsNormalization = acceptedMcpRequestNeedsNormalization(request)

if (needsNormalization === null) {
return null
}

if (!needsNormalization) {
return request
const body = await request.text()
const headers: Record<string, string> = {}

request.headers.forEach((value, key) => {
headers[key] = value
})

if (needsNormalization) {
headers.accept = NORMALIZED_ACCEPT
}

const headers = new Headers(request.headers)
headers.set('accept', NORMALIZED_ACCEPT)
return new Request(request, { headers })
return new Request(request.url, {
method: request.method,
headers,
body,
})
}

function isCanonicalMcpRootRequest(request: Request) {
Expand Down Expand Up @@ -188,7 +197,7 @@ export async function POST(request: Request) {
return jsonRpcError(request, 415, -32600, 'Content-Type must be application/json')
}

const mcpRequest = normalizedMcpRequest(request)
const mcpRequest = await normalizedMcpRequest(request)

if (!mcpRequest) {
return jsonRpcError(request, 406, -32600, 'Accept must include application/json or */*; text/event-stream alone is not supported for JSON responses')
Expand Down
2 changes: 1 addition & 1 deletion lib/ella-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from './entity-data'

export const ELLA_CANONICAL_ENTITY_ID = 'https://ellaentity.ai/#ella' as const
export const ELLA_MCP_SERVER_INFO = { name: 'ellaentity-mcp', version: '1.1.3' } as const
export const ELLA_MCP_SERVER_INFO = { name: 'ellaentity-mcp', version: '1.1.4' } as const
export const ELLA_MCP_PROTOCOL_VERSIONS = ['2025-11-25', '2025-06-18'] as const
export const ELLA_MCP_DEFAULT_PROTOCOL_VERSION = ELLA_MCP_PROTOCOL_VERSIONS[0]
export const ELLA_REGISTRY_DATA_VERSION = '2026-07-13.mcp-v1-1' as const
Expand Down
9 changes: 8 additions & 1 deletion tests/mcp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,21 @@ async function pingWithHeaders(headers: HeadersInit, includeDefaultAccept = true
}

test('POST validates content negotiation and origins', async () => {
const jsonOnly = await pingWithHeaders({ accept: 'Application/Json; charset=utf-8' })
const accepted = [
await pingWithHeaders({}, false),
await pingWithHeaders({ accept: '' }),
await pingWithHeaders({ accept: '*/*' }),
await pingWithHeaders({ accept: 'Application/Json; charset=utf-8' }),
jsonOnly,
await pingWithHeaders({ accept }),
]

assert.deepEqual(jsonOnly.body, {
jsonrpc: '2.0',
id: 'ping-accept',
result: {},
})

for (const result of accepted) {
assert.equal(result.response.status, 200)
assert.deepEqual(result.body.result, {})
Expand Down
Loading