MESC Overview
To get started quickly, see Quickstart.
To learn what MESC is, see What is MESC?.
To learn the motivation behind MESC, see Why MESC?.
To integrate MESC into an existing tool, see Integrating MESC.
To implement MESC in a new programming language, see Implementing MESC.
For information about existing MESC implementations, see:
Quickstart
The quickest way to use MESC is
- create a
mesc.json
config file - set the
MESC_PATH
environment variable to the path of this file
Creating a config file
You can create a mesc.json
by one of two ways:
- use the interactive MESC cli tool (install using
cargo install mesc_cli
and runmesc setup
) - modify the template below:
{
"mesc_version": "MESC 1.0",
"default_endpoint": "local_ethereum",
"network_defaults": {
"1": "local_ethereum"
},
"network_names": {},
"endpoints": {
"local_ethereum": {
"name": "local_ethereum",
"url": "http://localhost:8545",
"chain_id": "1",
"endpoint_metadata": {}
}
},
"profiles": {
"xyz": {
"name": "xyz",
"default_endpoint": "local_ethereum",
"network_defaults": {
"1": "local_ethereum"
},
"profile_metadata": {},
"use_mesc": true
}
},
"global_metadata": {}
}
The structure of the config must follow the MESC specification.
Installing the mesc
cli on some linux distributions may require installing ssl libraries (e.g. sudo apt-get install pkg-config libssl-dev
on ubunutu)
Setting environment variables
The typical way to set environment variables is in your shell configuration files: ~/.bashrc
, ~.profile
, and/or ~/.bash_profile
. Including this line in those files will enable MESC:
export MESC_PATH=/path/to/your/mesc.json
You can avoid editing these files yourself by running the MESC setup tool (mesc setup
) as specified above. It will give you the option to automatically edit your shell files.
What is MESC?
MESC (Multiple Endpoint Shared Configuration) is a standardized approach for configuring RPC endpoints. Using MESC, a user creates a single RPC config that is shared by all RPC tools on their system.
Design Goals
MESC has two main design goals:
- make it easy to share RPC configuration data across tools, languages, and environments
- make it easy to manage the configuration of a large number of RPC endpoints
MESC also has many secondary goals. It aims to be a solution that:
- allows specifying multiple providers for multiple chains
- allows selection of a default endpoint for each chain
- allows using either environment variables or config files
- is a single source of truth across multiple tools
- is OS-agnostic, using no OS-specific features
- is language-agnostic, using no language-specific features
- is backwards compatible with previous solutions
MESC is opt-in
MESC is an opt-in standard: MESC is only enabled if a user has set a MESC-specific environment variable in their environment. This maximizes backward-compatiblity for existing tools that want to integrate MESC: If a user has not opted-in to MESC then simply fall back to the existing configuration method.
Why MESC?
Between mainnet, testnets, chainforks, rollups, and alternative L1's, modern crypto tools must manage the configuration of multiple RPC endpoints. This configuration process is not standardized across tools.
The most common approach for configuring RPC endpoint information is the ETH_RPC_URL
environment variable (dapptools, forge, heimdall, checkthechain). However, this is not a formal standard and many tools use other approaches. Furthermore, using ETH_RPC_URL
can only specify a single provider for a single chain, and it cannot specify any provider metadata beyond the url.
Instead it would be desirable to have a solution that:
- allows specifying multiple providers for multiple chains
- allows selection of a default endpoint for each chain
- allows using either environment variables or config files
- is a single source of truth across multiple tools
- is OS-agnostic, using no OS-specific features
- is language-agnostic, using no language-specific features
- is backwards compatible with previous solutions
MESC aims to satisfy all of these constraints.
As a developer, why should I integrate MESC into my tools?
- Easier Onboarding. As soon as a user installs your tool, they will be able to use your tool with all of their configured networks. This eliminates one of the major setup steps for most RPC consuming tools.
- Interoperability. If you maintain multiple tools, or your tool has components in multiple languages, MESC will create a single, shared source of truth across all of these tool components.
- Safety and Robustness. MESC is thoroughly tested against a large number of config-related edge cases. In many cases it will be safer to user MESC than to create a configuration system from scratch.
- Minimize maintenance burden. Leaning on MESC to handle configuration means there is one less thing you need to maintain. You can spend your time on other things.
- Developer Features. If you need to develop or test your tool with multiple endpoints, the
mesc
CLI tools contains many useful developer features for managing endpoints. - Go config-free. In some cases, adopting MESC means that your tool no longer needs its own config. You can store your tool's config data in MESC's metadata and then just use MESC for all config IO.
Roadmap
Once the MESC specification reaches version 1.0, it will become ossified forever. This will maximize forward- and backward-compatibility between MESC integrations. Client libraries for reading or writing MESC configurations might continue development, but the underlying MESC specification will not change.
MESC currently has implementations for CLI, python, and rust. Implementations for go and typescript are coming soon. If there is another language you have interest in bringing MESC to an additional programming language or environment, feel free to share on the issue tracker.
Using MESC
- To set MESC up, see Setup up MESC
- To use different MESC settings for different tools, see Profiles
- To use MESC for tracking miscellaneous metadata, see Metadata
- To quickly override MESC settings without editing files, see Overrides
Setting up MESC
Basic setup
MESC becomes enabled by setting one or more environment variables.
In the simplest case, only one variable necessary: MESC_PATH
is set to the path of a mesc.json
config file.
As described in the quickstart, the mesc.json
file is usually created using either 1) the interactive mesc setup
command, or 2) copying from a starter template. The quickstart guide also describes how to set environment variables in your terminal shell.
Alternative setup without a mesc.json
Sometimes it is convenient to configure a system without editing any files (e.g. inside a container, or when creating lots of unit tests, or in a low-privilege environment).
This can be accomplished with MESC by setting the MESC_ENV
variable instead of the MESC_PATH
variable. MESC_ENV
should simply contain the JSON content of a MESC configuration.
If both MESC_PATH
and MESC_ENV
are set, you can select which one to use by setting MESC_MODE
to either PATH
or ENV
. MESC_PATH
takes precedence over MESC_ENV
if MESC_MODE
is not set.
Disabling MESC
MESC can be disabled by either 1) unsetting all MESC_*
variables, or 2) setting MESC_MODE=DISABLED
.
If MESC is disabled, the is_mesc_disabled()
function will return false
and all MESC querying functions will return an error (depending on language).
Overrides
MESC also uses environment variables for overrides. See the overrides section for details.
Profiles
Profiles are a way for each tool to customize its own MESC settings.
Profiles allow each tool to:
- set its own default endpoint
- set its own default endpoints for each network
- override global metadata with its own metadata
- avoid using MESC for that tool without disabling MESC globally
Profiles are an optional feature
If a MESC query does not specify a profile, the global configuration values are used.
If a MESC query specifies a profile, but that profile does not exist or does not specify the relevant information, MESC will fallback to using global configuration values.
Setting up a profile
The easiest way to create a profile is by using the interactive mesc
cli tool, using the mesc setup
subcommand.
Alternatively, you can manually add a new Profile
to the profiles
key inside your mesc.json
. The following is a template Profile
:
{
"name": "PROFILE_NAME",
"default_endpoint": null,
"network_defaults": {},
"profile_metadata": {},
"use_mesc": true
}
Metadata
In a MESC configuration, the global_metadata
, profile_metadata
, and endpoint_metadata
fields allow for optional or idiosyncratic metadata to be stored alongside the core RPC data.
Tools using MESC can choose to ignore these fields.
Metadata fields
Contents of MESC metadata is only loosely specified. This is intentional to allow for some degree of future-proofing. It enables MESC to handle use-cases that are either unanticipated or highly-specific to a given tool.
Examples
Endpoint metadata
key | value type | description | examples |
---|---|---|---|
rate_limit_rps | int or float | ratelimit in requests per second | 250 |
rate_limit_cups | int or float | ratelimit in CUPS | 1000 |
rate_limit_per_method | Mapping[str, int or float] | ratelimit in RPS for each method | {"trace_block": 200} |
api_key | str | api key | a2798f237a2398rf7 |
jwt_secret | str | jwt secret | |
host | str | name of provider host | "llamanodes" , "alchemy" , "quicknode" , "localhost" |
ecosystem | str | ecosystem of chain, (e.g. relates mainnets to testnets) | "ethereum" , "polygon" |
node_client | str | versioned node client | erigon/2.48.1/linux-amd64/go1.20.5 reth/v0.1.0-alpha.10-7b781eb60/x86_64-unknown-linux-gnu |
namespaces | Sequence[str] | RPC name spaces enabled for endpoint | ["eth", "trace, "debug"] |
explorer | str | block explorer url | https://etherscan.io |
location | str | geographic region | Paris, France |
cloud_region | str | cloud provider region | aws-us-east-1a |
labels | Sequence[str] | tags | private_mempool , cache , archive , consensus_layer , execution_layer , validator , ephemeral |
Global Metadata and Profile Metadata
key | value type | description | examples |
---|---|---|---|
last_modified_by | str | versioned tool used to create configuration | mesc__1.0 |
last_modified_time | int | timestamp of config modification | 1700200462 |
creation_time | int | timestamp of config creation | 1700200462 |
api_keys | Mapping[str, str] | API keys to RPC-related services | {"etherscan": "abc123"} |
groups | Mapping[str, Sequence[str]] | groupings of endpoints, mapping of group name to list of endpoint names | {"load_balancer": ["alchemy_optimism", "quicknode_optimism"]} |
conceal | bool | whether tool should avoid casually revealing private RPC url's unprompted | true |
Overrides
Overrides are a way to quickly modify a MESC configuration without needing to modify any files.
Each override is an environment variable that overrides a specific MESC configuration key.
Each override uses a syntax that is quick and easy to write by hand.
Example usage
The MESC_DEFAULT_ENDPOINT
override changes the default endpoint.
Use in a script
Sometimes it might be useful tweak a MESC config for a shell script. This can be achieved by inserting the MESC overrides into the script:
#!/usr/bin/env bash
export MESC_DEFAULT_ENDPOINT=local_goerli
# ...rest of script that does RPC things
Prepending syntax
Adding VAR_NAME=VAR_VALUE
before a cli command will set an environment variable for just that command.
So if before the default url is this:
mesc url
> https://eth.llamarpc.com
Adding the override before the command will change the default url:
MESC_DEFAULT_ENDPOINT=local_goerli mesc url
> localhost:8545
This syntax works for any cli program, not just the mesc
cli tool.
List of overrides
Every type of information within a MESC configuration can be modified using overrides:
override variable | value syntax | example |
---|---|---|
MESC_DEFAULT_ENDPOINT | url, endpoint name, or network name | localhost:9999 |
MESC_NETWORK_DEFAULTS | space-separated pairs of <chain_id>=<endpoint> | 5=alchemy_optimism 1=local_mainnet |
MESC_NETWORK_NAMES | space-separated pairs of <network_name>=<chain_id> | zora=7777777 |
MESC_ENDPOINTS | space-separated items of [<endpoint_name>[:<chain_id>]=]<url> | alchemy_optimism=https://alchemy.com/fjsj local_goerli:5=localhost:8545 |
MESC_PROFILES | space-separated pairs of <profile>.<key>[.<subkey]=<endpoint> | foundry.default_endpoint=local_goerli foundry.network_defaults.5=alchemy_optimism |
MESC_GLOBAL_METADATA | JSON formatted global metadata | {} |
MESC_ENDPOINT_METADATA | JSON mapping of {"endpoint_name": {<ENDPOINT_METADATA>}} | {} |
Querying MESC data
Each MESC implementation provides the same set of 7 functions for querying MESC data.
The behavior of these functions is the same across languages.
function | output type | description | example call |
---|---|---|---|
is_mesc_enabled() | bool | return whether MESC is enabled | is_mesc_enabled() |
get_default_endpoint() | Endpoint or None | get default MESC endpoint | get_default_endpoint(profile='xyz') |
get_endpoint_by_network() | Endpoint or None | get default endpoint for network | get_endpoint_by_network(5, profile='xyz') |
get_endpoint_by_name() | Endpoint or None | get endpoint by name | get_endpoint_by_name('local_goerli') |
get_endpoint_by_query() | Endpoint or None | get endpoint for user input query | get_endpoint_by_query(user_str, profile='xyz') |
find_endpoints() | Sequence[Endpoint] | find endpoint that match input criteria | find_endpoints(chain_id=5) |
get_global_metadata() | Mapping[str, Any] | get non-endpoint metadata | get_global_metadata(profile='xyz') |
The profile
argument is optional for each function (it allows users to customize the settings for each tool, see Profiles for details).
Developer Resources
The MESC specification and its reference implementations are developed in the github repository.
- For information about integrating MESC into an existing tool, see Integrating MESC.
- For information about implementing a new MESC client, see Implementing MESC.
- For information about running MESC tests, see MESC Test README.
- For information about building these docs, see here.
Integrating MESC
MESC is designed to be easy to integrate into any existing tool in a backward-compatible manner.
MESC integration patterns can be designed so that they only affect users that have opted-in to MESC, while leaving other users unaffected.
Examples below are shown in python but work nearly identically for each language.
Workflow for getting the default RPC endpoint
Let's say that an existing tool named xyz
currently gets its default RPC endpoint from an environment variable ETH_RPC_URL
like so:
def get_default_rpc_url() -> str | None:
return os.environ.get('ETH_RPC_URL')
MESC can be integrated using a few lines of code:
import mesc
def get_default_rpc_url() -> str | None:
if mesc.is_mesc_enabled():
endpoint = mesc.get_default_endpoint(profile='xyz')
if endpoint is not None:
return endpoint['url']
return os.environ.get('ETH_RPC_URL')
This new function loads the MESC default endpoint for users that have opted-in to MESC. But it falls back to using ETH_RPC_URL
if MESC is not enabled or MESC does not have a default endpoint set.
Using profile='xyz'
is optional, but it allows users to set custom settings for the xyz
tool instead of using the global settings.
Workflow for letting users select an RPC endpoint
Let's say that an existing tool named xyz
currently lets users choose an RPC endpoint using an -r
input argument. Users might use the tool in a similar manner to xyz -r https://eth.llamarpc.com
or xyz -r localhost:8545
.
If we add an extra parsing step for the user input, we can allow the user to select from any endpoint inside the MESC configuration by name, by network name, or by chain id. Using a pattern like this:
def get_endpoint_url(user_input: str) -> str:
if mesc.is_mesc_enabled():
endpoint = mesc.get_endpoint_by_query(user_input)
if endpoint is not None:
return endpoint['url']
return user_input
# ...
url = get_endpoint_url(user_input)
Then users will be able to do any of the following
xyz -r localhost:8545
(use a url)xyz -r llamanodes_goerli
(use the endpoint namedllamanodes_goerli
)xyz -r 5
(use the default endpoint for network with chain id5
)xyz -r goerli
(use the default endpoint for the network namedgoerli
)
Implementing MESC
One of MESC's goals is to have an implementation for every programming language in the cryptocurrency ecosystem.
If you are creating a new MESC implementation, you may find the following useful:
-
The main functionality that a MESC implementation provides is the core MESC interface. This is a set of functions for reading whatever MESC data a user has configured on their system.
-
The ability to write MESC configurations is useful, but should be considered a secondary goal. Users already have the ability to create MESC configurations either by 1) editing JSON by hand, 2) editing JSON programmatically, or 3) using the interactive MESC cli tool.
-
A MESC implementation's compliance to the specification can be checked using the language-agnostic MESC test suite. Passing the test suite means that an implementation is complete. More details on the test suite can be found here.
-
It is desirable to use the same names, types, and behaviors across each MESC implementation. This increases interoperability and makes MESC easier to learn and use. However it is also desirable to obey the common conventions of each programming language. Each MESC implementation must find a balance between language-agnostic conventions vs language-specific conventions.
-
If parts of the MESC specification are confusing or difficult to implement, it may be helpful to look at existing implementations. These currently exist for python and rust.
Implementation Checklist
- Implement the core MESC interface functions. These functions should have the same behavior in each implementation.
- Create an adapter to run the MESC test suite. Passing these tests means the implementation is fully compliant with the MESC specification.
- Add an entry to the generate_network_names.py script. This script creates a native language code file for mapping between network names and chain id's using the standard ethereum-lists/chains repository.
MESC Tests
A language-agnostic set of tests is used to check whether each MESC implementation is compliant with the MESC specification.
Usage
-
Install
pytest
withpytest-xdist
:pip install pytest pytest-xdist
-
Go to the tests directory:
cd $MESC_REPO/mesc/tests
-
Run one of these commands:
description | command |
---|---|
run tests | pytest |
run test in parallel mode (much faster) | pytest -n auto |
run tests in debug mode (helpful for debugging) | pytest --pdb |
run tests only tests that previously failed | pytest --lf |
run tests for specific adapters only | pytest --adapters adapters/python adapters/cli |
By default, tests will run for all MESC implementations. If you do not have all of these implementations installed, you will need to use --adapters
to select only the subset that that you have installed.
Adapters
Each MESC implementation has an adapter that receives a test as input and prints the result as output. Adapters are located in the adapters directory.
To make a custom adapter:
- adapter should be a script that takes a JSON
MescQuery
as its single argument - the adapter should run the query, and then print the result as JSON
- if the config loading or the query fails, simply print the word
FAIL
The adapter should never crash upon failure, just print the word FAIL
Files
adapters/
contains a test adapter for each MESC implementationconftest.py
configuration file for pytestgenerate.py
generates all of the MESC test casestest_mesc.py
packages MESC tests into form usable by pypi
MESC Libraries
MESC aims to have an implementation for every common language in the cryptocurrency ecosystem.
Implementations currently exist for:
If you want to create a MESC implementation for a new language, see implementing MESC.
MESC CLI
This is a utility for creating and managing MESC RPC configurations.
Under the hood, this cli is implemented using the rust crate here.
The most important cli subcommands:
mesc setup
: create and modify MESC configsmesc ls
: list endpointsmesc ping
: ping endpointsmesc url
: print endpoint url
View help for each subcommand by typing mesc [SUBCOMMAND] --help
Contents
Installation
Use one of the 3 options below. Check that mesc
is properly installed and on your PATH
by running mesc -h
.
Install from crates.io
cargo install mesc_cli
Ensure that your cargo install path is on your cli path
Install from source
# install rust and cargo
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# install mesc
git clone https://github.com/paradigmxyz/mesc
cd mesc
cargo install --path rust/crates/cli
Example Usage
Quickly obtain RPC url's:
# curl the default network rpc url
curl $(mesc url) ...
# curl the default goerli url
curl $(mesc url goerli) ...
# curl an endpoint by name
curl $(mesc url local_goerli) ...
Print configuration data
# print all endpoints in table
mesc ls
# ping endpoints and collect metadata
mesc ping
# print default goerli endpoint data, human readable
mesc endpoint goerli
# print default goerli endpoint data, as json
mesc endpoint goerli --json
Reference
Show in terminal by typing mesc --help
:
command line interface for creating, loading, and modifying MESC configuration data
Usage: mesc <COMMAND>
Commands:
setup Create or modify config interactively
import Modify config by importing from file or other source
set Modify config by setting specific values
ping Ping endpoints and fetch metadata
defaults Print list of defaults
endpoint Print endpoint
help Print help
ls Print list of endpoints
metadata Print metadata
status Print status of configuration
url Print endpoint URL
Options:
-h, --help Print help
-V, --version Print version
Help topics: (print these with mesc help <TOPIC>)
env Environmental variables
python Python interface
rust Rust interface
schema Schemas of configs, endpoints, and profiles
setup How to set up MESC
- If an endpoint is omitted, use the default endpoint
- If a chain_id or network name is provided, use the default endpoint of network
- Can use
--profile PROFILENAME
to use defaults of a particular profile
Go MESC Implementation
This is a reference implementation of the Go MESC standard.
Installation
To use this project within your Golang project, execute the following within your project:
go get github.com/paradigmxyz/mesc/go
Example Usage
// TODO: pending doc
Reference
Refer to the function signatures defined in endpoints.go for the list of available functions.
Models are available in the model package.
Python MESC Implementation
This is a reference implementation of the Python MESC Standard
It has no external dependencies.
Installation
From PyPI
pip install mesc
From Source
git clone https://github.com/paradigmxyz/mesc
cd mesc
pip install ./
Example Usage
from typing import Any, Mapping, Sequence
import mesc
# check whether mesc is enabled
enabled: bool = mesc.is_mesc_enabled()
# get the default endpoint
endpoint: Endpoint | None = mesc.get_default_endpoint()
# get the default endpoint of a network
endpoint: Endpoint | None = mesc.get_endpoint_by_network(5)
# get the default endpoint for a particular tool
endpoint: Endpoint | None = mesc.get_default_endpoint(profile='xyz_tool')
# get the default endpoint of a network for a particular tool
endpoint: Endpoint | None = mesc.get_endpoint_by_network(5, profile='xyz_tool')
# get an endpoint by name
endpoint: Endpoint | None = mesc.get_endpoint_by_name('local_goerli')
# parse a user-provided string into a matching endpoint
# (first try 1. endpoint name, then 2. chain id, then 3. network name)
endpoint: Endpoint | None = mesc.get_endpoint_by_query(user_str, profile='xyz_tool')
# find all endpoints matching given criteria
endpoints: Sequence[Endpoint] = mesc.find_endpoints(chain_id=5)
# get non-endpoint metadata
metadata: Mapping[str, Any] = mesc.get_global_metadata(profile='xyz_tool')
Reference
from typing import Any, MutableMapping, TypedDict, Literal, Sequence
class RpcConfig(TypedDict):
mesc_version: str
default_endpoint: str | None
endpoints: MutableMapping[str, Endpoint]
network_defaults: MutableMapping[str, str]
network_names: MutableMapping[str, str]
profiles: MutableMapping[str, Profile]
global_metadata: MutableMapping[str, Any]
class Endpoint(TypedDict):
name: str
url: str
chain_id: str | None
endpoint_metadata: MutableMapping[str, Any]
class Profile(TypedDict):
name: str
default_endpoint: str | None
network_defaults: MutableMapping[str, str]
Rust MESC Implementation
This is a reference rust implementation of the MESC standard.
The crates/mesc
crate contains rust libraries for reading, writing, and validating MESC configurations.
The crates/mesc_cli
crate is a tool for reading, writing, and validating MESC from the command line. See CLI for details.
Contents
Installation
Inside a cargo project: cargo add mesc
Inside a Cargo.toml
: mesc = "0.2.1"
Example Usage
Basic data structures
#![allow(unused)] fn main() { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct RpcConfig { pub mesc_version: String, pub default_endpoint: Option<String>, pub endpoints: HashMap<String, Endpoint>, pub network_defaults: HashMap<ChainId, String>, pub network_names: HashMap<String, ChainId>, pub profiles: HashMap<String, Profile>, pub global_metadata: HashMap<String, serde_json::Value>, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Endpoint { pub name: String, pub url: String, pub chain_id: Option<ChainId>, pub endpoint_metadata: HashMap<String, serde_json::Value>, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Profile { pub name: String, pub default_endpoint: Option<String>, pub network_defaults: HashMap<ChainId, String>, pub profile_metadata: HashMap<String, serde_json::Value>, pub use_mesc: bool, } #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash)] pub struct ChainId(String); }
Basic read functions
#![allow(unused)] fn main() { use mesc::{MescError, Endpoint}; use std::collections::HashMap; type OptionalResult = Result<Option<Endpoint>, MescError>; type MultiResult = Result<Vec<Endpoint>, MescError>; type MetadataResult = Result<HashMap<String, serde_json::Value>, MescError>; // check whether mesc is enabled let enabled: bool = mesc::is_mesc_enabled(); // get the default endpoint let endpoint: OptionalResult = mesc::get_default_endpoint(None); // get the default endpoint of a network let endpoint: OptionalResult = mesc::get_endpoint_by_network("5", None); // get the default network for a particular tool let chain_id: OptionalResult = mesc::get_default_endpoint(Some("xyz_tool")); // get the default endpoint of a network for a particular tool let endpoint: OptionalResult = mesc::get_endpoint_by_network("5", Some("xyz_tool")); // get an endpoint by name let endpoint: OptionalResult = mesc::get_endpoint_by_name("local_goerli"); // parse a user-provided string into a matching endpoint // (first try 1. endpoint name, then 2. chain id, then 3. network name) let user_str = "local_goerli"; let endpoint: OptionalResult = mesc::get_endpoint_by_query(user_str, Some("xyz_tool")); // find all endpoints matching given criteria let query = mesc::MultiEndpointQuery::new().chain_id("5").unwrap(); let endpoints: MultiResult = mesc::find_endpoints(query); // get non-endpoint metadata let metadata: MetadataResult = mesc::get_global_metadata(Some("xyz_tool")); }
Typescript MESC Implementation
[WIP]