> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcpfy.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting started

# Getting Started

This guide shows how to install `mcpfy-sdk`, create an MCP server, register tools, run the server over stdio or HTTP, and connect to MCP servers using the mcpfy client.

mcpfy is a lightweight TypeScript SDK built on top of the official Model Context Protocol SDK. It provides higher-level APIs for common MCP operations while keeping access to the underlying official MCP implementation when needed.

***

## Prerequisites

Before using mcpfy, make sure your development environment has:

* Node.js `^20.19.0` or `>=22.12.0` (Node.js 21.x is not supported)
* npm, pnpm, or another Node.js package manager
* Basic TypeScript knowledge
* Basic understanding of MCP concepts such as servers, clients, tools, resources, and prompts

The package declares the following Node.js engine requirement:

```text theme={null}
^20.19.0 || >=22.12.0
```

***

## Installation

Install the SDK using your preferred package manager.

### npm

```bash theme={null}
npm install mcpfy-sdk
```

### pnpm

```bash theme={null}
pnpm add mcpfy-sdk
```

### yarn

```bash theme={null}
yarn add mcpfy-sdk
```

mcpfy uses ES modules, so projects consuming the package should use an ESM-compatible configuration.

For example:

```json theme={null}
{
  "type": "module"
}
```

***

## Creating a TypeScript Project

A simple MCP server project can be structured as:

```text theme={null}
my-mcp-server/
├── package.json
├── tsconfig.json
└── src/
    └── server.ts
```

A minimal `package.json` can look like:

```json theme={null}
{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "tsx src/server.ts"
  },
  "dependencies": {
    "mcpfy-sdk": "^0.3.1",
    "zod": "^3.25.0"
  },
  "devDependencies": {
    "tsx": "^4.19.2",
    "typescript": "^5.6.3"
  }
}
```

***

## Creating Your First MCP Server

The main server class is `MCPServer`.

Import it from:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";
```

Create a server by providing a name and version:

```typescript theme={null}
const server = new MCPServer({
  name: "my-server",
  version: "1.0.0",
});
```

`MCPServer` wraps the official MCP `McpServer` implementation and provides higher-level APIs for registering tools, prompts, resources, resource templates, and widgets.

***

## Adding a Tool

Tools are executable functionality exposed by an MCP server.

Register a tool with:

```typescript theme={null}
server.tool(definition, callback?);
```

For example:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";

const server = new MCPServer({
  name: "calculator",
  version: "1.0.0",
});

server.tool(
  {
    name: "add",
    description: "Add two numbers",
  },
  async ({ a, b }) => {
    return object({
      result: a + b,
    });
  }
);

await server.listen();
```

The tool definition can include a Zod input schema:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";
import { z } from "zod";

const server = new MCPServer({
  name: "calculator",
  version: "1.0.0",
});

server.tool(
  {
    name: "add",
    description: "Add two numbers",
    schema: z.object({
      a: z.number(),
      b: z.number(),
    }),
  },
  async ({ a, b }) => object({
    result: a + b,
  })
);

await server.listen();
```

A tool callback receives the tool input and the mcpfy `ToolContext`:

```typescript theme={null}
async (params, ctx) => {
  // ...
}
```

The callback returns a tool result or a supported mcpfy content result.

Tools can also define an `outputSchema` when structured output should be constrained.

***

## Starting the Server

mcpfy supports two transport modes:

* `stdio`
* `http`

The default transport is `stdio`.

Therefore:

```typescript theme={null}
await server.listen();
```

is equivalent to:

```typescript theme={null}
await server.listen({
  transport: "stdio",
});
```

***

## Using the stdio Transport

stdio is commonly used when an MCP host launches and manages the server process itself.

Example:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";

const server = new MCPServer({
  name: "calculator",
  version: "1.0.0",
});

server.tool(
  {
    name: "add",
    description: "Add two numbers",
  },
  async ({ a, b }) => object({
    result: a + b,
  })
);

await server.listen({
  transport: "stdio",
});
```

The server communicates through standard input and standard output.

The stdio `listen()` result is:

```json theme={null}
{
  "transport": "stdio"
}
```

***

## Using the HTTP Transport

mcpfy can also expose an MCP server over HTTP.

Use:

```typescript theme={null}
await server.listen({
  transport: "http",
});
```

Example:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";

const server = new MCPServer({
  name: "calculator",
  version: "1.0.0",
});

server.tool(
  {
    name: "add",
    description: "Add two numbers",
  },
  async ({ a, b }) => object({
    result: a + b,
  })
);

const result = await server.listen({
  transport: "http",
});

