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
8 changes: 8 additions & 0 deletions packages/core/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to the SmythOS CORE Runtime Engine will be documented in thi
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v1.5.50]

### Features

- Added support for OpenAI Responses API
- Added support for GPT-5 family models with reasoning capabilities .
- MCP Client component : support for Streamable HTTP transport

## [v1.5.31]

### LLM & Model Support:
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@smythos/sre",
"version": "1.5.46",
"version": "1.5.50",
"description": "Smyth Runtime Environment",
"author": "Alaa-eddine KADDOURI",
"license": "MIT",
Expand Down
40 changes: 33 additions & 7 deletions packages/core/src/Components/MCPClient.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TemplateString } from '@sre/helpers/TemplateString.helper';
import { Component } from './Component.class';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

export class MCPClient extends Component {
protected configSchema = Joi.object({
Expand Down Expand Up @@ -50,13 +51,8 @@ export class MCPClient extends Component {
}

// TODO [Forhad]: Need to check and validate input prompt token
const baseUrl = new URL(mcpUrl);
const transport = new SSEClientTransport(baseUrl);
const client = new Client({
name: 'sse-client',
version: '1.0.0',
});
await client.connect(transport);
const { client } = await this.connectMCP(mcpUrl);

const toolsData = await client.listTools();
const conv = new Conversation(
model,
Expand Down Expand Up @@ -109,4 +105,34 @@ export class MCPClient extends Component {
return { _error: `Error on running MCP Client!\n${error?.message || JSON.stringify(error)}`, _debug: logger.output };
}
}
private async connectMCP(mcpUrl: string) {
const client = new Client({ name: 'auto-client', version: '1.0.0' });

// 1) Try Streamable HTTP first
try {
const st = new StreamableHTTPClientTransport(new URL(mcpUrl));
await client.connect(st);
console.debug('Connected to MCP using Streamable HTTP');
return { client, transport: 'streamable' as const };
} catch (e: any) {
console.debug('Failed to connect to MCP using Streamable HTTP, falling back to SSE');
// 2) If clearly unsupported, fall back to SSE
const msg = String(e?.message || e);
const isUnsupported =
/404|405|ENOTFOUND|ECONNREFUSED|CORS/i.test(msg);

// 406 means wrong/missing Accept for Streamable → retry Streamable with proper header
const isAcceptProblem = /406|Not Acceptable|text\/event-stream/i.test(msg);
if (isAcceptProblem) {
throw new Error('Server is Streamable; include Accept: application/json, text/event-stream');
}

if (!isUnsupported) throw e;

// SSE fallback
const sse = new SSEClientTransport(new URL(mcpUrl));
await client.connect(sse);
return { client, transport: 'sse' as const };
}
}
}