Skip to content

Commit 01c1f62

Browse files
committed
test: add MCP server test suite
1 parent 3afc0be commit 01c1f62

File tree

3 files changed

+275
-0
lines changed

3 files changed

+275
-0
lines changed

mcp-server/LICENSE

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
MIT License
2+
3+
Copyright (c) 2024 LTB Lightning
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+
23+
---
24+
25+
Apache License
26+
Version 2.0, January 2004
27+
28+
http://www.apache.org/licenses/
29+
30+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
31+
32+
1. Definitions.
33+
34+
"License" shall mean the terms and conditions for use, reproduction,
35+
and distribution as defined in Sections 1 through 9 of this document.
36+
37+
"Licensor" shall mean the copyright owner or entity authorized by
38+
the copyright owner that is granting the License.
39+
40+
"Legal Entity" shall mean the union of the acting entity and all
41+
other entities that control, are controlled by, or are under common
42+
control with that entity. For the purposes of this definition,
43+
"control" means the power, direct or indirect, to cause the
44+
direction or management of such entity, whether by contract or
45+
otherwise, or the ownership of fifty percent (50%) or more of the
46+
outstanding shares, or the beneficial ownership of such entity.
47+
48+
"You" (or "Your") shall mean an individual or Legal Entity exercising
49+
permissions granted by this License.
50+
51+
"Source" form shall mean the preferred form for making modifications,
52+
including but not limited to software source code, documentation
53+
source, and configuration files.
54+
55+
"Object" form shall mean any form resulting from mechanical
56+
transformation or translation of a Source form, including but
57+
not limited to compiled object code, generated documentation,
58+
and conversions to other media types.
59+
60+
"Work" shall mean the work of authorship, whether in Source or Object
61+
form, made available under the License, including but not limited to
62+
the files, modifications to each file, and any additional files that
63+
are incorporated in or with the work.
64+
65+
"Derivative Works" shall mean any work, whether in Source or Object
66+
form, that is based on (or derived from) the Work and for which the
67+
editorial revisions, annotations, elaborations, or other modifications
68+
represent, as a whole, an original work of authorship.
69+
70+
"Contribution" shall mean any work of authorship, including
71+
the original Work and any Derivative Works thereof, that is
72+
intentionally submitted to, or received by, Licensor for inclusion
73+
in the Work by the copyright owner or by an individual or Legal
74+
Entity authorized to submit on behalf of the copyright owner.
75+
76+
"Contributor" shall mean Licensor and any individual or Legal Entity
77+
on behalf of whom a Contribution has been received by Licensor and
78+
subsequently incorporated within the Work.
79+
80+
2. Grant of Copyright License. Subject to the terms and conditions of
81+
this License, each Contributor hereby grants to You a perpetual,
82+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
83+
copyright license to reproduce, prepare Derivative Works of,
84+
publicly display, publicly perform, sublicense, and distribute the
85+
Work and such Derivative Works in Source or Object form.
86+
87+
3. Grant of Patent License. Subject to the terms and conditions of
88+
this License, each Contributor hereby grants to You a perpetual,
89+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
90+
(except as stated in this section) patent license to make, have made,
91+
use, offer to sell, sell, import, and otherwise transfer the Work,
92+
where such license applies only to those patent claims licensable
93+
by such Contributor that are necessarily infringed by their
94+
Contribution(s) alone or by combination of their Contribution(s)
95+
with the Work to which such Contribution(s) was submitted.
96+
97+
4. Redistribution. You may reproduce and distribute copies of the
98+
Work or Derivative Works thereof in any medium, with or without
99+
modifications, and in Source or Object form, provided that You
100+
meet the following conditions:
101+
102+
(a) You must give any other recipients of the Work or
103+
Derivative Works a copy of this License; and
104+
105+
(b) You must cause any modified files to carry prominent notices
106+
stating that You changed the files; and
107+
108+
(c) You must retain, in the Source form of any Derivative Works
109+
that You distribute, all copyright, patent, trademark, and
110+
attribution notices from the Source form of the Work,
111+
excluding those notices that do not pertain to any part of
112+
the Derivative Works; and
113+
114+
(d) If the Work includes a "NOTICE" text file, then any
115+
Derivative Works that You distribute must include a readable
116+
copy of the attribution notices contained
117+
within such NOTICE file, excluding those notices that do not
118+
pertain to any part of the Derivative Works, in at least one
119+
of the following places: within a NOTICE text file distributed
120+
as part of the Derivative Works; within the Source form or
121+
documentation, if provided along with the Derivative Works; or,
122+
within a display generated by the Derivative Works, if and
123+
wherever such third-party notices normally appear.
124+
125+
5. Submission of Contributions. Unless You explicitly state otherwise,
126+
any Contribution intentionally submitted for inclusion in the Work
127+
by You to Licensor shall be under the terms and conditions of
128+
this License, without any additional terms or conditions.
129+
130+
6. Trademarks. This License does not grant permission to use the trade
131+
names, trademarks, service marks, or product names of the Licensor,
132+
except as required for reasonable and customary use in describing the
133+
origin of the Work and reproducing the content of the NOTICE file.
134+
135+
7. Disclaimer of Warranty. Unless required by applicable law or
136+
agreed to in writing, Licensor provides the Work (and each
137+
Contributor provides its Contributions) on an "AS IS" BASIS,
138+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
139+
implied, including, without limitation, any warranties or conditions
140+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
141+
PARTICULAR PURPOSE.
142+
143+
8. Limitation of Liability. In no event and under no legal theory,
144+
whether in tort (including negligence), contract, or otherwise,
145+
unless required by applicable law (such as deliberate and grossly
146+
negligent acts) or agreed to in writing, shall any Contributor be
147+
liable to You for damages, including any direct, indirect, special,
148+
incidental, or consequential damages of any character arising as a
149+
result of this License or out of the use or inability to use the
150+
Work (including but not limited to damages for loss of goodwill,
151+
work stoppage, computer failure or malfunction, or any and all
152+
other commercial damages or losses), even if such Contributor
153+
has been advised of the possibility of such damages.
154+
155+
9. Accepting Warranty or Additional Liability. While redistributing
156+
the Work or Derivative Works thereof, You may choose to offer,
157+
and charge a fee for, acceptance of support, warranty, indemnity,
158+
or other liability obligations and/or rights consistent with this
159+
License. However, in accepting such obligations, You may act only
160+
on Your own behalf and on Your sole responsibility, not on behalf
161+
of any other Contributor, and only if You agree to indemnify,
162+
defend, and hold each Contributor harmless for any liability
163+
incurred by, or claims asserted against, such Contributor by reason
164+
of your accepting any such warranty or additional liability.
165+
166+
END OF TERMS AND CONDITIONS

