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

# Servers

> Understand what an MCP server is, how it differs from a traditional server, and how Pylee helps you define, version, secure, and connect them across your organization.

**Related:** [What is MCP](/what-is-mcp) • [Why build an MCP](/why-build-mcp) • [Quickstart](/quickstart) • [Platform overview](/platform-overview) • [Pylee Marketplace](/pylee-marketplace) • [MCP vs API](/mcp-vs-api) • [Hosting and deployment of MCPs](/hosting-and-deployment-of-mcps) • [Publishing MCP servers](/publishing-mcp-servers)

## Overview

An MCP server is not just “some code running on a machine.” It’s a structured way to expose implemented capabilities through the [Model Context Protocol](/what-is-mcp) once running.

Each server starts with a **specification** (the manifest describing its tools, resources, and prompts), has **implementation code** that fulfills that specification, and can be turned into a **running instance**.

Pylee helps manage that lifecycle: versioning, registries, runtime secret injection, access control, monitoring, and audit.

***

## Core MCP Server Building Blocks

Every MCP server defines what it can do using three primitives:

* **Tools** — actions the client or agent can perform. Each tool has a schema for inputs and outputs (e.g. `sendEmail(to, subject, body)` or `createCalendarEvent(title, start, end)`).

* **Resources** — structured data sources available to clients, identified by URIs. (e.g. `file:///notes/project.md`, `calendar://events/2025`, or `vault://secret/{name}`.)

* **Prompts** — reusable workflows or templates that guide how tools and resources are used together.\
  (e.g. `triageSupportTicket(ticket_id)` or `planVacation(destination, duration)`).

Together, tools, resources, and prompts make servers predictable and reusable across clients.

***

## Server Hierarchy and Ownership

Everything in Pylee belongs to an **organization**, which is the top level entity.

**Organization** → **Servers** → **Server Versions** → **Deployments**

* **Organizations** own servers, registries, deployments, variables, secrets, and memberships.
* **Servers** belong to exactly one organization and live under a namespace like `@org-slug/server-name`.
* **Server versions** are immutable snapshots of a server, tied back to the organization.
* **Deployments** are running instances of specific server versions.
* **Registries** are owned by organizations. They act as curated collections of servers for teams or projects.

### Relationship model

```text theme={null}
Pylee Organization
├── Servers (0 to many)
│   ├── Server Versions (immutable, org-owned)
│   │   └── Variables & Secrets Placeholders
│   │   └── Deployments (instances of versions)
├── Registries (0 to many)
│   ├── Server Versions (many-to-many relationship)
│   └── Variables & Secrets
└── Memberships & Access Control
└── Variables & Secrets
```

This model keeps ownership clear: organizations own everything, while registries and versions provide flexibility to share and govern servers.

***

## Talking about MCP "servers"

The word **server** inevitably comes up in conversations about MCP in a few nuanced but important ways. To avoid confusion, here's how we think of this at Pylee:

1. **Server specification** — a manifest file that describes what the server can do (its tools, resources, and prompts) and configuration (connection type, transportation type, and arguments). Think of this as a **blueprint**.\
   *Example:* a JSON manifest listing an `issue:create` tool and a `projects://roadmap` resource via a remote HTTP server.

2. **Server implementation** — the actual code, package, or container that fulfills the specification. This is what you, as a developer, write.\
   *Example:* a Python package that knows how to create issues in GitHub.

3. **Running instance** — a live process that clients can connect to. This is the "server" in the classic sense.\
   *Example:* a process running on your laptop, or an HTTP server hosted in your cloud.

You'll see us use these terms explicitly throughout this page.

## Deployment, Connection, and Transport

Another common source of confusion while speaking about MCP servers is confounding the deployment, connection type, and transportation protocol. We like to separate into three distinct questions:

1. **Deployment / Location** — *Where is the server running?*
   * **Local**: runs on the same machine as the client (e.g. your IDE spawns it).
   * **Remote**: runs elsewhere (a container, VM, or hosted service).

2. **Connection / Entry Point** — *How do I reach it?*\
   Think of this as the **connection method**, **startup mode**, or **endpoint type**.
   * **Package (start on demand)**: the client starts a child process server by running a command.\
     *Example:* `["python", "-m", "my_mcp"]`
   * **Remote (prerunning)**: the client connects to a server already running at a URL.\
     *Example:* `https://my-server.acme.com`

3. **Transport** — *Once connected, how do messages flow?*
   * **stdio**: when one program starts another, they talk through built-in text channels (stdin/stdout) - like how terminals and editors communicate with tools they launch.
   * **http/sse**: network-friendly web protocols; common in production.

**Common patterns**

| Use case              | Location | Entry point                  | Transport | How the client connects                      | Typical fit                        |
| --------------------- | -------- | ---------------------------- | --------- | -------------------------------------------- | ---------------------------------- |
| Editor/CLI local tool | Local    | Package (start command)      | STDIO     | Client launches the process; no network port | Local file access, quick iteration |
| Local web testing     | Local    | Remote (URL on localhost)    | HTTP/SSE  | Client connects to `http://localhost:PORT`   | Test the same server you’ll deploy |
| Team/shared service   | Remote   | Remote (public/internal URL) | HTTP/SSE  | Client connects to URL (often via registry)  | Production and shared integrations |

**Notes**

* A **local package** is often paired with **stdio**, but could also spawn an **HTTP/SSE** server that the client then connects to.
* A **remote** almost always uses **HTTP/SSE**, since `stdio` only works with parent/child processes.
* A **pre-running server** can still be on your local machine at `http://localhost` - useful when testing servers during development.

```mermaid theme={null}
graph LR
    Cmd["Run command"] -->|stdio| Editor["Editor extensions / CLI tools"]
    Cmd -->|http/sse| LocalHTTP["Local HTTP server"]
    URL["Connect to URL"] -->|http/sse| Hosted["Hosted services / APIs"]
```