console.log(result.url);
```

By default, the HTTP server uses:

```text theme={null}
Host: localhost
Port: 3000
Path: /mcp
```

Therefore, the default endpoint is:

```text theme={null}
http://localhost:3000/mcp
```

***

## Configuring the HTTP Port

The HTTP port can be configured directly:

```typescript theme={null}
await server.listen({
  transport: "http",
  port: 4000,
});
```

The server will then be available at:

```text theme={null}
http://localhost:4000/mcp
```

mcpfy resolves the HTTP port using this priority:

1. `listen()` `port` option
2. `--port` command-line argument
3. `PORT` environment variable
4. `3000`

For example:

```typescript theme={null}
await server.listen({
  transport: "http",
  port: 4000,
});
```

takes priority over:

```bash theme={null}
node server.js --port 5000
```

and:

```text theme={null}
PORT=6000
```

You can also pass `0` as the port to let the operating system choose a free port. The actual bound port is returned by `listen()`.

***

## Command-Line Port Configuration

mcpfy supports both:

```text theme={null}
--port 4000
```

and:

```text theme={null}
--port=4000
```

For example:

```bash theme={null}
node server.js --port 8080
```

The exported `parsePortFromArgv()` function reads these arguments:

```typescript theme={null}
import { parsePortFromArgv } from "mcpfy-sdk/server";

const port = parsePortFromArgv();
```

If multiple valid `--port` arguments are present, the last one wins.

***

## Using the `PORT` Environment Variable

The port can also be supplied through the environment.

On PowerShell:

```powershell theme={null}
$env:PORT=5000
npm run dev
```

On Unix-like shells:

```bash theme={null}
PORT=5000 npm run dev
```

The environment variable is used when no explicit `listen()` port or valid command-line port is provided.

***

## Using a Custom MCP Path

The default MCP HTTP pathname is:

```text theme={null}
/mcp
```

A custom path can be configured through `basePath`:

```typescript theme={null}
const server = new MCPServer({
  name: "weather-server",
  version: "1.0.0",
  basePath: "/weather",
});

await server.listen({
  transport: "http",
});
```

The MCP endpoint will then be:

```text theme={null}
http://localhost:3000/weather
```

***

## Using a Custom Host

The HTTP host can be configured using the `host` option:

```typescript theme={null}
await server.listen({
  transport: "http",
  host: "0.0.0.0",
  port: 4000,
});
```

The default host is:

```text theme={null}
localhost
```

The `host` option is only relevant to HTTP transport.

***

## Suppressing the HTTP Startup Message

By default, mcpfy logs the local MCP URL when an HTTP server starts.

This can be disabled using:

```typescript theme={null}
await server.listen({
  transport: "http",
  silent: true,
});
```

***

## Understanding the Listen Result

`listen()` returns a `ListenResult`.

For HTTP:

```typescript theme={null}
const result = await server.listen({
  transport: "http",
  port: 4000,
});

console.log(result);
```

The result contains:

```json theme={null}
{
  "transport": "http",
  "port": 4000,
  "host": "localhost",
  "url": "http://localhost:4000/mcp"
}
```

The HTTP `port`, `host`, and `url` describe the bound HTTP server.

For stdio:

```typescript theme={null}
const result = await server.listen({
  transport: "stdio",
});
```

the result is:

```json theme={null}
{
  "transport": "stdio"
}
```

***

## Complete HTTP Server Example

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";
import { z } from "zod";

const server = new MCPServer({
  name: "calculator",
  version: "1.0.0",
  description: "A simple calculator MCP server",
});

server.tool(
  {
    name: "add",
    description: "Add two numbers",
    schema: z.object({
      a: z.number(),
      b: z.number(),
    }),
  },
  async ({ a, b }) => object({
    result: a + b,
  })
);

const result = await server.listen({
  transport: "http",
  port: 4000,
});

console.log(`MCP server running at ${result.url}`);
```

***

## Server Metadata

When creating an `MCPServer`, the configuration is:

```typescript theme={null}
interface MCPServerConfig {
  name: string;
  version: string;
  description?: string;
  basePath?: string;
  icon?: string | ServerIcon;
  auth?: AuthConfig;
  widgetsDir?: string;
}
```

### `name`

Required server name.

```typescript theme={null}
name: "weather-server"
```

### `version`

Required server version.

```typescript theme={null}
version: "1.0.0"
```

### `description`

Optional server description.

```typescript theme={null}
description: "Provides weather information"
```

The description is passed to the underlying MCP server as its instructions.

### `basePath`

Optional HTTP pathname for the MCP endpoint.

Default:

```text theme={null}
/mcp
```

### `icon`

Optional server icon advertised through MCP initialization.

