phone-a-friend-mcp-server 0.2.0__py3-none-any.whl → 0.3.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -85,17 +85,18 @@ replacing <file="…"> blocks as needed. Commentary goes outside those tags."""
85
85
  "all_related_context": {
86
86
  "type": "string",
87
87
  "description": (
88
- "MANDATORY. General, non-code context for the friend AI. "
89
- "Include known constraints (Python version, allowed deps, etc.), "
90
- "failing test output, or tracebacks. DO NOT include file contents here."
88
+ "General context for the friend AI. Include known constraints "
89
+ "(Python version, allowed deps, etc.), failing test output, tracebacks, "
90
+ "or code snippets for reference. For complete files, use file_list instead."
91
91
  ),
92
92
  },
93
93
  "file_list": {
94
94
  "type": "array",
95
95
  "items": {"type": "string"},
96
96
  "description": (
97
- "MANDATORY. A list of file paths or glob patterns to be included in the code context. "
98
- "The tool will automatically read these files, filter them against .gitignore, and build the context."
97
+ "Optional but recommended. A list of file paths or glob patterns to be included in the code context. "
98
+ "The tool will automatically read these files, filter them against .gitignore, and build the context. "
99
+ "Better and faster than including complete files in all_related_context."
99
100
  ),
100
101
  },
101
102
  "task": {
@@ -119,7 +120,7 @@ replacing <file="…"> blocks as needed. Commentary goes outside those tags."""
119
120
  ),
120
121
  },
121
122
  },
122
- "required": ["all_related_context", "file_list", "task", "output_directory"],
123
+ "required": ["all_related_context", "task", "output_directory"],
123
124
  }
124
125
 
125
126
  async def run(self, **kwargs) -> dict[str, Any]:
@@ -87,17 +87,18 @@ replacing <file="…"> blocks as needed. Commentary goes outside those tags."""
87
87
  "all_related_context": {
88
88
  "type": "string",
89
89
  "description": (
90
- "MANDATORY. General, non-code context for the friend AI. "
91
- "Include known constraints (Python version, allowed deps, etc.), "
92
- "failing test output, or tracebacks. DO NOT include file contents here."
90
+ "General context for the friend AI. Include known constraints "
91
+ "(Python version, allowed deps, etc.), failing test output, tracebacks, "
92
+ "or code snippets for reference. For complete files, use file_list instead."
93
93
  ),
94
94
  },
95
95
  "file_list": {
96
96
  "type": "array",
97
97
  "items": {"type": "string"},
98
98
  "description": (
99
- "MANDATORY. A list of file paths or glob patterns to be included in the code context. "
100
- "The tool will automatically read these files, filter them against .gitignore, and build the context."
99
+ "Optional but recommended. A list of file paths or glob patterns to be included in the code context. "
100
+ "The tool will automatically read these files, filter them against .gitignore, and build the context. "
101
+ "Better and faster than including complete files in all_related_context."
101
102
  ),
102
103
  },
103
104
  "task": {
@@ -112,7 +113,7 @@ replacing <file="…"> blocks as needed. Commentary goes outside those tags."""
112
113
  ),
113
114
  },
114
115
  },
115
- "required": ["all_related_context", "file_list", "task"],
116
+ "required": ["all_related_context", "task"],
116
117
  }
117
118
 
118
119
  async def run(self, **kwargs) -> dict[str, Any]:
@@ -14,6 +14,20 @@ def load_gitignore(base_dir: str) -> pathspec.PathSpec:
14
14
  return pathspec.PathSpec.from_lines("gitwildmatch", patterns)
15
15
 
16
16
 
17
+ def get_all_project_files(base_dir: str = ".") -> list[str]:
18
+ """Get all files in the project directory recursively."""
19
+ all_files = []
20
+ for root, dirs, files in os.walk(base_dir):
21
+ # Skip hidden directories like .git, .venv, etc.
22
+ dirs[:] = [d for d in dirs if not d.startswith('.')]
23
+
24
+ for file in files:
25
+ if not file.startswith('.'): # Skip hidden files
26
+ rel_path = os.path.relpath(os.path.join(root, file), base_dir)
27
+ all_files.append(rel_path)
28
+ return sorted(all_files)
29
+
30
+
17
31
  def filter_paths(paths: list[str], spec: pathspec.PathSpec, base_dir: str = ".") -> list[str]:
18
32
  """Filters out paths that match the .gitignore spec and non-text files."""
19
33
  filtered_paths = []
