npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mcp-layer/attach

v1.1.2

Published

Attach to an in-process MCP server instance and return a Session.

Downloads

199

Readme

@mcp-layer/attach

@mcp-layer/attach attaches to an in-process MCP server instance and returns a shared Session. This is the way to layer REST/GraphQL/UI functionality on top of an existing server without spawning a new process.

Table of Contents

Installation

pnpm add @mcp-layer/attach
# or
npm install @mcp-layer/attach
# or
yarn add @mcp-layer/attach

Usage

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { attach } from '@mcp-layer/attach';

const server = new McpServer({ name: 'my-server', version: '1.0.0' });

// Register tools/resources/prompts on the server before attaching.
// server.registerTool(...)
// server.registerResource(...)

const session = await attach(server, 'my-server');

await session.client.ping();
await session.close();

Platformatic MCP (Fastify)

If you're using the Platformatic MCP Fastify plugin, you can pass the Fastify instance directly to attach and the adapter will talk to the MCP endpoint in-process.

import fastify from 'fastify';
import mcp from '@platformatic/mcp';
import { attach } from '@mcp-layer/attach';

const app = fastify();
await app.register(mcp, {
  serverInfo: { name: 'platformatic-demo', version: '1.0.0' }
});

// Register tools/resources/prompts using app.mcpAddTool/app.mcpAddResource/app.mcpAddPrompt.

const session = await attach(app, 'platformatic-demo', { path: '/mcp' });
await session.client.ping();
await session.close();
await app.close();

Notes:

  • This adapter uses Fastify inject() against the MCP HTTP endpoint (default /mcp).
  • Pass path when your MCP endpoint is mounted elsewhere.

When to use attach vs connect

  • Use attach when you already have an in-process McpServer instance and want to layer new behavior (REST/GraphQL/UI) without spawning another process.
  • Use @mcp-layer/connect when you only have a configuration entry and need to spawn a stdio process.

API (authoritative)

attach(server, name, options?)

  • server: an McpServer or Server instance from the MCP SDK
  • name: logical server name for the Session
  • options:
    • info: overrides for client identity (name, version)
    • source: override the Session source string (defaults to in-memory)

Returns a Session (from @mcp-layer/session) with:

  • client, transport, info, name, source, entry

Behavior and constraints

  • In-memory transport: attach uses the SDK’s in-memory transport to connect client and server inside one process.
  • Single transport: the target server must not already be connected. If it is, attach throws.
  • Lifecycle: session.close() closes the client and the in-memory transport. The server instance remains yours to manage.
  • Errors: if the server fails during handshake, the attach call will throw; you are still responsible for server cleanup.

Testing

pnpm test --filter @mcp-layer/attach

Runtime Error Reference

This section is written for high-pressure debugging moments. Each entry maps directly to the @mcp-layer/attach call path and transport lifecycle.

Expected server name to be a non-empty string.

Thrown from: attach

This happens when attach(instance, name, opts) receives a missing or blank name. The value is used as Session.name, so attach fails before opening transports.

Step-by-step resolution:

  1. Inspect the attach(...) call site and confirm the second argument is a non-empty string.
  2. Check for argument shifting bugs (for example passing opts as the second argument by mistake).
  3. Normalize CLI/env inputs (trim) before passing the session name.
  4. Add a test that rejects empty names and accepts a valid one.
const name = typeof input.name === 'string' ? input.name.trim() : '';
if (!name)
  throw new Error('attach() requires a non-empty session name.');

const session = await attach(server, name, { source: 'in-memory' });

Server is already connected to a transport; attach requires an unconnected server.

Thrown from: attach

This happens when the SDK server instance already has an attached transport (server.transport). attach intentionally refuses to stack a second transport onto the same server instance.

Step-by-step resolution:

  1. Find where the same server object is reused across multiple attach calls.
  2. Confirm whether another code path already called server.connect(...).
  3. Use one attach per server instance, or construct a fresh server for each independent session.
  4. Add lifecycle tests that fail on duplicate attach and pass on fresh instances.
const serverA = createMcpServer();
const sessionA = await attach(serverA, 'a');

const serverB = createMcpServer();
const sessionB = await attach(serverB, 'b');

await Promise.all([sessionA.close(), sessionB.close()]);

Unknown attach provider "{provider}".

Thrown from: attachWithProvider

This happens when provider resolution returns a name that attachWithProvider does not implement. Right now the package only supports the platformatic provider branch.

Step-by-step resolution:

  1. Confirm the incoming instance is actually a Platformatic Fastify MCP instance (mcpAddTool + inject).
  2. If the instance is wrapped, pass the underlying MCP server object (wrapper.server) to attach.
  3. If you are adding a new runtime integration, implement a provider branch before calling with that provider id.
  4. Add a test for provider detection and branch coverage.
const target = app.server ?? app;
const session = await attach(target, 'api');
await session.close();

Transport is not started.

Thrown from: FastifyInjectTransport.send

This happens when FastifyInjectTransport.send(...) is invoked before the transport has been started. In normal flows, client.connect(transport) starts it; direct low-level send calls can bypass that.

Step-by-step resolution:

  1. Check whether code is calling transport internals directly instead of going through Client/Session.
  2. Ensure connection initialization (client.connect(...) or attach(...)) happens before any request send.
  3. Remove direct transport calls from tests unless you explicitly start the transport.
  4. Add a regression test for aborted pre-start sends if you maintain custom transport code.
const session = await attach(app, 'fastify-dev', { path: '/mcp' });
const tools = await session.client.listTools();
console.log(tools.tools.length);
await session.close();

Expected an MCP server instance.

Thrown from: resolveServer

This happens when attach receives a value that is not an MCP SDK server instance, not a wrapper exposing .server, and not a supported provider instance.

Step-by-step resolution:

  1. Log the exact object passed to attach and verify its shape.
  2. Pass an actual MCP server instance (McpServer/SDK Server) or supported wrapper.
  3. If you are integrating a framework wrapper, pass the underlying .server object.
  4. Add a type guard before attach in your integration boundary.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

const server = new McpServer({ name: 'demo', version: '1.0.0' });
const session = await attach(server, 'demo');
await session.close();

License

MIT