Supported sources include:

* Remote URLs
* `data:` URIs
* Local file paths
* `file:` URLs

For example:

```typescript theme={null}
const server = new MCPServer({
  name: "weather",
  version: "1.0.0",
  icon: "./icon.png",
});
```

Local icons are converted to data URIs before being advertised.

### `auth`

Optional HTTP authentication configuration.

```typescript theme={null}
const server = new MCPServer({
  name: "protected-server",
  version: "1.0.0",
  auth: verifier,
});
```

Authentication applies to HTTP transport.

Authentication helpers such as `jwksVerifier`, `oauthAuth0Provider`, and `oauthWorkOSProvider` are available from the server package.

### `widgetsDir`

Optional root directory for widget folders.

Default:

```text theme={null}
src/widgets
```

This directory is used when tools reference widgets by folder name.

***

## Accessing the Native MCP Server

mcpfy does not completely hide the official MCP SDK.

The underlying official server instance is available through:

```typescript theme={null}
server.nativeServer
```

For example:

```typescript theme={null}
const nativeServer = server.nativeServer;
```

Its type is based on the official MCP SDK's `McpServer`.

This provides an escape hatch for advanced use cases that require direct access to the underlying MCP implementation.

***

## Closing a Server

A server can be stopped using:

```typescript theme={null}
await server.close();
```

Example:

```typescript theme={null}
const server = new MCPServer({
  name: "example",
  version: "1.0.0",
});

await server.listen({
  transport: "http",
  port: 4000,
});

// Later
await server.close();
```

`close()`:

* Closes the HTTP server if it is running.
* Closes mounted remote connections.
* Clears the remote connection list.
* Closes the underlying native MCP server.

***

## Refreshing MCP Data

mcpfy provides methods for notifying clients when registered MCP data changes.

### Refresh a resource

```typescript theme={null}
await server.refreshResource("resource://example");
```

This notifies subscribed clients that the resource has new content.

### Refresh resources

```typescript theme={null}
server.refreshResources();
```

This tells clients to refresh their resource list.

### Refresh tools

```typescript theme={null}
server.refreshTools();
```

This tells clients to refresh their tool list.

### Refresh prompts

```typescript theme={null}
server.refreshPrompts();
```

This tells clients to refresh their prompt list.

Resource subscriptions and resource-list-change notifications are enabled by the server runtime.

***

## Using the MCP Client

mcpfy also provides a client abstraction for connecting to configured MCP servers.

Import it from:

```typescript theme={null}
import { MCPClient } from "mcpfy-sdk/client";
```

Create a client with an `mcpServers` configuration:

```typescript theme={null}
const client = new MCPClient({
  mcpServers: {
    weather: {
      // server configuration
    },
  },
});
```

The client maintains MCP sessions for configured servers.

### Creating a Session

Create a session for a configured server:

```typescript theme={null}
const session = await client.createSession("weather");
```

If a session for that server already exists, mcpfy reuses it rather than creating another connection.

### Creating All Sessions

To create sessions for all configured servers:

```typescript theme={null}
const sessions = await client.createAllSessions();
```

The result is keyed by the configured server names:

```typescript theme={null}
{
  weather: session,
}
```

***

## Project Structure Recommendation

A small MCP project can use:

```text theme={null}
my-mcp-server/
├── package.json
├── tsconfig.json
└── src/
    ├── server.ts
    └── tools/
        └── calculator.ts
```

For a larger project:

```text theme={null}
my-mcp-server/
├── package.json
├── tsconfig.json
└── src/
    ├── server.ts
    ├── tools/
    │   ├── calculator.ts
    │   └── weather.ts
    ├── prompts/
    │   └── assistant.ts
    ├── resources/
    │   └── documentation.ts
    └── widgets/
        └── weather/
            └── ...
```

This structure is not required by the SDK, but provides a clean way to organize larger MCP applications.

***

## Package Entry Points

mcpfy exposes functionality through separate package entry points.

### Main package

```typescript theme={null}
import ... from "mcpfy-sdk";
```

### Server

```typescript theme={null}
import {
  MCPServer,
  parsePortFromArgv,
} from "mcpfy-sdk/server";
```

The server entry point includes:

* `MCPServer`
* `parsePortFromArgv`
* Server configuration and listen types
* Tool and prompt types
* Resource types
* Tool context types
* Widget types
* Authentication helpers
* Response helpers
* Server icon types
* Remote server configuration

### Client

```typescript theme={null}
import {
  MCPClient,
  MCPSession,
  HttpConnector,
  StdioConnector,
} from "mcpfy-sdk/client";
```

The client entry point provides:

