mirror of
https://github.com/aljazceru/contextvm-docs.git
synced 2025-12-18 22:44:25 +01:00
fix: some typos and format
This commit is contained in:
56
README.md
56
README.md
@@ -1,54 +1,4 @@
|
|||||||
# Starlight Starter Kit: Basics
|
# ContextVM Docs
|
||||||
|
|
||||||
[](https://starlight.astro.build)
|
This is the documentation site for the ContextVM protocol.
|
||||||
|
Built with [Astro](https://astro.build), and starlight theme.
|
||||||
```
|
|
||||||
bun create astro@latest -- --template starlight
|
|
||||||
```
|
|
||||||
|
|
||||||
[](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
|
|
||||||
[](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
|
|
||||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/withastro/starlight&create_from_path=examples/basics)
|
|
||||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)
|
|
||||||
|
|
||||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
|
||||||
|
|
||||||
## 🚀 Project Structure
|
|
||||||
|
|
||||||
Inside of your Astro + Starlight project, you'll see the following folders and files:
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── public/
|
|
||||||
├── src/
|
|
||||||
│ ├── assets/
|
|
||||||
│ ├── content/
|
|
||||||
│ │ └── docs/
|
|
||||||
│ └── content.config.ts
|
|
||||||
├── astro.config.mjs
|
|
||||||
├── package.json
|
|
||||||
└── tsconfig.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Starlight looks for `` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
|
|
||||||
|
|
||||||
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
|
|
||||||
|
|
||||||
Static assets, like favicons, can be placed in the `public/` directory.
|
|
||||||
|
|
||||||
## 🧞 Commands
|
|
||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
|
||||||
|
|
||||||
| Command | Action |
|
|
||||||
| :------------------------ | :----------------------------------------------- |
|
|
||||||
| `bun install` | Installs dependencies |
|
|
||||||
| `bun dev` | Starts local dev server at `localhost:4321` |
|
|
||||||
| `bun build` | Build your production site to `./dist/` |
|
|
||||||
| `bun preview` | Preview your build locally, before deploying |
|
|
||||||
| `bun astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
||||||
| `bun astro -- --help` | Get help using the Astro CLI |
|
|
||||||
|
|
||||||
## 👀 Want to learn more?
|
|
||||||
|
|
||||||
Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
|
|
||||||
@@ -1,65 +1,79 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from "astro/config";
|
||||||
import starlight from '@astrojs/starlight';
|
import starlight from "@astrojs/starlight";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: 'https://contextvm.github.io',
|
site: "https://contextvm.github.io",
|
||||||
base: 'contextvm-docs',
|
base: "contextvm-docs",
|
||||||
integrations: [
|
integrations: [
|
||||||
starlight({
|
starlight({
|
||||||
title: 'ContextVM Documentation',
|
title: "ContextVM Documentation",
|
||||||
description: 'Documentation for the ContextVM SDK - a virtual machine for context-controlled computation',
|
description: "Documentation for ContextVM",
|
||||||
logo: {
|
logo: {
|
||||||
light: './src/assets/contextvm-logo.svg',
|
light: "./src/assets/contextvm-logo.svg",
|
||||||
dark: './src/assets/contextvm-logo.svg',
|
dark: "./src/assets/contextvm-logo.svg",
|
||||||
replacesTitle: false,
|
replacesTitle: false,
|
||||||
},
|
},
|
||||||
social: [
|
social: [
|
||||||
{ icon: 'github', label: 'ContextVM', href: 'https://github.com/contextvm/ts-sdk' },
|
{
|
||||||
|
icon: "github",
|
||||||
|
label: "ContextVM",
|
||||||
|
href: "https://github.com/contextvm/ts-sdk",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
sidebar: [
|
sidebar: [
|
||||||
{
|
{
|
||||||
label: 'Getting Started',
|
label: "Getting Started",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Quick Overview', slug: 'getting-started/quick-overview' },
|
{ label: "Quick Overview", slug: "getting-started/quick-overview" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Specification',
|
label: "Specification",
|
||||||
|
items: [{ label: "Specification", slug: "ctxvm-draft-spec" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Core Concepts",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Specification', slug: 'ctxvm-draft-spec' },
|
{ label: "Constants", slug: "core/constants" },
|
||||||
|
{ label: "Interfaces", slug: "core/interfaces" },
|
||||||
|
{ label: "Encryption", slug: "core/encryption" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Core Concepts',
|
label: "Transports",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Constants', slug: 'core/constants' },
|
{
|
||||||
{ label: 'Interfaces', slug: 'core/interfaces' },
|
label: "Base Nostr Transport",
|
||||||
{ label: 'Encryption', slug: 'core/encryption' },
|
slug: "transports/base-nostr-transport",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Nostr Client",
|
||||||
|
slug: "transports/nostr-client-transport",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Nostr Server",
|
||||||
|
slug: "transports/nostr-server-transport",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Components',
|
label: "Components",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Gateway', slug: 'gateway/overview' },
|
{ label: "Gateway", slug: "gateway/overview" },
|
||||||
{ label: 'Relay', slug: 'relay/simple-relay-pool' },
|
{ label: "Relay", slug: "relay/simple-relay-pool" },
|
||||||
{ label: 'Signer', slug: 'signer/private-key-signer' },
|
{ label: "Signer", slug: "signer/private-key-signer" },
|
||||||
{ label: 'Proxy', slug: 'proxy/overview' },
|
{ label: "Proxy", slug: "proxy/overview" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Tutorials',
|
label: "Tutorials",
|
||||||
items: [
|
items: [
|
||||||
{ label: 'Client-Server Communication', slug: 'tutorials/client-server-communication' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Transports',
|
label: "Client-Server Communication",
|
||||||
items: [
|
slug: "tutorials/client-server-communication",
|
||||||
{ label: 'Base Nostr Transport', slug: 'transports/base-nostr-transport' },
|
},
|
||||||
{ label: 'Nostr Client', slug: 'transports/nostr-client-transport' },
|
|
||||||
{ label: 'Nostr Server', slug: 'transports/nostr-server-transport' },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
3
bun.lock
3
bun.lock
@@ -6,6 +6,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/starlight": "^0.35.0",
|
"@astrojs/starlight": "^0.35.0",
|
||||||
"astro": "^5.6.1",
|
"astro": "^5.6.1",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
"sharp": "^0.34.2",
|
"sharp": "^0.34.2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -689,6 +690,8 @@
|
|||||||
|
|
||||||
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||||
|
|
||||||
|
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||||
|
|
||||||
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
|
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
|
||||||
|
|
||||||
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/starlight": "^0.35.0",
|
"@astrojs/starlight": "^0.35.0",
|
||||||
"astro": "^5.6.1",
|
"astro": "^5.6.1",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
"sharp": "^0.34.2"
|
"sharp": "^0.34.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { defineCollection } from 'astro:content';
|
import { defineCollection } from "astro:content";
|
||||||
import { docsLoader } from '@astrojs/starlight/loaders';
|
import { docsLoader } from "@astrojs/starlight/loaders";
|
||||||
import { docsSchema } from '@astrojs/starlight/schema';
|
import { docsSchema } from "@astrojs/starlight/schema";
|
||||||
|
|
||||||
export const collections = {
|
export const collections = {
|
||||||
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ The `@contextvm/sdk` exports a set of constants that are used throughout the lib
|
|||||||
The ContextVM protocol defines several Nostr event kinds for different types of messages.
|
The ContextVM protocol defines several Nostr event kinds for different types of messages.
|
||||||
|
|
||||||
| Constant | Kind | Description |
|
| Constant | Kind | Description |
|
||||||
| ----------------------------- | ----- | --------------------------------------------------------------------------- |
|
| ----------------------------- | ----- | ----------------------------------------------------------------------------- |
|
||||||
| `CTXVM_MESSAGES_KIND` | 25910 | The kind for standard, ephemeral ContextVM messages. |
|
| `CTXVM_MESSAGES_KIND` | 25910 | The kind for standard, ephemeral ContextVM messages. |
|
||||||
| `GIFT_WRAP_KIND` | 1059 | The kind for encrypted messages, wrapped using the NIP-59 gift wrap standard. |
|
| `GIFT_WRAP_KIND` | 1059 | The kind for encrypted messages, wrapped using the NIP-59 gift wrap standard. |
|
||||||
| `SERVER_ANNOUNCEMENT_KIND` | 11316 | A replaceable event for announcing a server's presence and basic info. |
|
| `SERVER_ANNOUNCEMENT_KIND` | 11316 | A replaceable event for announcing a server's presence and basic info. |
|
||||||
@@ -26,7 +26,7 @@ The ContextVM protocol defines several Nostr event kinds for different types of
|
|||||||
The SDK defines an object `NOSTR_TAGS` that contains constants for the various Nostr event tags used in the ContextVM protocol.
|
The SDK defines an object `NOSTR_TAGS` that contains constants for the various Nostr event tags used in the ContextVM protocol.
|
||||||
|
|
||||||
| Key | Tag | Description |
|
| Key | Tag | Description |
|
||||||
| -------------------- | -------------------- | ------------------------------------------------------------------------ |
|
| -------------------- | -------------------- | ---------------------------------------------------------------------- |
|
||||||
| `PUBKEY` | `p` | The public key of the message recipient. |
|
| `PUBKEY` | `p` | The public key of the message recipient. |
|
||||||
| `EVENT_ID` | `e` | The event ID used to correlate requests and responses. |
|
| `EVENT_ID` | `e` | The event ID used to correlate requests and responses. |
|
||||||
| `CAPABILITY` | `cap` | A tag for specifying pricing metadata for a tool, resource, or prompt. |
|
| `CAPABILITY` | `cap` | A tag for specifying pricing metadata for a tool, resource, or prompt. |
|
||||||
@@ -41,11 +41,11 @@ The `announcementMethods` object maps capability types to their corresponding MC
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export const announcementMethods = {
|
export const announcementMethods = {
|
||||||
server: 'initialize',
|
server: "initialize",
|
||||||
tools: 'tools/list',
|
tools: "tools/list",
|
||||||
resources: 'resources/list',
|
resources: "resources/list",
|
||||||
resourceTemplates: 'resources/templates/list',
|
resourceTemplates: "resources/templates/list",
|
||||||
prompts: 'prompts/list',
|
prompts: "prompts/list",
|
||||||
} as const;
|
} as const;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ The standard implementation of NIP-17 is designed for persistent private message
|
|||||||
Encryption is configured at the transport level using the `EncryptionMode` enum. You can set the desired mode when creating a `NostrClientTransport` or `NostrServerTransport`.
|
Encryption is configured at the transport level using the `EncryptionMode` enum. You can set the desired mode when creating a `NostrClientTransport` or `NostrServerTransport`.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { NostrClientTransport } from '@ctxvm/sdk/transport';
|
import { NostrClientTransport } from "@ctxvm/sdk/transport";
|
||||||
import { EncryptionMode } from '@ctxvm/sdk/core';
|
import { EncryptionMode } from "@ctxvm/sdk/core";
|
||||||
|
|
||||||
const transport = new NostrClientTransport({
|
const transport = new NostrClientTransport({
|
||||||
// ... other options
|
// ... other options
|
||||||
|
|||||||
@@ -68,9 +68,9 @@ The `EncryptionMode` enum defines the encryption policy for a transport.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export enum EncryptionMode {
|
export enum EncryptionMode {
|
||||||
OPTIONAL = 'optional',
|
OPTIONAL = "optional",
|
||||||
REQUIRED = 'required',
|
REQUIRED = "required",
|
||||||
DISABLED = 'disabled',
|
DISABLED = "disabled",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -84,11 +84,11 @@ The `AnnouncementMethods` interface defines methods for announcing server capabi
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface AnnouncementMethods {
|
export interface AnnouncementMethods {
|
||||||
server: InitializeRequest['method'];
|
server: InitializeRequest["method"];
|
||||||
tools: ListToolsRequest['method'];
|
tools: ListToolsRequest["method"];
|
||||||
resources: ListResourcesRequest['method'];
|
resources: ListResourcesRequest["method"];
|
||||||
resourceTemplates: ListResourceTemplatesRequest['method'];
|
resourceTemplates: ListResourceTemplatesRequest["method"];
|
||||||
prompts: ListPromptsRequest['method'];
|
prompts: ListPromptsRequest["method"];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ title: ContextVM Protocol Specification
|
|||||||
description: Technical specification for the ContextVM protocol
|
description: Technical specification for the ContextVM protocol
|
||||||
---
|
---
|
||||||
|
|
||||||
**MCP Version:** `mcp:2025-03-26`
|
|
||||||
**Status:** Draft
|
**Status:** Draft
|
||||||
|
|
||||||
## Abstract
|
## Abstract
|
||||||
|
|
||||||
The Context Vending Machine (ContextVM) specification defines how Nostr and Context Vending Machines can be used to expose Model Context Protocol (MCP) server capabilities, enabling standardized usage of these resources through a decentralized, cryptographically secure messaging system.
|
The Context Vending Machine (ContextVM) specification defines how Nostr can be used to expose Model Context Protocol (MCP) server capabilities, enabling standardized usage of these resources through a decentralized, cryptographically secure messaging system.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
|
|||||||
@@ -43,19 +43,19 @@ export interface NostrMCPGatewayOptions {
|
|||||||
This example shows how to create a gateway that connects to a local MCP server (running in a separate process) and exposes it to the Nostr network.
|
This example shows how to create a gateway that connects to a local MCP server (running in a separate process) and exposes it to the Nostr network.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/stdio';
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/stdio";
|
||||||
import { NostrMCPGateway } from '@ctxvm/sdk/gateway';
|
import { NostrMCPGateway } from "@ctxvm/sdk/gateway";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
|
|
||||||
// 1. Configure the signer and relay handler for the Nostr transport
|
// 1. Configure the signer and relay handler for the Nostr transport
|
||||||
const signer = new PrivateKeySigner('your-gateway-private-key');
|
const signer = new PrivateKeySigner("your-gateway-private-key");
|
||||||
const relayPool = new SimpleRelayPool(['wss://relay.damus.io']);
|
const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]);
|
||||||
|
|
||||||
// 2. Configure the transport to connect to your existing MCP server
|
// 2. Configure the transport to connect to your existing MCP server
|
||||||
const serverTransport = new StdioClientTransport({
|
const serverTransport = new StdioClientTransport({
|
||||||
command: 'bun',
|
command: "bun",
|
||||||
args: ['run', 'path/to/your/mcp-server.ts'],
|
args: ["run", "path/to/your/mcp-server.ts"],
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Create the gateway instance
|
// 3. Create the gateway instance
|
||||||
@@ -71,7 +71,7 @@ const gateway = new NostrMCPGateway({
|
|||||||
// 4. Start the gateway
|
// 4. Start the gateway
|
||||||
await gateway.start();
|
await gateway.start();
|
||||||
|
|
||||||
console.log('Gateway is running, exposing the MCP server to Nostr.');
|
console.log("Gateway is running, exposing the MCP server to Nostr.");
|
||||||
|
|
||||||
// To stop the gateway: await gateway.stop();
|
// To stop the gateway: await gateway.stop();
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: ContextVM Documentation
|
title: ContextVM Documentation
|
||||||
description: A virtual machine for context-controlled computation using Nostr protocol
|
description: ContextVM - The intersection of Nostr and MCP
|
||||||
template: splash
|
template: splash
|
||||||
hero:
|
hero:
|
||||||
tagline: ContextVM - The context-controlled virtual machine built on Nostr
|
tagline: ContextVM - The intersection of Nostr and MCP
|
||||||
image:
|
image:
|
||||||
file: ../../assets/contextvm-logo.svg
|
file: ../../assets/contextvm-logo.svg
|
||||||
actions:
|
actions:
|
||||||
@@ -16,7 +16,7 @@ hero:
|
|||||||
variant: minimal
|
variant: minimal
|
||||||
---
|
---
|
||||||
|
|
||||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
import { Card, CardGrid } from "@astrojs/starlight/components";
|
||||||
|
|
||||||
## Core Concepts
|
## Core Concepts
|
||||||
|
|
||||||
|
|||||||
@@ -43,15 +43,15 @@ export interface NostrMCPProxyOptions {
|
|||||||
This example demonstrates how to create a proxy that listens for a local client over standard I/O and connects to a remote server over Nostr.
|
This example demonstrates how to create a proxy that listens for a local client over standard I/O and connects to a remote server over Nostr.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/stdio';
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/stdio";
|
||||||
import { NostrMCPProxy } from '@ctxvm/sdk/proxy';
|
import { NostrMCPProxy } from "@ctxvm/sdk/proxy";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
|
|
||||||
// 1. Configure the signer and relay handler for the Nostr connection
|
// 1. Configure the signer and relay handler for the Nostr connection
|
||||||
const signer = new PrivateKeySigner('your-private-key');
|
const signer = new PrivateKeySigner("your-private-key");
|
||||||
const relayPool = new SimpleRelayPool(['wss://relay.damus.io']);
|
const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]);
|
||||||
const REMOTE_SERVER_PUBKEY = 'remote-server-public-key';
|
const REMOTE_SERVER_PUBKEY = "remote-server-public-key";
|
||||||
|
|
||||||
// 2. Configure the transport for the local client
|
// 2. Configure the transport for the local client
|
||||||
// In this case, a stdio transport that the local client can connect to
|
// In this case, a stdio transport that the local client can connect to
|
||||||
@@ -70,7 +70,7 @@ const proxy = new NostrMCPProxy({
|
|||||||
// 4. Start the proxy
|
// 4. Start the proxy
|
||||||
await proxy.start();
|
await proxy.start();
|
||||||
|
|
||||||
console.log('Proxy is running. Connect your local MCP client.');
|
console.log("Proxy is running. Connect your local MCP client.");
|
||||||
|
|
||||||
// To stop the proxy: await proxy.stop();
|
// To stop the proxy: await proxy.stop();
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -26,28 +26,30 @@ To create a custom relay handler, you need to create a class that implements the
|
|||||||
Here is a simple example of a custom `RelayHandler` that wraps the default `SimpleRelayPool` and adds logging to each operation. This illustrates how you can extend or compose existing handlers.
|
Here is a simple example of a custom `RelayHandler` that wraps the default `SimpleRelayPool` and adds logging to each operation. This illustrates how you can extend or compose existing handlers.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { RelayHandler } from '@ctxvm/sdk/core';
|
import { RelayHandler } from "@ctxvm/sdk/core";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
import { Filter, NostrEvent } from 'nostr-tools';
|
import { Filter, NostrEvent } from "nostr-tools";
|
||||||
|
|
||||||
class LoggingRelayHandler implements RelayHandler {
|
class LoggingRelayHandler implements RelayHandler {
|
||||||
private readonly innerHandler: RelayHandler;
|
private readonly innerHandler: RelayHandler;
|
||||||
|
|
||||||
constructor(relayUrls: string[]) {
|
constructor(relayUrls: string[]) {
|
||||||
this.innerHandler = new SimpleRelayPool(relayUrls);
|
this.innerHandler = new SimpleRelayPool(relayUrls);
|
||||||
console.log(`[LoggingRelayHandler] Initialized with relays: ${relayUrls.join(', ')}`);
|
console.log(
|
||||||
|
`[LoggingRelayHandler] Initialized with relays: ${relayUrls.join(", ")}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(): Promise<void> {
|
async connect(): Promise<void> {
|
||||||
console.log('[LoggingRelayHandler] Attempting to connect...');
|
console.log("[LoggingRelayHandler] Attempting to connect...");
|
||||||
await this.innerHandler.connect();
|
await this.innerHandler.connect();
|
||||||
console.log('[LoggingRelayHandler] Connected successfully.');
|
console.log("[LoggingRelayHandler] Connected successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect(): Promise<void> {
|
async disconnect(): Promise<void> {
|
||||||
console.log('[LoggingRelayHandler] Disconnecting...');
|
console.log("[LoggingRelayHandler] Disconnecting...");
|
||||||
await this.innerHandler.disconnect();
|
await this.innerHandler.disconnect();
|
||||||
console.log('[LoggingRelayHandler] Disconnected.');
|
console.log("[LoggingRelayHandler] Disconnected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(event: NostrEvent): void {
|
publish(event: NostrEvent): void {
|
||||||
@@ -64,13 +66,13 @@ class LoggingRelayHandler implements RelayHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsubscribe(): void {
|
unsubscribe(): void {
|
||||||
console.log('[LoggingRelayHandler] Unsubscribing from all.');
|
console.log("[LoggingRelayHandler] Unsubscribing from all.");
|
||||||
this.innerHandler.unsubscribe();
|
this.innerHandler.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage
|
// Usage
|
||||||
const loggingHandler = new LoggingRelayHandler(['wss://relay.damus.io']);
|
const loggingHandler = new LoggingRelayHandler(["wss://relay.damus.io"]);
|
||||||
|
|
||||||
const transport = new NostrClientTransport({
|
const transport = new NostrClientTransport({
|
||||||
relayHandler: loggingHandler,
|
relayHandler: loggingHandler,
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ The constructor takes a single argument:
|
|||||||
## Usage Example
|
## Usage Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
import { NostrClientTransport } from '@ctxvm/sdk/transport';
|
import { NostrClientTransport } from "@ctxvm/sdk/transport";
|
||||||
|
|
||||||
// 1. Define the list of relays you want to connect to
|
// 1. Define the list of relays you want to connect to
|
||||||
const myRelays = [
|
const myRelays = [
|
||||||
'wss://relay.damus.io',
|
"wss://relay.damus.io",
|
||||||
'wss://relay.primal.net',
|
"wss://relay.primal.net",
|
||||||
'wss://nos.lol',
|
"wss://nos.lol",
|
||||||
];
|
];
|
||||||
|
|
||||||
// 2. Create an instance of the SimpleRelayPool
|
// 2. Create an instance of the SimpleRelayPool
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ A common use case for a custom signer is in a web application that needs to inte
|
|||||||
Here is how you could implement a `NostrSigner` that wraps the `window.nostr` object:
|
Here is how you could implement a `NostrSigner` that wraps the `window.nostr` object:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { NostrSigner } from '@ctxvm/sdk/core';
|
import { NostrSigner } from "@ctxvm/sdk/core";
|
||||||
import { UnsignedEvent, NostrEvent } from 'nostr-tools';
|
import { UnsignedEvent, NostrEvent } from "nostr-tools";
|
||||||
|
|
||||||
// Define the NIP-07 window.nostr interface for type-safety
|
// Define the NIP-07 window.nostr interface for type-safety
|
||||||
declare global {
|
declare global {
|
||||||
@@ -46,31 +46,31 @@ declare global {
|
|||||||
class Nip07Signer implements NostrSigner {
|
class Nip07Signer implements NostrSigner {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!window.nostr) {
|
if (!window.nostr) {
|
||||||
throw new Error('NIP-07 compatible browser extension not found.');
|
throw new Error("NIP-07 compatible browser extension not found.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKey(): Promise<string> {
|
async getPublicKey(): Promise<string> {
|
||||||
if (!window.nostr) throw new Error('window.nostr not found.');
|
if (!window.nostr) throw new Error("window.nostr not found.");
|
||||||
return await window.nostr.getPublicKey();
|
return await window.nostr.getPublicKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
async signEvent(event: UnsignedEvent): Promise<NostrEvent> {
|
async signEvent(event: UnsignedEvent): Promise<NostrEvent> {
|
||||||
if (!window.nostr) throw new Error('window.nostr not found.');
|
if (!window.nostr) throw new Error("window.nostr not found.");
|
||||||
return await window.nostr.signEvent(event);
|
return await window.nostr.signEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
nip44 = {
|
nip44 = {
|
||||||
encrypt: async (pubkey: string, plaintext: string): Promise<string> => {
|
encrypt: async (pubkey: string, plaintext: string): Promise<string> => {
|
||||||
if (!window.nostr?.nip44) {
|
if (!window.nostr?.nip44) {
|
||||||
throw new Error('The extension does not support NIP-44 encryption.');
|
throw new Error("The extension does not support NIP-44 encryption.");
|
||||||
}
|
}
|
||||||
return await window.nostr.nip44.encrypt(pubkey, plaintext);
|
return await window.nostr.nip44.encrypt(pubkey, plaintext);
|
||||||
},
|
},
|
||||||
|
|
||||||
decrypt: async (pubkey: string, ciphertext: string): Promise<string> => {
|
decrypt: async (pubkey: string, ciphertext: string): Promise<string> => {
|
||||||
if (!window.nostr?.nip44) {
|
if (!window.nostr?.nip44) {
|
||||||
throw new Error('The extension does not support NIP-44 decryption.');
|
throw new Error("The extension does not support NIP-44 decryption.");
|
||||||
}
|
}
|
||||||
return await window.nostr.nip44.decrypt(pubkey, ciphertext);
|
return await window.nostr.nip44.decrypt(pubkey, ciphertext);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ When instantiated, the `PrivateKeySigner` will immediately convert the hex strin
|
|||||||
## Usage Example
|
## Usage Example
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
|
|
||||||
// Replace with a securely stored private key
|
// Replace with a securely stored private key
|
||||||
const privateKeyHex = 'your-32-byte-private-key-in-hex';
|
const privateKeyHex = "your-32-byte-private-key-in-hex";
|
||||||
|
|
||||||
const signer = new PrivateKeySigner(privateKeyHex);
|
const signer = new PrivateKeySigner(privateKeyHex);
|
||||||
|
|
||||||
|
|||||||
@@ -36,18 +36,18 @@ export interface NostrTransportOptions extends BaseNostrTransportOptions {
|
|||||||
Here's how you can use the `NostrClientTransport` with an MCP client from the `@modelcontextprotocol/sdk`:
|
Here's how you can use the `NostrClientTransport` with an MCP client from the `@modelcontextprotocol/sdk`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Client } from '@modelcontextprotocol/sdk/client';
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
||||||
import { NostrClientTransport } from '@ctxvm/sdk/transport';
|
import { NostrClientTransport } from "@ctxvm/sdk/transport";
|
||||||
import { EncryptionMode } from '@ctxvm/sdk/core';
|
import { EncryptionMode } from "@ctxvm/sdk/core";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
|
|
||||||
// 1. Configure the signer and relay handler
|
// 1. Configure the signer and relay handler
|
||||||
const signer = new PrivateKeySigner('your-private-key'); // Replace with your actual private key
|
const signer = new PrivateKeySigner("your-private-key"); // Replace with your actual private key
|
||||||
const relayPool = new SimpleRelayPool(['wss://relay.damus.io']);
|
const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]);
|
||||||
|
|
||||||
// 2. Set the public key of the target server
|
// 2. Set the public key of the target server
|
||||||
const REMOTE_SERVER_PUBKEY = 'remote-server-public-key';
|
const REMOTE_SERVER_PUBKEY = "remote-server-public-key";
|
||||||
|
|
||||||
// 3. Create the transport instance
|
// 3. Create the transport instance
|
||||||
const clientNostrTransport = new NostrClientTransport({
|
const clientNostrTransport = new NostrClientTransport({
|
||||||
@@ -63,7 +63,7 @@ await mcpClient.connect(clientNostrTransport);
|
|||||||
|
|
||||||
// 5. Use the client to interact with the server
|
// 5. Use the client to interact with the server
|
||||||
const tools = await mcpClient.listTools();
|
const tools = await mcpClient.listTools();
|
||||||
console.log('Available tools:', tools);
|
console.log("Available tools:", tools);
|
||||||
|
|
||||||
// 6. Close the connection when done
|
// 6. Close the connection when done
|
||||||
// await mcpClient.close();
|
// await mcpClient.close();
|
||||||
|
|||||||
@@ -38,19 +38,19 @@ export interface NostrServerTransportOptions extends BaseNostrTransportOptions {
|
|||||||
Here's how to use the `NostrServerTransport` with an `McpServer` from the `@modelcontextprotocol/sdk`:
|
Here's how to use the `NostrServerTransport` with an `McpServer` from the `@modelcontextprotocol/sdk`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { McpServer } from '@modelcontextprotocol/sdk/server';
|
import { McpServer } from "@modelcontextprotocol/sdk/server";
|
||||||
import { NostrServerTransport } from '@ctxvm/sdk/transport';
|
import { NostrServerTransport } from "@ctxvm/sdk/transport";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
|
|
||||||
// 1. Configure the signer and relay pool
|
// 1. Configure the signer and relay pool
|
||||||
const signer = new PrivateKeySigner('your-server-private-key');
|
const signer = new PrivateKeySigner("your-server-private-key");
|
||||||
const relayPool = new SimpleRelayPool(['wss://relay.damus.io']);
|
const relayPool = new SimpleRelayPool(["wss://relay.damus.io"]);
|
||||||
|
|
||||||
// 2. Create the McpServer instance
|
// 2. Create the McpServer instance
|
||||||
const mcpServer = new McpServer({
|
const mcpServer = new McpServer({
|
||||||
name: 'demo-server',
|
name: "demo-server",
|
||||||
version: '1.0.0',
|
version: "1.0.0",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register your server's tools, resources, etc.
|
// Register your server's tools, resources, etc.
|
||||||
@@ -62,15 +62,15 @@ const serverNostrTransport = new NostrServerTransport({
|
|||||||
relayHandler: relayPool,
|
relayHandler: relayPool,
|
||||||
isPublicServer: true, // Announce the server publicly
|
isPublicServer: true, // Announce the server publicly
|
||||||
serverInfo: {
|
serverInfo: {
|
||||||
name: 'My Awesome MCP Server',
|
name: "My Awesome MCP Server",
|
||||||
website: 'https://example.com',
|
website: "https://example.com",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 4. Connect the server
|
// 4. Connect the server
|
||||||
await mcpServer.connect(serverNostrTransport);
|
await mcpServer.connect(serverNostrTransport);
|
||||||
|
|
||||||
console.log('MCP server is running and available on Nostr.');
|
console.log("MCP server is running and available on Nostr.");
|
||||||
|
|
||||||
// Keep the process running...
|
// Keep the process running...
|
||||||
// To shut down: await mcpServer.close();
|
// To shut down: await mcpServer.close();
|
||||||
|
|||||||
@@ -28,16 +28,17 @@ First, let's create the MCP server. This server will use the `NostrServerTranspo
|
|||||||
Create a new file named `server.ts`:
|
Create a new file named `server.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { McpServer, Tool } from '@modelcontextprotocol/sdk/server';
|
import { McpServer, Tool } from "@modelcontextprotocol/sdk/server";
|
||||||
import { NostrServerTransport } from '@ctxvm/sdk/transport';
|
import { NostrServerTransport } from "@ctxvm/sdk/transport";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
import { generateSecretKey, getPublicKey } from 'nostr-tools/pure';
|
import { generateSecretKey, getPublicKey } from "nostr-tools/pure";
|
||||||
|
|
||||||
// --- Configuration ---
|
// --- Configuration ---
|
||||||
// IMPORTANT: Replace with your own private key
|
// IMPORTANT: Replace with your own private key
|
||||||
const SERVER_PRIVATE_KEY_HEX = process.env.SERVER_PRIVATE_KEY || 'your-32-byte-server-private-key-in-hex';
|
const SERVER_PRIVATE_KEY_HEX =
|
||||||
const RELAYS = ['wss://relay.damus.io', 'wss://nos.lol'];
|
process.env.SERVER_PRIVATE_KEY || "your-32-byte-server-private-key-in-hex";
|
||||||
|
const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"];
|
||||||
|
|
||||||
// --- Main Server Logic ---
|
// --- Main Server Logic ---
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -47,33 +48,26 @@ async function main() {
|
|||||||
const serverPubkey = await signer.getPublicKey();
|
const serverPubkey = await signer.getPublicKey();
|
||||||
|
|
||||||
console.log(`Server Public Key: ${serverPubkey}`);
|
console.log(`Server Public Key: ${serverPubkey}`);
|
||||||
console.log('Connecting to relays...');
|
console.log("Connecting to relays...");
|
||||||
|
|
||||||
// 2. Create and Configure the MCP Server
|
// 2. Create and Configure the MCP Server
|
||||||
const mcpServer = new McpServer({
|
const mcpServer = new McpServer({
|
||||||
name: 'nostr-echo-server',
|
name: "nostr-echo-server",
|
||||||
version: '1.0.0',
|
version: "1.0.0",
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Define a simple "echo" tool
|
// 3. Define a simple "echo" tool
|
||||||
const echoTool = new Tool({
|
server.registerTool(
|
||||||
name: 'echo',
|
"echo",
|
||||||
description: 'Replies with the input it received.',
|
{
|
||||||
inputSchema: {
|
title: "Echo Tool",
|
||||||
type: 'object',
|
description: "Echoes back the provided message",
|
||||||
properties: {
|
inputSchema: { message: z.string() },
|
||||||
message: { type: 'string' },
|
|
||||||
},
|
},
|
||||||
required: ['message'],
|
async ({ message }) => ({
|
||||||
},
|
content: [{ type: "text", text: `Tool echo: ${message}` }],
|
||||||
execute: async (input) => {
|
}),
|
||||||
return {
|
);
|
||||||
content: `You said: ${input.message}`
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mcpServer.tools.add(echoTool);
|
|
||||||
|
|
||||||
// 4. Configure the Nostr Server Transport
|
// 4. Configure the Nostr Server Transport
|
||||||
const serverTransport = new NostrServerTransport({
|
const serverTransport = new NostrServerTransport({
|
||||||
@@ -81,19 +75,19 @@ async function main() {
|
|||||||
relayHandler: relayPool,
|
relayHandler: relayPool,
|
||||||
isPublicServer: true, // Announce this server on the Nostr network
|
isPublicServer: true, // Announce this server on the Nostr network
|
||||||
serverInfo: {
|
serverInfo: {
|
||||||
name: 'CTXVM Echo Server',
|
name: "CTXVM Echo Server",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5. Connect the server
|
// 5. Connect the server
|
||||||
await mcpServer.connect(serverTransport);
|
await mcpServer.connect(serverTransport);
|
||||||
|
|
||||||
console.log('Server is running and listening for requests on Nostr...');
|
console.log("Server is running and listening for requests on Nostr...");
|
||||||
console.log('Press Ctrl+C to exit.');
|
console.log("Press Ctrl+C to exit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error('Failed to start server:', error);
|
console.error("Failed to start server:", error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -117,31 +111,27 @@ Next, let's create the client that will connect to our server.
|
|||||||
Create a new file named `client.ts`:
|
Create a new file named `client.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Client } from '@modelcontextprotocol/sdk/client';
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
||||||
import { NostrClientTransport } from '@ctxvm/sdk/transport';
|
import { NostrClientTransport } from "@ctxvm/sdk/transport";
|
||||||
import { PrivateKeySigner } from '@ctxvm/sdk/signer';
|
import { PrivateKeySigner } from "@ctxvm/sdk/signer";
|
||||||
import { SimpleRelayPool } from '@ctxvm/sdk/relay';
|
import { SimpleRelayPool } from "@ctxvm/sdk/relay";
|
||||||
|
|
||||||
// --- Configuration ---
|
// --- Configuration ---
|
||||||
// IMPORTANT: Replace with the server's public key from the server output
|
// IMPORTANT: Replace with the server's public key from the server output
|
||||||
const SERVER_PUBKEY = 'the-public-key-printed-by-server.ts';
|
const SERVER_PUBKEY = "the-public-key-printed-by-server.ts";
|
||||||
|
|
||||||
// IMPORTANT: Replace with your own private key
|
// IMPORTANT: Replace with your own private key
|
||||||
const CLIENT_PRIVATE_KEY_HEX = process.env.CLIENT_PRIVATE_KEY || 'your-32-byte-client-private-key-in-hex';
|
const CLIENT_PRIVATE_KEY_HEX =
|
||||||
const RELAYS = ['wss://relay.damus.io', 'wss://nos.lol'];
|
process.env.CLIENT_PRIVATE_KEY || "your-32-byte-client-private-key-in-hex";
|
||||||
|
const RELAYS = ["wss://relay.damus.io", "wss://nos.lol"];
|
||||||
|
|
||||||
// --- Main Client Logic ---
|
// --- Main Client Logic ---
|
||||||
async function main() {
|
async function main() {
|
||||||
if (SERVER_PUBKEY.startsWith('the-public-key')) {
|
|
||||||
console.error('Please replace SERVER_PUBKEY with the actual public key from the server.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 1. Setup Signer and Relay Pool
|
// 1. Setup Signer and Relay Pool
|
||||||
const signer = new PrivateKeySigner(CLIENT_PRIVATE_KEY_HEX);
|
const signer = new PrivateKeySigner(CLIENT_PRIVATE_KEY_HEX);
|
||||||
const relayPool = new SimpleRelayPool(RELAYS);
|
const relayPool = new SimpleRelayPool(RELAYS);
|
||||||
|
|
||||||
console.log('Connecting to relays...');
|
console.log("Connecting to relays...");
|
||||||
|
|
||||||
// 2. Configure the Nostr Client Transport
|
// 2. Configure the Nostr Client Transport
|
||||||
const clientTransport = new NostrClientTransport({
|
const clientTransport = new NostrClientTransport({
|
||||||
@@ -154,26 +144,28 @@ async function main() {
|
|||||||
const mcpClient = new Client();
|
const mcpClient = new Client();
|
||||||
await mcpClient.connect(clientTransport);
|
await mcpClient.connect(clientTransport);
|
||||||
|
|
||||||
console.log('Connected to server!');
|
console.log("Connected to server!");
|
||||||
|
|
||||||
// 4. List the available tools
|
// 4. List the available tools
|
||||||
console.log('\nListing available tools...');
|
console.log("\nListing available tools...");
|
||||||
const tools = await mcpClient.listTools();
|
const tools = await mcpClient.listTools();
|
||||||
console.log('Tools:', tools);
|
console.log("Tools:", tools);
|
||||||
|
|
||||||
// 5. Call the "echo" tool
|
// 5. Call the "echo" tool
|
||||||
console.log('\nCalling the "echo" tool...');
|
console.log('\nCalling the "echo" tool...');
|
||||||
const echoResult = await mcpClient.callTool('echo', { message: 'Hello, Nostr!' });
|
const echoResult = await mcpClient.callTool({
|
||||||
console.log('Echo result:', echoResult.content);
|
name: "echo",
|
||||||
|
arguments: { message: "Hello, Nostr!" },
|
||||||
|
});
|
||||||
|
console.log("Echo result:", echoResult);
|
||||||
|
|
||||||
// 6. Close the connection
|
// 6. Close the connection
|
||||||
await mcpClient.close();
|
await mcpClient.close();
|
||||||
console.log('\nConnection closed.');
|
console.log("\nConnection closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
console.error('Client failed:', error);
|
console.error("Client failed:", error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -212,4 +204,5 @@ Echo result: You said: Hello, Nostr!
|
|||||||
|
|
||||||
Connection closed.
|
Connection closed.
|
||||||
```
|
```
|
||||||
|
|
||||||
And that's it! You've successfully created an MCP client and server that communicate securely and decentrally over the Nostr network.
|
And that's it! You've successfully created an MCP client and server that communicate securely and decentrally over the Nostr network.
|
||||||
Reference in New Issue
Block a user