@@ -76,18 +90,25 @@ def build_code_context(file_list: list[str], base_dir: str = ".") -> str:
76
90
  """
77
91
  spec = load_gitignore(base_dir)
78
92
 
79
- all_files = []
80
- for pattern in file_list:
81
- all_files.extend(glob.glob(pattern, recursive=True))
82
-
83
- unique_files = sorted(list(set(all_files)))
84
-
85
- filtered_files = filter_paths(unique_files, spec, base_dir)
86
-
87
- if not filtered_files:
88
- return "No files to display. Check your `file_list` and `.gitignore`."
89
-
90
- file_tree = build_file_tree(filtered_files, base_dir)
91
- file_blocks = build_file_blocks(filtered_files, base_dir)
92
-
93
- return f"<file_tree>\n{file_tree}\n</file_tree>\n\n{file_blocks}"
93
+ # Get complete project tree (like tree --gitignore)
94
+ all_project_files = get_all_project_files(base_dir)
95
+ filtered_all_files = filter_paths(all_project_files, spec, base_dir)
96
+ complete_tree = build_file_tree(filtered_all_files, base_dir)
97
+
98
+ # Handle selected files from file_list
99
+ if file_list:
100
+ selected_files = []
101
+ for pattern in file_list:
102
+ selected_files.extend(glob.glob(pattern, recursive=True))
103
+
104
+ unique_selected_files = sorted(list(set(selected_files)))
105
+ filtered_selected_files = filter_paths(unique_selected_files, spec, base_dir)
106
+
107
+ if filtered_selected_files:
108
+ file_blocks = build_file_blocks(filtered_selected_files, base_dir)
109
+ return f"<file_tree>\n{complete_tree}\n</file_tree>\n\n{file_blocks}"
110
+ else:
111
+ return f"<file_tree>\n{complete_tree}\n</file_tree>\n\nNo files to display from file_list. Check your patterns and .gitignore."
112
+ else:
113
+ # No file_list provided, just show the tree
114
+ return f"<file_tree>\n{complete_tree}\n</file_tree>\n\nNo specific files selected. Use file_list parameter to include file contents."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phone-a-friend-mcp-server
3
- Version: 0.2.0
3
+ Version: 0.3.0rc1
4
4
  Summary: MCP Server for Phone-a-Friend assistance
5
5
  Project-URL: GitHub, https://github.com/abhishekbhakat/phone-a-friend-mcp-server
6
6
  Project-URL: Issues, https://github.com/abhishekbhakat/phone-a-friend-mcp-server/issues
@@ -47,7 +47,7 @@ This enables AI systems to leverage other AI models as "consultants" for complex
47
47
  ## Architecture 🏗️
48
48
 
49
49
  ```
50
- Primary AI → Phone-a-Friend MCP → OpenRouter → External AI (GPT-4, Claude, etc.) → Processed Response → Primary AI
50
+ Primary AI → Phone-a-Friend MCP → OpenRouter → External AI (O3, Claude, etc.) → Processed Response → Primary AI
51
51
  ```
52
52
 
53
53
  **Sequential Workflow:**
@@ -71,22 +71,21 @@ The `uv` runner will automatically download and execute the server package if it
71
71
 
72
72
  Add the following JSON configuration to your MCP client and replace `<YOUR_API_KEY>` with your key:
73
73
 
74
- ```json
75
- {
76
- "mcpServers": {
77
- "phone-a-friend": {
78
- "command": "uv",
79
- "args": [
80
- "run",
81
- "phone-a-friend-mcp-server",
82
- "--provider", "openai",
83
- "--api-key", "<YOUR_API_KEY>"
84
- ]
85
- }
86
- }
74
+ ```json
75
+ {
76
+ "mcpServers": {
77
+ "phone-a-friend": {
78
+ "command": "uvx",
79
+ "args": [
80
+ "phone-a-friend-mcp-server",
81
+ "--provider", "openai",
82
+ "--api-key", "<YOUR_API_KEY>"
83
+ ]
87
84
  }
88
- ```
89
- > That's it! You can now use the `phone_a_friend` tool in any compatible client. For more options, see the Advanced Configuration section.
85
+ }
86
+ }
87
+ ```
88
+ > That's it! You can now use the `phone_a_friend` tool in any compatible client. For more options, see the Advanced Configuration section.
90
89
 
91
90
  ## Available Tools 🛠️
92
91
 
@@ -150,12 +149,12 @@ You can override the default model for each provider.
150
149
 
151
150
  **Override with CLI:**
152
151
  ```bash
153
- phone-a-friend-mcp-server --model "gpt-4-turbo"
152
+ phone-a-friend-mcp-server --model "o3"
154
153
  ```
155
154
 
156
155
  **Override with Environment Variable:**
157
156
  ```bash
158
- export PHONE_A_FRIEND_MODEL="gpt-4-turbo"
157
+ export PHONE_A_FRIEND_MODEL="o3"
159
158
  ```
160
159
 
161
160
  ### Additional Options
@@ -5,13 +5,13 @@ phone_a_friend_mcp_server/server.py,sha256=z-O20j-j2oHFfFK8o0u9kn-MR8Q-Te0lRZOQf
5
5
  phone_a_friend_mcp_server/client/__init__.py,sha256=fsa8DXjz4rzYXmOUAdLdTpTwPSlZ3zobmBGXqnCEaWs,47
6
6
  phone_a_friend_mcp_server/tools/__init__.py,sha256=jtuvmcStXzbaM8wuhOKC8M8mBqDjHr-ypZ2ct1Rgi7Q,46
7
7
  phone_a_friend_mcp_server/tools/base_tools.py,sha256=DMjFq0E3TO9a9I7QY4wQ_B4-SntdXzSZzrYymFzSmVE,765
8
- phone_a_friend_mcp_server/tools/fax_tool.py,sha256=esQwxt-j69CiBRQHaVVShRbwEHdcvAppwO1uBD6UCQs,8836
9
- phone_a_friend_mcp_server/tools/phone_tool.py,sha256=4OLRGThNQO8aAFWL8Bz5J40RPKqDqSZuGXpJc0oRL94,8396
8
+ phone_a_friend_mcp_server/tools/fax_tool.py,sha256=muihVHXqLrP-H5TU8Ns2Civ_EOay_wuZO7y2Pcge5n8,8953
9
+ phone_a_friend_mcp_server/tools/phone_tool.py,sha256=X8MGkTxqAbo7RlaEYBdqGvfVVxhrbZ75RNnRwN_QK-s,8513
10
10
  phone_a_friend_mcp_server/tools/tool_manager.py,sha256=VVtENC-n3D4GV6Cy3l9--30SJi06mJdyEiG7F_mfP7I,1474
11
11
  phone_a_friend_mcp_server/utils/__init__.py,sha256=1IwFDtwJ76i1O7_iM4LLGqwgtt11y0PIV0DWubh8nLU,58
12
- phone_a_friend_mcp_server/utils/context_builder.py,sha256=bw3FwnRg1WQsXjxyKPwLpqrTObPkmQnZ_MtBzaz6WnM,3398
13
- phone_a_friend_mcp_server-0.2.0.dist-info/METADATA,sha256=wMrRoQMFcWN8DZoHDV1eqHKmsCziQxy3H7dsxIccepY,6126
14
- phone_a_friend_mcp_server-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- phone_a_friend_mcp_server-0.2.0.dist-info/entry_points.txt,sha256=c_08XI-vG07VmUT3mtzyuCQjaus5l1NBl4q00Q3jLug,86
16
- phone_a_friend_mcp_server-0.2.0.dist-info/licenses/LICENSE,sha256=-8bInetillKZC0qZDT8RWYIOrph3HIU5cr5N4Pg7bBE,1065
17
- phone_a_friend_mcp_server-0.2.0.dist-info/RECORD,,
12
+ phone_a_friend_mcp_server/utils/context_builder.py,sha256=Fc1ej3disKnCrHbyYUInkHygOUr93izOyhFz3reP5gE,4580
13
+ phone_a_friend_mcp_server-0.3.0rc1.dist-info/METADATA,sha256=9i3VyjgZbDWTFOAhDocfSMIiAZCQG2Ec_uB_YCsTxts,6030
14
+ phone_a_friend_mcp_server-0.3.0rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ phone_a_friend_mcp_server-0.3.0rc1.dist-info/entry_points.txt,sha256=c_08XI-vG07VmUT3mtzyuCQjaus5l1NBl4q00Q3jLug,86
16
+ phone_a_friend_mcp_server-0.3.0rc1.dist-info/licenses/LICENSE,sha256=-8bInetillKZC0qZDT8RWYIOrph3HIU5cr5N4Pg7bBE,1065
17
+ phone_a_friend_mcp_server-0.3.0rc1.dist-info/RECORD,,