Skip to content

Commit e7c24f0

Browse files
authored
feat: REPO.md for LLM
1 parent e420eb5 commit e7c24f0

1 file changed

Lines changed: 133 additions & 0 deletions

File tree

REPO.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
## Overview
2+
3+
`deepset-mcp-server` provides an API SDK and MCP (model context protocol) tools to interact with the deepset API.
4+
deepset is an AI platform that allows users to develop and deploy AI applications.
5+
All applications are defined as Haystack pipelines.
6+
Haystack is an Open Source Python framework for AI application building.
7+
8+
## Project Structure
9+
10+
All source code is in `src/deepset_mcp`.
11+
Code for the API SDK is in `src/deepset_mcp/api`.
12+
Code for tools is in `src/deepset_mcp/tools`.
13+
The tools are added to an MCP server which is defined in main.py
14+
15+
Tests are in the `test` directory.
16+
All unit tests go into `test/unit`, integration tests go into `test/integration`.
17+
18+
We use uv to manage the project.
19+
All project level configurations are defined in `pyproject.toml` at the root of the repository.
20+
21+
### API SDK structure
22+
23+
The API SDK is 'async first'.
24+
All API interactions run through a common facade called `AsyncDeepsetClient`.
25+
The client exposes resources that in turn expose methods to interact with these resources through the deepset API.
26+
27+
As an example, to fetch a specific pipeline a user might do:
28+
29+
```python
30+
from deepset_mcp.api.client import AsyncDeepsetClient
31+
32+
async with AsyncDeepsetClient() as client:
33+
response = await client.pipelines(workspace="some_workspace").get("my_pipeline")
34+
35+
```
36+
37+
### Tool Structure
38+
39+
Tools are meant to be used by large language models. Therefore, the output of a tool should always be a string.
40+
Known exceptions should usually be caught and converted to strings as well.
41+
Typically, we have one tool file per resource.
42+
A tool can make multiple calls to different resources or different methods on the same resource to produce the desired output.
43+
Most tools are imported into `src/deepset_mcp/main.py` where they are added to the MCP server.
44+
45+
46+
## Instructions for common tasks
47+
48+
### Task: Adding a new resource
49+
50+
Let's assume we want to add a `PipelineFeedbackResource`.
51+
You would need to make the following changes:
52+
53+
1. add a package for the resource at `src/deepset_mcp/api/pipeline_feedback`
54+
2. the resource goes into `src/deepset_mcp/api/pipeline_feedback/resource.py`
55+
3. (optional) if you need to define models for API response they would go into `src/deepset_mcp/api/pipeline_feedback/models.py`
56+
4. add a Protocol for the resource in `src/deepset_mcp/api/protocols.py`
57+
5. add the resource to the AsyncClientProtocol in the same file (depending on the resource you need client and workspace or just client)
58+
6. add a method for the resource to the `AsyncDeepsetClient` in `src/deepset_mcp/api/client.py`
59+
60+
#### Testing the resource
61+
Each resource gets unit and integration tests for all methods.
62+
63+
1. first add a stub for the resource to the `BaseFakeClient` in `test/unit/conftest.py`
64+
2. create a directory for the unit tests in `test/unit/api/` (i.e. `test/unit/api/pipeline_feedback`)
65+
3. we use pytest for all unit tests
66+
4. import the `BaseFakeClient` from `test/unit/conftest.py`
67+
5. Overwrite the `pipeline_feedback`-method on the client so that it returns your actual `PipelineFeedbackResource`
68+
6. Add fake responses to the client according to what you want to test
69+
7. Create comprehensive unit tests
70+
8. all tests must have complete type hints including return types
71+
9. `test/unit/api/haystack_service/test_haystack_service_resource.py` has a good example of how to structure unit tests for a resource
72+
73+
10. integration tests go into `test/integration`
74+
11. create an integration test file at `test/integration/test_integration_pipeline_feedback_resource.py`
75+
12. `test/integration/test_integration_haystack_service_resource.py` has a good example for how integration tests may look like
76+
13. don't add too many integration tests, they are mostly a sanity check, the bulk of the testing should be written as unit tests
77+
78+
### Task: Adding a new tool
79+
80+
Let's assume we want to add a `fetch_pipeline_resource`-tool that will use our newly added resource.
81+
You would need to perform the following steps:
82+
83+
1. the tool would go into `src/deepset_mcp/tools/pipeline_feedback.py`
84+
2. the client will ALWAYS be passed to the tool as a dependency injection (type: `AsyncClientProtocol`)
85+
3. the tool should call the methods on the resource through the client
86+
4. refer to `src/deepset_mcp/tools/pipeline.py` as a good example for tool implementations
87+
5. extract model or response serialization into reusable helper functions
88+
6. once you added a tool, import it in `src/deepset_mcp/main.py`
89+
7. add a corresponding mcp tool using the `@mcp.tool`-decorator
90+
8. the docstring of the tool will serve as the prompt for the large language model calling the tool, make sure it has good instructions on when to use the tool, how to best use it, and what kind of answer to expect.
91+
92+
#### Testing the tool
93+
94+
We ONLY add unit tests for the tool. The mcp integration will not have tests.
95+
96+
1. the tool tests will go into `test/unit/tools` (i.e. `test/unit/tools/test_pipeline_feedback.py`)
97+
2. use a FakeResource to test the tool
98+
3. import the `BaseFakeClient` and overwrite the resource method to return your fake resource
99+
4. `test/unit/tools/test_pipeline.py` has a good example for how to test a tool
100+
101+
102+
## Code Style Guidelines
103+
104+
- Our code is clean and maintainable
105+
- Pay attention to great code structure and optimize for readability
106+
- We use mypy (strict) and ruff for type checking and linting
107+
- Docstrings MUST follow the reStructuredText style (this is a new change and many docstrings follow a different style)
108+
Example:
109+
```python
110+
def foo(arg1: Type1, arg2: Type2) -> ReturnType:
111+
"""Returns the result of fooing ``arg1`` with ``arg2``.
112+
113+
:param arg1: A good argument.
114+
:param arg2: Another good argument.
115+
116+
:returns: Some nifty thing or other.
117+
"""
118+
```
119+
- We use Python 3.12
120+
- We use many modern code constructs throughout the code base (Protocols, Generics, Dependency Injection)
121+
- Generally follow the coding style that you are already observing throughout the code base
122+
123+
124+
## Contributions
125+
126+
- keep changes minimal and only implement what was requested in the issue
127+
- all changes need to be tested according to our testing guidelines
128+
- use clear commit messages following the conventional commits style
129+
- we typically make changes in relatively small PRs (e.g. 1 PR for adding a resource and another PR for adding the tools)
130+
- use docstrings, add comments only where needed, follow our code style guidelines
131+
- be kind!
132+
133+

0 commit comments

Comments
 (0)