programmatic-mcp

programmatic-mcp

A meta MCP server that orchestrates other MCP servers by lazily connecting to them and exposing their tools as JavaScript libraries. It allows users to execute JavaScript code that programmatically interacts with multiple MCP servers within a unified environment.

Category
Visit Server

README

jsmcp

jsmcp exists for cases where an agent needs to do more than a single MCP tool call.

Most MCP clients are great at one tool call at a time, but awkward when work requires:

  • several related tool calls
  • branching logic based on earlier results
  • loops, retries, or result aggregation
  • transforming tool output before the next call

jsmcp solves that by exposing approved MCP tools as JavaScript namespaces. Instead of forcing the model to juggle many separate tool invocations, it can discover what is available and then write a small amount of JavaScript to use those tools programmatically.

In practice, this means:

  • the agent first learns what servers and tools are available, while jsmcp constrains access to whatever servers and tools you allow in a preset
  • the agent can then write JavaScript for multi-step work
  • logs stay separate from return values so the code stays easier to reason about

Config is read from $XDG_CONFIG_HOME/jsmcp/ or, if XDG_CONFIG_HOME is not set, ~/.config/jsmcp/. Exactly one of config.json, config.yaml, or config.yml must exist there.

Why

Use jsmcp when you want agents to treat MCP tools more like a small programmable API surface than a sequence of isolated button presses.

This is especially useful when an agent needs to:

  • combine results from several MCP tools
  • script workflows across one or more MCP servers
  • make decisions in code instead of repeatedly re-planning between tool calls
  • keep tool access constrained to a reviewed preset

Install

npm install -g @alesya_h/jsmcp

Or run it without installing globally:

npx @alesya_h/jsmcp

Run

jsmcp
jsmcp work
jsmcp auth
jsmcp auth firefox_devtools

If you are running from a source checkout instead of an installed package, replace jsmcp with node src/index.js.

When running the MCP server, the only optional argument is the preset name. If omitted, default is used.

Use jsmcp auth to manage OAuth for remote servers. With no arguments it lists remote servers that have OAuth enabled. With a server name it starts the OAuth flow for that server.

If no graphical environment is detected, or if you pass --no-browser, jsmcp auth <server> prints the authorization URL and waits for either the localhost callback or a pasted callback URL/code.

Config

The config file may be JSON or YAML and uses these top-level keys:

  • servers: server definitions
  • presets: optional overrides for which servers and tools are exposed to the agent

Server names must be valid JavaScript identifiers because execute_code() exposes them directly as globals.

jsmcp accepts both OpenCode MCP config style and the overlapping Claude Code MCP style for the common fields:

  • local servers: type: "local" or type: "stdio"
  • remote servers: type: "remote", type: "http", or type: "sse"
  • commands: either command: ["cmd", "arg1"] or command: "cmd" with args: ["arg1"]
  • environment variables: either environment or env

Supported servers.<name> fields:

  • type: required; one of local, stdio, remote, http, sse
  • description: optional string shown in list_servers()
  • enabled: optional boolean; defaults to true
  • timeout: optional number in milliseconds used for initial tool discovery

For local / stdio servers:

  • command: required; non-empty string or non-empty array
  • args: optional array; appended to command when command is a string, and also accepted when command is an array
  • env: optional object of environment variables
  • environment: optional object of environment variables; merged with env, and wins on duplicate keys
  • cwd: optional working directory

For remote / HTTP / SSE servers:

  • url: required string
  • headers: optional object of request headers
  • oauth: optional OAuth config

Supported oauth forms:

  • omitted, null, or true: enable OAuth with default behavior
  • false: disable OAuth for that server
  • object with any of:
    • clientId
    • clientSecret
    • scope

Supported value substitutions in string fields:

  • {env:NAME}: expand from the current environment
  • ${NAME}: Claude Code-style environment expansion
  • ${NAME:-default}: Claude Code-style expansion with fallback
  • {file:path}: replace with file contents

For {file:path}:

  • relative paths are resolved relative to the config file directory
  • ~/... resolves from the user home directory
  • absolute paths are used as-is

If presets is omitted, the default preset includes every server with enabled !== false and allows all of that server's tools.

If presets is present, it is an object of preset names. Each preset is an object of per-server overrides layered on top of the server definitions:

  • presets.default: optional overrides for the default preset
  • any other preset name, such as presets.work: additional named preset overrides

Within a preset, server rules work like this:

  • omitted server rule: use the server definition as-is
  • true: include that server and allow all its tools
  • false: exclude that server from that preset
  • "tool_name": include only that exact tool
  • array entries may be:
    • exact tool name strings
    • { "regex": "..." } selectors
    • { "glob": "..." } selectors

If a server has enabled: false in servers, adding it to a preset enables it for that preset.

Example:

{
  "servers": {
    "math": {
      "type": "stdio",
      "description": "Basic arithmetic tools",
      "command": "node",
      "args": ["/absolute/path/to/math-server.js"],
      "env": {
        "LOG_LEVEL": "debug"
      },
      "cwd": "${PWD}"
    },
    "docs": {
      "type": "http",
      "description": "Documentation search and retrieval",
      "url": "https://example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${DOCS_TOKEN}"
      },
      "oauth": {
        "scope": "docs.read"
      }
    }
  },
  "presets": {
    "default": {
      "math": ["add", { "glob": "mul_*" }],
      "docs": [{ "regex": "(search|fetch)" }]
    },
    "work": {
      "docs": true
    }
  }
}

Compatibility notes:

  • Claude Code-style env, type: "stdio", type: "http", type: "sse", and command plus args are supported
  • OpenCode-style type: "local", type: "remote", command arrays, and environment are also supported
  • Claude Code-specific features such as headersHelper and advanced OAuth fields like callbackPort or authServerMetadataUrl are not supported yet

OAuth tokens and registration state are stored in $XDG_DATA_HOME/jsmcp/oauth.json or ~/.local/share/jsmcp/oauth.json.

Exposed Tools

  • list_servers
  • list_tools
  • execute_code
  • fetch_logs
  • clear_logs

Behavior

  • servers in the default preset are started when jsmcp starts
  • list_servers() is the required first step so the agent can learn what capabilities are available
  • you must call list_tools(server) before using a server in execute_code() so you know the exact tool names, aliases, and schemas
  • list_tools(server) returns only the tools allowed for that server in the preset
  • execute_code(code) does not manage server lifecycle; it can only use servers that are already started
  • prefer execute_code(code) whenever the work would require more than a single tool call
  • console.log, console.info, console.warn, and console.error inside execute_code() are stored for fetch_logs()
  • fetch_logs() drains the log buffer on read

execute_code

execute_code runs JavaScript as the body of an async function.

Started servers are injected as globals. Each allowed MCP tool becomes a function on that server object. Prefer underscore aliases when available.

You should call list_tools(server) before using a server in execute_code(). For multi-step work, prefer writing JavaScript instead of trying to mentally chain several tool calls.

Example:

return await math.add({ a: 2, b: 5 });

If the MCP tool returns structuredContent, that is what the JavaScript call resolves to. So the example above can return:

{
  "sum": 7
}

If a tool name is not a valid JavaScript identifier, prefer its underscore alias:

return await math.tool_name({ value: 1 });

The original tool name still works with bracket access:

return await math["tool-name"]({ value: 1 });

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured