MCP Integration (Node.js)
Node has two MCP stories:
- Wrap an MCP transport with signing and verification
- Register JACS operations as MCP tools on an existing server
If you want a full out-of-the-box server instead, prefer the Rust jacs-mcp binary.
Install
npm install @hai.ai/jacs @modelcontextprotocol/sdk
1. Wrap A Transport
Use this when you already have an MCP server or client and want signed JSON-RPC messages.
With a loaded client
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { JacsClient } from '@hai.ai/jacs/client';
import { createJACSTransportProxy } from '@hai.ai/jacs/mcp';
const client = await JacsClient.quickstart({
name: 'mcp-agent',
domain: 'mcp.local',
});
const transport = new StdioServerTransport();
const secureTransport = createJACSTransportProxy(transport, client, 'server');
With only a config path
import { createJACSTransportProxyAsync } from '@hai.ai/jacs/mcp';
const secureTransport = await createJACSTransportProxyAsync(
transport,
'./jacs.config.json',
'server',
);
createJACSTransportProxy() does not take a config path. Use the async factory when the agent is not already loaded.
2. Register JACS Tools On Your MCP Server
Use this when the model should explicitly call JACS operations such as signing, verification, agreement creation, or trust-store inspection.
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { JacsClient } from '@hai.ai/jacs/client';
import { registerJacsTools } from '@hai.ai/jacs/mcp';
const server = new Server(
{ name: 'jacs-tools', version: '1.0.0' },
{ capabilities: { tools: {} } },
);
const client = await JacsClient.quickstart({
name: 'mcp-agent',
domain: 'mcp.local',
});
registerJacsTools(server, client);
The registered tool set includes:
- document signing and verification
- agreement helpers
- audit and agent-info helpers
- trust-store helpers
- setup and registry helper stubs
For lower-level integration, use getJacsMcpToolDefinitions() plus handleJacsMcpToolCall().
Failure Behavior
The transport proxy is not permissive by default.
- Signing or verification failures fail closed unless you explicitly pass
allowUnsignedFallback: true createJACSTransportProxy()expects a realJacsClientorJacsAgent, not an unloaded shell
Common Pattern
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { JacsClient } from '@hai.ai/jacs/client';
import { createJACSTransportProxy } from '@hai.ai/jacs/mcp';
const client = await JacsClient.quickstart({
name: 'my-agent',
domain: 'my-agent.example.com',
});
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
const transport = new StdioServerTransport();
const secureTransport = createJACSTransportProxy(transport, client, 'server');
await server.connect(secureTransport);
For stdio servers, keep logs on stderr, not stdout.
Example Paths In This Repo
jacsnpm/examples/mcp.stdio.server.jsjacsnpm/examples/mcp.stdio.client.jsjacsnpm/examples/mcp.sse.server.jsjacsnpm/examples/mcp.sse.client.js
When To Use LangChain Instead
Choose LangChain.js Integration instead when:
- the model and tools already live in the same Node.js process
- you only need signed tool outputs, not an MCP boundary
- you do not need other MCP clients to connect