mcp-server/tests/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""Test configuration."""
2+
3+
import sys
4+
from pathlib import Path
5+
6+
# Add the src directory to the path
7+
src_path = Path(__file__).parent.parent / "src"
8+
sys.path.insert(0, str(src_path))

mcp-server/tests/test_server.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""Tests for the ldk_node MCP server."""
2+
3+
import pytest
4+
from pathlib import Path
5+
from ldk_node_mcp.server import LdkNodeMcpServer, PACKAGE_ROOT
6+
7+
8+
def test_package_root_exists():
9+
"""Test that PACKAGE_ROOT points to the correct directory."""
10+
assert PACKAGE_ROOT.exists()
11+
assert (PACKAGE_ROOT / "AGENTS.md").exists()
12+
assert (PACKAGE_ROOT / "examples" / "ai-ready").exists()
13+
14+
15+
def test_server_initialization():
16+
"""Test that the server can be initialized."""
17+
server = LdkNodeMcpServer()
18+
assert server.server is not None
19+
assert server.server.name == "ldk-node-flutter"
20+
21+
22+
@pytest.mark.asyncio
23+
async def test_validate_code_async_await():
24+
"""Test code validation catches missing await."""
25+
server = LdkNodeMcpServer()
26+
27+
bad_code = """
28+
final node = await builder.build();
29+
node.start(); // Missing await!
30+
"""
31+
32+
result = await server._validate_code(bad_code)
33+
assert len(result) > 0
34+
assert "await" in result[0].text.lower()
35+
36+
37+
@pytest.mark.asyncio
38+
async def test_validate_code_old_api():
39+
"""Test code validation catches old API usage."""
40+
server = LdkNodeMcpServer()
41+
42+
bad_code = """
43+
final bolt11 = await node.bolt11Payment();
44+
await bolt11.receive(amountMsat: amount); // Should be receiveUnsafe
45+
"""
46+
47+
result = await server._validate_code(bad_code)
48+
assert len(result) > 0
49+
assert "Unsafe" in result[0].text or "receiveUnsafe" in result[0].text
50+
51+
52+
@pytest.mark.asyncio
53+
async def test_validate_code_secure_storage():
54+
"""Test code validation catches insecure mnemonic storage."""
55+
server = LdkNodeMcpServer()
56+
57+
bad_code = """
58+
SharedPreferences prefs = await SharedPreferences.getInstance();
59+
prefs.setString('mnemonic', mnemonic.seedPhrase); // INSECURE!
60+
"""
61+
62+
result = await server._validate_code(bad_code)
63+
assert len(result) > 0
64+
text = result[0].text.lower()
65+
assert "never" in text or "secure" in text or "sharedpreferences" in text
66+
67+
68+
@pytest.mark.asyncio
69+
async def test_get_code_example():
70+
"""Test getting code examples."""
71+
server = LdkNodeMcpServer()
72+
73+
result = await server._get_code_example("initialize_node", True)
74+
assert len(result) > 0
75+
assert "Builder" in result[0].text
76+
assert "start()" in result[0].text
77+
78+
79+
@pytest.mark.asyncio
80+
async def test_get_setup_guide():
81+
"""Test getting setup guides for different networks."""
82+
server = LdkNodeMcpServer()
83+
84+
for network in ["testnet", "mutinynet", "mainnet"]:
85+
result = await server._get_setup_guide(network)
86+
assert len(result) > 0
87+
assert network.title() in result[0].text or network.upper() in result[0].text
88+
89+
90+
def test_api_reference_generation():
91+
"""Test API reference generation."""
92+
server = LdkNodeMcpServer()
93+
api_ref = server._generate_api_reference()
94+
95+
assert "version" in api_ref
96+
assert api_ref["version"] == "0.7.0"
97+
assert "core_apis" in api_ref
98+
assert "Node" in api_ref["core_apis"]
99+
assert "Builder" in api_ref["core_apis"]
100+
assert "Bolt11Payment" in api_ref["core_apis"]
101+
assert "critical_notes" in api_ref

0 commit comments

Comments
 (0)