***

## How Servers Map into Pylee

In Pylee, a server is the top level MCP definition your organization owns. Servers specs evolve through server versions, which are immutable snapshots that declare:

* **Entry point** — how clients connect (either a Package launched locally via STDIO, or a Remote at a URL over HTTP/SSE).
* **Capabilities** — the tools, resources, and prompts exposed.
* **Placeholders** — configuration keys (like `API_KEY`, `BASE_URL`) that Pylee fills in at runtime.

A deployment is a live instance of a particular server version — running locally, in your infrastructure, or on Pylee hosted infrastructure.

Servers and versions can be shared through registries, which provide governance, discovery, version pinning, and configuration overrides.

***

## Configuration: Connection Type, Versions, & Placeholders

To create an MCP server spec, you first instantiate a server version.

While configuring arguments, server versions may declare **placeholders** (like `{API_KEY}`, `{BASE_URL}`) instead of hardcoding values. At runtime, Pylee fills in these placeholders with the right values.

### Versioning

Servers evolve through versions. A server version first declares the appropriate connection or entry point type(s). e.g. Package or Remote and associated approrpiate runtime or header arguments. Each version is immutable and should be pinned for consistency.

* Versions are **editable until published**; after publish they’re **immutable**.
* Any **alphanumeric string** is accepted as a version label.
* **Best practice:** use semantic versioning (`1.2.0`) to signal breaking, minor, and patch changes.
* Pinning makes CI, IDEs, and agents more reliable.
* Immutable versions make rollbacks simple.

### Placeholders

Declare placeholders (e.g., `API_KEY`, `BASE_URL`) in the **Server Version**. Pylee resolves them at runtime using the following order for runtime:

1. **Registry values** — highest priority, often used to scope per team or project.
2. **Organization values** — defaults shared across the org.

Secrets are always stored encrypted in Pylee’s vault and injected only when the server runs. They never appear in configs, logs, or client files.

***

## Visibility and Sharing

Servers can be:

* **Private** — default. Visible only inside your organization and its registries.
* **Public** — listed in the [Pylee Marketplace](/pylee-marketplace), and optionally mirrored to Anthropic’s global registry.

Most teams start private, then promote servers into registries for controlled sharing. See [Publishing MCP servers](/publishing-mcp-servers) for details.

***

## Deployment and running instances

Once you’ve written your **implementation code** (your repo), the next question is: *where do I want this code to run?*\
There are three main options. Each one ties back to how MCP defines a server in the spec (as a **package** or a **remote**).

### 1. Run locally (on your laptop)

* **Where it runs:** directly on your machine.
* **How it works:**
  * If the server is a **package (stdio)**, the client launches it as a local process. No network port is used — the client and server just talk through stdin/stdout.
  * If the server is a **remote (HTTP/SSE)**, you can still run it locally on a port like `http://localhost:3000`. Even though it’s on your laptop, you configure it as a *remote* in the server spec.
* **When to use it:** quick iteration, debugging, or servers that need access to your local files.
* **How to connect:** usually via **direct connect** in your IDE or client. You can also use a registry if you want to share consistent settings across multiple clients.

***

### 2. Run in your own infrastructure

* **Where it runs:** in your cloud or on-prem environment (e.g., AWS, GCP, Azure, or your own servers).
* **How it works:**
  * Always configured as a **remote (HTTP/SSE)**.
  * The same process you tested on `localhost:3000` during development can be deployed behind your own public or internal URL. Update the server version in Pylee to point to the new URL.
* **When to use it:** when your team already manages hosting and scaling.
* **How to connect:** recommended via registries (for audit and governance), but direct connect is still possible for testing.

***

### 3. Run on Pylee (hosted deployment)

* **Where it runs:** Pylee builds and runs your implementation for you in a managed environment.
* **How it works:**
  * Pylee deploys it as a **remote (HTTP/SSE)**.
  * You don’t need to assign a URL — Pylee issues a secure one automatically.
  * Variables and secrets are injected safely at runtime.
* **When to use it:** when you want a production-ready server without setting up infrastructure.
* **How to connect:** usually through registries, which add visibility, approvals, and version pinning.

***

## Localhost during development

When you’re building a server that will eventually be a **remote**, it’s normal to run it first on `http://localhost:3000`.

1. Create or select a server version.
2. Register `localhost:3000` as the remote.
3. Run your implementation code locally and connect to it.
4. Optionally use a tool like **ngrok** if you need to expose it temporarily for external clients.
5. Later, swap the remote URL for a production endpoint (your own infra or Pylee-hosted).

Remember:

* A “remote” just means “a server with an HTTP/SSE endpoint.” That endpoint can point to localhost during dev or a hosted URL in production.
* A stdio server is always a **package** and never runs on a port.

***

## Pylee Usage

Where the server runs (local, your infra, or Pylee) is separate from how to use through Pylee. There are two ways:

* **Direct connection** — attach to one server at a time. Simple for testing or focused tasks.
* **Registry connection** — attach through a registry, which can include many servers. Registries also provide approvals, pinning, and audit. This is the recommended way for production.

***

## Putting it together

A common path looks like this:

1. Write your implementation code.
2. Run it locally:
   * as a **package (stdio)**, or
   * as a **remote (HTTP/SSE)** bound to `localhost:3000`.
3. Create a server version in Pylee, marking it as a package or remote.
4. Promote the same implementation:
   * run it in your own infra and update the remote URL, or
   * deploy on Pylee and use the URL provided for you.
5. Pin the version in a registry so teams connect to the same server securely with variables and secrets resolved.

For a step-by-step guide, see the [Hello World tutorial](/quickstart).