* `MCPClient`
* `MCPSession`
* `BaseConnector`
* `StdioConnector`
* `HttpConnector`
* `createConnectorFromConfig`

### React Widget

React widget functionality is exposed through:

```typescript theme={null}
import {
  HostRuntime,
  useCallTool,
  useHostContext,
  useToolPayload,
} from "mcpfy-sdk/widget";
```

See the widget documentation for the complete React widget API.

***

## API Summary

### `MCPServer`

Creates and manages an MCP server.

```typescript theme={null}
const server = new MCPServer({
  name: "example",
  version: "1.0.0",
});
```

### `server.tool()`

Registers an MCP tool.

```typescript theme={null}
server.tool(definition, callback?);
```

### `server.prompt()`

Registers an MCP prompt.

```typescript theme={null}
server.prompt(definition, callback?);
```

### `server.resource()`

Registers a static MCP resource.

```typescript theme={null}
server.resource(definition, callback?);
```

### `server.resourceTemplate()`

Registers a dynamic MCP resource template.

```typescript theme={null}
server.resourceTemplate(definition, callback?);
```

### `server.listen()`

Starts the MCP server.

```typescript theme={null}
await server.listen({
  transport: "stdio",
});
```

or:

```typescript theme={null}
await server.listen({
  transport: "http",
  port: 4000,
});
```

### `server.close()`

Stops the server and closes associated connections.

```typescript theme={null}
await server.close();
```

### `server.nativeServer`

Provides direct access to the underlying official MCP server.

```typescript theme={null}
server.nativeServer;
```

### `server.refreshResource()`

Notifies subscribed clients that a resource has changed.

```typescript theme={null}
await server.refreshResource("resource://example");
```

### `server.refreshResources()`

Notifies clients that the resource list should be refreshed.

```typescript theme={null}
server.refreshResources();
```

### `server.refreshTools()`

Notifies clients that the tool list should be refreshed.

```typescript theme={null}
server.refreshTools();
```

### `server.refreshPrompts()`

Notifies clients that the prompt list should be refreshed.

```typescript theme={null}
server.refreshPrompts();
```

### `parsePortFromArgv()`

Reads a valid `--port` argument from command-line arguments.

```typescript theme={null}
const port = parsePortFromArgv();
```

The last valid port argument wins.

***

## Best Practices

### Use `MCPServer` for common server operations

Use the higher-level mcpfy APIs rather than manually registering every operation against the native MCP server.

```typescript theme={null}
server.tool(...);
server.prompt(...);
server.resource(...);
server.resourceTemplate(...);
```

### Use schemas for tool inputs

When a tool expects structured input, define its input schema explicitly:

```typescript theme={null}
schema: z.object({
  city: z.string(),
})
```

This makes the expected tool input clear and allows the underlying MCP registration to use the schema.

### Use HTTP and stdio according to the deployment environment

Use stdio when an MCP host launches the server as a child process.

Use HTTP when the MCP server needs to be exposed as an HTTP endpoint.

### Keep server metadata meaningful

Use descriptive names, versions, descriptions, and paths:

```typescript theme={null}
const server = new MCPServer({
  name: "weather-server",
  version: "1.0.0",
  description: "Provides weather information",
  basePath: "/weather",
});
```

### Use the native server only when necessary

For common operations, prefer mcpfy's higher-level APIs.

Use:

```typescript theme={null}
server.nativeServer
```

when direct access to functionality from the official MCP SDK is required.

### Detect optional widget capabilities

Widgets should not assume every MCP host supports every optional feature. Use the widget runtime's capability information before relying on host-specific functionality.

***

## Summary

mcpfy provides a lightweight API for building MCP applications while remaining compatible with the official MCP SDK.

The main server workflow is:

```typescript theme={null}
import { MCPServer, object } from "mcpfy-sdk/server";

const server = new MCPServer({
  name: "example-server",
  version: "1.0.0",
});

server.tool(
  {
    name: "hello",
    description: "Return a greeting",
  },
  async ({ name }) => object({
    message: `Hello, ${name}!`,
  })
);

await server.listen({
  transport: "stdio",
});
```

For HTTP:

```typescript theme={null}
await server.listen({
  transport: "http",
  port: 4000,
});
```

For clients:

```typescript theme={null}
import { MCPClient } from "mcpfy-sdk/client";

const client = new MCPClient({
  mcpServers: {
    weather: {
      // server configuration
    },
  },
});

const session = await client.createSession("weather");
```

mcpfy provides higher-level APIs for servers, clients, tools, prompts, resources, resource templates, authentication, and widgets while retaining access to the underlying official MCP implementation when advanced control is required.
