diff --git a/docs/README.md b/docs/README.md
index 317b6d7..c5ae30a 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -32,6 +32,8 @@ You can use it to:
[Achieving Agent Interoperability](./learn-more/achieving-agent-interoperability.md)
+[Speed Up MCPC with In-Memory Transport](./learn-more/speed-up-with-in-memory-transport.md)
+
[Plugin System](./plugins.md)
[Logging and Tracing](./logging-and-tracing.md)
diff --git a/docs/faq.md b/docs/faq.md
index cdf5a6a..e8c43c8 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -51,6 +51,14 @@ That's it. The agent can now call these tools.
All MCP transports work:
-- **stdio**
-- **streamable-http**
-- **sse**
+- **stdio**: Spawns external processes
+- **streamable-http**: HTTP-based communication
+- **sse**: Server-Sent Events
+- **memory**: In-memory transport for same-process communication
+
+> **Performance Tip**: If MCPC feels slow, try using `memory` transport.
+> Connecting multiple MCP servers has overhead - memory transport eliminates it.
+
+> **Learn More**: See
+> [Speed Up MCPC with In-Memory Transport](./learn-more/speed-up-with-in-memory-transport.md)
+> for detailed examples and use cases.
diff --git a/docs/learn-more/speed-up-with-in-memory-transport.md b/docs/learn-more/speed-up-with-in-memory-transport.md
new file mode 100644
index 0000000..b5ec58b
--- /dev/null
+++ b/docs/learn-more/speed-up-with-in-memory-transport.md
@@ -0,0 +1,89 @@
+# Speed Up MCPC with In-Memory Transport
+
+Connect MCP servers in the same process. No external processes, no network
+overhead.
+
+## Why Use It
+
+**Zero overhead**: Same-process communication is instant\
+**Simple testing**: No external dependencies to mock\
+**Easy embedding**: Integrate MCP directly into your app
+
+## Usage
+
+**Step 1**: Create an MCP server
+
+```typescript
+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+
+const myServer = new McpServer({ name: "my-server", version: "1.0.0" });
+
+myServer.tool(
+ "greet",
+ "Greet a user",
+ { name: "string" },
+ ({ name }) => ({
+ content: [{ type: "text", text: `Hello, ${name}!` }],
+ }),
+);
+```
+
+**Step 2**: Pass server instance to MCPC
+
+```typescript
+import { mcpc } from "@mcpc/core";
+
+const server = await mcpc(
+ [{ name: "my-agent", version: "1.0.0" }, { capabilities: { tools: {} } }],
+ [{
+ name: "greeter",
+ description: 'Available tools:\n',
+ deps: {
+ mcpServers: {
+ "my-server": {
+ transportType: "memory",
+ server: myServer, // Pass the server instance
+ },
+ },
+ },
+ }],
+);
+```
+
+## The Advantage
+
+**Other transports** spawn processes or make network calls:
+
+```typescript
+deps: {
+ mcpServers: {
+ "desktop-commander": {
+ command: "npx", // Spawns external process
+ args: ["-y", "@wonderwhy-er/desktop-commander"],
+ transportType: "stdio"
+ }
+ }
+}
+```
+
+**Memory transport** runs in the same process:
+
+```typescript
+deps: {
+ mcpServers: {
+ "my-server": {
+ transportType: "memory",
+ server: myServerInstance, // Instant, no overhead
+ },
+ },
+}
+```
+
+## Try the Example
+
+```bash
+deno run --allow-all packages/core/examples/13-in-memory-transport.ts
+```
+
+See the [example code](../../packages/core/examples/13-in-memory-transport.ts)
+for a complete working implementation.
diff --git a/docs/quickstart/create-your-first-agentic-mcp.md b/docs/quickstart/create-your-first-agentic-mcp.md
index 04f96b6..fdd9090 100644
--- a/docs/quickstart/create-your-first-agentic-mcp.md
+++ b/docs/quickstart/create-your-first-agentic-mcp.md
@@ -43,7 +43,7 @@ See the magic in action 👇
The MCPC framework becomes truly powerful when you reuse and compose existing
MCP Servers, much like your favorite AI-integrated clients (e.g., Cursor or
VSCode). We offer full support for the MCP transport protocol, including
-`stdio`, `sse`, and `streamable-http`.
+`stdio`, `sse`, `streamable-http`, and `memory` (in-memory).
```typescript
import { type ComposeDefinition, mcpc } from "@mcpc/core";
@@ -71,6 +71,11 @@ const deps: ComposeDefinition["deps"] = {
};
```
+> **💡 Tip**: For testing or embedding MCP servers in the same process, you can
+> use `memory` transport. See
+> [FAQ Q5](../faq.md#q5-what-transport-types-does-mcpc-support) for in-memory
+> transport examples.
+
# Then write the documentation for your agent
A documentation for your agent helps LLM understand the purpose of the agent,
diff --git a/packages/cli/deno.json b/packages/cli/deno.json
index 7b716c7..eb676b8 100644
--- a/packages/cli/deno.json
+++ b/packages/cli/deno.json
@@ -1,6 +1,6 @@
{
"name": "@mcpc/cli",
- "version": "0.1.9",
+ "version": "0.1.10",
"repository": {
"type": "git",
"url": "git+https://github.com/mcpc-tech/mcpc.git"
diff --git a/packages/core/deno.json b/packages/core/deno.json
index 5fa52f2..9fb44ab 100644
--- a/packages/core/deno.json
+++ b/packages/core/deno.json
@@ -1,6 +1,6 @@
{
"name": "@mcpc/core",
- "version": "0.2.8",
+ "version": "0.2.9",
"repository": {
"type": "git",
"url": "git+https://github.com/mcpc-tech/mcpc.git"
diff --git a/packages/core/examples/13-in-memory-transport.ts b/packages/core/examples/13-in-memory-transport.ts
new file mode 100644
index 0000000..c8f20bc
--- /dev/null
+++ b/packages/core/examples/13-in-memory-transport.ts
@@ -0,0 +1,95 @@
+/**
+ * MCPC Example 13: In-Memory Transport
+ *
+ * Demonstrates the in-memory transport feature:
+ * - Using InMemoryTransport for in-process communication
+ * - Useful for testing and embedding MCP servers
+ * - No external process spawning required
+ *
+ * This creates a file manager that communicates with an embedded MCP server
+ * via in-memory transport, perfect for testing and integration scenarios.
+ */
+
+import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { type ComposeDefinition, mcpc } from "../mod.ts";
+
+// Create a simple in-memory MCP server for demonstration
+function createTestMcpServer() {
+ const mcpServer = new McpServer({
+ name: "test-memory-server",
+ version: "1.0.0",
+ });
+
+ // Register a simple tool
+ mcpServer.tool(
+ "greet",
+ "Greet a user by name",
+ { name: "string" },
+ ({ name }) => ({
+ content: [{
+ type: "text" as const,
+ text:
+ `Hello, ${name}! This message comes from an in-memory MCP server.`,
+ }],
+ }),
+ );
+
+ return mcpServer;
+}
+
+// Initialize the in-memory server
+const testServer = createTestMcpServer();
+
+export const toolDefinitions: ComposeDefinition[] = [
+ {
+ name: "memory-agent",
+ description:
+ `I am an agent that uses in-memory transport to communicate with MCP servers.
+
+Available tools:
+
+
+I can greet users using the in-memory MCP server. This demonstrates how MCPC can work with
+in-memory transports for testing and embedded scenarios where you don't want to spawn
+external processes.`,
+
+ deps: {
+ mcpServers: {
+ "test-memory-server": {
+ transportType: "memory" as const,
+ server: testServer,
+ },
+ },
+ },
+ },
+];
+
+export const server = await mcpc(
+ [
+ {
+ name: "in-memory-example",
+ version: "1.0.0",
+ },
+ {
+ capabilities: {
+ tools: {
+ listChanged: true,
+ },
+ },
+ },
+ ],
+ toolDefinitions,
+);
+
+// Only run if executed directly
+if (import.meta.main) {
+ console.log("Starting In-Memory Transport Example Server...");
+ console.log("\nThis example demonstrates in-memory transport:");
+ console.log("- No external processes spawned");
+ console.log("- Useful for testing and embedding");
+ console.log("- Fast and efficient for in-process communication\n");
+
+ await server.connect(new StdioServerTransport());
+ console.log("Server running with in-memory transport support!");
+}
diff --git a/packages/core/src/service/tools.ts b/packages/core/src/service/tools.ts
index 87048ed..bc95ea4 100644
--- a/packages/core/src/service/tools.ts
+++ b/packages/core/src/service/tools.ts
@@ -32,10 +32,17 @@ export const StdioConfigSchema: z.ZodObject> =
transportType: z.literal("stdio").optional(),
});
+export const InMemoryConfigSchema: z.ZodObject> =
+ BaseConfigSchema.extend({
+ transportType: z.literal("memory"),
+ server: z.any(), // Server instance from @modelcontextprotocol/sdk
+ });
+
export const ServerConfigSchema: z.ZodTypeAny = z.union([
StdioConfigSchema,
SseConfigSchema,
StreamableHTTPSchema,
+ InMemoryConfigSchema,
]);
export const McpSettingsSchema: z.ZodObject> = z
diff --git a/packages/core/src/utils/common/mcp.ts b/packages/core/src/utils/common/mcp.ts
index 673e5a0..ea7f01d 100644
--- a/packages/core/src/utils/common/mcp.ts
+++ b/packages/core/src/utils/common/mcp.ts
@@ -2,6 +2,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
+import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import type {
McpSettingsSchema,
ServerConfigSchema,
@@ -28,7 +29,95 @@ function defSignature(
def: z.input | z.infer,
) {
// KISS: stringify full definition for a stable signature
- return JSON.stringify(def);
+ // Handle circular references from InMemoryTransport or other objects
+ const defCopy = { ...def };
+
+ // For in-memory transport, create a unique signature without circular refs
+ if (
+ (defCopy as any).transportType === "memory" || (defCopy as any).transport
+ ) {
+ return `memory:${Date.now()}:${Math.random()}`;
+ }
+
+ return JSON.stringify(defCopy);
+}
+
+/**
+ * Creates appropriate transport based on server config definition.
+ * Supports: stdio, sse, streamable-http, and in-memory transports.
+ *
+ * Compatible with multiple IDE/client config formats:
+ * - MCPC: explicit "transportType" field
+ * - VSCode/Cursor: explicit "type" field
+ * - Cline/Claude Desktop: implicit detection (command → stdio, url → http/sse)
+ */
+function createTransport(
+ def: z.input | z.infer,
+):
+ | StdioClientTransport
+ | StreamableHTTPClientTransport
+ | SSEClientTransport
+ | InMemoryTransport {
+ const defAny = def as any;
+
+ // Normalize transport type from different IDE formats
+ // Priority: transportType (MCPC) → type (VSCode/Cursor) → implicit detection (Cline)
+ const explicitType = defAny.transportType || defAny.type;
+
+ // Check for in-memory transport - user provides a Server instance
+ if (explicitType === "memory") {
+ if (!defAny.server) {
+ throw new Error(
+ "In-memory transport requires a 'server' field with a Server instance",
+ );
+ }
+
+ const [clientTransport, serverTransport] = InMemoryTransport
+ .createLinkedPair();
+ // Connect the server to serverTransport asynchronously
+ defAny.server.connect(serverTransport).catch((err: Error) => {
+ console.error("Error connecting in-memory server:", err);
+ });
+ return clientTransport;
+ }
+
+ // Check for SSE transport (explicit or has url with sse type)
+ if (explicitType === "sse") {
+ const options: any = {};
+ if (defAny.headers) {
+ options.requestInit = { headers: defAny.headers };
+ options.eventSourceInit = { headers: defAny.headers };
+ }
+ return new SSEClientTransport(new URL(defAny.url), options);
+ }
+
+ // Check for streamable HTTP transport (has url but not sse)
+ // Cline/Claude Desktop format: { url: "...", headers: {...} }
+ if (defAny.url && typeof defAny.url === "string") {
+ const options: any = {};
+ if (defAny.headers) {
+ options.requestInit = { headers: defAny.headers };
+ }
+ return new StreamableHTTPClientTransport(new URL(defAny.url), options);
+ }
+
+ // Check for stdio transport (explicit type or has command)
+ // Cline/Claude Desktop format: { command: "...", args: [...], env: {...} }
+ if (explicitType === "stdio" || defAny.command) {
+ return new StdioClientTransport({
+ command: defAny.command,
+ args: defAny.args,
+ env: {
+ ...(process.env as any),
+ ...(defAny.env ?? {}),
+ },
+ cwd: cwd(),
+ });
+ }
+
+ throw new Error(
+ `Unsupported transport configuration: ${JSON.stringify(def)}`,
+ );
}
async function getOrCreateMcpClient(
@@ -49,47 +138,7 @@ async function getOrCreateMcpClient(
return client;
}
- let transport:
- | StdioClientTransport
- | StreamableHTTPClientTransport
- | SSEClientTransport;
- // Runtime type guards for union shape
- if (
- typeof (def as any).transportType === "string" &&
- (def as any).transportType === "sse"
- ) {
- const options: any = {};
- if ((def as any).headers) {
- options.requestInit = { headers: (def as any).headers };
- options.eventSourceInit = { headers: (def as any).headers };
- }
- transport = new SSEClientTransport(new URL((def as any).url), options);
- } else if ("url" in (def as any) && typeof (def as any).url === "string") {
- const options: any = {};
- if ((def as any).headers) {
- options.requestInit = { headers: (def as any).headers };
- }
- transport = new StreamableHTTPClientTransport(
- new URL((def as any).url),
- options,
- );
- } else if (
- (typeof (def as any).transportType === "string" &&
- (def as any).transportType === "stdio") ||
- ("command" in (def as any))
- ) {
- transport = new StdioClientTransport({
- command: (def as any).command,
- args: (def as any).args,
- env: {
- ...(process.env as any),
- ...((def as any).env ?? {}),
- },
- cwd: cwd(),
- });
- } else {
- throw new Error(`Unsupported transport type: ${JSON.stringify(def)}`);
- }
+ const transport = createTransport(def);
const connecting = (async () => {
const client = new Client({
diff --git a/packages/mcp-sampling-ai-provider/deno.json b/packages/mcp-sampling-ai-provider/deno.json
index 80dcd1d..5003e86 100644
--- a/packages/mcp-sampling-ai-provider/deno.json
+++ b/packages/mcp-sampling-ai-provider/deno.json
@@ -1,6 +1,6 @@
{
"name": "@mcpc/mcp-sampling-ai-provider",
- "version": "0.1.8",
+ "version": "0.1.9",
"repository": {
"type": "git",
"url": "git+https://github.com/mcpc-tech/mcpc.git"
diff --git a/packages/utils/deno.json b/packages/utils/deno.json
index 17eda89..fbde954 100644
--- a/packages/utils/deno.json
+++ b/packages/utils/deno.json
@@ -1,6 +1,6 @@
{
"name": "@mcpc/utils",
- "version": "0.2.3",
+ "version": "0.2.4",
"repository": {
"type": "git",
"url": "git+https://github.com/mcpc-tech/mcpc.git"