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

@langgraph-toolkit/mcp

v0.2.3

Published

Typed MCP client integration for Langgraph-Toolkit with async credentials and framework-agnostic execution.

Readme

@langgraph-toolkit/mcp

Connect a resource once, let the graph use it from any host. MCP provides a typed gateway boundary for tools, resources, schema discovery, async credentials, and structured errors. It can be used from Core, a worker, a CLI, an HTTP server, or any framework adapter without importing Express, Fastify, NestJS, or StruxJS.

Install the MCP gateway

npm install @langgraph-toolkit/core @langgraph-toolkit/mcp

MCP does not install model providers, framework adapters, or database clients. Add only the optional boundary your application uses. When an application needs a provider, install Community and declare its model configuration explicitly:

npm install @langgraph-toolkit/community

Canonical composition facade

The root package keeps the common path small. useStreamableHttp() declares a lazy remote server, useMCPServer() declares an application-owned or asynchronous server, createMCP() composes one or more named servers, and createMCPAgent() provides a generic model-plus-tools loop. None of these APIs knows about SQL, rows, approval terminology, or a framework host.

import { createMCP, createMCPAgent, useStreamableHttp } from "@langgraph-toolkit/mcp";
import { createModelRegistry } from "@langgraph-toolkit/community";

const models = createModelRegistry({
  tiers: { smart: { fromEnvironment: true, temperature: 0.1 } },
});

const mcp = createMCP({
  servers: {
    search: useStreamableHttp(undefined, { name: "search" }),
  },
  discover: true,
  discoverTools: true,
  routing: "semantic",
});

const agent = createMCPAgent({
  model: models.model("smart"),
  mcp,
  name: "research-agent",
});

const result = await agent.run({ query: "Find the latest release notes." });
await agent.close();

fromEnvironment: true retains explicit provider ownership while removing application parsing helpers: it reads MODEL_DRIVER, MODEL_NAME, MODEL_API_KEY, and optionally MODEL_BASE_URL. useStreamableHttp(undefined) reads MCP_SERVER_URL. Missing model configuration fails at bootstrap rather than selecting a hidden default.

The aggregate MCPClient contract exposes discover, callTool, readResource, and getPrompt across named servers. MCPDiscovery, MCPDiscoveryServer, and McpPromptDescriptor describe discovery and prompt lifecycle without forcing a specific transport.

Async credentials with no graph pollution

Credentials may come from environment variables, a database, a secret manager, or an application-owned resolver. Resolution is asynchronous and happens at the gateway boundary. Secrets never need to become graph input.

import { fromMcpCredentials } from "@langgraph-toolkit/mcp";
import { createMCP, useStreamableHttp } from "@langgraph-toolkit/mcp";

type SecretStore = {
  tokenForTenant(tenantId: string): Promise<string>;
};

declare const secretStore: SecretStore;

const mcp = createMCP({
  servers: {
    analytics: useStreamableHttp(
      process.env.ANALYTICS_MCP_URL ?? "http://localhost:8811/mcp",
      {
        credentials: fromMcpCredentials(async ({ tenantId }) => ({
          headers: {
            Authorization: `Bearer ${await secretStore.tokenForTenant(tenantId ?? "public")}`,
          },
        })),
      },
    ),
  },
  context: { tenantId: "public" },
});

const gateway = await mcp.server("analytics");

const tools = await gateway.listTools();
const result = await gateway.callTool("execute_query", {
  sql: "select count(*) from users",
});

await gateway.close();

For credentials that depend on a request or tenant, the resolver receives typed request context. The resulting connector can be closed once by the owning resource; a controller should not rebuild it for each request.

Wrap one discovered tool once

createMcpTool keeps the tool name, typed argument boundary, default object validation, gateway error propagation, and context formatting outside graph nodes. The graph receives a callable typed tool instead of repeating callTool() and result parsing.

import type { JsonValue } from "@langgraph-toolkit/core";
import { createMcpTool } from "@langgraph-toolkit/mcp/tools";
import { formatMcpContext } from "@langgraph-toolkit/mcp/context";

type SearchArgs = { query: string; limit?: number };

const gateway = await mcp.server("search");
const [descriptor] = await gateway.listTools();
if (descriptor === undefined) throw new Error("search tool is not available");

const search = createMcpTool<SearchArgs, JsonValue>({
  gateway,
  descriptor,
  output: (result) => result.structuredContent ?? result.content,
});

const context = await search({ query: "testing", limit: 3 });
const promptContext = formatMcpContext(context);

createMCP is the process-level composition boundary when an application owns several lazily-created MCP servers. It exposes a named server lookup, caches safe shared-credential gateways, keeps dynamic credential connections request-scoped, and provides one close hook for framework lifecycle.

const connector = createMCP({
  servers: {
    analytics: analyticsDeclaration,
    search: searchDeclaration,
  },
});

const analytics = await connector.server("analytics");
const search = await connector.server("search");
await connector.close();

Use fromMcpEnv when process-level environment variables are enough. Use the async resolver when credentials depend on tenant, actor, secret-manager, or database state.

Database declarations stay transport-neutral

MCP does not ship a database agent, SQL policy, prompt, or domain-specific state. useDatabase() records the database family and connection metadata while keeping the transport explicit. Pass mcpUrl when the database capability is exposed by a remote MCP server, or pass an application-owned transport when the server is created locally.

import { createMCP, useDatabase } from "@langgraph-toolkit/mcp";

const databaseUrl = process.env.DATABASE_URL;
const databaseMcpUrl = process.env.DATABASE_MCP_URL;
if (!databaseUrl || !databaseMcpUrl) throw new Error("DATABASE_URL and DATABASE_MCP_URL are required");

const mcp = createMCP({
  servers: {
    database: useDatabase("postgres", databaseUrl, {
      mcpUrl: databaseMcpUrl,
      readOnly: true,
    }),
  },
});

useDatabase() is only a transport declaration. Applications that need data chat, retrieval, background tasks, classification, or custom agents compose their own visible Core graph and MCP-aware role agents. Neither MCP nor Community ships a database workflow preset.

Same gateway, any host

| Host | Host code owns | MCP code owns | |---|---|---| | Express | Router and response lifecycle | Credentials, tools, schema, and resource errors | | Fastify | Plugin registration and reply lifecycle | Credentials, tools, schema, and resource errors | | NestJS | Module and controller binding | Credentials, tools, schema, and resource errors | | StruxJS | Provider lifecycle and agent scanning | Credentials, tools, schema, and resource errors | | Worker or CLI | Process bootstrap | Credentials, tools, schema, and resource errors |

The gateway contract is the portable seam. A framework adapter should not learn how a database table or prompt works.

Transport and package boundary

The gateway supports streamable-http, legacy sse, and application-owned custom transports. MCP normalizes protocol and tool errors. The graph or host owns actor authorization, tenant isolation, SQL classification, and retention policy.

core
└── mcp
    ├── root facades: createMCP, useStreamableHttp, useDatabase, createMCPAgent
    ├── advanced: gateway registry and legacy connector construction
    ├── tools: typed MCP tool adaptation
    └── context: MCP value and prompt formatting

MCP is independently useful with a custom gateway and a caller-supplied model. Community providers are optional, and no provider or fallback model is selected implicitly.

Development

npm install
npm run build
npm test

Contributor tests should cover tool listing, schema discovery, query rejection, async credential resolution, approval interrupt, resume, final stream event preservation, and gateway close behavior.

License

MIT